From d4d3a3c54f5e26dec0cc79e273dc488f8a47f2b3 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:32:51 -0700 Subject: fix(node): Implement `fs.lchown` (and `process.getegid`) (#24418) Closes https://github.com/denoland/deno/issues/21260. Part of https://github.com/denoland/deno/issues/18218. Implements `node:fs.lchown`, and enables the node_compat test for it. The test uses `process.getegid`, which we didn't have implemented, so I went ahead and implemented that as well to get the test working. --- ext/fs/in_memory_fs.rs | 18 ++++++++++++++++++ ext/fs/interface.rs | 13 +++++++++++++ ext/fs/std_fs.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) (limited to 'ext/fs') diff --git a/ext/fs/in_memory_fs.rs b/ext/fs/in_memory_fs.rs index e2babf40a..027539e84 100644 --- a/ext/fs/in_memory_fs.rs +++ b/ext/fs/in_memory_fs.rs @@ -178,6 +178,24 @@ impl FileSystem for InMemoryFs { self.chown_sync(&path, uid, gid) } + fn lchown_sync( + &self, + _path: &Path, + _uid: Option, + _gid: Option, + ) -> FsResult<()> { + Err(FsError::NotSupported) + } + + async fn lchown_async( + &self, + path: PathBuf, + uid: Option, + gid: Option, + ) -> FsResult<()> { + self.lchown_sync(&path, uid, gid) + } + fn remove_sync(&self, _path: &Path, _recursive: bool) -> FsResult<()> { Err(FsError::NotSupported) } diff --git a/ext/fs/interface.rs b/ext/fs/interface.rs index cb6fc4f63..f639a700b 100644 --- a/ext/fs/interface.rs +++ b/ext/fs/interface.rs @@ -146,6 +146,19 @@ pub trait FileSystem: std::fmt::Debug + MaybeSend + MaybeSync { gid: Option, ) -> FsResult<()>; + fn lchown_sync( + &self, + path: &Path, + uid: Option, + gid: Option, + ) -> FsResult<()>; + async fn lchown_async( + &self, + path: PathBuf, + uid: Option, + gid: Option, + ) -> FsResult<()>; + fn remove_sync(&self, path: &Path, recursive: bool) -> FsResult<()>; async fn remove_async(&self, path: PathBuf, recursive: bool) -> FsResult<()>; diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs index c501b8928..7903700c3 100644 --- a/ext/fs/std_fs.rs +++ b/ext/fs/std_fs.rs @@ -303,6 +303,24 @@ impl FileSystem for RealFs { .await? } + fn lchown_sync( + &self, + path: &Path, + uid: Option, + gid: Option, + ) -> FsResult<()> { + lchown(path, uid, gid) + } + + async fn lchown_async( + &self, + path: PathBuf, + uid: Option, + gid: Option, + ) -> FsResult<()> { + spawn_blocking(move || lchown(&path, uid, gid)).await? + } + fn write_file_sync( &self, path: &Path, @@ -431,6 +449,31 @@ fn chown(_path: &Path, _uid: Option, _gid: Option) -> FsResult<()> { Err(FsError::NotSupported) } +#[cfg(unix)] +fn lchown(path: &Path, uid: Option, gid: Option) -> FsResult<()> { + use std::os::unix::ffi::OsStrExt; + let c_path = std::ffi::CString::new(path.as_os_str().as_bytes()).unwrap(); + // -1 = leave unchanged + let uid = uid + .map(|uid| uid as libc::uid_t) + .unwrap_or(-1i32 as libc::uid_t); + let gid = gid + .map(|gid| gid as libc::gid_t) + .unwrap_or(-1i32 as libc::gid_t); + // SAFETY: `c_path` is a valid C string and lives throughout this function call. + let result = unsafe { libc::lchown(c_path.as_ptr(), uid, gid) }; + if result != 0 { + return Err(io::Error::last_os_error().into()); + } + Ok(()) +} + +// TODO: implement lchown for Windows +#[cfg(not(unix))] +fn lchown(_path: &Path, _uid: Option, _gid: Option) -> FsResult<()> { + Err(FsError::NotSupported) +} + fn remove(path: &Path, recursive: bool) -> FsResult<()> { // TODO: this is racy. This should open fds, and then `unlink` those. let metadata = fs::symlink_metadata(path)?; -- cgit v1.2.3