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(¤t_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}