kernel/fs/vfs_v2/
syscall.rs

1//! VFS v2 System Call Interface
2//!
3//! This module implements system call handlers for VFS v2, providing the user-space
4//! interface to filesystem operations. All system calls follow capability-based
5//! semantics and work with the task's VFS namespace.
6//!
7//! ## Supported System Calls
8//!
9//! ### VFS Operations (400-series)
10//! - `sys_vfs_open()`: Open files and directories (VfsOpen 400)
11//! - `sys_vfs_remove()`: Unified remove for files/directories (VfsRemove 401)
12//! - `sys_vfs_create_file()`: Create regular files (VfsCreateFile 402)
13//! - `sys_vfs_create_directory()`: Create directories (VfsCreateDirectory 403)
14//! - `sys_vfs_change_directory()`: Change working directory (VfsChangeDirectory 404)
15//! - `sys_vfs_truncate()`: Truncate files by path (VfsTruncate 405)
16//!
17//! ### Filesystem Operations (500-series)
18//! - `sys_fs_mount()`: Mount filesystems (FsMount 500)
19//! - `sys_fs_umount()`: Unmount filesystems (FsUmount 501)
20//! - `sys_fs_pivot_root()`: Change root filesystem (FsPivotRoot 502)
21//!
22//! ### Utility Operations
23//! - (deprecated - use VfsCreateFile 402 instead)
24//!
25//! ## VFS Namespace Isolation
26//!
27//! Each task can have its own VFS namespace (Option<Arc<VfsManager>>).
28//! System calls operate within the task's namespace, enabling containerization
29//! and process isolation.
30//!
31//! ## Error Handling
32//!
33//! System calls return usize::MAX (-1) on error and appropriate values on success.
34//! 
35
36use alloc::{string::String, vec::Vec, string::ToString, sync::Arc};
37
38use crate::{arch::Trapframe, fs::FileType, library::std::string::cstring_to_string, task::mytask};
39
40use crate::fs::{VfsManager, MAX_PATH_LENGTH};
41
42/// Open a file or directory using VFS (VfsOpen)
43/// 
44/// This system call opens a file or directory at the specified path using the VFS layer.
45/// 
46/// # Arguments
47/// 
48/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
49/// * `trapframe.get_arg(1)` - Open flags (O_RDONLY, O_WRONLY, O_RDWR, etc.)
50/// * `trapframe.get_arg(2)` - File mode for creation (if applicable)
51/// 
52/// # Returns
53/// 
54/// * Handle number on success
55/// * `usize::MAX` on error (file not found, permission denied, etc.)
56pub fn sys_vfs_open(trapframe: &mut Trapframe) -> usize {
57    let task = mytask().unwrap();
58    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
59    let _flags = trapframe.get_arg(1) as i32;
60    let _mode = trapframe.get_arg(2) as i32;
61
62    // Increment PC to avoid infinite loop if open fails
63    trapframe.increment_pc_next(task);
64
65    // Parse path as a null-terminated C string
66    let mut path_bytes = Vec::new();
67    let mut i = 0;
68    unsafe {
69        loop {
70            let byte = *path_ptr.add(i);
71            if byte == 0 {
72                break;
73            }
74            path_bytes.push(byte);
75            i += 1;
76
77            if i > MAX_PATH_LENGTH {
78                return usize::MAX; // Path too long
79            }
80        }
81    }
82
83    // Convert path bytes to string
84    let path_str = match str::from_utf8(&path_bytes) {
85        Ok(s) => match to_absolute_path_v2(&task, s) {
86            Ok(abs) => abs,
87            Err(_) => return usize::MAX,
88        },
89        Err(_) => return usize::MAX, // Invalid UTF-8
90    };
91
92    // Try to open the file using VFS
93    let vfs = match task.get_vfs() {
94        Some(vfs) => vfs,
95        None => return usize::MAX, // VFS not initialized
96    };
97    let file_obj = vfs.open(&path_str, 0);
98    match file_obj {
99        Ok(kernel_obj) => {
100            // Use simplified handle role classification
101            use crate::object::handle::{HandleMetadata, HandleType, AccessMode};
102            
103            // For now, all opened files are classified as Regular usage
104            // Future enhancements could infer specific roles based on path patterns,
105            // but keeping it simple with the 3-category system: IpcChannel, StandardInputOutput, Regular
106            let handle_type = HandleType::Regular;
107            
108            // Infer access mode from flags (simplified - full implementation would parse all open flags)
109            let access_mode = if _flags & 0x1 != 0 { // O_WRONLY-like
110                AccessMode::WriteOnly
111            } else if _flags & 0x2 != 0 { // O_RDWR-like
112                AccessMode::ReadWrite
113            } else {
114                AccessMode::ReadOnly // Default
115            };
116            
117            let metadata = HandleMetadata {
118                handle_type,
119                access_mode,
120                special_semantics: None, // Could be inferred from flags like O_CLOEXEC
121            };
122            
123            let handle = task.handle_table.insert_with_metadata(kernel_obj, metadata);
124            match handle {
125                Ok(handle) => handle as usize,
126                Err(_) => usize::MAX, // Handle table full
127            }
128        }
129        Err(_) => usize::MAX, // File open error
130    }
131}
132
133
134
135/// Truncate a file by path (VfsTruncate)
136/// 
137/// This system call truncates a file at the specified path to the given length.
138/// 
139/// # Arguments
140/// 
141/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
142/// * `trapframe.get_arg(1)` - New length for the file
143/// 
144/// # Returns
145/// 
146/// * `0` on success
147/// * `usize::MAX` on error (file not found, permission denied, etc.)
148pub fn sys_vfs_truncate(trapframe: &mut Trapframe) -> usize {
149    let task = mytask().unwrap();
150    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
151    let length = trapframe.get_arg(1) as u64;
152    
153    trapframe.increment_pc_next(task);
154
155    // Convert path bytes to string
156    let path_str: String = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
157        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
158            Ok(abs_path) => abs_path,
159            Err(_) => return usize::MAX,
160        },
161        Err(_) => return usize::MAX, // Invalid UTF-8
162    };
163    
164    let vfs = match task.vfs.as_ref() {
165        Some(vfs) => vfs,
166        None => return usize::MAX, // VFS not initialized
167    };
168
169    let file_obj = match vfs.open(&path_str, 0) {
170        Ok(obj) => obj,
171        Err(_) => return usize::MAX,
172    };
173    let file = match file_obj.as_file() {
174        Some(f) => f,
175        None => return usize::MAX,
176    };
177    match file.truncate(length) {
178        Ok(_) => 0,
179        Err(_) => usize::MAX, // -1
180    }
181}
182
183/// Create a regular file using VFS (VfsCreateFile)
184/// 
185/// This system call creates a new regular file at the specified path using the VFS layer.
186/// 
187/// # Arguments
188/// 
189/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
190/// * `trapframe.get_arg(1)` - File mode (reserved for future use)
191/// 
192/// # Returns
193/// 
194/// * `0` on success
195/// * `usize::MAX` on error (path already exists, permission denied, etc.)
196pub fn sys_vfs_create_file(trapframe: &mut Trapframe) -> usize {
197    let task = mytask().unwrap();
198    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
199    let _mode = trapframe.get_arg(1) as i32;
200
201    trapframe.increment_pc_next(task);
202
203    // Convert path bytes to string
204    let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
205        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
206            Ok(abs_path) => abs_path,
207            Err(_) => return usize::MAX,
208        },
209        Err(_) => return usize::MAX, // Invalid UTF-8
210    };
211    
212    let vfs = match task.vfs.as_ref() {
213        Some(vfs) => vfs,
214        None => return usize::MAX, // VFS not initialized
215    };
216
217    match vfs.create_file(&path_str, FileType::RegularFile) {
218        Ok(_) => 0,
219        Err(_) => usize::MAX, // -1
220    }
221}
222
223/// Create a directory using VFS (VfsCreateDirectory)
224/// 
225/// This system call creates a new directory at the specified path using the VFS layer.
226/// 
227/// # Arguments
228/// 
229/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
230/// 
231/// # Returns
232/// 
233/// * `0` on success
234/// * `usize::MAX` on error (path already exists, permission denied, etc.)
235pub fn sys_vfs_create_directory(trapframe: &mut Trapframe) -> usize {
236    let task = mytask().unwrap();
237    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
238    
239    trapframe.increment_pc_next(task);
240
241    // Convert path bytes to string
242    let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
243        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
244            Ok(abs_path) => abs_path,
245            Err(_) => return usize::MAX,
246        },
247        Err(_) => return usize::MAX, // Invalid UTF-8
248    };
249    
250    let vfs = match task.vfs.as_ref() {
251        Some(vfs) => vfs,
252        None => return usize::MAX, // VFS not initialized
253    };
254    
255    match vfs.create_dir(&path_str) {
256        Ok(_) => 0,
257        Err(_) => usize::MAX, // -1
258    }
259}
260
261/// Mount a filesystem (FsMount)
262/// 
263/// This system call mounts a filesystem at the specified target path.
264/// 
265/// # Arguments
266/// 
267/// * `trapframe.get_arg(0)` - Pointer to source path (device/filesystem)
268/// * `trapframe.get_arg(1)` - Pointer to target mount point path
269/// * `trapframe.get_arg(2)` - Pointer to filesystem type string
270/// * `trapframe.get_arg(3)` - Mount flags
271/// * `trapframe.get_arg(4)` - Pointer to mount data/options
272/// 
273/// # Returns
274/// 
275/// * `0` on success
276/// * `usize::MAX` on error (invalid path, filesystem not supported, etc.)
277pub fn sys_fs_mount(trapframe: &mut Trapframe) -> usize {
278    let task = mytask().unwrap();
279    let source_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
280    let target_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(1)).unwrap() as *const u8;
281    let fstype_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(2)).unwrap() as *const u8;
282    let flags = trapframe.get_arg(3) as u32;
283    let data_ptr = if trapframe.get_arg(4) == 0 {
284        core::ptr::null()
285    } else {
286        task.vm_manager.translate_vaddr(trapframe.get_arg(4)).unwrap() as *const u8
287    };
288
289    trapframe.increment_pc_next(task);
290
291    // Convert paths and parameters to strings
292    let source_str = match cstring_to_string(source_ptr, MAX_PATH_LENGTH) {
293        Ok((s, _)) => s,
294        Err(_) => return usize::MAX,
295    };
296    
297    let target_str = match cstring_to_string(target_ptr, MAX_PATH_LENGTH) {
298        Ok((s, _)) => s,
299        Err(_) => return usize::MAX,
300    };
301    
302    let fstype_str = match cstring_to_string(fstype_ptr, MAX_PATH_LENGTH) {
303        Ok((s, _)) => s,
304        Err(_) => return usize::MAX,
305    };
306    
307    let data_str = if !data_ptr.is_null() {
308        match cstring_to_string(data_ptr, MAX_PATH_LENGTH) {
309            Ok((s, _)) => Some(s),
310            Err(_) => return usize::MAX,
311        }
312    } else {
313        None
314    };
315
316    // Get VFS reference
317    let vfs = match task.vfs.as_ref() {
318        Some(vfs) => vfs,
319        None => return usize::MAX,
320    };
321
322    // Handle different mount types
323    match fstype_str.as_str() {
324        "bind" => {
325            // Handle bind mount - this is a special case handled by VFS
326            let _read_only = (flags & 1) != 0; // MS_RDONLY
327            match vfs.bind_mount(&source_str, &target_str) {
328                Ok(_) => 0,
329                Err(_) => usize::MAX,
330            }
331        },
332        _ => {
333            // Handle filesystem creation using drivers
334            let options = data_str.unwrap_or_default();
335            match create_filesystem_and_mount(vfs, &fstype_str, &target_str, &options) {
336                Ok(_) => 0,
337                Err(_) => usize::MAX,
338            }
339        }
340    }
341}
342
343// Helper function to parse overlay mount options
344#[allow(dead_code)]
345fn parse_overlay_options(data: &str) -> Result<(Option<String>, Vec<String>), ()> {
346    let mut upperdir = None;
347    let mut lowerdirs = Vec::new();
348    
349    for option in data.split(',') {
350        if let Some(value) = option.strip_prefix("upperdir=") {
351            upperdir = Some(value.to_string());
352        } else if let Some(value) = option.strip_prefix("lowerdir=") {
353            // Multiple lowerdirs can be separated by ':'
354            for lowerdir in value.split(':') {
355                lowerdirs.push(lowerdir.to_string());
356            }
357        }
358    }
359    
360    if lowerdirs.is_empty() {
361        return Err(()); // At least one lowerdir is required
362    }
363    
364    Ok((upperdir, lowerdirs))
365}
366
367/// Create a filesystem using the driver and mount it
368/// 
369/// This function uses the new driver-based approach where option parsing
370/// is delegated to the filesystem driver, and registration is handled
371/// by sys_mount.
372fn create_filesystem_and_mount(
373    vfs: &crate::fs::VfsManager,
374    fstype: &str,
375    target: &str,
376    options: &str,
377) -> Result<(), crate::fs::FileSystemError> {
378    use crate::fs::get_fs_driver_manager;
379    let driver_manager = get_fs_driver_manager();
380    // v2: directly create FS as Arc and mount it
381    let filesystem = driver_manager.create_from_option_string(fstype, options)?;
382    vfs.mount(filesystem, target, 0)?;
383    Ok(())
384}
385
386/// Unmount a filesystem (FsUmount)
387/// 
388/// This system call unmounts a filesystem at the specified path.
389/// 
390/// # Arguments
391/// 
392/// * `trapframe.get_arg(0)` - Pointer to target path to unmount
393/// * `trapframe.get_arg(1)` - Unmount flags (reserved for future use)
394/// 
395/// # Returns
396/// 
397/// * `0` on success
398/// * `usize::MAX` on error (path not found, filesystem busy, etc.)
399pub fn sys_fs_umount(trapframe: &mut Trapframe) -> usize {
400    let task = mytask().unwrap();
401    let target_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
402    let _flags = trapframe.get_arg(1) as u32; // Reserved for future use
403
404    trapframe.increment_pc_next(task);
405
406    // Convert target path to string
407    let target_str: String = match cstring_to_string(target_ptr, MAX_PATH_LENGTH) {
408        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
409            Ok(abs_path) => abs_path,
410            Err(_) => return usize::MAX,
411        },
412        Err(_) => return usize::MAX, // Invalid UTF-8
413    };
414
415    // Get VFS reference
416    let vfs = match task.vfs.as_ref() {
417        Some(vfs) => vfs,
418        None => return usize::MAX,
419    };
420
421    // Perform umount operation
422    match vfs.unmount(&target_str) {
423        Ok(_) => 0,
424        Err(_) => usize::MAX,
425    }
426}
427
428/// 
429/// This system call mounts a filesystem at the specified target path.
430/// 
431/// # Arguments
432/// 
433/// * `trapframe.get_arg(0)` - Pointer to source path (device/filesystem)
434/// * `trapframe.get_arg(1)` - Pointer to target mount point path
435/// * `trapframe.get_arg(2)` - Pointer to filesystem type string
436/// * `trapframe.get_arg(3)` - Mount flags
437/// * `trapframe.get_arg(4)` - Pointer to mount data/options
438/// 
439/// # Returns
440/// 
441/// * `0` on success
442/// * `usize::MAX` on error (invalid path, filesystem not supported, etc.)
443/// Unmount a filesystem (FsUmount)
444/// 
445/// This system call unmounts a filesystem at the specified path.
446/// 
447/// # Arguments
448/// 
449/// * `trapframe.get_arg(0)` - Pointer to target path to unmount
450/// * `trapframe.get_arg(1)` - Unmount flags (reserved for future use)
451/// 
452/// # Returns
453/// 
454/// * `0` on success
455/// * `usize::MAX` on error (path not found, filesystem busy, etc.)
456/// Change root filesystem (FsPivotRoot)
457/// 
458/// This system call changes the root filesystem of the calling process.
459/// 
460/// # Arguments
461/// 
462/// * `trapframe.get_arg(0)` - Pointer to new root path
463/// * `trapframe.get_arg(1)` - Pointer to old root mount point
464/// 
465/// # Returns
466/// 
467/// * `0` on success
468/// * `usize::MAX` on error (invalid path, operation not permitted, etc.)
469pub fn sys_fs_pivot_root(trapframe: &mut Trapframe) -> usize {
470    let task = mytask().unwrap();
471    let new_root_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
472    let old_root_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(1)).unwrap() as *const u8;
473
474    trapframe.increment_pc_next(&task);
475
476    // Convert new_root path to string
477    let new_root_str: String = match cstring_to_string(new_root_ptr, MAX_PATH_LENGTH) {
478        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
479            Ok(abs_path) => abs_path,
480            Err(_) => return usize::MAX,
481        },
482        Err(_) => return usize::MAX, // Invalid UTF-8
483    };
484
485    // Convert old_root path to string
486    let old_root_str: String = match cstring_to_string(old_root_ptr, MAX_PATH_LENGTH) {
487        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
488            Ok(abs_path) => abs_path,
489            Err(_) => return usize::MAX,
490        },
491        Err(_) => return usize::MAX, // Invalid UTF-8
492    };
493
494    // Get current VFS reference - pivot_root requires isolated VFS namespace
495    let current_vfs = match task.vfs.as_ref() {
496        Some(vfs) => vfs.clone(),
497        None => {
498            // pivot_root requires a task-specific VFS namespace
499            // Tasks without VFS should use the global namespace, but pivot_root
500            // is a namespace operation that doesn't make sense in that context
501            return usize::MAX;
502        },
503    };
504
505    // Perform pivot_root by replacing the mount_tree inside the existing VfsManager
506    match pivot_root_in_place(&current_vfs, &new_root_str, &old_root_str) {
507        Ok(_) => 0,
508        Err(e) => {
509            crate::println!("Failed to pivot root: {}", e.message);
510            usize::MAX // -1
511        }
512    }
513}
514
515/// Pivot root by replacing the mount tree inside the existing VfsManager
516/// 
517/// This function implements pivot_root without creating a new VfsManager instance.
518/// Instead, it manipulates the mount_tree directly to achieve the same effect.
519/// This approach preserves the relationship between the init process and the global VFS.
520fn pivot_root_in_place(
521    vfs: &Arc<VfsManager>, 
522    new_root_path: &str, 
523    old_root_path: &str
524) -> Result<(), crate::fs::FileSystemError> {
525    // Use bind mount to mount the new root as "/" in the new mount tree
526    let temp_vfs = VfsManager::new();
527    temp_vfs.bind_mount_from(&vfs, new_root_path, "/")?;
528    let old_root_path = if old_root_path == new_root_path {
529        return Err(crate::fs::FileSystemError {
530            kind: crate::fs::FileSystemErrorKind::InvalidPath,
531            message: "Old root path cannot be the same as new root path".to_string(),
532        });
533    } else if old_root_path.starts_with(new_root_path) {
534        &old_root_path[new_root_path.len()..]
535    } else {
536        old_root_path
537    };
538
539    let temp_root_entry = vfs.mount_tree.resolve_path(new_root_path)?.0;
540    let temp_root = temp_root_entry.node();
541    let fs = match temp_root.filesystem() {
542        Some(fs) => {
543            match fs.upgrade() {
544                Some(fs) => fs,
545                None => return Err(crate::fs::FileSystemError {
546                    kind: crate::fs::FileSystemErrorKind::InvalidPath,
547                    message: "New root path does not have a valid filesystem".to_string(),
548                }),
549            }
550        }
551        None => return Err(crate::fs::FileSystemError {
552            kind: crate::fs::FileSystemErrorKind::InvalidPath,
553            message: "New root path does not have a filesystem".to_string(),
554        }),
555    };
556    // Mount the new root filesystem at "/"
557    match temp_vfs.mount(fs, "/", 0) {
558        Ok(_) => {},
559        Err(e) => {
560            crate::println!("Failed to mount new root filesystem: {}", e.message);
561            return Err(e);
562        }
563    }
564
565    // Create old_root directory if it doesn't exist
566    if temp_vfs.resolve_path(old_root_path).is_err() {
567        match temp_vfs.create_dir(old_root_path) {
568            Ok(_) => {},
569            Err(e) if e.kind == crate::fs::FileSystemErrorKind::AlreadyExists => {
570                // Directory already exists, which is fine
571            },
572            Err(e) => return Err(e),
573        }
574    }
575
576    match temp_vfs.bind_mount_from(&vfs, "/", old_root_path) {
577        Ok(_) => {},
578        Err(e) => {
579            crate::println!("Failed to bind mount old root path: {}", e.message);
580            return Err(e);
581        }
582    }
583
584    {
585        let mut original_guard = temp_vfs.mount_tree.root_mount.write();
586        let mut temp_guard = vfs.mount_tree.root_mount.write();
587        core::mem::swap(&mut *original_guard, &mut *temp_guard);
588    }
589
590    {
591        let mut vfs_fs = vfs.mounted_filesystems.write();
592        let temp_fs = temp_vfs.mounted_filesystems.read();
593        *vfs_fs = temp_fs.clone();
594    }
595
596    Ok(())
597}
598
599/// Change current working directory using VFS (VfsChangeDirectory)
600/// 
601/// This system call changes the current working directory of the calling task
602/// to the specified path using the VFS layer.
603/// 
604/// # Arguments
605/// 
606/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
607/// 
608/// # Returns
609/// 
610/// * `0` on success
611/// * `usize::MAX` on error (path not found, not a directory, etc.)
612pub fn sys_vfs_change_directory(trapframe: &mut Trapframe) -> usize {
613    let task = mytask().unwrap();
614    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
615    
616    // Increment PC to avoid infinite loop if chdir fails
617    trapframe.increment_pc_next(task);
618    
619    // Convert path pointer to string
620    let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
621        Ok(p) => p.0,
622        Err(_) => return usize::MAX,
623    };
624    
625    // Get the VFS manager (either task-specific or global)
626    let vfs = match task.get_vfs() {
627        Some(vfs) => vfs,
628        None => return usize::MAX,
629    };
630
631    // Resolve absolute path
632    let absolute_path = match to_absolute_path_v2(&task, &path) {
633        Ok(path) => path,
634        Err(_) => return usize::MAX,
635    };
636    
637    // Check if the path exists and is a directory
638    match vfs.resolve_path(&absolute_path) {
639        Ok(entry) => {
640            if entry.node().file_type().unwrap() == FileType::Directory {
641                // Update the task's current working directory
642                task.set_cwd(absolute_path);
643                0 // Success
644            } else {
645                usize::MAX // Not a directory
646            }
647        }
648        Err(_) => return usize::MAX, // Path resolution error
649    }
650}
651
652/// Remove a file or directory (unified VfsRemove)
653/// 
654/// This system call provides a unified interface for removing both files and directories,
655/// replacing the traditional separate `unlink` (for files) and `rmdir` (for directories)
656/// operations with a single system call.
657/// 
658/// For directories, they must be empty to be removed successfully.
659/// 
660/// # Arguments
661/// 
662/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
663/// 
664/// # Returns
665/// 
666/// * `0` on success
667/// * `usize::MAX` on error (file/directory not found, permission denied, directory not empty, etc.)
668pub fn sys_vfs_remove(trapframe: &mut Trapframe) -> usize {
669    let task = mytask().unwrap();
670    let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
671
672    // Increment PC to avoid infinite loop if remove fails
673    trapframe.increment_pc_next(task);
674
675    // Convert path pointer to Rust string
676    let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
677        Ok((s, _)) => s,
678        Err(_) => return usize::MAX,
679    };
680
681    // Resolve absolute path
682    let absolute_path = match to_absolute_path_v2(&task, &path) {
683        Ok(path) => path,
684        Err(_) => return usize::MAX,
685    };
686
687    // Get VFS manager instance
688    let vfs = match task.get_vfs() {
689        Some(vfs) => vfs,
690        None => return usize::MAX, // VFS not initialized
691    };
692
693    // Try to resolve the path to check if it exists
694    match vfs.resolve_path(&absolute_path) {
695        Ok(_) => {
696            // Path exists, attempt to remove it using unified VFS remove method
697            match vfs.remove(&absolute_path) {
698                Ok(_) => 0,
699                Err(_) => usize::MAX,
700            }
701        }
702        Err(_) => usize::MAX, // Path not found
703    }
704}
705
706
707// Use a local path normalization function
708fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
709    if path.starts_with('/') {
710        Ok(path.to_string())
711    } else {
712        let cwd = task.cwd.clone().ok_or(())?;
713        let mut absolute_path = cwd;
714        if !absolute_path.ends_with('/') {
715            absolute_path.push('/');
716        }
717        absolute_path.push_str(path);
718        // Simple normalization (removes "//", ".", etc.)
719        let mut components = Vec::new();
720        for comp in absolute_path.split('/') {
721            match comp {
722                "" | "." => {},
723                ".." => { components.pop(); },
724                _ => components.push(comp),
725            }
726        }
727        Ok("/".to_string() + &components.join("/"))
728    }
729}