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, string::ToString, sync::Arc, vec::Vec};
37
38use crate::{arch::Trapframe, fs::FileType, library::std::string::cstring_to_string, task::mytask};
39
40use crate::fs::{MAX_PATH_LENGTH, VfsManager};
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
59        .vm_manager
60        .translate_vaddr(trapframe.get_arg(0))
61        .unwrap() as *const u8;
62    let _flags = trapframe.get_arg(1) as i32;
63    let _mode = trapframe.get_arg(2) as i32;
64
65    // Increment PC to avoid infinite loop if open fails
66    trapframe.increment_pc_next(task);
67
68    // Parse path as a null-terminated C string
69    let mut path_bytes = Vec::new();
70    let mut i = 0;
71    unsafe {
72        loop {
73            let byte = *path_ptr.add(i);
74            if byte == 0 {
75                break;
76            }
77            path_bytes.push(byte);
78            i += 1;
79
80            if i > MAX_PATH_LENGTH {
81                return usize::MAX; // Path too long
82            }
83        }
84    }
85
86    // Convert path bytes to string
87    let path_str = match str::from_utf8(&path_bytes) {
88        Ok(s) => match to_absolute_path_v2(&task, s) {
89            Ok(abs) => abs,
90            Err(_) => return usize::MAX,
91        },
92        Err(_) => return usize::MAX, // Invalid UTF-8
93    };
94
95    // Try to open the file using VFS
96    let vfs = match task.get_vfs() {
97        Some(vfs) => vfs,
98        None => return usize::MAX, // VFS not initialized
99    };
100    let file_obj = vfs.open(&path_str, 0);
101    match file_obj {
102        Ok(kernel_obj) => {
103            // Use simplified handle role classification
104            use crate::object::handle::{AccessMode, HandleMetadata, HandleType};
105
106            // For now, all opened files are classified as Regular usage
107            // Future enhancements could infer specific roles based on path patterns,
108            // but keeping it simple with the 3-category system: IpcChannel, StandardInputOutput, Regular
109            let handle_type = HandleType::Regular;
110
111            // Infer access mode from flags (simplified - full implementation would parse all open flags)
112            let access_mode = if _flags & 0x1 != 0 {
113                // O_WRONLY-like
114                AccessMode::WriteOnly
115            } else if _flags & 0x2 != 0 {
116                // O_RDWR-like
117                AccessMode::ReadWrite
118            } else {
119                AccessMode::ReadOnly // Default
120            };
121
122            let metadata = HandleMetadata {
123                handle_type,
124                access_mode,
125                special_semantics: None, // Could be inferred from flags like O_CLOEXEC
126            };
127
128            let handle = task.handle_table.insert_with_metadata(kernel_obj, metadata);
129            match handle {
130                Ok(handle) => handle as usize,
131                Err(_) => usize::MAX, // Handle table full
132            }
133        }
134        Err(_) => usize::MAX, // File open error
135    }
136}
137
138/// Truncate a file by path (VfsTruncate)
139///
140/// This system call truncates a file at the specified path to the given length.
141///
142/// # Arguments
143///
144/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
145/// * `trapframe.get_arg(1)` - New length for the file
146///
147/// # Returns
148///
149/// * `0` on success
150/// * `usize::MAX` on error (file not found, permission denied, etc.)
151pub fn sys_vfs_truncate(trapframe: &mut Trapframe) -> usize {
152    let task = mytask().unwrap();
153    let path_ptr = task
154        .vm_manager
155        .translate_vaddr(trapframe.get_arg(0))
156        .unwrap() as *const u8;
157    let length = trapframe.get_arg(1) as u64;
158
159    trapframe.increment_pc_next(task);
160
161    // Convert path bytes to string
162    let path_str: String = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
163        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
164            Ok(abs_path) => abs_path,
165            Err(_) => return usize::MAX,
166        },
167        Err(_) => return usize::MAX, // Invalid UTF-8
168    };
169
170    let vfs_guard = task.vfs.read();
171    let vfs = match vfs_guard.as_ref() {
172        Some(vfs) => vfs,
173        None => return usize::MAX, // VFS not initialized
174    };
175
176    let file_obj = match vfs.open(&path_str, 0) {
177        Ok(obj) => obj,
178        Err(_) => return usize::MAX,
179    };
180    let file = match file_obj.as_file() {
181        Some(f) => f,
182        None => return usize::MAX,
183    };
184    match file.truncate(length) {
185        Ok(_) => 0,
186        Err(_) => usize::MAX, // -1
187    }
188}
189
190/// Create a regular file using VFS (VfsCreateFile)
191///
192/// This system call creates a new regular file at the specified path using the VFS layer.
193///
194/// # Arguments
195///
196/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
197/// * `trapframe.get_arg(1)` - File mode (reserved for future use)
198///
199/// # Returns
200///
201/// * `0` on success
202/// * `usize::MAX` on error (path already exists, permission denied, etc.)
203pub fn sys_vfs_create_file(trapframe: &mut Trapframe) -> usize {
204    let task = mytask().unwrap();
205    let path_ptr = task
206        .vm_manager
207        .translate_vaddr(trapframe.get_arg(0))
208        .unwrap() as *const u8;
209    let _mode = trapframe.get_arg(1) as i32;
210
211    trapframe.increment_pc_next(task);
212
213    // Convert path bytes to string
214    let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
215        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
216            Ok(abs_path) => abs_path,
217            Err(_) => return usize::MAX,
218        },
219        Err(_) => return usize::MAX, // Invalid UTF-8
220    };
221
222    let vfs_guard = task.vfs.read();
223    let vfs = match vfs_guard.as_ref() {
224        Some(vfs) => vfs,
225        None => return usize::MAX, // VFS not initialized
226    };
227
228    match vfs.create_file(&path_str, FileType::RegularFile) {
229        Ok(_) => 0,
230        Err(_) => usize::MAX, // -1
231    }
232}
233
234/// Create a directory using VFS (VfsCreateDirectory)
235///
236/// This system call creates a new directory at the specified path using the VFS layer.
237///
238/// # Arguments
239///
240/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
241///
242/// # Returns
243///
244/// * `0` on success
245/// * `usize::MAX` on error (path already exists, permission denied, etc.)
246pub fn sys_vfs_create_directory(trapframe: &mut Trapframe) -> usize {
247    let task = mytask().unwrap();
248    let path_ptr = task
249        .vm_manager
250        .translate_vaddr(trapframe.get_arg(0))
251        .unwrap() as *const u8;
252
253    trapframe.increment_pc_next(task);
254
255    // Convert path bytes to string
256    let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
257        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
258            Ok(abs_path) => abs_path,
259            Err(_) => return usize::MAX,
260        },
261        Err(_) => return usize::MAX, // Invalid UTF-8
262    };
263
264    let vfs_guard = task.vfs.read();
265    let vfs = match vfs_guard.as_ref() {
266        Some(vfs) => vfs,
267        None => return usize::MAX, // VFS not initialized
268    };
269
270    match vfs.create_dir(&path_str) {
271        Ok(_) => 0,
272        Err(_) => usize::MAX, // -1
273    }
274}
275
276/// Mount a filesystem (FsMount)
277///
278/// This system call mounts a filesystem at the specified target path.
279///
280/// # Arguments
281///
282/// * `trapframe.get_arg(0)` - Pointer to source path (device/filesystem)
283/// * `trapframe.get_arg(1)` - Pointer to target mount point path
284/// * `trapframe.get_arg(2)` - Pointer to filesystem type string
285/// * `trapframe.get_arg(3)` - Mount flags
286/// * `trapframe.get_arg(4)` - Pointer to mount data/options
287///
288/// # Returns
289///
290/// * `0` on success
291/// * `usize::MAX` on error (invalid path, filesystem not supported, etc.)
292pub fn sys_fs_mount(trapframe: &mut Trapframe) -> usize {
293    let task = mytask().unwrap();
294    let source_ptr = task
295        .vm_manager
296        .translate_vaddr(trapframe.get_arg(0))
297        .unwrap() as *const u8;
298    let target_ptr = task
299        .vm_manager
300        .translate_vaddr(trapframe.get_arg(1))
301        .unwrap() as *const u8;
302    let fstype_ptr = task
303        .vm_manager
304        .translate_vaddr(trapframe.get_arg(2))
305        .unwrap() as *const u8;
306    let flags = trapframe.get_arg(3) as u32;
307    let data_ptr = if trapframe.get_arg(4) == 0 {
308        core::ptr::null()
309    } else {
310        task.vm_manager
311            .translate_vaddr(trapframe.get_arg(4))
312            .unwrap() as *const u8
313    };
314
315    trapframe.increment_pc_next(task);
316
317    // Convert paths and parameters to strings
318    let source_str = match cstring_to_string(source_ptr, MAX_PATH_LENGTH) {
319        Ok((s, _)) => s,
320        Err(_) => return usize::MAX,
321    };
322
323    let target_str = match cstring_to_string(target_ptr, MAX_PATH_LENGTH) {
324        Ok((s, _)) => s,
325        Err(_) => return usize::MAX,
326    };
327
328    let fstype_str = match cstring_to_string(fstype_ptr, MAX_PATH_LENGTH) {
329        Ok((s, _)) => s,
330        Err(_) => return usize::MAX,
331    };
332
333    let data_str = if !data_ptr.is_null() {
334        match cstring_to_string(data_ptr, MAX_PATH_LENGTH) {
335            Ok((s, _)) => Some(s),
336            Err(_) => return usize::MAX,
337        }
338    } else {
339        None
340    };
341
342    // Get VFS reference
343    let vfs_guard = task.vfs.read();
344    let vfs = match vfs_guard.as_ref() {
345        Some(vfs) => vfs,
346        None => return usize::MAX,
347    };
348
349    // Handle different mount types
350    match fstype_str.as_str() {
351        "bind" => {
352            // Handle bind mount - this is a special case handled by VFS
353            let _read_only = (flags & 1) != 0; // MS_RDONLY
354            match vfs.bind_mount(&source_str, &target_str) {
355                Ok(_) => 0,
356                Err(_) => usize::MAX,
357            }
358        }
359        _ => {
360            // Handle filesystem creation using drivers
361            let options = data_str.unwrap_or_default();
362            match create_filesystem_and_mount(vfs, &fstype_str, &target_str, &options) {
363                Ok(_) => 0,
364                Err(_) => usize::MAX,
365            }
366        }
367    }
368}
369
370// Helper function to parse overlay mount options
371#[allow(dead_code)]
372fn parse_overlay_options(data: &str) -> Result<(Option<String>, Vec<String>), ()> {
373    let mut upperdir = None;
374    let mut lowerdirs = Vec::new();
375
376    for option in data.split(',') {
377        if let Some(value) = option.strip_prefix("upperdir=") {
378            upperdir = Some(value.to_string());
379        } else if let Some(value) = option.strip_prefix("lowerdir=") {
380            // Multiple lowerdirs can be separated by ':'
381            for lowerdir in value.split(':') {
382                lowerdirs.push(lowerdir.to_string());
383            }
384        }
385    }
386
387    if lowerdirs.is_empty() {
388        return Err(()); // At least one lowerdir is required
389    }
390
391    Ok((upperdir, lowerdirs))
392}
393
394/// Create a filesystem using the driver and mount it
395///
396/// This function uses the new driver-based approach where option parsing
397/// is delegated to the filesystem driver, and registration is handled
398/// by sys_mount.
399fn create_filesystem_and_mount(
400    vfs: &crate::fs::VfsManager,
401    fstype: &str,
402    target: &str,
403    options: &str,
404) -> Result<(), crate::fs::FileSystemError> {
405    use crate::fs::get_fs_driver_manager;
406    let driver_manager = get_fs_driver_manager();
407    // v2: directly create FS as Arc and mount it
408    let filesystem = driver_manager.create_from_option_string(fstype, options)?;
409    vfs.mount(filesystem, target, 0)?;
410    Ok(())
411}
412
413/// Unmount a filesystem (FsUmount)
414///
415/// This system call unmounts a filesystem at the specified path.
416///
417/// # Arguments
418///
419/// * `trapframe.get_arg(0)` - Pointer to target path to unmount
420/// * `trapframe.get_arg(1)` - Unmount flags (reserved for future use)
421///
422/// # Returns
423///
424/// * `0` on success
425/// * `usize::MAX` on error (path not found, filesystem busy, etc.)
426pub fn sys_fs_umount(trapframe: &mut Trapframe) -> usize {
427    let task = mytask().unwrap();
428    let target_ptr = task
429        .vm_manager
430        .translate_vaddr(trapframe.get_arg(0))
431        .unwrap() as *const u8;
432    let _flags = trapframe.get_arg(1) as u32; // Reserved for future use
433
434    trapframe.increment_pc_next(task);
435
436    // Convert target path to string
437    let target_str: String = match cstring_to_string(target_ptr, MAX_PATH_LENGTH) {
438        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
439            Ok(abs_path) => abs_path,
440            Err(_) => return usize::MAX,
441        },
442        Err(_) => return usize::MAX, // Invalid UTF-8
443    };
444
445    // Get VFS reference
446    let vfs_guard = task.vfs.read();
447    let vfs = match vfs_guard.as_ref() {
448        Some(vfs) => vfs,
449        None => return usize::MAX,
450    };
451
452    // Perform umount operation
453    match vfs.unmount(&target_str) {
454        Ok(_) => 0,
455        Err(_) => usize::MAX,
456    }
457}
458
459///
460/// This system call mounts a filesystem at the specified target path.
461///
462/// # Arguments
463///
464/// * `trapframe.get_arg(0)` - Pointer to source path (device/filesystem)
465/// * `trapframe.get_arg(1)` - Pointer to target mount point path
466/// * `trapframe.get_arg(2)` - Pointer to filesystem type string
467/// * `trapframe.get_arg(3)` - Mount flags
468/// * `trapframe.get_arg(4)` - Pointer to mount data/options
469///
470/// # Returns
471///
472/// * `0` on success
473/// * `usize::MAX` on error (invalid path, filesystem not supported, etc.)
474/// Unmount a filesystem (FsUmount)
475///
476/// This system call unmounts a filesystem at the specified path.
477///
478/// # Arguments
479///
480/// * `trapframe.get_arg(0)` - Pointer to target path to unmount
481/// * `trapframe.get_arg(1)` - Unmount flags (reserved for future use)
482///
483/// # Returns
484///
485/// * `0` on success
486/// * `usize::MAX` on error (path not found, filesystem busy, etc.)
487/// Change root filesystem (FsPivotRoot)
488///
489/// This system call changes the root filesystem of the calling process.
490///
491/// # Arguments
492///
493/// * `trapframe.get_arg(0)` - Pointer to new root path
494/// * `trapframe.get_arg(1)` - Pointer to old root mount point
495///
496/// # Returns
497///
498/// * `0` on success
499/// * `usize::MAX` on error (invalid path, operation not permitted, etc.)
500pub fn sys_fs_pivot_root(trapframe: &mut Trapframe) -> usize {
501    let task = mytask().unwrap();
502    let new_root_ptr = task
503        .vm_manager
504        .translate_vaddr(trapframe.get_arg(0))
505        .unwrap() as *const u8;
506    let old_root_ptr = task
507        .vm_manager
508        .translate_vaddr(trapframe.get_arg(1))
509        .unwrap() as *const u8;
510
511    trapframe.increment_pc_next(&task);
512
513    // Convert new_root path to string
514    let new_root_str: String = match cstring_to_string(new_root_ptr, MAX_PATH_LENGTH) {
515        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
516            Ok(abs_path) => abs_path,
517            Err(_) => return usize::MAX,
518        },
519        Err(_) => return usize::MAX, // Invalid UTF-8
520    };
521
522    // Convert old_root path to string
523    let old_root_str: String = match cstring_to_string(old_root_ptr, MAX_PATH_LENGTH) {
524        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
525            Ok(abs_path) => abs_path,
526            Err(_) => return usize::MAX,
527        },
528        Err(_) => return usize::MAX, // Invalid UTF-8
529    };
530
531    // Get current VFS reference - pivot_root requires isolated VFS namespace
532    let current_vfs = match task.vfs.read().clone() {
533        Some(vfs) => vfs.clone(),
534        None => {
535            // pivot_root requires a task-specific VFS namespace
536            // Tasks without VFS should use the global namespace, but pivot_root
537            // is a namespace operation that doesn't make sense in that context
538            return usize::MAX;
539        }
540    };
541
542    // Perform pivot_root by replacing the mount_tree inside the existing VfsManager
543    match pivot_root_in_place(&current_vfs, &new_root_str, &old_root_str) {
544        Ok(_) => 0,
545        Err(e) => {
546            crate::println!("Failed to pivot root: {}", e.message);
547            usize::MAX // -1
548        }
549    }
550}
551
552/// Pivot root by replacing the mount tree inside the existing VfsManager
553///
554/// This function implements pivot_root without creating a new VfsManager instance.
555/// Instead, it manipulates the mount_tree directly to achieve the same effect.
556/// This approach preserves the relationship between the init process and the global VFS.
557fn pivot_root_in_place(
558    vfs: &Arc<VfsManager>,
559    new_root_path: &str,
560    old_root_path: &str,
561) -> Result<(), crate::fs::FileSystemError> {
562    let old_root_path = if old_root_path == new_root_path {
563        return Err(crate::fs::FileSystemError {
564            kind: crate::fs::FileSystemErrorKind::InvalidPath,
565            message: "Old root path cannot be the same as new root path".to_string(),
566        });
567    } else if old_root_path.starts_with(new_root_path) {
568        &old_root_path[new_root_path.len()..]
569    } else {
570        old_root_path
571    };
572
573    let (new_root_entry, parent_mount) = vfs.mount_tree.resolve_mount_point(new_root_path)?;
574    let new_root_mount = match parent_mount.get_child(&new_root_entry) {
575        Some(child) => child,
576        None => {
577            return Err(crate::fs::FileSystemError {
578                kind: crate::fs::FileSystemErrorKind::InvalidPath,
579                message: "New root path is not a mount point".to_string(),
580            });
581        }
582    };
583
584    let old_root_mount = vfs.mount_tree.root_mount.read().clone();
585    let old_root_entry = old_root_mount.root.clone();
586
587    let detached =
588        parent_mount
589            .remove_child(&new_root_entry)
590            .ok_or_else(|| crate::fs::FileSystemError {
591                kind: crate::fs::FileSystemErrorKind::NotFound,
592                message: "New root mount point not found in parent".to_string(),
593            })?;
594    let new_root_mount = detached;
595
596    unsafe {
597        let mut_ptr =
598            Arc::as_ptr(&new_root_mount) as *mut crate::fs::vfs_v2::mount_tree::MountPoint;
599        (*mut_ptr).parent = None;
600        (*mut_ptr).parent_entry = None;
601        (*mut_ptr).path = "/".to_string();
602    }
603
604    vfs.mount_tree.replace_root(new_root_mount);
605
606    // Create old_root directory if it doesn't exist
607    if vfs.resolve_path(old_root_path).is_err() {
608        match vfs.create_dir(old_root_path) {
609            Ok(_) => {}
610            Err(e) if e.kind == crate::fs::FileSystemErrorKind::AlreadyExists => {
611                // Directory already exists, which is fine
612            }
613            Err(e) => return Err(e),
614        }
615    }
616
617    match vfs.bind_mount_from_entry(old_root_entry, old_root_mount, old_root_path) {
618        Ok(_) => {}
619        Err(e) => {
620            crate::println!("Failed to bind mount old root path: {}", e.message);
621            return Err(e);
622        }
623    }
624
625    Ok(())
626}
627
628/// Change current working directory using VFS (VfsChangeDirectory)
629///
630/// This system call changes the current working directory of the calling task
631/// to the specified path using the VFS layer.
632///
633/// # Arguments
634///
635/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
636///
637/// # Returns
638///
639/// * `0` on success
640/// * `usize::MAX` on error (path not found, not a directory, etc.)
641pub fn sys_vfs_change_directory(trapframe: &mut Trapframe) -> usize {
642    let task = mytask().unwrap();
643    let path_ptr = task
644        .vm_manager
645        .translate_vaddr(trapframe.get_arg(0))
646        .unwrap() as *const u8;
647
648    // Increment PC to avoid infinite loop if chdir fails
649    trapframe.increment_pc_next(task);
650
651    // Convert path pointer to string
652    let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
653        Ok(p) => p.0,
654        Err(_) => return usize::MAX,
655    };
656
657    // Get the VFS manager (either task-specific or global)
658    let vfs = match task.get_vfs() {
659        Some(vfs) => vfs,
660        None => return usize::MAX,
661    };
662
663    // Resolve absolute path
664    let absolute_path = match to_absolute_path_v2(&task, &path) {
665        Ok(path) => path,
666        Err(_) => return usize::MAX,
667    };
668
669    // Check if the path exists and is a directory
670    match vfs.resolve_path(&absolute_path) {
671        Ok((entry, _mount_point)) => {
672            if entry.node().file_type().unwrap() == FileType::Directory {
673                // Update the current working directory via VfsManager
674                match vfs.set_cwd_by_path(&absolute_path) {
675                    Ok(()) => 0,          // Success
676                    Err(_) => usize::MAX, // Failed to set cwd
677                }
678            } else {
679                usize::MAX // Not a directory
680            }
681        }
682        Err(_) => return usize::MAX, // Path resolution error
683    }
684}
685
686/// Remove a file or directory (unified VfsRemove)
687///
688/// This system call provides a unified interface for removing both files and directories,
689/// replacing the traditional separate `unlink` (for files) and `rmdir` (for directories)
690/// operations with a single system call.
691///
692/// For directories, they must be empty to be removed successfully.
693///
694/// # Arguments
695///
696/// * `trapframe.get_arg(0)` - Pointer to the null-terminated path string
697///
698/// # Returns
699///
700/// * `0` on success
701/// * `usize::MAX` on error (file/directory not found, permission denied, directory not empty, etc.)
702pub fn sys_vfs_remove(trapframe: &mut Trapframe) -> usize {
703    let task = mytask().unwrap();
704    let path_ptr = task
705        .vm_manager
706        .translate_vaddr(trapframe.get_arg(0))
707        .unwrap() as *const u8;
708
709    // Increment PC to avoid infinite loop if remove fails
710    trapframe.increment_pc_next(task);
711
712    // Convert path pointer to Rust string
713    let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
714        Ok((s, _)) => s,
715        Err(_) => return usize::MAX,
716    };
717
718    // Resolve absolute path
719    let absolute_path = match to_absolute_path_v2(&task, &path) {
720        Ok(path) => path,
721        Err(_) => return usize::MAX,
722    };
723
724    // Get VFS manager instance
725    let vfs = match task.get_vfs() {
726        Some(vfs) => vfs,
727        None => return usize::MAX, // VFS not initialized
728    };
729
730    // Try to resolve the path to check if it exists
731    match vfs.resolve_path(&absolute_path) {
732        Ok(_) => {
733            // Path exists, attempt to remove it using unified VFS remove method
734            match vfs.remove(&absolute_path) {
735                Ok(_) => 0,
736                Err(_) => usize::MAX,
737            }
738        }
739        Err(_) => usize::MAX, // Path not found
740    }
741}
742
743/// Create a symbolic link (VfsCreateSymlink)
744///
745/// This system call creates a symbolic link at the specified path pointing to the target.
746///
747/// # Arguments
748///
749/// * `trapframe.get_arg(0)` - Pointer to symlink path (where to create the symlink)
750/// * `trapframe.get_arg(1)` - Pointer to target path (what the symlink points to)
751///
752/// # Returns
753///
754/// * `0` on success
755/// * `usize::MAX` on error (path already exists, permission denied, etc.)
756pub fn sys_vfs_create_symlink(trapframe: &mut Trapframe) -> usize {
757    let task = mytask().unwrap();
758    let symlink_path_ptr = task
759        .vm_manager
760        .translate_vaddr(trapframe.get_arg(0))
761        .unwrap() as *const u8;
762    let target_path_ptr = task
763        .vm_manager
764        .translate_vaddr(trapframe.get_arg(1))
765        .unwrap() as *const u8;
766
767    trapframe.increment_pc_next(task);
768
769    // Convert symlink path bytes to string
770    let symlink_path_str = match cstring_to_string(symlink_path_ptr, MAX_PATH_LENGTH) {
771        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
772            Ok(abs_path) => abs_path,
773            Err(_) => return usize::MAX,
774        },
775        Err(_) => return usize::MAX, // Invalid UTF-8
776    };
777
778    // Convert target path bytes to string (target can be relative, don't convert to absolute)
779    let target_path_str = match cstring_to_string(target_path_ptr, MAX_PATH_LENGTH) {
780        Ok((s, _)) => s,
781        Err(_) => return usize::MAX, // Invalid UTF-8
782    };
783
784    let vfs_guard = task.vfs.read();
785    let vfs = match vfs_guard.as_ref() {
786        Some(vfs) => vfs,
787        None => return usize::MAX, // VFS not initialized
788    };
789
790    match vfs.create_symlink(&symlink_path_str, &target_path_str) {
791        Ok(_) => 0,
792        Err(_) => usize::MAX, // -1
793    }
794}
795
796/// Read symbolic link target (VfsReadlink)
797///
798/// This system call reads the target of a symbolic link.
799///
800/// # Arguments
801///
802/// * `trapframe.get_arg(0)` - Pointer to symlink path
803/// * `trapframe.get_arg(1)` - Pointer to buffer to store target path
804/// * `trapframe.get_arg(2)` - Buffer size
805///
806/// # Returns
807///
808/// * Number of bytes written to buffer on success
809/// * `usize::MAX` on error (not a symlink, permission denied, etc.)
810pub fn sys_vfs_readlink(trapframe: &mut Trapframe) -> usize {
811    let task = mytask().unwrap();
812    let symlink_path_ptr = task
813        .vm_manager
814        .translate_vaddr(trapframe.get_arg(0))
815        .unwrap() as *const u8;
816    let buffer_ptr = task
817        .vm_manager
818        .translate_vaddr(trapframe.get_arg(1))
819        .unwrap() as *mut u8;
820    let buffer_size = trapframe.get_arg(2);
821
822    trapframe.increment_pc_next(task);
823
824    // Convert symlink path bytes to string
825    let symlink_path_str = match cstring_to_string(symlink_path_ptr, MAX_PATH_LENGTH) {
826        Ok((s, _)) => match to_absolute_path_v2(&task, &s) {
827            Ok(abs_path) => abs_path,
828            Err(_) => return usize::MAX,
829        },
830        Err(_) => return usize::MAX, // Invalid UTF-8
831    };
832
833    let vfs_guard = task.vfs.read();
834    let vfs = match vfs_guard.as_ref() {
835        Some(vfs) => vfs,
836        None => return usize::MAX, // VFS not initialized
837    };
838
839    // Open the symlink entry with no_follow to avoid following the link
840    let options = crate::fs::vfs_v2::PathResolutionOptions::no_follow();
841    let entry = match vfs.resolve_path_with_options(&symlink_path_str, &options) {
842        Ok((entry, _)) => entry,
843        Err(_) => return usize::MAX, // Path not found or error
844    };
845
846    // Check if it's actually a symlink
847    let node = entry.node();
848    let is_symlink = match node.is_symlink() {
849        Ok(is_link) => is_link,
850        Err(_) => return usize::MAX, // Error checking file type
851    };
852
853    if !is_symlink {
854        return usize::MAX; // Not a symlink
855    }
856
857    // Read the symlink target
858    let target = match node.read_link() {
859        Ok(target) => target,
860        Err(_) => return usize::MAX, // Error reading symlink
861    };
862
863    let target_bytes = target.as_bytes();
864    let bytes_to_copy = core::cmp::min(target_bytes.len(), buffer_size);
865
866    // Copy target to user buffer
867    unsafe {
868        core::ptr::copy_nonoverlapping(target_bytes.as_ptr(), buffer_ptr, bytes_to_copy);
869    }
870
871    bytes_to_copy
872}
873
874/// Get current working directory path (VfsGetCwdPath)
875///
876/// This system call writes the calling task's current working directory as a UTF-8 path
877/// into the provided user buffer.
878///
879/// # Arguments
880///
881/// * `trapframe.get_arg(0)` - Pointer to buffer to store path
882/// * `trapframe.get_arg(1)` - Buffer size
883///
884/// # Returns
885///
886/// * Number of bytes written to buffer on success
887/// * `usize::MAX` on error
888pub fn sys_vfs_get_cwd_path(trapframe: &mut Trapframe) -> usize {
889    let task = mytask().unwrap();
890    let buffer_ptr = task
891        .vm_manager
892        .translate_vaddr(trapframe.get_arg(0))
893        .unwrap() as *mut u8;
894    let buffer_size = trapframe.get_arg(1);
895
896    trapframe.increment_pc_next(task);
897
898    let vfs_guard = task.vfs.read();
899    let vfs = match vfs_guard.as_ref() {
900        Some(vfs) => vfs,
901        None => return usize::MAX,
902    };
903
904    let cwd = vfs.get_cwd_path();
905    let cwd_bytes = cwd.as_bytes();
906    let bytes_to_copy = core::cmp::min(cwd_bytes.len(), buffer_size);
907
908    unsafe {
909        core::ptr::copy_nonoverlapping(cwd_bytes.as_ptr(), buffer_ptr, bytes_to_copy);
910    }
911
912    bytes_to_copy
913}
914
915// Use VfsManager-based path normalization function
916fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
917    if path.starts_with('/') {
918        Ok(path.to_string())
919    } else {
920        let vfs = task.vfs.read().clone().ok_or(())?;
921        Ok(vfs.resolve_path_to_absolute(path))
922    }
923}