1use 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
42pub 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 trapframe.increment_pc_next(task);
67
68 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; }
83 }
84 }
85
86 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, };
94
95 let vfs = match task.get_vfs() {
97 Some(vfs) => vfs,
98 None => return usize::MAX, };
100 let file_obj = vfs.open(&path_str, 0);
101 match file_obj {
102 Ok(kernel_obj) => {
103 use crate::object::handle::{AccessMode, HandleMetadata, HandleType};
105
106 let handle_type = HandleType::Regular;
110
111 let access_mode = if _flags & 0x1 != 0 {
113 AccessMode::WriteOnly
115 } else if _flags & 0x2 != 0 {
116 AccessMode::ReadWrite
118 } else {
119 AccessMode::ReadOnly };
121
122 let metadata = HandleMetadata {
123 handle_type,
124 access_mode,
125 special_semantics: None, };
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, }
133 }
134 Err(_) => usize::MAX, }
136}
137
138pub 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 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, };
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, };
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, }
188}
189
190pub 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 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, };
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, };
227
228 match vfs.create_file(&path_str, FileType::RegularFile) {
229 Ok(_) => 0,
230 Err(_) => usize::MAX, }
232}
233
234pub 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 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, };
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, };
269
270 match vfs.create_dir(&path_str) {
271 Ok(_) => 0,
272 Err(_) => usize::MAX, }
274}
275
276pub 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 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 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 match fstype_str.as_str() {
351 "bind" => {
352 let _read_only = (flags & 1) != 0; match vfs.bind_mount(&source_str, &target_str) {
355 Ok(_) => 0,
356 Err(_) => usize::MAX,
357 }
358 }
359 _ => {
360 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#[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 for lowerdir in value.split(':') {
382 lowerdirs.push(lowerdir.to_string());
383 }
384 }
385 }
386
387 if lowerdirs.is_empty() {
388 return Err(()); }
390
391 Ok((upperdir, lowerdirs))
392}
393
394fn 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 let filesystem = driver_manager.create_from_option_string(fstype, options)?;
409 vfs.mount(filesystem, target, 0)?;
410 Ok(())
411}
412
413pub 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; trapframe.increment_pc_next(task);
435
436 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, };
444
445 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 match vfs.unmount(&target_str) {
454 Ok(_) => 0,
455 Err(_) => usize::MAX,
456 }
457}
458
459pub 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 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, };
521
522 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, };
530
531 let current_vfs = match task.vfs.read().clone() {
533 Some(vfs) => vfs.clone(),
534 None => {
535 return usize::MAX;
539 }
540 };
541
542 match pivot_root_in_place(¤t_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 }
549 }
550}
551
552fn 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 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 }
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
628pub 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 trapframe.increment_pc_next(task);
650
651 let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
653 Ok(p) => p.0,
654 Err(_) => return usize::MAX,
655 };
656
657 let vfs = match task.get_vfs() {
659 Some(vfs) => vfs,
660 None => return usize::MAX,
661 };
662
663 let absolute_path = match to_absolute_path_v2(&task, &path) {
665 Ok(path) => path,
666 Err(_) => return usize::MAX,
667 };
668
669 match vfs.resolve_path(&absolute_path) {
671 Ok((entry, _mount_point)) => {
672 if entry.node().file_type().unwrap() == FileType::Directory {
673 match vfs.set_cwd_by_path(&absolute_path) {
675 Ok(()) => 0, Err(_) => usize::MAX, }
678 } else {
679 usize::MAX }
681 }
682 Err(_) => return usize::MAX, }
684}
685
686pub 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 trapframe.increment_pc_next(task);
711
712 let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
714 Ok((s, _)) => s,
715 Err(_) => return usize::MAX,
716 };
717
718 let absolute_path = match to_absolute_path_v2(&task, &path) {
720 Ok(path) => path,
721 Err(_) => return usize::MAX,
722 };
723
724 let vfs = match task.get_vfs() {
726 Some(vfs) => vfs,
727 None => return usize::MAX, };
729
730 match vfs.resolve_path(&absolute_path) {
732 Ok(_) => {
733 match vfs.remove(&absolute_path) {
735 Ok(_) => 0,
736 Err(_) => usize::MAX,
737 }
738 }
739 Err(_) => usize::MAX, }
741}
742
743pub 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 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, };
777
778 let target_path_str = match cstring_to_string(target_path_ptr, MAX_PATH_LENGTH) {
780 Ok((s, _)) => s,
781 Err(_) => return usize::MAX, };
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, };
789
790 match vfs.create_symlink(&symlink_path_str, &target_path_str) {
791 Ok(_) => 0,
792 Err(_) => usize::MAX, }
794}
795
796pub 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 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, };
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, };
838
839 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, };
845
846 let node = entry.node();
848 let is_symlink = match node.is_symlink() {
849 Ok(is_link) => is_link,
850 Err(_) => return usize::MAX, };
852
853 if !is_symlink {
854 return usize::MAX; }
856
857 let target = match node.read_link() {
859 Ok(target) => target,
860 Err(_) => return usize::MAX, };
862
863 let target_bytes = target.as_bytes();
864 let bytes_to_copy = core::cmp::min(target_bytes.len(), buffer_size);
865
866 unsafe {
868 core::ptr::copy_nonoverlapping(target_bytes.as_ptr(), buffer_ptr, bytes_to_copy);
869 }
870
871 bytes_to_copy
872}
873
874pub 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
915fn 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}