From 8f00af7587761906d88608052a802298dc974b26 Mon Sep 17 00:00:00 2001 From: ootinnyoo Date: Mon, 22 Dec 2025 18:34:22 -0500 Subject: [PATCH] implement sys_fchdir --- etc/syscalls_linux_aarch64.md | 2 +- libkernel/src/fs/path.rs | 10 ++++++- libkernel/src/fs/pathbuf.rs | 8 +++++- src/arch/arm64/exceptions/syscall.rs | 14 ++++----- src/fs/mod.rs | 5 ++-- src/fs/open_file.rs | 13 +++++++-- src/fs/syscalls/chdir.rs | 19 +++++++++++- usertest/src/main.rs | 43 +++++++++++++++++++++++++++- 8 files changed, 95 insertions(+), 19 deletions(-) diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index 7905488..9a56cd6 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -50,7 +50,7 @@ | 0x2f (47) | fallocate | (int fd, int mode, loff_t offset, loff_t len) | __arm64_sys_fallocate | false | | 0x30 (48) | faccessat | (int dfd, const char *filename, int mode) | __arm64_sys_faccessat | true | | 0x31 (49) | chdir | (const char *filename) | __arm64_sys_chdir | true | -| 0x32 (50) | fchdir | (unsigned int fd) | __arm64_sys_fchdir | false | +| 0x32 (50) | fchdir | (unsigned int fd) | __arm64_sys_fchdir | true | | 0x33 (51) | chroot | (const char *filename) | __arm64_sys_chroot | true | | 0x34 (52) | fchmod | (unsigned int fd, umode_t mode) | __arm64_sys_fchmod | false | | 0x35 (53) | fchmodat | (int dfd, const char *filename, umode_t mode) | __arm64_sys_fchmodat | false | diff --git a/libkernel/src/fs/path.rs b/libkernel/src/fs/path.rs index 5eb7c0b..8f3a5d8 100644 --- a/libkernel/src/fs/path.rs +++ b/libkernel/src/fs/path.rs @@ -3,7 +3,7 @@ //! This module provides a `Path` struct that is a thin wrapper around `&str`, //! offering various methods for path inspection and manipulation. -use alloc::vec::Vec; +use alloc::{borrow::ToOwned, vec::Vec}; use super::pathbuf::PathBuf; @@ -217,6 +217,14 @@ impl AsRef for str { } } +impl ToOwned for Path { + type Owned = PathBuf; + + fn to_owned(&self) -> Self::Owned { + PathBuf::from(self.as_str()) + } +} + /// An iterator over the components of a `Path`. #[derive(Clone, Debug)] pub struct Components<'a> { diff --git a/libkernel/src/fs/pathbuf.rs b/libkernel/src/fs/pathbuf.rs index 1795db4..ad4d076 100644 --- a/libkernel/src/fs/pathbuf.rs +++ b/libkernel/src/fs/pathbuf.rs @@ -6,7 +6,7 @@ use super::path::Path; use alloc::string::String; -use core::ops::Deref; +use core::{borrow::Borrow, ops::Deref}; /// An owned, mutable path, akin to `String`. /// @@ -164,6 +164,12 @@ impl Deref for PathBuf { } } +impl Borrow for PathBuf { + fn borrow(&self) -> &Path { + self + } +} + #[cfg(test)] mod tests { use super::PathBuf; diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 77a314f..5dcd7d6 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -1,8 +1,3 @@ -use crate::fs::syscalls::chdir::sys_chroot; -use crate::fs::syscalls::trunc::sys_ftruncate; -use crate::kernel::power::sys_reboot; -use crate::kernel::rand::sys_getrandom; -use crate::memory::mmap::sys_mprotect; use crate::{ arch::{Arch, ArchImpl}, clock::{gettime::sys_clock_gettime, timeofday::sys_gettimeofday}, @@ -18,7 +13,7 @@ use crate::{ stat::sys_newfstatat, unlink::sys_unlinkat, }, - chdir::{sys_chdir, sys_getcwd}, + chdir::{sys_chdir, sys_chroot, sys_fchdir, sys_getcwd}, close::sys_close, ioctl::sys_ioctl, iov::{sys_readv, sys_writev}, @@ -27,13 +22,13 @@ use crate::{ splice::sys_sendfile, stat::sys_fstat, sync::sys_sync, + trunc::sys_ftruncate, }, }, - kernel::sysinfo::sys_sysinfo, - kernel::uname::sys_uname, + kernel::{power::sys_reboot, rand::sys_getrandom, sysinfo::sys_sysinfo, uname::sys_uname}, memory::{ brk::sys_brk, - mmap::{sys_mmap, sys_munmap}, + mmap::{sys_mmap, sys_mprotect, sys_munmap}, }, process::{ clone::sys_clone, @@ -101,6 +96,7 @@ pub async fn handle_syscall() { 0x2e => sys_ftruncate(arg1.into(), arg2 as _).await, 0x30 => sys_faccessat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x31 => sys_chdir(TUA::from_value(arg1 as _)).await, + 0x32 => sys_fchdir(arg1.into()).await, 0x33 => sys_chroot(TUA::from_value(arg1 as _)).await, 0x38 => { sys_openat( diff --git a/src/fs/mod.rs b/src/fs/mod.rs index cb11224..c2b2b45 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -1,3 +1,4 @@ +use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::{collections::btree_map::BTreeMap, sync::Arc}; use async_trait::async_trait; @@ -337,14 +338,14 @@ impl VFS { FileType::File => { let mut open_file = OpenFile::new(Box::new(RegFile::new(target_inode.clone())), flags); - open_file.set_inode(target_inode); + open_file.update(target_inode, path.to_owned()); Ok(Arc::new(open_file)) } FileType::Directory => { let mut open_file = OpenFile::new(Box::new(DirFile::new(target_inode.clone())), flags); - open_file.set_inode(target_inode); + open_file.update(target_inode, path.to_owned()); Ok(Arc::new(open_file)) } diff --git a/src/fs/open_file.rs b/src/fs/open_file.rs index 2c95ca9..ce005dc 100644 --- a/src/fs/open_file.rs +++ b/src/fs/open_file.rs @@ -7,7 +7,7 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec}; use core::{future, pin::Pin, task::Poll}; use libkernel::{ error::Result, - fs::{Inode, OpenFlags}, + fs::{Inode, OpenFlags, path::Path, pathbuf::PathBuf}, }; pub struct FileCtx { @@ -23,6 +23,7 @@ impl FileCtx { pub struct OpenFile { inode: Option>, + path: Option, state: Mutex<(Box, FileCtx)>, } @@ -31,17 +32,23 @@ impl OpenFile { Self { state: Mutex::new((ops, FileCtx::new(flags))), inode: None, + path: None, } } - pub fn set_inode(&mut self, inode: Arc) { - self.inode = Some(inode) + pub fn update(&mut self, inode: Arc, path: PathBuf) { + self.inode = Some(inode); + self.path = Some(path); } pub fn inode(&self) -> Option> { self.inode.clone() } + pub fn path(&self) -> Option<&Path> { + self.path.as_deref() + } + pub async fn flags(&self) -> OpenFlags { self.state.lock().await.1.flags } diff --git a/src/fs/syscalls/chdir.rs b/src/fs/syscalls/chdir.rs index 88d76e6..755fb18 100644 --- a/src/fs/syscalls/chdir.rs +++ b/src/fs/syscalls/chdir.rs @@ -1,9 +1,10 @@ use crate::{ fs::VFS, memory::uaccess::{copy_to_user_slice, cstr::UserCStr}, + process::fd_table::Fd, sched::current_task, }; -use alloc::{ffi::CString, string::ToString}; +use alloc::{borrow::ToOwned, ffi::CString, string::ToString}; use core::{ffi::c_char, str::FromStr}; use libkernel::{ error::{KernelError, Result}, @@ -55,3 +56,19 @@ pub async fn sys_chroot(path: TUA) -> Result { Ok(0) } + +pub async fn sys_fchdir(fd: Fd) -> Result { + let task = current_task(); + let file = task + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; + + *task.cwd.lock_save_irq() = ( + file.inode().ok_or(KernelError::BadFd)?, + file.path().ok_or(KernelError::BadFd)?.to_owned(), + ); + + Ok(0) +} diff --git a/usertest/src/main.rs b/usertest/src/main.rs index a02c199..2454ac9 100644 --- a/usertest/src/main.rs +++ b/usertest/src/main.rs @@ -47,11 +47,51 @@ fn test_readdir() { fn test_chdir() { print!("Testing chdir syscall ..."); - let path = std::ffi::CString::new("/").unwrap(); + let path = std::ffi::CString::new("/dev").unwrap(); + let mut buffer = [1u8; 16]; unsafe { if libc::chdir(path.as_ptr()) != 0 { panic!("chdir failed"); } + if libc::getcwd( + buffer.as_mut_ptr() as *mut libc::c_char, + buffer.len() as libc::size_t, + ) + .is_null() + { + panic!("getcwd failed"); + } + if std::ffi::CStr::from_ptr(buffer.as_ptr()).to_string_lossy() != "/dev" { + panic!("chdir failed"); + } + } + println!(" OK"); +} + +fn test_fchdir() { + print!("Testing fchdir syscall ..."); + let path = std::ffi::CString::new("/dev").unwrap(); + let mut buffer = [1u8; 16]; + unsafe { + let fd = libc::open(path.as_ptr(), libc::O_RDONLY); + if fd == -1 { + panic!("open failed"); + } + if libc::fchdir(fd) != 0 { + panic!("fchdir failed"); + } + if libc::getcwd( + buffer.as_mut_ptr() as *mut libc::c_char, + buffer.len() as libc::size_t, + ) + .is_null() + { + panic!("getcwd failed"); + } + if std::ffi::CStr::from_ptr(buffer.as_ptr()).to_string_lossy() != "/dev" { + panic!("fchdir failed"); + } + libc::close(fd); } println!(" OK"); } @@ -240,6 +280,7 @@ fn main() { run_test(test_opendir); run_test(test_readdir); run_test(test_chdir); + run_test(test_fchdir); run_test(test_chroot); run_test(test_fork); run_test(test_read);