1use crate::{
2 abi::linux::riscv64::LinuxRiscv64Abi,
3 arch::Trapframe,
4 device::manager::DeviceManager,
5 executor::TransparentExecutor,
6 fs::{DirectoryEntry, FileType, SeekFrom},
7 library::std::string::{
8 cstring_to_string, parse_c_string_from_userspace, parse_string_array_from_userspace,
9 },
10 object::capability::StreamError,
11 sched::scheduler::get_scheduler,
12 task::mytask,
13};
14use alloc::{
15 string::{String, ToString},
16 vec,
17 vec::Vec,
18};
19use core::sync::atomic::{AtomicU64, Ordering};
20
21use super::errno;
22
23static XORSHIFT_STATE: AtomicU64 = AtomicU64::new(0);
24
25fn remap_shm_path(path: &str) -> String {
26 if let Some(rest) = path.strip_prefix("/dev/shm/") {
27 alloc::format!("/tmp/{}", rest)
28 } else if path == "/dev/shm" || path == "/dev/shm/" {
29 "/tmp".to_string()
30 } else {
31 path.to_string()
32 }
33}
34
35fn is_wl_shm_path(path: &str) -> bool {
36 path.starts_with("/tmp/wl_shm-")
37}
38
39#[derive(Debug, Clone, Copy)]
42#[repr(C)]
43pub struct LinuxStat {
44 pub st_dev: u64, pub st_ino: u64, pub st_mode: u32, pub st_nlink: u32, pub st_uid: u32, pub st_gid: u32, pub st_rdev: u64, pub __pad1: u64, pub st_size: i64, pub st_blksize: i32, pub __pad2: i32, pub st_blocks: i64, pub st_atime: i64, pub st_atime_nsec: u64, pub st_mtime: i64, pub st_mtime_nsec: u64, pub st_ctime: i64, pub st_ctime_nsec: u64, pub __unused4: u32, pub __unused5: u32, }
65
66#[derive(Debug, Clone, Copy, Default)]
68#[repr(C)]
69pub struct LinuxStatxTimestamp {
70 pub tv_sec: i64,
71 pub tv_nsec: u32,
72 pub __reserved: i32,
73}
74
75#[derive(Debug, Clone, Copy, Default)]
77#[repr(C)]
78pub struct LinuxStatx {
79 pub stx_mask: u32,
80 pub stx_blksize: u32,
81 pub stx_attributes: u64,
82 pub stx_nlink: u32,
83 pub stx_uid: u32,
84 pub stx_gid: u32,
85 pub stx_mode: u16,
86 pub __spare0: [u16; 1],
87 pub stx_ino: u64,
88 pub stx_size: u64,
89 pub stx_blocks: u64,
90 pub stx_attributes_mask: u64,
91 pub stx_atime: LinuxStatxTimestamp,
92 pub stx_btime: LinuxStatxTimestamp,
93 pub stx_ctime: LinuxStatxTimestamp,
94 pub stx_mtime: LinuxStatxTimestamp,
95 pub stx_rdev_major: u32,
96 pub stx_rdev_minor: u32,
97 pub stx_dev_major: u32,
98 pub stx_dev_minor: u32,
99 pub stx_mnt_id: u64,
100 pub stx_dio_mem_align: u32,
101 pub stx_dio_offset_align: u32,
102 pub stx_subvol: u64,
103 pub stx_atomic_write_unit_min: u32,
104 pub stx_atomic_write_unit_max: u32,
105 pub stx_atomic_write_segments_max: u32,
106 pub stx_dio_read_offset_align: u32,
107 pub __spare3: [u64; 9],
108}
109
110#[allow(dead_code)]
112pub const S_IFMT: u32 = 0o170000; pub const S_IFSOCK: u32 = 0o140000; pub const S_IFLNK: u32 = 0o120000; pub const S_IFREG: u32 = 0o100000; pub const S_IFBLK: u32 = 0o060000; pub const S_IFDIR: u32 = 0o040000; pub const S_IFCHR: u32 = 0o020000; pub const S_IFIFO: u32 = 0o010000; #[allow(dead_code)]
123pub const S_IRWXU: u32 = 0o0700; pub const S_IRUSR: u32 = 0o0400; pub const S_IWUSR: u32 = 0o0200; pub const S_IXUSR: u32 = 0o0100; #[allow(dead_code)]
128pub const S_IRWXG: u32 = 0o0070; pub const S_IRGRP: u32 = 0o0040; #[allow(dead_code)]
131pub const S_IWGRP: u32 = 0o0020; pub const S_IXGRP: u32 = 0o0010; #[allow(dead_code)]
134pub const S_IRWXO: u32 = 0o0007; pub const S_IROTH: u32 = 0o0004; #[allow(dead_code)]
137pub const S_IWOTH: u32 = 0o0002; pub const S_IXOTH: u32 = 0o0001; #[allow(dead_code)]
142pub const STATX_TYPE: u32 = 0x00000001;
143#[allow(dead_code)]
144pub const STATX_MODE: u32 = 0x00000002;
145#[allow(dead_code)]
146pub const STATX_NLINK: u32 = 0x00000004;
147#[allow(dead_code)]
148pub const STATX_UID: u32 = 0x00000008;
149#[allow(dead_code)]
150pub const STATX_GID: u32 = 0x00000010;
151#[allow(dead_code)]
152pub const STATX_ATIME: u32 = 0x00000020;
153#[allow(dead_code)]
154pub const STATX_MTIME: u32 = 0x00000040;
155#[allow(dead_code)]
156pub const STATX_CTIME: u32 = 0x00000080;
157#[allow(dead_code)]
158pub const STATX_INO: u32 = 0x00000100;
159#[allow(dead_code)]
160pub const STATX_SIZE: u32 = 0x00000200;
161#[allow(dead_code)]
162pub const STATX_BLOCKS: u32 = 0x00000400;
163pub const STATX_BASIC_STATS: u32 = 0x000007ff;
164#[allow(dead_code)]
165pub const STATX_BTIME: u32 = 0x00000800;
166
167#[allow(dead_code)]
169pub const GRND_NONBLOCK: u32 = 0x0001;
170#[allow(dead_code)]
171pub const GRND_RANDOM: u32 = 0x0002;
172#[allow(dead_code)]
173pub const GRND_INSECURE: u32 = 0x0004;
174
175pub const F_DUPFD: u32 = 0; pub const F_GETFD: u32 = 1; pub const F_SETFD: u32 = 2; pub const F_GETFL: u32 = 3; pub const F_SETFL: u32 = 4; pub const F_GETLK: u32 = 5; pub const F_SETLK: u32 = 6; pub const F_SETLKW: u32 = 7; pub const F_SETOWN: u32 = 8; pub const F_GETOWN: u32 = 9; pub const F_SETSIG: u32 = 10; pub const F_GETSIG: u32 = 11; pub const F_SETLEASE: u32 = 1024; pub const F_GETLEASE: u32 = 1025; pub const F_NOTIFY: u32 = 1026; pub const F_DUPFD_CLOEXEC: u32 = 1030; pub const FD_CLOEXEC: u32 = 1; #[allow(dead_code)]
198pub const O_RDONLY: i32 = 0o0; #[allow(dead_code)]
200pub const O_WRONLY: i32 = 0o1; #[allow(dead_code)]
202pub const O_RDWR: i32 = 0o2; pub const O_CREAT: i32 = 0o100; pub const O_EXCL: i32 = 0o200; #[allow(dead_code)]
206pub const O_NOCTTY: i32 = 0o400; pub const O_TRUNC: i32 = 0o1000; pub const O_APPEND: i32 = 0o2000; #[allow(dead_code)]
210pub const O_NONBLOCK: i32 = 0o4000; #[allow(dead_code)]
212pub const O_DSYNC: i32 = 0o10000; #[allow(dead_code)]
214pub const O_ASYNC: i32 = 0o20000; #[allow(dead_code)]
216pub const O_DIRECT: i32 = 0o40000; #[allow(dead_code)]
218pub const O_LARGEFILE: i32 = 0o100000; pub const O_DIRECTORY: i32 = 0o200000; #[allow(dead_code)]
221pub const O_NOFOLLOW: i32 = 0o400000; #[allow(dead_code)]
223pub const O_NOATIME: i32 = 0o1000000; pub const O_CLOEXEC: i32 = 0o2000000; #[allow(dead_code)]
226pub const O_SYNC: i32 = O_DSYNC; #[allow(dead_code)]
228pub const O_PATH: i32 = 0o10000000; #[allow(dead_code)]
230pub const O_TMPFILE: i32 = 0o20000000; use crate::device::DeviceCapability;
233
234impl LinuxStat {
235 pub fn from_metadata(metadata: &crate::fs::FileMetadata) -> Self {
237 let st_mode = match metadata.file_type {
238 FileType::RegularFile => S_IFREG,
239 FileType::Directory => S_IFDIR,
240 FileType::CharDevice(_) => S_IFCHR,
241 FileType::BlockDevice(_) => S_IFBLK,
242 FileType::SymbolicLink(_) => S_IFLNK,
243 FileType::Pipe => S_IFIFO,
244 FileType::Socket(_) => S_IFSOCK,
245 FileType::Unknown => S_IFREG, } | if metadata.permissions.read {
247 S_IRUSR | S_IRGRP | S_IXGRP | S_IROTH
248 } else {
249 0
250 } | if metadata.permissions.write {
251 S_IWUSR
252 } else {
253 0
254 } | if metadata.permissions.execute {
255 S_IXUSR | S_IXGRP | S_IXOTH
256 } else {
257 0
258 };
259
260 Self {
261 st_dev: 0, st_ino: metadata.file_id,
263 st_mode,
264 st_nlink: metadata.link_count as u32,
265 st_uid: 0, st_gid: 0, st_rdev: 0, __pad1: 0,
269 st_size: metadata.size as i64,
270 st_blksize: 4096, __pad2: 0,
272 st_blocks: ((metadata.size + 511) / 512) as i64, st_atime: metadata.accessed_time as i64,
274 st_atime_nsec: 0,
275 st_mtime: metadata.modified_time as i64,
276 st_mtime_nsec: 0,
277 st_ctime: metadata.created_time as i64,
278 st_ctime_nsec: 0,
279 __unused4: 0,
280 __unused5: 0,
281 }
282 }
283}
284
285fn statx_timestamp_from_secs(seconds: u64) -> LinuxStatxTimestamp {
286 LinuxStatxTimestamp {
287 tv_sec: seconds as i64,
288 tv_nsec: 0,
289 __reserved: 0,
290 }
291}
292
293fn next_pseudo_random_u64() -> u64 {
294 loop {
295 let mut state = XORSHIFT_STATE.load(Ordering::Relaxed);
296 if state == 0 {
297 state = crate::time::current_time() ^ 0x9e3779b97f4a7c15;
298 if state == 0 {
299 state = 0x4f1bbcdcb7a43413;
300 }
301 }
302 let mut x = state;
303 x ^= x << 13;
304 x ^= x >> 7;
305 x ^= x << 17;
306 if XORSHIFT_STATE
307 .compare_exchange(state, x, Ordering::Relaxed, Ordering::Relaxed)
308 .is_ok()
309 {
310 return x;
311 }
312 }
313}
314
315fn fill_pseudo_random(buffer: &mut [u8]) {
316 let mut offset = 0;
317 while offset < buffer.len() {
318 let bytes = next_pseudo_random_u64().to_le_bytes();
319 let to_copy = core::cmp::min(bytes.len(), buffer.len() - offset);
320 buffer[offset..offset + to_copy].copy_from_slice(&bytes[..to_copy]);
321 offset += to_copy;
322 }
323}
324
325fn fill_statx_from_stat(
326 statx: &mut LinuxStatx,
327 stat: &LinuxStat,
328 created_time: u64,
329 requested_mask: u32,
330) {
331 let supported_mask = STATX_BASIC_STATS | STATX_BTIME;
332 let effective_mask = if requested_mask == 0 {
333 STATX_BASIC_STATS
334 } else {
335 requested_mask
336 };
337
338 statx.stx_mask = supported_mask & effective_mask;
339 statx.stx_blksize = stat.st_blksize as u32;
340 statx.stx_attributes = 0;
341 statx.stx_nlink = stat.st_nlink;
342 statx.stx_uid = stat.st_uid;
343 statx.stx_gid = stat.st_gid;
344 statx.stx_mode = stat.st_mode as u16;
345 statx.__spare0 = [0; 1];
346 statx.stx_ino = stat.st_ino;
347 statx.stx_size = stat.st_size as u64;
348 statx.stx_blocks = stat.st_blocks as u64;
349 statx.stx_attributes_mask = 0;
350 statx.stx_atime = statx_timestamp_from_secs(stat.st_atime as u64);
351 statx.stx_btime = statx_timestamp_from_secs(created_time);
352 statx.stx_ctime = statx_timestamp_from_secs(stat.st_ctime as u64);
353 statx.stx_mtime = statx_timestamp_from_secs(stat.st_mtime as u64);
354 statx.stx_rdev_major = 0;
355 statx.stx_rdev_minor = 0;
356 statx.stx_dev_major = 0;
357 statx.stx_dev_minor = 0;
358 statx.stx_mnt_id = 0;
359 statx.stx_dio_mem_align = 0;
360 statx.stx_dio_offset_align = 0;
361 statx.stx_subvol = 0;
362 statx.stx_atomic_write_unit_min = 0;
363 statx.stx_atomic_write_unit_max = 0;
364 statx.stx_atomic_write_segments_max = 0;
365 statx.stx_dio_read_offset_align = 0;
366 statx.__spare3 = [0; 9];
367}
368
369const MAX_PATH_LENGTH: usize = 1024; const MAX_ARG_COUNT: usize = 64;
403
404#[allow(dead_code)]
416pub fn sys_exec(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
417 let task = mytask().unwrap();
418
419 trapframe.increment_pc_next(task);
421
422 let path_ptr = trapframe.get_arg(0);
424 let argv_ptr = trapframe.get_arg(1);
425
426 let path_str = match parse_c_string_from_userspace(task, path_ptr, MAX_PATH_LENGTH) {
428 Ok(path) => match to_absolute_path_v2(&task, &path) {
429 Ok(abs_path) => abs_path,
430 Err(_) => return usize::MAX, },
432 Err(_) => return usize::MAX, };
434
435 let argv_strings =
437 match parse_string_array_from_userspace(task, argv_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
438 Ok(args) => args,
439 Err(_) => return usize::MAX, };
441
442 let argv_refs: Vec<&str> = argv_strings.iter().map(|s| s.as_str()).collect();
444
445 match TransparentExecutor::execute_binary(&path_str, &argv_refs, &[], task, trapframe, false) {
447 Ok(_) => {
448 trapframe.get_return_value()
452 }
453 Err(_) => {
454 usize::MAX }
458 }
459}
460
461#[repr(i32)]
462#[allow(dead_code)]
463enum OpenMode {
464 ReadOnly = 0x000,
465 WriteOnly = 0x001,
466 ReadWrite = 0x002,
467 Create = 0x200,
468 Truncate = 0x400,
469}
470
471pub fn sys_openat(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
486 let task = mytask().unwrap();
487 let dirfd = trapframe.get_arg(0) as i32;
488 let path_ptr = task
489 .vm_manager
490 .translate_vaddr(trapframe.get_arg(1))
491 .unwrap() as *const u8;
492 let flags = trapframe.get_arg(2) as i32;
493
494 trapframe.increment_pc_next(task);
496
497 let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
499 Ok((path, _)) => path,
500 Err(_) => return errno::to_result(errno::EFAULT), };
502
503 let path_str = remap_shm_path(&path_str);
504
505 let vfs_guard = task.vfs.read();
508 let vfs = vfs_guard.as_deref().unwrap();
509
510 use crate::fs::vfs_v2::core::VfsFileObject;
512
513 const AT_FDCWD: i32 = -100;
514 let (base_entry, base_mount) = if dirfd == AT_FDCWD {
515 vfs.get_cwd().unwrap_or_else(|| {
517 let root_mount = vfs.mount_tree.root_mount.read().clone();
518 (root_mount.root.clone(), root_mount)
519 })
520 } else {
521 let handle = match abi.get_handle(dirfd as usize) {
523 Some(h) => h,
524 None => return errno::to_result(errno::EBADF), };
526 let kernel_obj = match task.handle_table.get(handle) {
527 Some(obj) => obj,
528 None => return errno::to_result(errno::EBADF), };
530 let file_obj = match kernel_obj.as_file() {
531 Some(f) => f,
532 None => return errno::to_result(errno::ENOTDIR), };
534 let vfs_file_obj = file_obj
535 .as_any()
536 .downcast_ref::<VfsFileObject>()
537 .ok_or(())
538 .unwrap();
539 (
540 vfs_file_obj.get_vfs_entry().clone(),
541 vfs_file_obj.get_mount_point().clone(),
542 )
543 };
544
545 let mapped_path = if path_str == "/dev/tty" {
548 "/dev/tty0".to_string()
549 } else if let Some(rest) = path_str.strip_prefix("/dev/vc/") {
550 alloc::format!("/dev/tty{}", rest)
552 } else if let Some(n) = path_str.strip_prefix("/dev/tty") {
553 if n != "0" && n.chars().all(|c| c.is_ascii_digit()) {
556 "/dev/tty0".to_string()
557 } else {
558 path_str.clone()
559 }
560 } else {
561 path_str.clone()
562 };
563
564 let file = vfs.open_from(&base_entry, &base_mount, &mapped_path, flags as u32);
585
586 let kernel_obj = match file {
587 Ok(obj) => {
588 obj
590 }
591 Err(e) => {
592 if flags & O_CREAT != 0 {
595 let absolute_path = if mapped_path.starts_with('/') {
598 mapped_path.to_string()
599 } else {
600 match to_absolute_path_v2(&task, &mapped_path) {
602 Ok(p) => p,
603 Err(_) => return errno::to_result(errno::ENOENT), }
605 };
606
607 let vfs_mut = match task.vfs.read().clone() {
609 Some(v) => v,
610 None => return errno::to_result(errno::EIO), };
612
613 match vfs_mut.create_file(&absolute_path, FileType::RegularFile) {
615 Ok(_) => {
616 let vfs_guard = task.vfs.read();
619 let vfs = vfs_guard.as_deref().unwrap();
620 match vfs.open_from(&base_entry, &base_mount, &mapped_path, flags as u32) {
621 Ok(obj) => obj,
622 Err(err) => return errno::to_result(errno::from_fs_error(&err)),
623 }
624 }
625 Err(create_err) => {
626 if flags & O_EXCL != 0
628 && create_err.kind == crate::fs::FileSystemErrorKind::AlreadyExists
629 {
630 return errno::to_result(errno::EEXIST); }
632 let vfs_guard = task.vfs.read();
634 let vfs = vfs_guard.as_deref().unwrap();
635 let reopen_flags = (flags as u32) & !((O_CREAT | O_EXCL) as u32);
636 match vfs.open_from(&base_entry, &base_mount, &mapped_path, reopen_flags) {
637 Ok(obj) => obj,
638 Err(open_err) => {
639 return errno::to_result(errno::from_fs_error(&open_err));
640 }
641 }
642 }
643 }
644 } else {
645 return errno::to_result(errno::from_fs_error(&e)); }
647 }
648 };
649
650 if let Some(file_obj) = kernel_obj.as_file() {
652 if (flags & O_DIRECTORY) != 0 {
653 if let Ok(meta) = file_obj.metadata() {
654 if !matches!(meta.file_type, FileType::Directory) {
655 return errno::to_result(errno::ENOTDIR);
656 }
657 }
658 }
659 if (flags & O_TRUNC) != 0 {
660 let _ = file_obj.truncate(0);
661 }
662 if (flags & O_APPEND) != 0 {
663 let _ = file_obj.seek(SeekFrom::End(0));
664 }
665 }
666
667 let handle = task.handle_table.insert(kernel_obj);
669 match handle {
670 Ok(handle) => {
671 match abi.allocate_fd(handle as u32) {
672 Ok(fd) => {
673 let mut status_flags: u32 = 0;
676 if (flags & O_NONBLOCK) != 0 {
677 status_flags |= O_NONBLOCK as u32;
678 }
679 let _ = abi.set_file_status_flags(fd, status_flags);
680
681 if let Some(obj) = task.handle_table.get(handle) {
683 if let Some(sel) = obj.as_selectable() {
684 sel.set_nonblocking(((status_flags as i32) & O_NONBLOCK) != 0);
685 }
686 }
687 fd
688 }
689 Err(_) => errno::to_result(errno::EMFILE), }
691 }
692 Err(_) => errno::to_result(errno::ENFILE), }
694}
695
696pub fn sys_dup(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
697 let task = mytask().unwrap();
698 let fd = trapframe.get_arg(0) as usize;
699 trapframe.increment_pc_next(task);
700
701 if let Some(old_handle) = abi.get_handle(fd) {
703 if let Some(kernel_obj) = task.handle_table.clone_for_dup(old_handle) {
705 let handle = task.handle_table.insert(kernel_obj);
706 match handle {
707 Ok(new_handle) => {
708 match abi.allocate_fd(new_handle as u32) {
709 Ok(fd) => fd,
710 Err(_) => errno::to_result(errno::EMFILE), }
712 }
713 Err(_) => errno::to_result(errno::ENFILE), }
715 } else {
716 errno::to_result(errno::EBADF) }
718 } else {
719 errno::to_result(errno::EBADF) }
721}
722
723pub fn sys_dup3(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
724 let task = mytask().unwrap();
725 let oldfd = trapframe.get_arg(0) as usize;
726 let newfd = trapframe.get_arg(1) as usize;
727 let flags = trapframe.get_arg(2) as u32;
728 trapframe.increment_pc_next(task);
729
730 if oldfd == newfd {
732 return usize::MAX; }
734
735 if flags != 0 && flags != (O_CLOEXEC as u32) {
737 return usize::MAX; }
739
740 if let Some(old_handle) = abi.get_handle(oldfd) {
742 if let Some(kernel_obj) = task.handle_table.clone_for_dup(old_handle) {
744 let handle = task.handle_table.insert(kernel_obj);
745 match handle {
746 Ok(new_handle) => {
747 if abi.get_handle(newfd).is_some() {
749 if let Some(old_new_handle) = abi.remove_fd(newfd) {
750 let _ = task.handle_table.remove(old_new_handle);
751 }
752 }
753
754 match abi.allocate_specific_fd(newfd, new_handle as u32) {
756 Ok(()) => {
757 if flags & (O_CLOEXEC as u32) != 0 {
759 let _ = abi.set_fd_flags(newfd, FD_CLOEXEC);
760 }
761 newfd
762 }
763 Err(_) => usize::MAX, }
765 }
766 Err(_) => usize::MAX, }
768 } else {
769 usize::MAX }
771 } else {
772 usize::MAX }
774}
775
776pub fn sys_close(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
777 let task = mytask().unwrap();
778 let fd = trapframe.get_arg(0) as usize;
779 trapframe.increment_pc_next(task);
780
781 if let Some(handle) = abi.remove_fd(fd) {
783 if task.handle_table.remove(handle).is_some() {
784 0 } else {
786 usize::MAX }
788 } else {
789 usize::MAX }
791}
792
793pub fn sys_read(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
794 let task = mytask().unwrap();
795 let fd = trapframe.get_arg(0) as usize;
796 let buf_ptr = task
797 .vm_manager
798 .translate_vaddr(trapframe.get_arg(1))
799 .unwrap() as *mut u8;
800 let count = trapframe.get_arg(2) as usize;
801
802 let handle = match abi.get_handle(fd) {
804 Some(h) => h,
805 None => {
806 trapframe.increment_pc_next(task);
807 return usize::MAX; }
809 };
810
811 let kernel_obj = match task.handle_table.get(handle) {
812 Some(obj) => obj,
813 None => {
814 trapframe.increment_pc_next(task);
815 return usize::MAX; }
817 };
818
819 let nonblocking = abi
821 .get_file_status_flags(fd)
822 .map(|f| ((f as i32) & O_NONBLOCK) != 0)
823 .unwrap_or(false);
824
825 let is_directory = if let Some(file_obj) = kernel_obj.as_file() {
827 if let Ok(metadata) = file_obj.metadata() {
828 matches!(metadata.file_type, FileType::Directory)
829 } else {
830 false
831 }
832 } else {
833 false
834 };
835
836 let stream = match kernel_obj.as_stream() {
837 Some(stream) => stream,
838 None => {
839 trapframe.increment_pc_next(task);
840 return usize::MAX; }
842 };
843
844 if is_directory {
845 trapframe.increment_pc_next(task);
881 return usize::MAX; } else {
883 let mut buffer = unsafe { core::slice::from_raw_parts_mut(buf_ptr, count) };
885
886 match stream.read(&mut buffer) {
887 Ok(n) => {
888 trapframe.increment_pc_next(task); n
890 } Err(e) => {
892 match e {
893 StreamError::EndOfStream => {
894 trapframe.increment_pc_next(task); 0 }
897 StreamError::WouldBlock => {
898 if nonblocking {
899 trapframe.increment_pc_next(task);
900 return errno::to_result(errno::EAGAIN);
901 } else {
902 get_scheduler().schedule(trapframe); usize::MAX }
905 }
906 _ => {
907 trapframe.increment_pc_next(task); usize::MAX
910 }
911 }
912 }
913 }
914 }
915}
916
917pub fn sys_write(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
918 let task = mytask().unwrap();
919 let fd = trapframe.get_arg(0) as usize;
920 let buf_ptr = task
921 .vm_manager
922 .translate_vaddr(trapframe.get_arg(1))
923 .unwrap() as *const u8;
924 let count = trapframe.get_arg(2) as usize;
925
926 trapframe.increment_pc_next(task);
928
929 let handle = match abi.get_handle(fd) {
931 Some(h) => h,
932 None => return usize::MAX, };
934
935 let kernel_obj = match task.handle_table.get(handle) {
936 Some(obj) => obj,
937 None => return usize::MAX, };
939
940 let stream = match kernel_obj.as_stream() {
941 Some(stream) => stream,
942 None => return usize::MAX, };
944
945 let nonblocking = abi
947 .get_file_status_flags(fd)
948 .map(|f| ((f as i32) & O_NONBLOCK) != 0)
949 .unwrap_or(false);
950
951 let buffer = unsafe { core::slice::from_raw_parts(buf_ptr, count) };
952
953 match stream.write(buffer) {
954 Ok(n) => n,
955 Err(StreamError::WouldBlock) => {
956 if nonblocking {
957 return errno::to_result(errno::EAGAIN);
958 } else {
959 get_scheduler().schedule(trapframe);
960 usize::MAX
961 }
962 }
963 Err(_) => usize::MAX, }
965}
966
967pub fn sys_pread64(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
968 let task = mytask().unwrap();
969 let fd = trapframe.get_arg(0) as usize;
970 let buf_addr = trapframe.get_arg(1);
971 let count = trapframe.get_arg(2) as usize;
972 let position = trapframe.get_arg(3) as i64;
973
974 if position < 0 {
975 trapframe.increment_pc_next(task);
976 return errno::to_result(errno::EINVAL);
977 }
978
979 if count == 0 {
980 trapframe.increment_pc_next(task);
981 return 0;
982 }
983
984 let buf_ptr = match task.vm_manager.translate_vaddr(buf_addr) {
985 Some(ptr) => ptr as *mut u8,
986 None => {
987 trapframe.increment_pc_next(task);
988 return errno::to_result(errno::EFAULT);
989 }
990 };
991
992 if buf_ptr.is_null() {
993 trapframe.increment_pc_next(task);
994 return errno::to_result(errno::EFAULT);
995 }
996
997 let handle = match abi.get_handle(fd) {
998 Some(h) => h,
999 None => {
1000 trapframe.increment_pc_next(task);
1001 return errno::to_result(errno::EBADF);
1002 }
1003 };
1004
1005 let kernel_obj = match task.handle_table.get(handle) {
1006 Some(obj) => obj,
1007 None => {
1008 trapframe.increment_pc_next(task);
1009 return errno::to_result(errno::EBADF);
1010 }
1011 };
1012
1013 let file = match kernel_obj.as_file() {
1014 Some(file) => file,
1015 None => {
1016 trapframe.increment_pc_next(task);
1017 if kernel_obj.as_stream().is_some() {
1018 return errno::to_result(errno::ESPIPE);
1019 }
1020 return errno::to_result(errno::EBADF);
1021 }
1022 };
1023
1024 let mut buffer = unsafe { core::slice::from_raw_parts_mut(buf_ptr, count) };
1025
1026 let nonblocking = abi
1027 .get_file_status_flags(fd)
1028 .map(|f| ((f as i32) & O_NONBLOCK) != 0)
1029 .unwrap_or(false);
1030
1031 match file.read_at(position as u64, &mut buffer) {
1032 Ok(n) => {
1033 trapframe.increment_pc_next(task);
1034 n
1035 }
1036 Err(StreamError::EndOfStream) => {
1037 trapframe.increment_pc_next(task);
1038 0
1039 }
1040 Err(StreamError::WouldBlock) => {
1041 if nonblocking {
1042 trapframe.increment_pc_next(task);
1043 errno::to_result(errno::EAGAIN)
1044 } else {
1045 get_scheduler().schedule(trapframe);
1046 usize::MAX
1047 }
1048 }
1049 Err(err) => {
1050 trapframe.increment_pc_next(task);
1051 errno::to_result(stream_error_to_errno(err))
1052 }
1053 }
1054}
1055
1056pub fn sys_pwrite64(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1057 let task = mytask().unwrap();
1058 let fd = trapframe.get_arg(0) as usize;
1059 let buf_addr = trapframe.get_arg(1);
1060 let count = trapframe.get_arg(2) as usize;
1061 let position = trapframe.get_arg(3) as i64;
1062
1063 if position < 0 {
1064 trapframe.increment_pc_next(task);
1065 return errno::to_result(errno::EINVAL);
1066 }
1067
1068 if count == 0 {
1069 trapframe.increment_pc_next(task);
1070 return 0;
1071 }
1072
1073 let buf_ptr = match task.vm_manager.translate_vaddr(buf_addr) {
1074 Some(ptr) => ptr as *const u8,
1075 None => {
1076 trapframe.increment_pc_next(task);
1077 return errno::to_result(errno::EFAULT);
1078 }
1079 };
1080
1081 if buf_ptr.is_null() {
1082 trapframe.increment_pc_next(task);
1083 return errno::to_result(errno::EFAULT);
1084 }
1085
1086 let handle = match abi.get_handle(fd) {
1087 Some(h) => h,
1088 None => {
1089 trapframe.increment_pc_next(task);
1090 return errno::to_result(errno::EBADF);
1091 }
1092 };
1093
1094 let kernel_obj = match task.handle_table.get(handle) {
1095 Some(obj) => obj,
1096 None => {
1097 trapframe.increment_pc_next(task);
1098 return errno::to_result(errno::EBADF);
1099 }
1100 };
1101
1102 let file = match kernel_obj.as_file() {
1103 Some(file) => file,
1104 None => {
1105 trapframe.increment_pc_next(task);
1106 if kernel_obj.as_stream().is_some() {
1107 return errno::to_result(errno::ESPIPE);
1108 }
1109 return errno::to_result(errno::EBADF);
1110 }
1111 };
1112
1113 let buffer = unsafe { core::slice::from_raw_parts(buf_ptr, count) };
1114
1115 let nonblocking = abi
1116 .get_file_status_flags(fd)
1117 .map(|f| ((f as i32) & O_NONBLOCK) != 0)
1118 .unwrap_or(false);
1119
1120 match file.write_at(position as u64, buffer) {
1121 Ok(n) => {
1122 trapframe.increment_pc_next(task);
1123 n
1124 }
1125 Err(StreamError::WouldBlock) => {
1126 if nonblocking {
1127 trapframe.increment_pc_next(task);
1128 errno::to_result(errno::EAGAIN)
1129 } else {
1130 get_scheduler().schedule(trapframe);
1131 usize::MAX
1132 }
1133 }
1134 Err(err) => {
1135 trapframe.increment_pc_next(task);
1136 errno::to_result(stream_error_to_errno(err))
1137 }
1138 }
1139}
1140
1141fn stream_error_to_errno(err: StreamError) -> usize {
1142 match err {
1143 StreamError::EndOfStream => errno::SUCCESS,
1144 StreamError::WouldBlock => errno::EAGAIN,
1145 StreamError::IoError => errno::EIO,
1146 StreamError::Closed => errno::EBADF,
1147 StreamError::InvalidArgument => errno::EINVAL,
1148 StreamError::Interrupted => errno::EINTR,
1149 StreamError::PermissionDenied => errno::EACCES,
1150 StreamError::DeviceError => errno::EIO,
1151 StreamError::NotSupported | StreamError::SeekError => errno::ESPIPE,
1152 StreamError::NoSpace => errno::ENOSPC,
1153 StreamError::BrokenPipe => errno::EPIPE,
1154 StreamError::FileSystemError(fs_err) => errno::from_fs_error(&fs_err),
1155 StreamError::Other(_) => errno::EIO,
1156 }
1157}
1158
1159pub fn sys_writev(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1174 let task = mytask().unwrap();
1175 let fd = trapframe.get_arg(0) as usize;
1176 let iovec_ptr = trapframe.get_arg(1);
1177 let iovcnt = trapframe.get_arg(2) as usize;
1178
1179 trapframe.increment_pc_next(task);
1181
1182 if iovcnt == 0 {
1184 return 0; }
1186
1187 const IOV_MAX: usize = 1024;
1189 if iovcnt > IOV_MAX {
1190 return usize::MAX; }
1192
1193 let handle = match abi.get_handle(fd) {
1195 Some(h) => h,
1196 None => return usize::MAX, };
1198
1199 let kernel_obj = match task.handle_table.get(handle) {
1200 Some(obj) => obj,
1201 None => return usize::MAX, };
1203
1204 let stream = match kernel_obj.as_stream() {
1205 Some(stream) => stream,
1206 None => return usize::MAX, };
1208
1209 let nonblocking = abi
1210 .get_file_status_flags(fd)
1211 .map(|f| ((f as i32) & O_NONBLOCK) != 0)
1212 .unwrap_or(false);
1213
1214 let iovec_vaddr = match task.vm_manager.translate_vaddr(iovec_ptr) {
1216 Some(addr) => addr as *const IoVec,
1217 None => return usize::MAX, };
1219
1220 if iovec_vaddr.is_null() {
1221 return usize::MAX; }
1223
1224 let iovecs = unsafe { core::slice::from_raw_parts(iovec_vaddr, iovcnt) };
1226
1227 let mut total_written = 0usize;
1228
1229 for iovec in iovecs {
1231 if iovec.iov_len == 0 {
1232 continue; }
1234
1235 let buf_vaddr = match task.vm_manager.translate_vaddr(iovec.iov_base as usize) {
1237 Some(addr) => addr as *const u8,
1238 None => return usize::MAX, };
1240
1241 if buf_vaddr.is_null() {
1242 return usize::MAX; }
1244
1245 let buffer = unsafe { core::slice::from_raw_parts(buf_vaddr, iovec.iov_len) };
1247
1248 match stream.write(buffer) {
1250 Ok(n) => {
1251 total_written = total_written.saturating_add(n);
1252
1253 if n < iovec.iov_len {
1256 break;
1257 }
1258 }
1259 Err(StreamError::WouldBlock) => {
1260 if nonblocking {
1261 if total_written == 0 {
1263 return errno::to_result(errno::EAGAIN);
1264 } else {
1265 break;
1266 }
1267 } else {
1268 get_scheduler().schedule(trapframe);
1269 return usize::MAX;
1270 }
1271 }
1272 Err(_) => {
1273 if total_written == 0 {
1276 return usize::MAX;
1277 } else {
1278 break;
1279 }
1280 }
1281 }
1282 }
1283
1284 total_written
1285}
1286
1287pub fn sys_lseek(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1288 let task = mytask().unwrap();
1289 let fd = trapframe.get_arg(0) as usize;
1290 let offset = trapframe.get_arg(1) as i64;
1291 let whence = trapframe.get_arg(2) as i32;
1292
1293 trapframe.increment_pc_next(task);
1295
1296 let handle = match abi.get_handle(fd) {
1298 Some(h) => h,
1299 None => return usize::MAX, };
1301
1302 let kernel_obj = match task.handle_table.get(handle) {
1303 Some(obj) => obj,
1304 None => return usize::MAX, };
1306
1307 let file = match kernel_obj.as_file() {
1308 Some(file) => file,
1309 None => return usize::MAX, };
1311
1312 let whence = match whence {
1313 0 => SeekFrom::Start(offset as u64),
1314 1 => SeekFrom::Current(offset),
1315 2 => SeekFrom::End(offset),
1316 _ => return usize::MAX, };
1318
1319 match file.seek(whence) {
1320 Ok(pos) => pos as usize,
1321 Err(e) => {
1322 crate::println!("sys_lseek: seek error: {:?}", e);
1323 usize::MAX }
1325 }
1326}
1327
1328pub fn sys_newfstatat(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1427 let task = mytask().unwrap();
1428 let dirfd = trapframe.get_arg(0) as i32;
1429 let path_ptr = task
1430 .vm_manager
1431 .translate_vaddr(trapframe.get_arg(1))
1432 .unwrap() as *const u8;
1433 let stat_ptr = task
1434 .vm_manager
1435 .translate_vaddr(trapframe.get_arg(2))
1436 .unwrap() as *mut u8;
1437 let flags = trapframe.get_arg(3) as i32;
1438
1439 trapframe.increment_pc_next(task);
1441
1442 let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
1444 Ok((path, _)) => path,
1445 Err(_) => return usize::MAX, };
1447
1448 let path_str = remap_shm_path(&path_str);
1449
1450 let vfs_guard = task.vfs.read();
1458 let vfs = vfs_guard.as_deref().unwrap();
1459
1460 use crate::fs::vfs_v2::core::VfsFileObject;
1462
1463 const AT_FDCWD: i32 = -100;
1464 const AT_SYMLINK_NOFOLLOW: i32 = 0x100;
1465
1466 let _follow_symlinks = (flags & AT_SYMLINK_NOFOLLOW) == 0;
1469
1470 let (base_entry, base_mount) = if dirfd == AT_FDCWD {
1471 vfs.get_cwd().unwrap_or_else(|| {
1473 let root_mount = vfs.mount_tree.root_mount.read().clone();
1474 (root_mount.root.clone(), root_mount)
1475 })
1476 } else {
1477 let handle = match abi.get_handle(dirfd as usize) {
1479 Some(h) => h,
1480 None => return usize::MAX,
1481 };
1482 let kernel_obj = match task.handle_table.get(handle) {
1483 Some(obj) => obj,
1484 None => return usize::MAX,
1485 };
1486 let file_obj = match kernel_obj.as_file() {
1487 Some(f) => f,
1488 None => return usize::MAX,
1489 };
1490 let vfs_file_obj = file_obj
1491 .as_any()
1492 .downcast_ref::<VfsFileObject>()
1493 .ok_or(())
1494 .unwrap();
1495 (
1496 vfs_file_obj.get_vfs_entry().clone(),
1497 vfs_file_obj.get_mount_point().clone(),
1498 )
1499 };
1500
1501 match vfs.resolve_path_from(&base_entry, &base_mount, &path_str) {
1503 Ok((entry, _mount_point)) => {
1504 let node = entry.node();
1506 match node.metadata() {
1507 Ok(metadata) => {
1508 if stat_ptr.is_null() {
1509 return usize::MAX; }
1511
1512 let stat = unsafe { &mut *(stat_ptr as *mut LinuxStat) };
1513 *stat = LinuxStat::from_metadata(&metadata);
1514 0 }
1521 Err(_) => usize::MAX, }
1523 }
1524 Err(_) => usize::MAX, }
1526}
1527
1528pub fn sys_statx(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1534 let task = match mytask() {
1535 Some(t) => t,
1536 None => return errno::to_result(errno::EIO),
1537 };
1538
1539 let dirfd = trapframe.get_arg(0) as i32;
1540 let pathname_ptr = trapframe.get_arg(1);
1541 let flags = trapframe.get_arg(2) as u32;
1542 let mask = trapframe.get_arg(3) as u32;
1543 let statx_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(4)) {
1544 Some(ptr) => ptr as *mut LinuxStatx,
1545 None => return errno::to_result(errno::EFAULT),
1546 };
1547
1548 trapframe.increment_pc_next(task);
1550
1551 if statx_ptr.is_null() {
1552 return errno::to_result(errno::EFAULT);
1553 }
1554
1555 const AT_FDCWD: i32 = -100;
1556 const AT_SYMLINK_NOFOLLOW: u32 = 0x100;
1557 const AT_EMPTY_PATH: u32 = 0x1000;
1558
1559 let path_str = match parse_c_string_from_userspace(task, pathname_ptr, MAX_PATH_LENGTH) {
1560 Ok(s) => s,
1561 Err(_) => return errno::to_result(errno::EFAULT),
1562 };
1563 let path_str = remap_shm_path(&path_str);
1564 let vfs = match task.vfs.read().clone() {
1573 Some(v) => v,
1574 None => return errno::to_result(errno::EIO),
1575 };
1576
1577 if path_str.is_empty() && (flags & AT_EMPTY_PATH) != 0 {
1579 let handle = match abi.get_handle(dirfd as usize) {
1580 Some(h) => h,
1581 None => return errno::to_result(errno::EBADF),
1582 };
1583 let kernel_obj = match task.handle_table.get(handle) {
1584 Some(obj) => obj,
1585 None => return errno::to_result(errno::EBADF),
1586 };
1587 let file_obj = match kernel_obj.as_file() {
1588 Some(f) => f,
1589 None => return errno::to_result(errno::EBADF),
1590 };
1591
1592 use crate::fs::vfs_v2::core::VfsFileObject;
1593 if let Some(vfs_file_obj) = file_obj.as_any().downcast_ref::<VfsFileObject>() {
1594 let entry = vfs_file_obj.get_vfs_entry();
1595 let node = entry.node();
1596 let metadata = match node.metadata() {
1597 Ok(m) => m,
1598 Err(e) => return errno::to_result(errno::from_fs_error(&e)),
1599 };
1600 let stat = LinuxStat::from_metadata(&metadata);
1601 let statx_ref = unsafe { &mut *statx_ptr };
1602 fill_statx_from_stat(statx_ref, &stat, metadata.created_time, mask);
1603 return 0;
1609 }
1610
1611 let stat = LinuxStat {
1612 st_dev: 0,
1613 st_ino: handle as u64,
1614 st_mode: S_IFCHR | 0o666,
1615 st_nlink: 1,
1616 st_uid: 0,
1617 st_gid: 0,
1618 st_rdev: handle as u64,
1619 __pad1: 0,
1620 st_size: 0,
1621 st_blksize: 4096,
1622 __pad2: 0,
1623 st_blocks: 0,
1624 st_atime: 0,
1625 st_atime_nsec: 0,
1626 st_mtime: 0,
1627 st_mtime_nsec: 0,
1628 st_ctime: 0,
1629 st_ctime_nsec: 0,
1630 __unused4: 0,
1631 __unused5: 0,
1632 };
1633 let statx_ref = unsafe { &mut *statx_ptr };
1634 fill_statx_from_stat(statx_ref, &stat, 0, mask);
1635 return 0;
1636 }
1637
1638 use crate::fs::vfs_v2::core::VfsFileObject;
1640
1641 let (base_entry, base_mount) = if dirfd == AT_FDCWD {
1642 vfs.get_cwd().unwrap_or_else(|| {
1643 let root_mount = vfs.mount_tree.root_mount.read().clone();
1644 (root_mount.root.clone(), root_mount)
1645 })
1646 } else {
1647 let handle = match abi.get_handle(dirfd as usize) {
1648 Some(h) => h,
1649 None => return errno::to_result(errno::EBADF),
1650 };
1651 let kernel_obj = match task.handle_table.get(handle) {
1652 Some(obj) => obj,
1653 None => return errno::to_result(errno::EBADF),
1654 };
1655 let file_obj = match kernel_obj.as_file() {
1656 Some(f) => f,
1657 None => return errno::to_result(errno::ENOTDIR),
1658 };
1659 let vfs_file_obj = match file_obj.as_any().downcast_ref::<VfsFileObject>() {
1660 Some(vfs_obj) => vfs_obj,
1661 None => return errno::to_result(errno::ENOTDIR),
1662 };
1663 (
1664 vfs_file_obj.get_vfs_entry().clone(),
1665 vfs_file_obj.get_mount_point().clone(),
1666 )
1667 };
1668
1669 let _follow_symlinks = (flags & AT_SYMLINK_NOFOLLOW) == 0;
1671
1672 let (entry, _mount_point) = match vfs.resolve_path_from(&base_entry, &base_mount, &path_str) {
1673 Ok(v) => v,
1674 Err(e) => return errno::to_result(errno::from_fs_error(&e)),
1675 };
1676
1677 let node = entry.node();
1678 let metadata = match node.metadata() {
1679 Ok(m) => m,
1680 Err(e) => return errno::to_result(errno::from_fs_error(&e)),
1681 };
1682
1683 let stat = LinuxStat::from_metadata(&metadata);
1684 let statx_ref = unsafe { &mut *statx_ptr };
1685 fill_statx_from_stat(statx_ref, &stat, metadata.created_time, mask);
1686 0
1692}
1693
1694#[allow(dead_code)]
1695pub fn sys_mkdir(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1696 let task = mytask().unwrap();
1697 trapframe.increment_pc_next(task);
1698
1699 let path_ptr = task
1700 .vm_manager
1701 .translate_vaddr(trapframe.get_arg(0))
1702 .unwrap() as *const u8;
1703 let path = match get_path_str_v2(path_ptr) {
1704 Ok(p) => to_absolute_path_v2(&task, &p).unwrap(),
1705 Err(_) => return usize::MAX, };
1707
1708 let vfs = task.vfs.read().clone().unwrap();
1710 match vfs.create_dir(&path) {
1711 Ok(_) => 0, Err(_) => usize::MAX, }
1714}
1715
1716#[allow(dead_code)]
1717pub fn sys_unlink(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1718 let task = mytask().unwrap();
1719 trapframe.increment_pc_next(task);
1720
1721 let path_ptr = task
1722 .vm_manager
1723 .translate_vaddr(trapframe.get_arg(0))
1724 .unwrap() as *const u8;
1725 let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
1726 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
1727 Err(_) => return usize::MAX, };
1729
1730 let vfs = task.vfs.read().clone().unwrap();
1732 match vfs.remove(&path) {
1733 Ok(_) => 0, Err(_) => usize::MAX, }
1736}
1737
1738#[allow(dead_code)]
1739pub fn sys_link(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1740 let task = mytask().unwrap();
1741 trapframe.increment_pc_next(task);
1742
1743 let src_path_ptr = task
1744 .vm_manager
1745 .translate_vaddr(trapframe.get_arg(0))
1746 .unwrap() as *const u8;
1747 let dst_path_ptr = task
1748 .vm_manager
1749 .translate_vaddr(trapframe.get_arg(1))
1750 .unwrap() as *const u8;
1751
1752 let src_path = match cstring_to_string(src_path_ptr, MAX_PATH_LENGTH) {
1753 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
1754 Err(_) => return usize::MAX, };
1756
1757 let dst_path = match cstring_to_string(dst_path_ptr, MAX_PATH_LENGTH) {
1758 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
1759 Err(_) => return usize::MAX, };
1761
1762 let vfs_guard = task.vfs.read();
1763 let vfs = vfs_guard.as_deref().unwrap();
1764 match vfs.create_hardlink(&src_path, &dst_path) {
1765 Ok(_) => 0, Err(err) => {
1767 errno::to_result(errno::from_fs_error(&err))
1769 }
1770 }
1771}
1772
1773pub fn sys_linkat(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1791 let task = match mytask() {
1792 Some(t) => t,
1793 None => return usize::MAX,
1794 };
1795
1796 let olddirfd = trapframe.get_arg(0) as i32;
1797 let oldpath_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
1798 Some(ptr) => ptr as *const u8,
1799 None => return usize::MAX,
1800 };
1801 let newdirfd = trapframe.get_arg(2) as i32;
1802 let newpath_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(3)) {
1803 Some(ptr) => ptr as *const u8,
1804 None => return usize::MAX,
1805 };
1806 let flags = trapframe.get_arg(4) as i32;
1807
1808 trapframe.increment_pc_next(task);
1810
1811 let oldpath_str = match cstring_to_string(oldpath_ptr, MAX_PATH_LENGTH) {
1813 Ok((path, _)) => path,
1814 Err(_) => return usize::MAX, };
1816
1817 let newpath_str = match cstring_to_string(newpath_ptr, MAX_PATH_LENGTH) {
1818 Ok((path, _)) => path,
1819 Err(_) => return usize::MAX, };
1821
1822 const AT_FDCWD: i32 = -100;
1824 const AT_SYMLINK_FOLLOW: i32 = 0x400;
1825 const AT_EMPTY_PATH: i32 = 0x1000;
1826
1827 let vfs = match task.vfs.read().clone() {
1828 Some(v) => v,
1829 None => return usize::MAX,
1830 };
1831
1832 use crate::fs::vfs_v2::core::VfsFileObject;
1834
1835 let (old_base_entry, old_base_mount) = if olddirfd == AT_FDCWD {
1836 vfs.get_cwd().unwrap_or_else(|| {
1838 let root_mount = vfs.mount_tree.root_mount.read().clone();
1839 (root_mount.root.clone(), root_mount)
1840 })
1841 } else {
1842 let handle = match abi.get_handle(olddirfd as usize) {
1844 Some(h) => h,
1845 None => return usize::MAX,
1846 };
1847 let kernel_obj = match task.handle_table.get(handle) {
1848 Some(obj) => obj,
1849 None => return usize::MAX,
1850 };
1851 let file_obj = match kernel_obj.as_file() {
1852 Some(f) => f,
1853 None => return usize::MAX,
1854 };
1855 let vfs_file_obj = file_obj
1856 .as_any()
1857 .downcast_ref::<VfsFileObject>()
1858 .ok_or(())
1859 .unwrap();
1860 (
1861 vfs_file_obj.get_vfs_entry().clone(),
1862 vfs_file_obj.get_mount_point().clone(),
1863 )
1864 };
1865
1866 let (_new_base_entry, _new_base_mount) = if newdirfd == AT_FDCWD {
1868 vfs.get_cwd().unwrap_or_else(|| {
1870 let root_mount = vfs.mount_tree.root_mount.read().clone();
1871 (root_mount.root.clone(), root_mount)
1872 })
1873 } else {
1874 let handle = match abi.get_handle(newdirfd as usize) {
1876 Some(h) => h,
1877 None => return usize::MAX,
1878 };
1879 let kernel_obj = match task.handle_table.get(handle) {
1880 Some(obj) => obj,
1881 None => return usize::MAX,
1882 };
1883 let file_obj = match kernel_obj.as_file() {
1884 Some(f) => f,
1885 None => return usize::MAX,
1886 };
1887 let vfs_file_obj = file_obj
1888 .as_any()
1889 .downcast_ref::<VfsFileObject>()
1890 .ok_or(())
1891 .unwrap();
1892 (
1893 vfs_file_obj.get_vfs_entry().clone(),
1894 vfs_file_obj.get_mount_point().clone(),
1895 )
1896 };
1897
1898 let _source_entry = match vfs.resolve_path_from(&old_base_entry, &old_base_mount, &oldpath_str)
1900 {
1901 Ok((entry, _mount_point)) => entry,
1902 Err(_) => return usize::MAX, };
1904
1905 let _old_absolute_path = if oldpath_str.starts_with('/') {
1910 oldpath_str.to_string()
1911 } else {
1912 match to_absolute_path_v2(&task, &oldpath_str) {
1913 Ok(p) => p,
1914 Err(_) => return usize::MAX,
1915 }
1916 };
1917
1918 let _new_absolute_path = if newpath_str.starts_with('/') {
1919 newpath_str.to_string()
1920 } else {
1921 match to_absolute_path_v2(&task, &newpath_str) {
1922 Ok(p) => p,
1923 Err(_) => return usize::MAX,
1924 }
1925 };
1926
1927 let _vfs_mut = match task.vfs.write().clone() {
1929 Some(v) => v,
1930 None => return usize::MAX,
1931 };
1932
1933 let _follow_symlinks = (flags & AT_SYMLINK_FOLLOW) != 0;
1937 let _empty_path = (flags & AT_EMPTY_PATH) != 0;
1938
1939 0 }
1958
1959fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
1961 if path.starts_with('/') {
1962 Ok(path.to_string())
1963 } else {
1964 let vfs_guard = task.vfs.read();
1965 let vfs = vfs_guard.as_ref().ok_or(())?;
1966 Ok(vfs.resolve_path_to_absolute(path))
1967 }
1968}
1969
1970fn get_path_str_v2(ptr: *const u8) -> Result<String, ()> {
1973 const MAX_PATH_LENGTH: usize = 1024; cstring_to_string(ptr, MAX_PATH_LENGTH)
1975 .map(|(s, _)| s)
1976 .map_err(|_| ())
1977}
1978
1979pub fn sys_ioctl(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
1994 let task = mytask().unwrap();
1995 let fd = trapframe.get_arg(0) as usize;
1996 let request = trapframe.get_arg(1) as u32;
1997 let arg = trapframe.get_arg(2);
1998
1999 trapframe.increment_pc_next(task);
2001
2002 let handle = match abi.get_handle(fd) {
2004 Some(h) => h,
2005 None => return usize::MAX, };
2007
2008 let kernel_object = match task.handle_table.get(handle) {
2010 Some(obj) => obj,
2011 None => return usize::MAX, };
2013
2014 let mut caps: Option<&'static [DeviceCapability]> = None;
2016 if let Some(file_obj) = kernel_object.as_file() {
2017 if let Ok(metadata) = file_obj.metadata() {
2018 if let FileType::CharDevice(info) = metadata.file_type {
2019 if let Some(dev) = DeviceManager::get_manager().get_device(info.device_id) {
2020 caps = Some(dev.capabilities());
2021 }
2022 }
2023 }
2024 }
2025
2026 if let Some(caps) = caps {
2027 if caps.iter().any(|c| *c == DeviceCapability::Tty) {
2029 match crate::abi::linux::device::tty::handle_ioctl(request, arg, &kernel_object) {
2030 Ok(Some(ret)) => return ret,
2031 Ok(None) => {
2032 return errno::to_result(errno::ENOTTY);
2035 }
2036 Err(_) => return errno::to_result(errno::ENOTTY),
2037 }
2038 }
2039 }
2041
2042 let result = match kernel_object.as_control() {
2044 Some(control_ops) => control_ops.control(request, arg),
2045 None => Err("Inappropriate ioctl for device"),
2046 };
2047
2048 match result {
2049 Ok(value) => {
2050 if value >= 0 {
2051 value as usize
2052 } else {
2053 errno::to_result(errno::EINVAL)
2054 }
2055 }
2056 Err(_) => errno::to_result(errno::ENOTTY),
2057 }
2058}
2059
2060pub fn sys_execve(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2074 let task = mytask().unwrap();
2075
2076 trapframe.increment_pc_next(task);
2078
2079 let path_ptr = trapframe.get_arg(0);
2081 let argv_ptr = trapframe.get_arg(1);
2082 let envp_ptr = trapframe.get_arg(2);
2083
2084 let path_str = match parse_c_string_from_userspace(task, path_ptr, MAX_PATH_LENGTH) {
2086 Ok(path) => match to_absolute_path_v2(&task, &path) {
2087 Ok(abs_path) => abs_path,
2088 Err(_) => return usize::MAX, },
2090 Err(_) => return usize::MAX, };
2092
2093 let argv_strings =
2095 match parse_string_array_from_userspace(task, argv_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
2096 Ok(args) => args,
2097 Err(_) => return usize::MAX, };
2099
2100 let envp_strings =
2102 match parse_string_array_from_userspace(task, envp_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
2103 Ok(envs) => envs,
2104 Err(_) => return usize::MAX, };
2106
2107 crate::println!(
2108 "sys_execve: path: {}, argv: {:?}, envp: {:?}",
2109 path_str,
2110 argv_strings,
2111 envp_strings
2112 );
2113
2114 for (i, arg) in argv_strings.iter().enumerate() {
2116 crate::println!(" argv[{}]: \"{}\" (len={})", i, arg, arg.len());
2117 for (j, byte) in arg.bytes().enumerate() {
2118 if byte < 32 || byte > 126 {
2119 crate::println!(" byte[{}]: 0x{:02x} (non-printable)", j, byte);
2120 }
2121 }
2122 }
2123
2124 let argv_refs: Vec<&str> = argv_strings.iter().map(|s| s.as_str()).collect();
2126 let envp_refs: Vec<&str> = envp_strings.iter().map(|s| s.as_str()).collect();
2127
2128 match TransparentExecutor::execute_binary(
2130 &path_str, &argv_refs, &envp_refs, task, trapframe, false,
2131 ) {
2132 Ok(_) => {
2133 trapframe.get_return_value()
2137 }
2138 Err(_) => {
2139 usize::MAX }
2143 }
2144}
2145
2146#[repr(C)]
2149#[derive(Debug, Clone, Copy)]
2150pub struct IoVec {
2151 pub iov_base: *mut u8,
2153 pub iov_len: usize,
2155}
2156
2157const LOG_FCNTL: bool = false;
2163pub fn sys_fcntl(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2164 let task = mytask().unwrap();
2165 let fd = trapframe.get_arg(0) as usize;
2166 let cmd = trapframe.get_arg(1) as u32;
2167 let arg = trapframe.get_arg(2);
2168
2169 trapframe.increment_pc_next(task);
2171
2172 match cmd {
2174 F_DUPFD => {
2175 if LOG_FCNTL {
2176 crate::println!(
2177 "[sys_fcntl] F_DUPFD: fd={}, arg={} - NOT IMPLEMENTED",
2178 fd,
2179 arg
2180 );
2181 }
2182 if fd >= super::MAX_FDS {
2183 return errno::to_result(errno::EBADF);
2184 }
2185 let min_fd = arg as usize;
2186 if min_fd >= super::MAX_FDS {
2187 return errno::to_result(errno::EMFILE);
2188 }
2189 let old_handle = match abi.get_handle(fd) {
2190 Some(h) => h,
2191 None => return errno::to_result(errno::EBADF),
2192 };
2193 let kernel_obj = match task.handle_table.clone_for_dup(old_handle) {
2194 Some(obj) => obj,
2195 None => return errno::to_result(errno::EBADF),
2196 };
2197 let mut new_fd = None;
2198 for candidate in min_fd..super::MAX_FDS {
2199 if abi.get_handle(candidate).is_none() {
2200 new_fd = Some(candidate);
2201 break;
2202 }
2203 }
2204 let new_fd = match new_fd {
2205 Some(fd) => fd,
2206 None => return errno::to_result(errno::EMFILE),
2207 };
2208 let new_handle = match task.handle_table.insert(kernel_obj) {
2209 Ok(handle) => handle,
2210 Err(_) => return errno::to_result(errno::ENFILE),
2211 };
2212 if abi.allocate_specific_fd(new_fd, new_handle as u32).is_err() {
2213 let _ = task.handle_table.remove(new_handle as u32);
2214 return errno::to_result(errno::EMFILE);
2215 }
2216 if let Some(flags) = abi.get_file_status_flags(fd) {
2217 let _ = abi.set_file_status_flags(new_fd, flags);
2218 }
2219 let _ = abi.set_fd_flags(new_fd, 0);
2220 return new_fd;
2221 }
2222 F_GETFD => {
2223 if let Some(_handle) = abi.get_handle(fd) {
2225 if let Some(flags) = abi.get_fd_flags(fd) {
2226 return flags as usize; } else {
2228 return usize::MAX; }
2230 } else {
2231 return usize::MAX; }
2233 }
2234 F_SETFD => {
2235 if let Some(_handle) = abi.get_handle(fd) {
2237 match abi.set_fd_flags(fd, arg as u32) {
2238 Ok(()) => return 0, Err(_) => return usize::MAX, }
2241 } else {
2242 return usize::MAX; }
2244 }
2245 F_GETFL => {
2246 if let Some(_handle) = abi.get_handle(fd) {
2247 if let Some(flags) = abi.get_file_status_flags(fd) {
2248 return flags as usize;
2249 } else {
2250 return usize::MAX;
2251 }
2252 } else {
2253 return usize::MAX;
2254 }
2255 }
2256 F_SETFL => {
2257 if let Some(_handle) = abi.get_handle(fd) {
2259 let curr = abi.get_file_status_flags(fd).unwrap_or(0);
2261 let mut new_flags = curr;
2262 const O_NONBLOCK_U32: u32 = O_NONBLOCK as u32;
2263 if (arg as u32) & O_NONBLOCK_U32 != 0 {
2264 new_flags |= O_NONBLOCK_U32;
2265 } else {
2266 new_flags &= !O_NONBLOCK_U32;
2267 }
2268 if abi.set_file_status_flags(fd, new_flags).is_err() {
2269 return usize::MAX;
2270 }
2271 if let Some(handle) = abi.get_handle(fd) {
2273 if let Some(obj) = task.handle_table.get(handle) {
2274 if let Some(sel) = obj.as_selectable() {
2275 sel.set_nonblocking(((new_flags as i32) & O_NONBLOCK) != 0);
2276 }
2277 }
2278 }
2279
2280 return 0;
2281 } else {
2282 return usize::MAX;
2283 }
2284 }
2285 F_GETLK => {
2286 if LOG_FCNTL {
2287 crate::println!(
2288 "[sys_fcntl] F_GETLK: fd={}, lock_ptr={:#x} - NOT IMPLEMENTED",
2289 fd,
2290 arg
2291 );
2292 }
2293 }
2295 F_SETLK => {
2296 if LOG_FCNTL {
2297 crate::println!(
2298 "[sys_fcntl] F_SETLK: fd={}, lock_ptr={:#x} - NOT IMPLEMENTED",
2299 fd,
2300 arg
2301 );
2302 }
2303 }
2305 F_SETLKW => {
2306 if LOG_FCNTL {
2307 crate::println!(
2308 "[sys_fcntl] F_SETLKW: fd={}, lock_ptr={:#x} - NOT IMPLEMENTED",
2309 fd,
2310 arg
2311 );
2312 }
2313 }
2315 F_SETOWN => {
2316 if LOG_FCNTL {
2317 crate::println!(
2318 "[sys_fcntl] F_SETOWN: fd={}, owner={} - NOT IMPLEMENTED",
2319 fd,
2320 arg
2321 );
2322 }
2323 }
2325 F_GETOWN => {
2326 if LOG_FCNTL {
2327 crate::println!("[sys_fcntl] F_GETOWN: fd={} - NOT IMPLEMENTED", fd);
2328 }
2329 }
2331 F_SETSIG => {
2332 if LOG_FCNTL {
2333 crate::println!(
2334 "[sys_fcntl] F_SETSIG: fd={}, sig={} - NOT IMPLEMENTED",
2335 fd,
2336 arg
2337 );
2338 }
2339 }
2341 F_GETSIG => {
2342 if LOG_FCNTL {
2343 crate::println!("[sys_fcntl] F_GETSIG: fd={} - NOT IMPLEMENTED", fd);
2344 }
2345 }
2347 F_SETLEASE => {
2348 if LOG_FCNTL {
2349 crate::println!(
2350 "[sys_fcntl] F_SETLEASE: fd={}, lease_type={} - NOT IMPLEMENTED",
2351 fd,
2352 arg
2353 );
2354 }
2355 }
2357 F_GETLEASE => {
2358 if LOG_FCNTL {
2359 crate::println!("[sys_fcntl] F_GETLEASE: fd={} - NOT IMPLEMENTED", fd);
2360 }
2361 }
2363 F_NOTIFY => {
2364 if LOG_FCNTL {
2365 crate::println!(
2366 "[sys_fcntl] F_NOTIFY: fd={}, events={:#x} - NOT IMPLEMENTED",
2367 fd,
2368 arg
2369 );
2370 }
2371 }
2373 F_DUPFD_CLOEXEC => {
2374 if LOG_FCNTL {
2375 crate::println!(
2376 "[sys_fcntl] F_DUPFD_CLOEXEC: fd={}, arg={} - NOT IMPLEMENTED",
2377 fd,
2378 arg
2379 );
2380 }
2381 if fd >= super::MAX_FDS {
2382 return errno::to_result(errno::EBADF);
2383 }
2384 let min_fd = arg as usize;
2385 if min_fd >= super::MAX_FDS {
2386 return errno::to_result(errno::EMFILE);
2387 }
2388 let old_handle = match abi.get_handle(fd) {
2389 Some(h) => h,
2390 None => return errno::to_result(errno::EBADF),
2391 };
2392 let kernel_obj = match task.handle_table.clone_for_dup(old_handle) {
2393 Some(obj) => obj,
2394 None => return errno::to_result(errno::EBADF),
2395 };
2396 let mut new_fd = None;
2397 for candidate in min_fd..super::MAX_FDS {
2398 if abi.get_handle(candidate).is_none() {
2399 new_fd = Some(candidate);
2400 break;
2401 }
2402 }
2403 let new_fd = match new_fd {
2404 Some(fd) => fd,
2405 None => return errno::to_result(errno::EMFILE),
2406 };
2407 let new_handle = match task.handle_table.insert(kernel_obj) {
2408 Ok(handle) => handle,
2409 Err(_) => return errno::to_result(errno::ENFILE),
2410 };
2411 if abi.allocate_specific_fd(new_fd, new_handle as u32).is_err() {
2412 let _ = task.handle_table.remove(new_handle as u32);
2413 return errno::to_result(errno::EMFILE);
2414 }
2415 if let Some(flags) = abi.get_file_status_flags(fd) {
2416 let _ = abi.set_file_status_flags(new_fd, flags);
2417 }
2418 let _ = abi.set_fd_flags(new_fd, FD_CLOEXEC);
2419 return new_fd;
2420 }
2421 _ => {
2422 if LOG_FCNTL {
2423 crate::println!(
2424 "[sys_fcntl] UNKNOWN_CMD: fd={}, cmd={}, arg={:#x} - NOT IMPLEMENTED",
2425 fd,
2426 cmd,
2427 arg
2428 );
2429 }
2430 }
2431 }
2432
2433 errno::to_result(errno::ENOSYS)
2435}
2436
2437pub fn sys_flock(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2452 let task = match mytask() {
2453 Some(t) => t,
2454 None => return usize::MAX,
2455 };
2456
2457 let fd = trapframe.get_arg(0) as i32;
2458 let _operation = trapframe.get_arg(1) as i32;
2459
2460 trapframe.increment_pc_next(task);
2462
2463 if abi.get_handle(fd as usize).is_none() {
2465 return usize::MAX;
2466 }
2467
2468 0
2472}
2473
2474pub fn sys_fallocate(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2489 use super::errno;
2490
2491 let task = match mytask() {
2492 Some(t) => t,
2493 None => return errno::to_result(errno::EFAULT),
2494 };
2495
2496 let fd = trapframe.get_arg(0) as usize;
2497 let mode = trapframe.get_arg(1) as i32;
2498 let offset = trapframe.get_arg(2) as i64;
2499 let len = trapframe.get_arg(3) as i64;
2500
2501 trapframe.increment_pc_next(task);
2502
2503 if offset < 0 || len <= 0 {
2504 return errno::to_result(errno::EINVAL);
2505 }
2506
2507 let handle = match abi.get_handle(fd) {
2508 Some(h) => h,
2509 None => return errno::to_result(errno::EBADF),
2510 };
2511
2512 let kernel_obj = match task.handle_table.get(handle) {
2513 Some(obj) => obj,
2514 None => return errno::to_result(errno::EBADF),
2515 };
2516
2517 if let Some(shared_memory) = kernel_obj.as_shared_memory() {
2519 const FALLOC_FL_KEEP_SIZE: i32 = 0x01;
2521
2522 let new_size = (offset + len) as usize;
2523 let current_size = shared_memory.size();
2524
2525 if (mode & FALLOC_FL_KEEP_SIZE) == 0 && new_size > current_size {
2527 if let Err(_e) = shared_memory.resize(new_size) {
2528 return errno::to_result(errno::ENOSPC);
2529 }
2530 }
2531
2532 return 0;
2533 }
2534
2535 0
2538}
2539
2540#[repr(C)]
2542pub struct LinuxDirent64 {
2543 pub d_ino: u64,
2544 pub d_off: i64,
2545 pub d_reclen: u16,
2546 pub d_type: u8,
2547 pub d_name: [u8; 256], }
2549
2550impl LinuxDirent64 {
2551 pub fn new(entry: &DirectoryEntry, d_off: i64) -> Self {
2552 let mut d_name = [0u8; 256];
2553 let name_len = entry.name_len as usize;
2554 d_name[..name_len].copy_from_slice(&entry.name[..name_len]);
2555 d_name[name_len] = 0; Self {
2557 d_ino: entry.file_id,
2558 d_off,
2559 d_reclen: (core::mem::size_of::<u64>()
2560 + core::mem::size_of::<i64>()
2561 + core::mem::size_of::<u16>()
2562 + core::mem::size_of::<u8>()
2563 + name_len
2564 + 1) as u16,
2565 d_type: entry.file_type,
2566 d_name,
2567 }
2568 }
2569 pub fn as_bytes(&self) -> &[u8] {
2570 let len = self.d_reclen as usize;
2571 unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, len) }
2572 }
2573}
2574
2575pub fn sys_getdents64(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2577 let task = mytask().unwrap();
2578 let fd = trapframe.get_arg(0) as usize;
2579 let buf_ptr = task
2580 .vm_manager
2581 .translate_vaddr(trapframe.get_arg(1))
2582 .unwrap() as *mut u8;
2583 let buf_size = trapframe.get_arg(2) as usize;
2584 trapframe.increment_pc_next(task);
2585
2586 let handle = match abi.get_handle(fd) {
2588 Some(h) => h,
2589 None => return usize::MAX,
2590 };
2591 let kernel_obj = match task.handle_table.get(handle) {
2592 Some(obj) => obj,
2593 None => return usize::MAX,
2594 };
2595 let stream = match kernel_obj.as_stream() {
2596 Some(s) => s,
2597 None => return usize::MAX,
2598 };
2599
2600 let mut dir_buffer = vec![0u8; core::mem::size_of::<DirectoryEntry>()];
2601 let mut written = 0usize;
2602 let mut d_off = 0i64;
2603 while written + core::mem::size_of::<LinuxDirent64>() <= buf_size {
2604 match stream.read(&mut dir_buffer) {
2605 Ok(n) if n == dir_buffer.len() => {
2606 if let Some(entry) = DirectoryEntry::parse(&dir_buffer) {
2607 let dirent = LinuxDirent64::new(&entry, d_off);
2608 let dirent_bytes = dirent.as_bytes();
2609 if written + dirent_bytes.len() > buf_size {
2610 break;
2611 }
2612 unsafe {
2613 core::ptr::copy_nonoverlapping(
2614 dirent_bytes.as_ptr(),
2615 buf_ptr.add(written),
2616 dirent_bytes.len(),
2617 );
2618 }
2619 written += dirent_bytes.len();
2620 d_off += 1;
2621 } else {
2622 break;
2623 }
2624 }
2625 Ok(0) => break, Ok(_) => break, Err(StreamError::EndOfStream) => break,
2628 Err(StreamError::WouldBlock) => {
2629 get_scheduler().schedule(trapframe);
2630 return usize::MAX;
2631 }
2632 Err(_) => break,
2633 }
2634 }
2635 written
2636}
2637
2638pub fn sys_readv(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2651 let task = mytask().unwrap();
2652 let fd = trapframe.get_arg(0) as usize;
2653 let iovec_ptr = trapframe.get_arg(1);
2654 let iovcnt = trapframe.get_arg(2) as usize;
2655 trapframe.increment_pc_next(task);
2656
2657 if iovcnt == 0 {
2658 return 0;
2659 }
2660 const IOV_MAX: usize = 1024;
2661 if iovcnt > IOV_MAX {
2662 return usize::MAX;
2663 }
2664 let handle = match abi.get_handle(fd) {
2665 Some(h) => h,
2666 None => return usize::MAX,
2667 };
2668 let kernel_obj = match task.handle_table.get(handle) {
2669 Some(obj) => obj,
2670 None => return usize::MAX,
2671 };
2672 let stream = match kernel_obj.as_stream() {
2673 Some(s) => s,
2674 None => return usize::MAX, };
2676
2677 let nonblocking = abi
2678 .get_file_status_flags(fd)
2679 .map(|f| ((f as i32) & O_NONBLOCK) != 0)
2680 .unwrap_or(false);
2681 let iovec_vaddr = match task.vm_manager.translate_vaddr(iovec_ptr) {
2682 Some(addr) => addr as *mut IoVec,
2683 None => return usize::MAX,
2684 };
2685 if iovec_vaddr.is_null() {
2686 return usize::MAX;
2687 }
2688 let iovecs = unsafe { core::slice::from_raw_parts_mut(iovec_vaddr, iovcnt) };
2689 let mut total_read = 0usize;
2690 for iovec in iovecs.iter_mut() {
2691 if iovec.iov_len == 0 {
2692 continue;
2693 }
2694 let buf_vaddr = match task.vm_manager.translate_vaddr(iovec.iov_base as usize) {
2695 Some(addr) => addr as *mut u8,
2696 None => return usize::MAX,
2697 };
2698 if buf_vaddr.is_null() {
2699 return usize::MAX;
2700 }
2701 let buffer = unsafe { core::slice::from_raw_parts_mut(buf_vaddr, iovec.iov_len) };
2702 match stream.read(buffer) {
2703 Ok(n) => {
2704 total_read = total_read.saturating_add(n);
2705 if n < iovec.iov_len {
2708 break;
2709 }
2710 }
2711 Err(StreamError::EndOfStream) => break,
2712 Err(StreamError::WouldBlock) => {
2713 if nonblocking {
2714 if total_read == 0 {
2715 return errno::to_result(errno::EAGAIN);
2716 } else {
2717 break;
2718 }
2719 } else {
2720 get_scheduler().schedule(trapframe);
2721 return usize::MAX;
2722 }
2723 }
2724 Err(_) => {
2725 if total_read == 0 {
2726 return usize::MAX;
2727 } else {
2728 break;
2729 }
2730 }
2731 }
2732 }
2733 total_read
2734}
2735
2736pub fn sys_fsync(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2746 let task = mytask().unwrap();
2747 let _fd = trapframe.get_arg(0);
2748 trapframe.increment_pc_next(task);
2749
2750 0
2753}
2754
2755pub fn sys_ftruncate(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2767 let task = match mytask() {
2768 Some(t) => t,
2769 None => return errno::to_result(errno::EFAULT),
2770 };
2771
2772 let fd = trapframe.get_arg(0) as usize;
2773 let length = trapframe.get_arg(1) as i64;
2774
2775 trapframe.increment_pc_next(task);
2776
2777 if length < 0 {
2778 return errno::to_result(errno::EINVAL);
2779 }
2780
2781 let handle = match abi.get_handle(fd) {
2782 Some(h) => h,
2783 None => return errno::to_result(errno::EBADF),
2784 };
2785
2786 let kernel_obj = match task.handle_table.get(handle) {
2787 Some(obj) => obj,
2788 None => return errno::to_result(errno::EBADF),
2789 };
2790
2791 if let Some(shared_memory) = kernel_obj.as_shared_memory() {
2792 if let Err(_err) = shared_memory.resize(length as usize) {
2793 return errno::to_result(errno::EINVAL);
2794 }
2795 return 0;
2796 }
2797
2798 let file_obj = match kernel_obj.as_file() {
2799 Some(f) => f,
2800 None => return errno::to_result(errno::EINVAL),
2801 };
2802
2803 let mut is_shm = false;
2804 let mut shm_path = None;
2805 if let Some(vfs_obj) = file_obj
2806 .as_any()
2807 .downcast_ref::<crate::fs::vfs_v2::core::VfsFileObject>()
2808 {
2809 let path = vfs_obj.get_original_path();
2810 if path.contains("wl_shm-") {
2811 is_shm = true;
2812 shm_path = Some(path);
2813 crate::println!("sys_ftruncate: shm path='{}' len={}", path, length);
2814 }
2815 }
2816
2817 match file_obj.truncate(length as u64) {
2818 Ok(()) => 0,
2819 Err(err) => {
2820 if is_shm {
2821 if let Ok(meta) = file_obj.metadata() {
2822 crate::println!(
2823 "sys_ftruncate: shm truncate failed len={} file_type={:?} size={}",
2824 length,
2825 meta.file_type,
2826 meta.size
2827 );
2828 }
2829 crate::println!("sys_ftruncate: shm truncate error={:?}", err);
2830 } else if length > 0 {
2831 let kind = match kernel_obj {
2832 crate::object::KernelObject::File(_) => "File",
2833 crate::object::KernelObject::Pipe(_) => "Pipe",
2834 crate::object::KernelObject::Counter(_) => "Counter",
2835 crate::object::KernelObject::EventChannel(_) => "EventChannel",
2836 crate::object::KernelObject::EventSubscription(_) => "EventSubscription",
2837 crate::object::KernelObject::SharedMemory(_) => "SharedMemory",
2838 #[cfg(feature = "network")]
2839 crate::object::KernelObject::Socket(_) => "Socket",
2840 };
2841 crate::println!(
2842 "sys_ftruncate: fd={} kind={} path={:?} len={} err={:?}",
2843 fd,
2844 kind,
2845 shm_path,
2846 length,
2847 err
2848 );
2849 }
2850 errno::to_result(errno::EIO)
2851 }
2852 }
2853}
2854
2855pub fn sys_faccessat(_abi: &mut LinuxRiscv64Abi, trapframe: &mut crate::arch::Trapframe) -> usize {
2864 let task = crate::task::mytask().unwrap();
2865 trapframe.increment_pc_next(task);
2866
2867 let dirfd = trapframe.get_arg(0) as i32;
2868 let path_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
2869 Some(ptr) => ptr as *const u8,
2870 None => return usize::MAX,
2871 };
2872 let mode = trapframe.get_arg(2) as i32;
2873 let path_str = match get_path_str_v2(path_ptr) {
2874 Ok(p) => p,
2875 Err(_) => return usize::MAX,
2876 };
2877
2878 0
2887}
2888
2889pub fn sys_faccessat2(_abi: &mut LinuxRiscv64Abi, trapframe: &mut crate::arch::Trapframe) -> usize {
2899 let task = crate::task::mytask().unwrap();
2900 trapframe.increment_pc_next(task);
2901
2902 let dirfd = trapframe.get_arg(0) as i32;
2903 let path_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
2904 Some(ptr) => ptr as *const u8,
2905 None => return usize::MAX,
2906 };
2907 let mode = trapframe.get_arg(2) as i32;
2908 let flags = trapframe.get_arg(3) as i32;
2909 let path_str = match get_path_str_v2(path_ptr) {
2910 Ok(p) => p,
2911 Err(_) => return usize::MAX,
2912 };
2913
2914 0
2924}
2925
2926pub fn sys_mkdirat(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2931 let task = match mytask() {
2932 Some(t) => t,
2933 None => return usize::MAX,
2934 };
2935 trapframe.increment_pc_next(task);
2936 let dirfd = trapframe.get_arg(0) as i32;
2937 let path_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
2938 Some(ptr) => ptr as *const u8,
2939 None => return usize::MAX,
2940 };
2941 let path = match cstring_to_string(path_ptr, 128) {
2942 Ok((p, _)) => p,
2943 Err(_) => return usize::MAX,
2944 };
2945 if dirfd != -100 {
2947 return usize::MAX;
2949 }
2950
2951 let abs_path = match to_absolute_path_v2(&task, &path) {
2952 Ok(p) => p,
2953 Err(_) => return usize::MAX,
2954 };
2955 let vfs = match task.vfs.write().clone() {
2956 Some(v) => v,
2957 None => return usize::MAX,
2958 };
2959 match vfs.create_dir(&abs_path) {
2960 Ok(_) => 0,
2961 Err(_) => usize::MAX,
2962 }
2963}
2964
2965pub fn sys_newfstat(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
2980 let task = match mytask() {
2981 Some(t) => t,
2982 None => return usize::MAX,
2983 };
2984
2985 let fd = trapframe.get_arg(0) as i32;
2986 let stat_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
2987 Some(ptr) => ptr as *mut u8,
2988 None => return usize::MAX,
2989 };
2990
2991 trapframe.increment_pc_next(task);
2993
2994 if stat_ptr.is_null() {
2996 return usize::MAX; }
2998
2999 let handle = match abi.get_handle(fd as usize) {
3001 Some(h) => h,
3002 None => return usize::MAX, };
3004
3005 let kernel_obj = match task.handle_table.get(handle) {
3007 Some(obj) => obj,
3008 None => return usize::MAX, };
3010
3011 let file_obj = match kernel_obj.as_file() {
3013 Some(f) => f,
3014 None => return usize::MAX, };
3016
3017 use crate::fs::vfs_v2::core::VfsFileObject;
3019 let vfs_file_obj = match file_obj.as_any().downcast_ref::<VfsFileObject>() {
3020 Some(vfs_obj) => vfs_obj,
3021 None => {
3022 let stat = unsafe { &mut *(stat_ptr as *mut LinuxStat) };
3024 *stat = LinuxStat {
3025 st_dev: 0,
3026 st_ino: handle as u64, st_mode: S_IFCHR | 0o666, st_nlink: 1,
3029 st_uid: 0,
3030 st_gid: 0,
3031 st_rdev: handle as u64,
3032 __pad1: 0,
3033 st_size: 0,
3034 st_blksize: 4096,
3035 __pad2: 0,
3036 st_blocks: 0,
3037 st_atime: 0,
3038 st_atime_nsec: 0,
3039 st_mtime: 0,
3040 st_mtime_nsec: 0,
3041 st_ctime: 0,
3042 st_ctime_nsec: 0,
3043 __unused4: 0,
3044 __unused5: 0,
3045 };
3046 return 0; }
3048 };
3049
3050 let entry = vfs_file_obj.get_vfs_entry();
3052 let node = entry.node();
3053
3054 match node.metadata() {
3055 Ok(metadata) => {
3056 let stat = unsafe { &mut *(stat_ptr as *mut LinuxStat) };
3057 *stat = LinuxStat::from_metadata(&metadata);
3058 0 }
3066 Err(_) => usize::MAX, }
3068}
3069
3070pub fn sys_unlinkat(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3087 let task = match mytask() {
3088 Some(t) => t,
3089 None => return usize::MAX,
3090 };
3091
3092 let dirfd = trapframe.get_arg(0) as i32;
3093 let path_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
3094 Some(ptr) => ptr as *const u8,
3095 None => return usize::MAX,
3096 };
3097 let flags = trapframe.get_arg(2) as i32;
3098
3099 trapframe.increment_pc_next(task);
3101
3102 let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
3104 Ok((path, _)) => path,
3105 Err(_) => return usize::MAX, };
3107
3108 let path_str = remap_shm_path(&path_str);
3109 if is_wl_shm_path(&path_str) {
3110 crate::println!("sys_unlinkat: shm ignore path='{}'", path_str);
3111 return 0;
3112 }
3113
3114 const AT_FDCWD: i32 = -100;
3116 const AT_REMOVEDIR: i32 = 0x200;
3117
3118 let vfs = match task.vfs.read().clone() {
3119 Some(v) => v,
3120 None => return usize::MAX,
3121 };
3122
3123 use crate::fs::vfs_v2::core::VfsFileObject;
3125
3126 let (base_entry, base_mount) = if dirfd == AT_FDCWD {
3127 vfs.get_cwd().unwrap_or_else(|| {
3129 let root_mount = vfs.mount_tree.root_mount.read().clone();
3130 (root_mount.root.clone(), root_mount)
3131 })
3132 } else {
3133 let handle = match abi.get_handle(dirfd as usize) {
3135 Some(h) => h,
3136 None => return usize::MAX,
3137 };
3138 let kernel_obj = match task.handle_table.get(handle) {
3139 Some(obj) => obj,
3140 None => return usize::MAX,
3141 };
3142 let file_obj = match kernel_obj.as_file() {
3143 Some(f) => f,
3144 None => return usize::MAX,
3145 };
3146 let vfs_file_obj = match file_obj.as_any().downcast_ref::<VfsFileObject>() {
3147 Some(vfs_obj) => vfs_obj,
3148 None => return usize::MAX,
3149 };
3150 (
3151 vfs_file_obj.get_vfs_entry().clone(),
3152 vfs_file_obj.get_mount_point().clone(),
3153 )
3154 };
3155
3156 match vfs.resolve_path_from(&base_entry, &base_mount, &path_str) {
3158 Ok((entry, _mount_point)) => {
3159 let absolute_path = if path_str.starts_with('/') {
3161 path_str.to_string()
3162 } else {
3163 match to_absolute_path_v2(&task, &path_str) {
3165 Ok(p) => p,
3166 Err(_) => return usize::MAX,
3167 }
3168 };
3169
3170 let vfs_mut = match task.vfs.write().clone() {
3172 Some(v) => v,
3173 None => return usize::MAX,
3174 };
3175
3176 if flags & AT_REMOVEDIR != 0 {
3178 let node = entry.node();
3180 match node.metadata() {
3181 Ok(metadata) => {
3182 if metadata.file_type == FileType::Directory {
3183 match vfs_mut.remove(&absolute_path) {
3185 Ok(_) => 0, Err(_) => usize::MAX, }
3188 } else {
3189 usize::MAX }
3191 }
3192 Err(_) => usize::MAX, }
3194 } else {
3195 match vfs_mut.remove(&absolute_path) {
3197 Ok(_) => 0, Err(_) => usize::MAX, }
3200 }
3201 }
3202 Err(_) => usize::MAX, }
3204}
3205
3206pub fn sys_epoll_create1(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3221 let task = match mytask() {
3222 Some(t) => t,
3223 None => return usize::MAX,
3224 };
3225
3226 let _flags = trapframe.get_arg(0) as i32;
3227
3228 trapframe.increment_pc_next(task);
3230
3231 const EPOLL_DUMMY_HANDLE: u32 = 0x1000_0000;
3237
3238 match abi.allocate_fd(EPOLL_DUMMY_HANDLE) {
3241 Ok(fd) => fd,
3242 Err(_) => usize::MAX,
3243 }
3244}
3245
3246pub fn sys_epoll_ctl(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3264 let task = match mytask() {
3265 Some(t) => t,
3266 None => return usize::MAX,
3267 };
3268
3269 let _epfd = trapframe.get_arg(0) as i32;
3270 let _op = trapframe.get_arg(1) as i32;
3271 let _fd = trapframe.get_arg(2) as i32;
3272 let _event_ptr = trapframe.get_arg(3);
3273
3274 trapframe.increment_pc_next(task);
3276
3277 0 }
3285
3286pub fn sys_epoll_wait(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3303 let task = match mytask() {
3304 Some(t) => t,
3305 None => return usize::MAX,
3306 };
3307
3308 let _epfd = trapframe.get_arg(0) as i32;
3309 let _events_ptr = trapframe.get_arg(1);
3310 let _maxevents = trapframe.get_arg(2) as i32;
3311 let _timeout = trapframe.get_arg(3) as i32;
3312
3313 trapframe.increment_pc_next(task);
3315
3316 0 }
3324
3325pub fn sys_epoll_pwait(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3343 let task = match mytask() {
3344 Some(t) => t,
3345 None => return usize::MAX,
3346 };
3347
3348 let _epfd = trapframe.get_arg(0) as i32;
3349 let _events_ptr = trapframe.get_arg(1);
3350 let _maxevents = trapframe.get_arg(2) as i32;
3351 let _timeout = trapframe.get_arg(3) as i32;
3352 let _sigmask_ptr = trapframe.get_arg(4);
3353
3354 trapframe.increment_pc_next(task);
3356
3357 0 }
3360
3361pub fn sys_pselect6(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3377 use crate::object::capability::selectable::{ReadyInterest, ReadySet};
3378 use crate::timer::ns_to_ticks;
3379
3380 let task = match mytask() {
3381 Some(t) => t,
3382 None => return usize::MAX,
3383 };
3384
3385 let nfds = trapframe.get_arg(0) as usize;
3386 let readfds_ptr = trapframe.get_arg(1);
3387 let writefds_ptr = trapframe.get_arg(2);
3388 let exceptfds_ptr = trapframe.get_arg(3);
3389 let timeout_ptr = trapframe.get_arg(4);
3390 let _sigmask_ptr = trapframe.get_arg(5);
3391
3392 let max_fds = core::cmp::min(nfds, 64);
3394
3395 let mut in_read: u64 = 0;
3397 let mut in_write: u64 = 0;
3398 let mut in_except: u64 = 0;
3399 if readfds_ptr != 0 {
3400 let kptr = task.vm_manager.translate_vaddr(readfds_ptr).unwrap() as *const u64;
3401 unsafe { in_read = core::ptr::read_unaligned(kptr) };
3402 }
3403 if writefds_ptr != 0 {
3404 let kptr = task.vm_manager.translate_vaddr(writefds_ptr).unwrap() as *const u64;
3405 unsafe { in_write = core::ptr::read_unaligned(kptr) };
3406 }
3407 if exceptfds_ptr != 0 {
3408 let kptr = task.vm_manager.translate_vaddr(exceptfds_ptr).unwrap() as *const u64;
3409 unsafe { in_except = core::ptr::read_unaligned(kptr) };
3410 }
3411
3412 #[repr(C)]
3414 struct LinuxTimespec {
3415 tv_sec: i64,
3416 tv_nsec: i64,
3417 }
3418 let mut timeout_ticks: Option<u64> = None;
3419 if timeout_ptr != 0 {
3420 let kptr = task.vm_manager.translate_vaddr(timeout_ptr).unwrap() as *const LinuxTimespec;
3421 let ts = unsafe { core::ptr::read_unaligned(kptr) };
3422 if ts.tv_sec == 0 && ts.tv_nsec == 0 {
3424 timeout_ticks = Some(0);
3425 } else {
3426 let ns = (ts.tv_sec as i128) * 1_000_000_000i128 + (ts.tv_nsec as i128);
3427 let ns_u = if ns <= 0 { 0 } else { (ns as u128) as u64 };
3428 timeout_ticks = Some(ns_to_ticks(ns_u));
3429 }
3430 }
3431
3432 let mut out_read: u64 = 0;
3434 let mut out_write: u64 = 0;
3435 let mut out_except: u64 = 0;
3436 let mut any_ready = false;
3437 let mut first_selectable_fd: Option<usize> = None;
3438
3439 for fd in 0..max_fds {
3440 let bit = 1u64 << fd;
3441 let want_read = (in_read & bit) != 0;
3442 let want_write = (in_write & bit) != 0;
3443 let want_except = (in_except & bit) != 0;
3444 if !(want_read || want_write || want_except) {
3445 continue;
3446 }
3447
3448 let Some(handle) = abi.get_handle(fd) else {
3450 continue;
3451 };
3452 let Some(kobj) = task.handle_table.get(handle) else {
3453 continue;
3454 };
3455
3456 if let Some(sel) = kobj.as_selectable() {
3458 if first_selectable_fd.is_none() {
3460 first_selectable_fd = Some(fd);
3461 }
3462
3463 let interest = ReadyInterest {
3464 read: want_read,
3465 write: want_write,
3466 except: want_except,
3467 };
3468 let rs: ReadySet = sel.current_ready(interest);
3469 if rs.read {
3470 out_read |= bit;
3471 any_ready = true;
3472 }
3473 if rs.write {
3474 out_write |= bit;
3475 any_ready = true;
3476 }
3477 if rs.except {
3478 out_except |= bit; }
3480 } else {
3481 if want_read {
3483 out_read |= bit;
3484 any_ready = true;
3485 }
3486 if want_write {
3487 out_write |= bit;
3488 any_ready = true;
3489 }
3490 }
3492 }
3493
3494 if !any_ready {
3496 let zero_poll = matches!(timeout_ticks, Some(t) if t == 0);
3497 if !zero_poll {
3498 if let Some(fd_wait) = first_selectable_fd {
3500 let bit = 1u64 << fd_wait;
3501 let want_read = (in_read & bit) != 0;
3502 let want_write = (in_write & bit) != 0;
3503 let want_except = (in_except & bit) != 0;
3504 if let Some(handlew) = abi.get_handle(fd_wait) {
3505 if let Some(kobjw) = task.handle_table.get(handlew) {
3506 if let Some(sel) = kobjw.as_selectable() {
3507 let _ = sel.wait_until_ready(
3508 ReadyInterest {
3509 read: want_read,
3510 write: want_write,
3511 except: want_except,
3512 },
3513 trapframe,
3514 timeout_ticks,
3515 );
3516 out_read = 0;
3518 out_write = 0;
3519 out_except = 0;
3520 for fd2 in 0..max_fds {
3521 let bit2 = 1u64 << fd2;
3522 let want_r = (in_read & bit2) != 0;
3523 let want_w = (in_write & bit2) != 0;
3524 let want_x = (in_except & bit2) != 0;
3525 if !(want_r || want_w || want_x) {
3526 continue;
3527 }
3528 if let Some(handle2) = abi.get_handle(fd2) {
3529 if let Some(kobj2) = task.handle_table.get(handle2) {
3530 if let Some(sel2) = kobj2.as_selectable() {
3531 let rs2: ReadySet = sel2.current_ready(ReadyInterest {
3532 read: want_r,
3533 write: want_w,
3534 except: want_x,
3535 });
3536 if rs2.read {
3537 out_read |= bit2;
3538 }
3539 if rs2.write {
3540 out_write |= bit2;
3541 }
3542 if rs2.except {
3543 out_except |= bit2;
3544 }
3545 } else {
3546 if want_r {
3547 out_read |= bit2;
3548 }
3549 if want_w {
3550 out_write |= bit2;
3551 }
3552 }
3553 }
3554 }
3555 }
3556 }
3557 }
3558 }
3559 }
3560 }
3561 }
3562
3563 if readfds_ptr != 0 {
3565 let kptr = task.vm_manager.translate_vaddr(readfds_ptr).unwrap() as *mut u64;
3566 unsafe { core::ptr::write_unaligned(kptr, out_read) };
3567 }
3568 if writefds_ptr != 0 {
3569 let kptr = task.vm_manager.translate_vaddr(writefds_ptr).unwrap() as *mut u64;
3570 unsafe { core::ptr::write_unaligned(kptr, out_write) };
3571 }
3572 if exceptfds_ptr != 0 {
3573 let kptr = task.vm_manager.translate_vaddr(exceptfds_ptr).unwrap() as *mut u64;
3574 unsafe { core::ptr::write_unaligned(kptr, out_except) };
3575 }
3576
3577 let ready_count = out_read.count_ones() as usize
3579 + out_write.count_ones() as usize
3580 + out_except.count_ones() as usize;
3581
3582 trapframe.increment_pc_next(task);
3583 ready_count
3584}
3585
3586pub fn sys_ppoll(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3597 use crate::object::capability::selectable::{ReadyInterest, ReadySet};
3598 use crate::timer::ns_to_ticks;
3599
3600 let task = match mytask() {
3601 Some(t) => t,
3602 None => return usize::MAX,
3603 };
3604
3605 #[repr(C)]
3606 struct PollFd {
3607 fd: i32,
3608 events: i16,
3609 revents: i16,
3610 }
3611
3612 const POLLIN: i16 = 0x0001;
3613 const POLLPRI: i16 = 0x0002;
3614 const POLLOUT: i16 = 0x0004;
3615 const POLLERR: i16 = 0x0008;
3616 const POLLHUP: i16 = 0x0010;
3617 const POLLNVAL: i16 = 0x0020;
3618
3619 let fds_ptr = trapframe.get_arg(0);
3620 let nfds = trapframe.get_arg(1) as usize;
3621 let timeout_ptr = trapframe.get_arg(2);
3622 let _sigmask = trapframe.get_arg(3);
3623 let _sigsetsize = trapframe.get_arg(4);
3624
3625 trapframe.increment_pc_next(task);
3626
3627 if fds_ptr == 0 {
3628 return usize::MAX;
3629 }
3630 let kptr = match task.vm_manager.translate_vaddr(fds_ptr) {
3631 Some(p) => p as *mut PollFd,
3632 None => return usize::MAX,
3633 };
3634 if kptr.is_null() {
3635 return usize::MAX;
3636 }
3637 let fds: &mut [PollFd] = unsafe { core::slice::from_raw_parts_mut(kptr, nfds) };
3638
3639 #[repr(C)]
3640 struct LinuxTimespec {
3641 tv_sec: i64,
3642 tv_nsec: i64,
3643 }
3644 let mut timeout_ticks: Option<u64> = None;
3645 if timeout_ptr != 0 {
3646 let tsp = match task.vm_manager.translate_vaddr(timeout_ptr) {
3647 Some(p) => p as *const LinuxTimespec,
3648 None => return usize::MAX,
3649 };
3650 let ts = unsafe { core::ptr::read_unaligned(tsp) };
3651 if ts.tv_sec == 0 && ts.tv_nsec == 0 {
3652 timeout_ticks = Some(0);
3653 } else {
3654 let ns = (ts.tv_sec as i128) * 1_000_000_000i128 + (ts.tv_nsec as i128);
3655 let ns_u = if ns <= 0 { 0 } else { (ns as u128) as u64 };
3656 timeout_ticks = Some(ns_to_ticks(ns_u));
3657 }
3665 }
3666
3667 struct EvalResult {
3668 ready: bool,
3669 selectable: bool,
3670 }
3671
3672 fn eval_pfd(
3673 pfd: &mut PollFd,
3674 abi_ref: &LinuxRiscv64Abi,
3675 task_ref: &crate::task::Task,
3676 ) -> EvalResult {
3677 pfd.revents = 0;
3678 if pfd.fd < 0 {
3679 pfd.revents |= POLLNVAL;
3680 return EvalResult {
3681 ready: true,
3682 selectable: false,
3683 };
3684 }
3685 let fd_usize = pfd.fd as usize;
3686 let Some(handle) = abi_ref.get_handle(fd_usize) else {
3687 pfd.revents |= POLLNVAL;
3688 return EvalResult {
3689 ready: true,
3690 selectable: false,
3691 };
3692 };
3693 let Some(kobj) = task_ref.handle_table.get(handle) else {
3694 pfd.revents |= POLLNVAL;
3695 return EvalResult {
3696 ready: true,
3697 selectable: false,
3698 };
3699 };
3700
3701 let want_read = (pfd.events & POLLIN) != 0;
3702 let want_write = (pfd.events & POLLOUT) != 0;
3703 let want_except = (pfd.events & POLLPRI) != 0;
3704
3705 let mut selectable = false;
3706
3707 if let Some(sel) = kobj.as_selectable() {
3708 selectable = true;
3709 let rs: ReadySet = sel.current_ready(ReadyInterest {
3710 read: want_read,
3711 write: want_write,
3712 except: want_except,
3713 });
3714 if rs.read && want_read {
3715 pfd.revents |= POLLIN;
3716 }
3717 if rs.write && want_write {
3718 pfd.revents |= POLLOUT;
3719 }
3720 if rs.except && want_except {
3721 pfd.revents |= POLLPRI;
3722 }
3723 } else {
3724 if want_read {
3725 pfd.revents |= POLLIN;
3726 }
3727 if want_write {
3728 pfd.revents |= POLLOUT;
3729 }
3730 }
3731
3732 if let Some(pipe) = kobj.as_pipe() {
3733 if pipe.is_readable() && !pipe.has_writers() {
3734 pfd.revents |= POLLHUP;
3735 if want_read && (pfd.revents & POLLIN) == 0 {
3736 pfd.revents |= POLLIN;
3737 }
3738 }
3739 if pipe.is_writable() && !pipe.has_readers() {
3740 pfd.revents |= POLLERR | POLLHUP;
3741 }
3742 }
3743
3744 EvalResult {
3745 ready: pfd.revents != 0,
3746 selectable,
3747 }
3748 }
3749
3750 let mut any_ready = false;
3751 let mut first_selectable_index: Option<usize> = None;
3752 let mut selectable_count = 0usize;
3753 let mut ready_count = 0usize;
3754 {
3755 let abi_ref = &*abi;
3756 let task_ref: &crate::task::Task = &*task;
3757 for (idx, pfd) in fds.iter_mut().enumerate() {
3758 let eval = eval_pfd(pfd, abi_ref, task_ref);
3759 if eval.ready {
3760 any_ready = true;
3761 ready_count += 1;
3762 }
3763 if eval.selectable {
3764 selectable_count += 1;
3765 }
3766 if first_selectable_index.is_none() && eval.selectable {
3767 first_selectable_index = Some(idx);
3768 }
3769
3770 let mut kind = "unknown";
3771 let mut socket_state: Option<u32> = None;
3772 let fd_usize = pfd.fd as usize;
3773 if let Some(handle) = abi_ref.get_handle(fd_usize) {
3774 if let Some(kobj) = task_ref.handle_table.get(handle) {
3775 match kobj {
3776 crate::object::KernelObject::File(_) => {
3777 kind = "file";
3778 }
3779 crate::object::KernelObject::Pipe(_) => {
3780 kind = "pipe";
3781 }
3782 crate::object::KernelObject::Counter(_) => {
3783 kind = "counter";
3784 }
3785 crate::object::KernelObject::EventChannel(_) => {
3786 kind = "event_channel";
3787 }
3788 crate::object::KernelObject::EventSubscription(_) => {
3789 kind = "event_sub";
3790 }
3791 #[cfg(feature = "network")]
3792 crate::object::KernelObject::Socket(socket) => {
3793 kind = "socket";
3794 socket_state = Some(socket.state() as u32);
3795 }
3796 crate::object::KernelObject::SharedMemory(_) => {
3797 kind = "shmem";
3798 }
3799 }
3800 }
3801 }
3802
3803 }
3813 }
3814
3815 {
3816 let zero_poll = matches!(timeout_ticks, Some(t) if t == 0);
3817 }
3829
3830 if !any_ready {
3831 let zero_poll = matches!(timeout_ticks, Some(t) if t == 0);
3832 if !zero_poll {
3833 if selectable_count > 1 {
3834 use crate::timer::get_tick;
3835
3836 let deadline = timeout_ticks.map(|ticks| get_tick().saturating_add(ticks));
3837 loop {
3838 if let Some(deadline) = deadline {
3839 let now = get_tick();
3840 if now >= deadline {
3841 break;
3842 }
3843 let remaining = deadline.saturating_sub(now);
3844 if remaining == 0 {
3845 break;
3846 }
3847 }
3848
3849 task.sleep(trapframe, 1);
3850
3851 any_ready = false;
3852 ready_count = 0;
3853 {
3854 let abi_ref = &*abi;
3855 let task_ref: &crate::task::Task = &*task;
3856 for pfd in fds.iter_mut() {
3857 let eval = eval_pfd(pfd, abi_ref, task_ref);
3858 if eval.ready {
3859 any_ready = true;
3860 ready_count += 1;
3861 }
3862 }
3863 }
3864
3865 if any_ready {
3866 break;
3867 }
3868 }
3869 } else if let Some(wait_idx) = first_selectable_index {
3870 let pfd = &fds[wait_idx];
3871 if pfd.fd >= 0 {
3872 let fd_usize = pfd.fd as usize;
3873 let abi_ref = &*abi;
3874 let task_ref: &crate::task::Task = &*task;
3875 if let Some(handle) = abi_ref.get_handle(fd_usize) {
3876 if let Some(kobj) = task_ref.handle_table.get(handle) {
3877 if let Some(sel) = kobj.as_selectable() {
3878 let want_read = (pfd.events & POLLIN) != 0;
3879 let want_write = (pfd.events & POLLOUT) != 0;
3880 let want_except = (pfd.events & POLLPRI) != 0;
3881 let _ = sel.wait_until_ready(
3882 ReadyInterest {
3883 read: want_read,
3884 write: want_write,
3885 except: want_except,
3886 },
3887 trapframe,
3888 timeout_ticks,
3889 );
3890 }
3891 }
3892 }
3893 }
3894
3895 let abi_ref = &*abi;
3896 let task_ref: &crate::task::Task = &*task;
3897 for pfd in fds.iter_mut() {
3898 let _ = eval_pfd(pfd, abi_ref, task_ref);
3899 }
3900 }
3901 }
3902 }
3903
3904 let mut count = 0usize;
3905 for pfd in fds.iter() {
3906 if pfd.revents != 0 {
3907 count += 1;
3908 }
3909 }
3910 count
3911}
3912
3913pub fn sys_fchmod(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3929 let task = match mytask() {
3930 Some(t) => t,
3931 None => return usize::MAX,
3932 };
3933
3934 let fd = trapframe.get_arg(0) as i32;
3935 let _mode = trapframe.get_arg(1) as u32;
3936
3937 trapframe.increment_pc_next(task);
3939
3940 let handle = match abi.get_handle(fd as usize) {
3942 Some(h) => h,
3943 None => return usize::MAX, };
3945
3946 match task.handle_table.get(handle) {
3948 Some(_) => {
3949 0 }
3953 None => usize::MAX, }
3955}
3956
3957pub fn sys_umask(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
3971 let task = match mytask() {
3972 Some(t) => t,
3973 None => return usize::MAX,
3974 };
3975
3976 let mask = trapframe.get_arg(0) as u32;
3977
3978 trapframe.increment_pc_next(task);
3980
3981 mask as usize }
3990
3991pub fn sys_readlinkat(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
4008 let task = match mytask() {
4009 Some(t) => t,
4010 None => return errno::to_result(errno::EIO),
4011 };
4012
4013 let dirfd = trapframe.get_arg(0) as i32;
4014 let pathname_ptr = trapframe.get_arg(1);
4015 let buf_ptr = trapframe.get_arg(2);
4016 let bufsiz = trapframe.get_arg(3) as usize;
4017
4018 trapframe.increment_pc_next(task);
4020
4021 if bufsiz == 0 {
4023 return 0;
4024 }
4025
4026 let path_str = match parse_c_string_from_userspace(task, pathname_ptr, MAX_PATH_LENGTH) {
4028 Ok(s) => s,
4029 Err(_) => return errno::to_result(errno::EFAULT),
4030 };
4031
4032 let vfs = match task.vfs.read().clone() {
4034 Some(v) => v,
4035 None => return errno::to_result(errno::EIO),
4036 };
4037
4038 use crate::fs::vfs_v2::core::VfsFileObject;
4040 const AT_FDCWD: i32 = -100;
4041
4042 let (base_entry, base_mount) = if dirfd == AT_FDCWD {
4043 vfs.get_cwd().unwrap_or_else(|| {
4044 let root_mount = vfs.mount_tree.root_mount.read().clone();
4045 (root_mount.root.clone(), root_mount)
4046 })
4047 } else {
4048 let handle = match abi.get_handle(dirfd as usize) {
4050 Some(h) => h,
4051 None => return errno::to_result(errno::EBADF),
4052 };
4053 let kernel_obj = match task.handle_table.get(handle) {
4054 Some(obj) => obj,
4055 None => return errno::to_result(errno::EBADF),
4056 };
4057 let file_obj = match kernel_obj.as_file() {
4058 Some(f) => f,
4059 None => return errno::to_result(errno::ENOTDIR),
4060 };
4061 let vfs_file_obj = match file_obj.as_any().downcast_ref::<VfsFileObject>() {
4062 Some(vfs_obj) => vfs_obj,
4063 None => return errno::to_result(errno::ENOTDIR),
4064 };
4065 (
4066 vfs_file_obj.get_vfs_entry().clone(),
4067 vfs_file_obj.get_mount_point().clone(),
4068 )
4069 };
4070
4071 let (entry, _mp) = match vfs.resolve_path_from(&base_entry, &base_mount, &path_str) {
4073 Ok(v) => v,
4074 Err(e) => return errno::to_result(errno::from_fs_error(&e)),
4075 };
4076
4077 let node = entry.node();
4079 let metadata = match node.metadata() {
4080 Ok(m) => m,
4081 Err(e) => return errno::to_result(errno::from_fs_error(&e)),
4082 };
4083
4084 let target = match metadata.file_type {
4085 FileType::SymbolicLink(ref t) => t.as_str(),
4086 _ => return errno::to_result(errno::EINVAL), };
4088
4089 let target_bytes = target.as_bytes();
4091 let copy_len = core::cmp::min(target_bytes.len(), bufsiz);
4092
4093 let user_buf = match task.vm_manager.translate_vaddr(buf_ptr) {
4094 Some(addr) => addr as *mut u8,
4095 None => return errno::to_result(errno::EFAULT),
4096 };
4097
4098 if copy_len > 0 {
4099 unsafe {
4100 core::ptr::copy_nonoverlapping(target_bytes.as_ptr(), user_buf, copy_len);
4101 }
4102 }
4103
4104 copy_len
4105}
4106
4107pub fn sys_getrandom(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
4111 let task = match mytask() {
4112 Some(t) => t,
4113 None => return errno::to_result(errno::EIO),
4114 };
4115
4116 let buf_ptr = trapframe.get_arg(0);
4117 let buflen = trapframe.get_arg(1) as usize;
4118 let flags = trapframe.get_arg(2) as u32;
4119
4120 trapframe.increment_pc_next(task);
4121
4122 if buflen == 0 {
4123 return 0;
4124 }
4125
4126 let user_buf = match task.vm_manager.translate_vaddr(buf_ptr) {
4127 Some(addr) => addr as *mut u8,
4128 None => return errno::to_result(errno::EFAULT),
4129 };
4130
4131 if user_buf.is_null() {
4132 return errno::to_result(errno::EFAULT);
4133 }
4134
4135 let buffer = unsafe { core::slice::from_raw_parts_mut(user_buf, buflen) };
4136 let bytes_read = crate::random::RandomManager::get_random_bytes(buffer);
4137
4138 if bytes_read == 0 {
4139 if (flags & GRND_NONBLOCK) != 0 {
4140 return errno::to_result(errno::EAGAIN);
4141 }
4142 fill_pseudo_random(buffer);
4143 return buflen;
4144 }
4145
4146 if bytes_read < buflen && (flags & GRND_NONBLOCK) == 0 {
4147 fill_pseudo_random(&mut buffer[bytes_read..]);
4148 return buflen;
4149 }
4150
4151 bytes_read
4152}
4153
4154pub fn sys_getcwd(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
4165 let task = mytask().unwrap();
4166 let buf_ptr = trapframe.get_arg(0);
4167 let size = trapframe.get_arg(1);
4168 trapframe.increment_pc_next(task);
4169
4170 if buf_ptr == 0 || size == 0 {
4172 return usize::MAX; }
4174
4175 let cwd = if let Some(vfs) = task.vfs.read().clone() {
4177 vfs.get_cwd_path()
4178 } else {
4179 "/".to_string() };
4181 let cwd_bytes = cwd.as_bytes();
4182
4183 if cwd_bytes.len() + 1 > size {
4185 return usize::MAX; }
4187
4188 let user_buf = match task.vm_manager.translate_vaddr(buf_ptr) {
4190 Some(addr) => addr as *mut u8,
4191 None => return usize::MAX, };
4193
4194 unsafe {
4196 core::ptr::copy_nonoverlapping(cwd_bytes.as_ptr(), user_buf, cwd_bytes.len());
4197 *user_buf.add(cwd_bytes.len()) = 0;
4199 }
4200
4201 cwd_bytes.len() + 1
4203}
4204
4205pub fn sys_chdir(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
4215 let task = match mytask() {
4216 Some(t) => t,
4217 None => return usize::MAX,
4218 };
4219
4220 let path_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(0)) {
4221 Some(ptr) => ptr as *const u8,
4222 None => return usize::MAX,
4223 };
4224
4225 trapframe.increment_pc_next(task);
4227
4228 let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
4230 Ok((path, _)) => path,
4231 Err(_) => return usize::MAX, };
4233
4234 crate::println!("sys_chdir: Changing directory to '{}'", path_str);
4235
4236 let absolute_path = if path_str.starts_with('/') {
4238 path_str
4239 } else {
4240 match to_absolute_path_v2(&task, &path_str) {
4241 Ok(p) => p,
4242 Err(_) => return usize::MAX,
4243 }
4244 };
4245
4246 let vfs = match task.vfs.read().clone() {
4247 Some(v) => v,
4248 None => return usize::MAX,
4249 };
4250
4251 match vfs.resolve_path(&absolute_path) {
4253 Ok((entry, _mount_point)) => {
4254 match entry.node().file_type() {
4255 Ok(file_type) => {
4256 if file_type == FileType::Directory {
4257 match vfs.set_cwd_by_path(&absolute_path) {
4259 Ok(()) => {
4260 crate::println!(
4261 "sys_chdir: Successfully changed directory to '{}'",
4262 absolute_path
4263 );
4264 0 }
4266 Err(_) => {
4267 crate::println!(
4268 "sys_chdir: Failed to set working directory to '{}'",
4269 absolute_path
4270 );
4271 usize::MAX }
4273 }
4274 } else {
4275 crate::println!("sys_chdir: '{}' is not a directory", absolute_path);
4276 usize::MAX }
4278 }
4279 Err(_) => {
4280 crate::println!("sys_chdir: Failed to get file type for '{}'", absolute_path);
4281 usize::MAX }
4283 }
4284 }
4285 Err(_) => {
4286 crate::println!("sys_chdir: Path '{}' not found", absolute_path);
4287 usize::MAX }
4289 }
4290}
4291
4292const RENAME_NOREPLACE: u32 = 1 << 0; const RENAME_EXCHANGE: u32 = 1 << 1; #[allow(dead_code)]
4296const RENAME_WHITEOUT: u32 = 1 << 2; pub fn sys_renameat2(_abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
4312 let task = match mytask() {
4313 Some(t) => t,
4314 None => return usize::MAX,
4315 };
4316
4317 let olddirfd = trapframe.get_arg(0) as i32;
4318 let oldpath_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(1)) {
4319 Some(ptr) => ptr as *const u8,
4320 None => return usize::MAX,
4321 };
4322 let newdirfd = trapframe.get_arg(2) as i32;
4323 let newpath_ptr = match task.vm_manager.translate_vaddr(trapframe.get_arg(3)) {
4324 Some(ptr) => ptr as *const u8,
4325 None => return usize::MAX,
4326 };
4327 let flags = trapframe.get_arg(4) as u32;
4328
4329 trapframe.increment_pc_next(task);
4331
4332 let oldpath_str = match cstring_to_string(oldpath_ptr, MAX_PATH_LENGTH) {
4334 Ok((path, _)) => path,
4335 Err(_) => return usize::MAX, };
4337
4338 let newpath_str = match cstring_to_string(newpath_ptr, MAX_PATH_LENGTH) {
4340 Ok((path, _)) => path,
4341 Err(_) => return usize::MAX, };
4343
4344 crate::println!(
4345 "sys_renameat2: olddirfd={}, oldpath='{}', newdirfd={}, newpath='{}', flags={:#x}",
4346 olddirfd,
4347 oldpath_str,
4348 newdirfd,
4349 newpath_str,
4350 flags
4351 );
4352
4353 const SUPPORTED_FLAGS: u32 = RENAME_NOREPLACE | RENAME_EXCHANGE;
4355 if (flags & !SUPPORTED_FLAGS) != 0 {
4356 crate::println!(
4357 "sys_renameat2: Unsupported flags: {:#x}",
4358 flags & !SUPPORTED_FLAGS
4359 );
4360 return usize::MAX; }
4362
4363 if (flags & RENAME_EXCHANGE) != 0 && (flags & RENAME_NOREPLACE) != 0 {
4365 crate::println!(
4366 "sys_renameat2: RENAME_EXCHANGE and RENAME_NOREPLACE are mutually exclusive"
4367 );
4368 return usize::MAX; }
4370
4371 let vfs = match task.vfs.read().clone() {
4372 Some(v) => v,
4373 None => return usize::MAX,
4374 };
4375
4376 let old_absolute_path = if oldpath_str.starts_with('/') {
4381 oldpath_str
4382 } else {
4383 match to_absolute_path_v2(&task, &oldpath_str) {
4384 Ok(p) => p,
4385 Err(_) => return usize::MAX,
4386 }
4387 };
4388
4389 let new_absolute_path = if newpath_str.starts_with('/') {
4390 newpath_str
4391 } else {
4392 match to_absolute_path_v2(&task, &newpath_str) {
4393 Ok(p) => p,
4394 Err(_) => return usize::MAX,
4395 }
4396 };
4397
4398 crate::println!(
4399 "sys_renameat2: Resolved paths: '{}' -> '{}'",
4400 old_absolute_path,
4401 new_absolute_path
4402 );
4403
4404 if (flags & RENAME_EXCHANGE) != 0 {
4406 crate::println!("sys_renameat2: Exchange operation not yet implemented");
4408 return usize::MAX; } else {
4410 let no_replace = (flags & RENAME_NOREPLACE) != 0;
4412
4413 if no_replace {
4415 match vfs.resolve_path(&new_absolute_path) {
4416 Ok(_) => {
4417 crate::println!(
4418 "sys_renameat2: Target exists and RENAME_NOREPLACE flag is set"
4419 );
4420 return usize::MAX; }
4422 Err(_) => {
4423 }
4425 }
4426 }
4427
4428 crate::println!("sys_renameat2: Full rename operation not yet implemented");
4435 0 }
4437}
4438
4439pub fn sys_eventfd2(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
4449 let task = match mytask() {
4450 Some(t) => t,
4451 None => return errno::to_result(errno::EIO),
4452 };
4453
4454 let initval = trapframe.get_arg(0) as u32;
4455 let flags = trapframe.get_arg(1) as u32;
4456
4457 trapframe.increment_pc_next(task);
4458
4459 const EFD_CLOEXEC: u32 = 0o02000000;
4461 const EFD_NONBLOCK: u32 = 0o00004000;
4462 const EFD_SEMAPHORE: u32 = 0x00000001;
4463
4464 let valid_flags = EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE;
4466 if flags & !valid_flags != 0 {
4467 crate::println!("[sys_eventfd2] Invalid flags: 0x{:x}", flags);
4468 return errno::to_result(errno::EINVAL);
4469 }
4470
4471 let counter_obj = crate::ipc::counter::Counter::create_kernel_object(initval, flags);
4473
4474 let handle = match task.handle_table.insert(counter_obj) {
4476 Ok(h) => h,
4477 Err(_) => return errno::to_result(errno::EMFILE),
4478 };
4479
4480 let fd = match abi.allocate_fd(handle as u32) {
4482 Ok(fd) => fd,
4483 Err(_) => {
4484 let _ = task.handle_table.remove(handle);
4485 return errno::to_result(errno::EMFILE);
4486 }
4487 };
4488
4489 if (flags & EFD_CLOEXEC) != 0 {
4491 let _ = abi.set_fd_flags(fd, FD_CLOEXEC);
4492 }
4493
4494 if (flags & EFD_NONBLOCK) != 0 {
4496 let _ = abi.set_file_status_flags(fd, O_NONBLOCK as u32);
4497 }
4498
4499 fd
4500}