Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions src/uucore/src/lib/features/perms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ use walkdir::WalkDir;
#[cfg(target_os = "linux")]
use crate::features::safe_traversal::{DirFd, SymlinkBehavior};

use std::ffi::CString;
use std::fs::Metadata;
use std::io::Error as IOError;
use std::io::Result as IOResult;
use std::os::unix::fs::MetadataExt;

use std::os::unix::ffi::OsStrExt;
use std::path::{MAIN_SEPARATOR, Path};

/// The various level of verbosity
Expand Down Expand Up @@ -59,19 +57,21 @@ impl Default for Verbosity {

/// Actually perform the change of owner on a path
fn chown<P: AsRef<Path>>(path: P, uid: uid_t, gid: gid_t, follow: bool) -> IOResult<()> {
let path = path.as_ref();
let s = CString::new(path.as_os_str().as_bytes()).unwrap();
let ret = unsafe {
if follow {
libc::chown(s.as_ptr(), uid, gid)
} else {
libc::lchown(s.as_ptr(), uid, gid)
}
};
if ret == 0 {
Ok(())
let final_path = if follow {
// Canonicalize is used to resolve symlinks
path.as_ref()
.canonicalize()
.map_err(|_| IOError::last_os_error())?
} else {
Err(IOError::last_os_error())
path.as_ref().to_path_buf()
};
match rustix::fs::chown(
final_path,
Some(rustix::process::Uid::from_raw(uid)),
Some(rustix::process::Gid::from_raw(gid)),
) {
Ok(_) => Ok(()),
Err(e) => Err(IOError::from_raw_os_error(e.raw_os_error())),
}
}

Expand Down
34 changes: 16 additions & 18 deletions src/uucore/src/lib/features/safe_traversal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// Available on Unix
//
// spell-checker:ignore CLOEXEC RDONLY TOCTOU closedir dirp fdopendir fstatat openat REMOVEDIR unlinkat smallfile
// spell-checker:ignore RAII dirfd fchownat fchown FchmodatFlags fchmodat fchmod mkdirat CREAT WRONLY ELOOP ENOTDIR
// spell-checker:ignore RAII chownat dirfd fchownat fchown FchmodatFlags fchmodat fchmod mkdirat CREAT WRONLY ELOOP ENOTDIR
// spell-checker:ignore atimensec mtimensec ctimensec

#[cfg(test)]
Expand All @@ -26,7 +26,7 @@ use nix::dir::Dir;
use nix::fcntl::{OFlag, openat};
use nix::libc;
use nix::sys::stat::{FchmodatFlags, FileStat, Mode, fchmodat, fstatat, mkdirat};
use nix::unistd::{Gid, Uid, UnlinkatFlags, fchown, fchownat, unlinkat};
use nix::unistd::{UnlinkatFlags, unlinkat};
use os_display::Quotable;

use crate::translate;
Expand Down Expand Up @@ -258,32 +258,30 @@ impl DirFd {
gid: Option<u32>,
symlink_behavior: SymlinkBehavior,
) -> io::Result<()> {
let name_cstr =
CString::new(name.as_bytes()).map_err(|_| SafeTraversalError::PathContainsNull)?;

let flags = if symlink_behavior.should_follow() {
nix::fcntl::AtFlags::empty()
rustix::fs::AtFlags::empty()
} else {
nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW
rustix::fs::AtFlags::SYMLINK_NOFOLLOW
};

let uid = uid.map(Uid::from_raw);
let gid = gid.map(Gid::from_raw);

fchownat(&self.fd, name_cstr.as_c_str(), uid, gid, flags)
.map_err(|e| io::Error::from_raw_os_error(e as i32))?;
let uid = uid.map(rustix::process::Uid::from_raw);
let gid = gid.map(rustix::process::Gid::from_raw);

Ok(())
match rustix::fs::chownat(&self.fd, name, uid, gid, flags) {
Ok(_) => Ok(()),
Err(e) => Err(io::Error::from_raw_os_error(e.raw_os_error())),
}
}

/// Change ownership of this directory
pub fn fchown(&self, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
let uid = uid.map(Uid::from_raw);
let gid = gid.map(Gid::from_raw);
let uid = uid.map(rustix::process::Uid::from_raw);
let gid = gid.map(rustix::process::Gid::from_raw);

fchown(&self.fd, uid, gid).map_err(|e| io::Error::from_raw_os_error(e as i32))?;

Ok(())
match rustix::fs::fchown(&self.fd, uid, gid) {
Ok(_) => Ok(()),
Err(e) => Err(io::Error::from_raw_os_error(e.raw_os_error())),
}
}

/// Change mode of a file relative to this directory
Expand Down
Loading