Skip to content

Commit

Permalink
feat: AT_EMPTY_PATH for fchownat on Linux/Android/FreeBSD/Hurd
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveLauC committed Jan 7, 2024
1 parent 0e8efe9 commit 327e7df
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 18 deletions.
1 change: 1 addition & 0 deletions changelog/2267.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enable the `AT_EMPTY_PATH` flag for the `fchownat()` function
1 change: 1 addition & 0 deletions changelog/2267.removed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The `FchownatFlags` type has been deprecated, please use `AtFlags` instead.
2 changes: 1 addition & 1 deletion src/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use crate::{sys::stat::Mode, NixPath, Result};
pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice};

#[cfg(not(target_os = "redox"))]
#[cfg(any(feature = "fs", feature = "process"))]
#[cfg(any(feature = "fs", feature = "process", feature = "user"))]
libc_bitflags! {
#[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))]
pub struct AtFlags: c_int {
Expand Down
28 changes: 15 additions & 13 deletions src/unistd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,11 +737,17 @@ pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
Errno::result(res).map(drop)
}

/// Flags for `fchownat` function.
#[derive(Clone, Copy, Debug)]
pub enum FchownatFlags {
FollowSymlink,
NoFollowSymlink,
// Just a wrapper around `AtFlags` so that we can help our users migrate.
#[cfg(not(target_os = "redox"))]
pub type FchownatFlags = AtFlags;
#[cfg(not(target_os = "redox"))]
impl FchownatFlags {
#[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
#[allow(non_upper_case_globals)]
pub const FollowSymlink: FchownatFlags = FchownatFlags::empty();
#[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
#[allow(non_upper_case_globals)]
pub const NoFollowSymlink: FchownatFlags = FchownatFlags::AT_SYMLINK_NOFOLLOW;
}

/// Change the ownership of the file at `path` to be owned by the specified
Expand All @@ -755,10 +761,10 @@ pub enum FchownatFlags {
/// with the file descriptor `dirfd` or the current working directory
/// if `dirfd` is `None`.
///
/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
/// If `flag` is `AtFlags::AT_SYMLINK_NOFOLLOW` and `path` names a symbolic link,
/// then the mode of the symbolic link is changed.
///
/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to
/// `fchownat(None, path, owner, group, AtFlags::AT_SYMLINK_NOFOLLOW)` is identical to
/// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in
/// the `nix` crate.
///
Expand All @@ -771,20 +777,16 @@ pub fn fchownat<P: ?Sized + NixPath>(
path: &P,
owner: Option<Uid>,
group: Option<Gid>,
flag: FchownatFlags,
flag: AtFlags,
) -> Result<()> {
let atflag = match flag {
FchownatFlags::FollowSymlink => AtFlags::empty(),
FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
};
let res = path.with_nix_path(|cstr| unsafe {
let (uid, gid) = chown_raw_ids(owner, group);
libc::fchownat(
at_rawfd(dirfd),
cstr.as_ptr(),
uid,
gid,
atflag.bits() as libc::c_int,
flag.bits()
)
})?;

Expand Down
9 changes: 5 additions & 4 deletions test/test_unistd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ fn test_fchown() {
#[test]
#[cfg(not(target_os = "redox"))]
fn test_fchownat() {
use nix::fcntl::AtFlags;

let _dr = crate::DirRestore::new();
// Testing for anything other than our own UID/GID is hard.
let uid = Some(getuid());
Expand All @@ -564,14 +566,13 @@ fn test_fchownat() {

let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();

fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink)
.unwrap();
fchownat(Some(dirfd), "file", uid, gid, AtFlags::empty()).unwrap();

chdir(tempdir.path()).unwrap();
fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap();

fs::remove_file(&path).unwrap();
fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err();
fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap_err();
}

#[test]
Expand Down

0 comments on commit 327e7df

Please sign in to comment.