mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
chown: use uucore::entries
This commit is contained in:
parent
799804e455
commit
40e01b94f3
4 changed files with 44 additions and 183 deletions
|
@ -8,19 +8,18 @@ name = "uu_chown"
|
||||||
path = "chown.rs"
|
path = "chown.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
getopts = "*"
|
|
||||||
glob = "*"
|
glob = "*"
|
||||||
libc = "*"
|
|
||||||
uucore = { path="../uucore" }
|
|
||||||
walkdir = "0.1"
|
walkdir = "0.1"
|
||||||
|
|
||||||
|
[dependencies.uucore]
|
||||||
|
path = "../uucore"
|
||||||
|
default-features = false
|
||||||
|
features = ["entries"]
|
||||||
|
|
||||||
[dependencies.clippy]
|
[dependencies.clippy]
|
||||||
version = "*"
|
version = "*"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "chown"
|
name = "chown"
|
||||||
path = "main.rs"
|
path = "main.rs"
|
||||||
|
|
|
@ -11,20 +11,14 @@
|
||||||
#![cfg_attr(feature="clippy", feature(plugin))]
|
#![cfg_attr(feature="clippy", feature(plugin))]
|
||||||
#![cfg_attr(feature="clippy", plugin(clippy))]
|
#![cfg_attr(feature="clippy", plugin(clippy))]
|
||||||
|
|
||||||
extern crate libc;
|
|
||||||
use libc::{uid_t, gid_t, c_char, c_int};
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
use uucore::libc::{self, uid_t, gid_t, lchown};
|
||||||
extern crate getopts;
|
pub use uucore::entries::{self, Locate, Passwd, Group};
|
||||||
use getopts::Options;
|
|
||||||
|
|
||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
pub mod passwd;
|
|
||||||
|
|
||||||
use std::fs::{self, Metadata};
|
use std::fs::{self, Metadata};
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
@ -37,21 +31,15 @@ use std::convert::AsRef;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
static NAME: &'static str = "chown";
|
static SYNTAX: &'static str = "[OPTION]... [OWNER][:[GROUP]] FILE...\n chown [OPTION]... --reference=RFILE FILE...";
|
||||||
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
static SUMMARY: &'static str = "change file owner and group";
|
||||||
|
|
||||||
const FTS_COMFOLLOW: u8 = 1;
|
const FTS_COMFOLLOW: u8 = 1;
|
||||||
const FTS_PHYSICAL: u8 = 1 << 1;
|
const FTS_PHYSICAL: u8 = 1 << 1;
|
||||||
const FTS_LOGICAL: u8 = 1 << 2;
|
const FTS_LOGICAL: u8 = 1 << 2;
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#[cfg_attr(all(target_os = "macos", target_arch = "x86"), link_name = "lchown$UNIX2003")]
|
|
||||||
pub fn lchown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uumain(args: Vec<String>) -> i32 {
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
let mut opts = Options::new();
|
let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");
|
||||||
|
|
||||||
opts.optflag("c",
|
opts.optflag("c",
|
||||||
"changes",
|
"changes",
|
||||||
"like verbose but report only when a change is made");
|
"like verbose but report only when a change is made");
|
||||||
|
@ -85,16 +73,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
"traverse every symbolic link to a directory encountered");
|
"traverse every symbolic link to a directory encountered");
|
||||||
opts.optflag("P", "", "do not traverse any symbolic links (default)");
|
opts.optflag("P", "", "do not traverse any symbolic links (default)");
|
||||||
|
|
||||||
opts.optflag("", "help", "display this help and exit");
|
let matches = opts.parse(args.clone());
|
||||||
opts.optflag("", "version", "output version information and exit");
|
|
||||||
|
|
||||||
let matches = match opts.parse(&args[1..]) {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(f) => {
|
|
||||||
disp_err!("{}", f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut bit_flag = FTS_PHYSICAL;
|
let mut bit_flag = FTS_PHYSICAL;
|
||||||
let mut preserve_root = false;
|
let mut preserve_root = false;
|
||||||
|
@ -121,13 +100,6 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.opt_present("help") {
|
|
||||||
return help();
|
|
||||||
} else if matches.opt_present("version") {
|
|
||||||
println!("{} {}", NAME, VERSION);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let recursive = matches.opt_present("recursive");
|
let recursive = matches.opt_present("recursive");
|
||||||
if recursive {
|
if recursive {
|
||||||
if bit_flag == FTS_PHYSICAL {
|
if bit_flag == FTS_PHYSICAL {
|
||||||
|
@ -222,25 +194,25 @@ fn parse_spec(spec: &str) -> Result<(Option<u32>, Option<u32>), String> {
|
||||||
let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();
|
let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();
|
||||||
|
|
||||||
if usr_only {
|
if usr_only {
|
||||||
Ok((Some(match passwd::getuid(args[0]) {
|
Ok((Some(match Passwd::locate(args[0]) {
|
||||||
Ok(uid) => uid,
|
Ok(v) => v.uid(),
|
||||||
Err(_) => return Err(format!("invalid user: ‘{}’", spec)),
|
_ => return Err(format!("invalid user: ‘{}’", spec)),
|
||||||
}),
|
}),
|
||||||
None))
|
None))
|
||||||
} else if grp_only {
|
} else if grp_only {
|
||||||
Ok((None,
|
Ok((None,
|
||||||
Some(match passwd::getgid(args[1]) {
|
Some(match Group::locate(args[1]) {
|
||||||
Ok(gid) => gid,
|
Ok(v) => v.gid(),
|
||||||
Err(_) => return Err(format!("invalid group: ‘{}’", spec)),
|
_ => return Err(format!("invalid group: ‘{}’", spec)),
|
||||||
})))
|
})))
|
||||||
} else if usr_grp {
|
} else if usr_grp {
|
||||||
Ok((Some(match passwd::getuid(args[0]) {
|
Ok((Some(match Passwd::locate(args[0]) {
|
||||||
Ok(uid) => uid,
|
Ok(v) => v.uid(),
|
||||||
Err(_) => return Err(format!("invalid user: ‘{}’", spec)),
|
_ => return Err(format!("invalid user: ‘{}’", spec)),
|
||||||
}),
|
}),
|
||||||
Some(match passwd::getgid(args[1]) {
|
Some(match Group::locate(args[1]) {
|
||||||
Ok(gid) => gid,
|
Ok(v) => v.gid(),
|
||||||
Err(_) => return Err(format!("invalid group: ‘{}’", spec)),
|
_ => return Err(format!("invalid group: ‘{}’", spec)),
|
||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
Ok((None, None))
|
Ok((None, None))
|
||||||
|
@ -401,10 +373,10 @@ impl Chowner {
|
||||||
if self.verbosity == Verbose {
|
if self.verbosity == Verbose {
|
||||||
println!("failed to change ownership of {} from {}:{} to {}:{}",
|
println!("failed to change ownership of {} from {}:{} to {}:{}",
|
||||||
path.display(),
|
path.display(),
|
||||||
passwd::uid2usr(meta.uid()).unwrap(),
|
entries::uid2usr(meta.uid()).unwrap(),
|
||||||
passwd::gid2grp(meta.gid()).unwrap(),
|
entries::gid2grp(meta.gid()).unwrap(),
|
||||||
passwd::uid2usr(dest_uid).unwrap(),
|
entries::uid2usr(dest_uid).unwrap(),
|
||||||
passwd::gid2grp(dest_gid).unwrap());
|
entries::gid2grp(dest_gid).unwrap());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -416,18 +388,18 @@ impl Chowner {
|
||||||
Changes | Verbose => {
|
Changes | Verbose => {
|
||||||
println!("changed ownership of {} from {}:{} to {}:{}",
|
println!("changed ownership of {} from {}:{} to {}:{}",
|
||||||
path.display(),
|
path.display(),
|
||||||
passwd::uid2usr(meta.uid()).unwrap(),
|
entries::uid2usr(meta.uid()).unwrap(),
|
||||||
passwd::gid2grp(meta.gid()).unwrap(),
|
entries::gid2grp(meta.gid()).unwrap(),
|
||||||
passwd::uid2usr(dest_uid).unwrap(),
|
entries::uid2usr(dest_uid).unwrap(),
|
||||||
passwd::gid2grp(dest_gid).unwrap());
|
entries::gid2grp(dest_gid).unwrap());
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
} else if self.verbosity == Verbose {
|
} else if self.verbosity == Verbose {
|
||||||
println!("ownership of {} retained as {}:{}",
|
println!("ownership of {} retained as {}:{}",
|
||||||
path.display(),
|
path.display(),
|
||||||
passwd::uid2usr(dest_uid).unwrap(),
|
entries::uid2usr(dest_uid).unwrap(),
|
||||||
passwd::gid2grp(dest_gid).unwrap());
|
entries::gid2grp(dest_gid).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
|
@ -444,54 +416,3 @@ impl Chowner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help() -> i32 {
|
|
||||||
println!(r#"
|
|
||||||
Usage: {0} [OPTION]... [OWNER][:[GROUP]] FILE...
|
|
||||||
or: {0} [OPTION]... --reference=RFILE FILE...
|
|
||||||
Change the owner and/or group of each FILE to OWNER and/or GROUP.
|
|
||||||
With --reference, change the owner and group of each FILE to those of RFILE.
|
|
||||||
|
|
||||||
-c, --changes like verbose but report only when a change is made
|
|
||||||
-f, --silent, --quiet suppress most error messages
|
|
||||||
-v, --verbose output a diagnostic for every file processed
|
|
||||||
--dereference affect the referent of each symbolic link (this is
|
|
||||||
the default), rather than the symbolic link itself
|
|
||||||
-h, --no-dereference affect symbolic links instead of any referenced file
|
|
||||||
(useful only on systems that can change the
|
|
||||||
ownership of a symlink)
|
|
||||||
--from=CURRENT_OWNER:CURRENT_GROUP
|
|
||||||
change the owner and/or group of each file only if
|
|
||||||
its current owner and/or group match those specified
|
|
||||||
here. Either may be omitted, in which case a match
|
|
||||||
is not required for the omitted attribute
|
|
||||||
--no-preserve-root do not treat '/' specially (the default)
|
|
||||||
--preserve-root fail to operate recursively on '/'
|
|
||||||
--reference=RFILE use RFILE's owner and group rather than
|
|
||||||
specifying OWNER:GROUP values
|
|
||||||
-R, --recursive operate on files and directories recursively
|
|
||||||
|
|
||||||
The following options modify how a hierarchy is traversed when the -R
|
|
||||||
option is also specified. If more than one is specified, only the final
|
|
||||||
one takes effect.
|
|
||||||
|
|
||||||
-H if a command line argument is a symbolic link
|
|
||||||
to a directory, traverse it
|
|
||||||
-L traverse every symbolic link to a directory
|
|
||||||
encountered
|
|
||||||
-P do not traverse any symbolic links (default)
|
|
||||||
|
|
||||||
--help display this help and exit
|
|
||||||
--version output version information and exit
|
|
||||||
|
|
||||||
Owner is unchanged if missing. Group is unchanged if missing, but changed
|
|
||||||
to login group if implied by a ':' following a symbolic OWNER.
|
|
||||||
OWNER and GROUP may be numeric as well as symbolic.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
chown root /u Change the owner of /u to "root".
|
|
||||||
chown root:staff /u Likewise, but also change its group to "staff".
|
|
||||||
chown -hR root /u Change the owner of /u and subfiles to "root".
|
|
||||||
"#,
|
|
||||||
NAME);
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
// (c) Jian Zeng <Anonymousknight96@gmail.com>
|
|
||||||
|
|
||||||
extern crate uucore;
|
|
||||||
use self::uucore::c_types::{getpwuid, getpwnam, getgrgid, getgrnam};
|
|
||||||
|
|
||||||
use std::ptr;
|
|
||||||
use std::ffi::{CString, CStr};
|
|
||||||
use std::io::Result as IOResult;
|
|
||||||
use std::io::{ErrorKind, Error};
|
|
||||||
|
|
||||||
macro_rules! gen_func {
|
|
||||||
($fun:ident, $getid:ident, $getnm:ident, $field:ident) => (
|
|
||||||
pub fn $fun(name_or_id: &str) -> IOResult<u32> {
|
|
||||||
if let Ok(id) = name_or_id.parse::<u32>() {
|
|
||||||
let data = unsafe {
|
|
||||||
$getid(id)
|
|
||||||
};
|
|
||||||
if !data.is_null() {
|
|
||||||
return Ok(id);
|
|
||||||
} else {
|
|
||||||
// last_os_error() returns success
|
|
||||||
return Err(Error::new(ErrorKind::NotFound, format!("No such id `{}`", id)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let name = CString::new(name_or_id).unwrap();
|
|
||||||
let data = unsafe {
|
|
||||||
$getnm(name.as_ptr())
|
|
||||||
};
|
|
||||||
if !data.is_null() {
|
|
||||||
return Ok(unsafe {
|
|
||||||
ptr::read(data).$field
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// last_os_error() returns success
|
|
||||||
return Err(Error::new(ErrorKind::NotFound, format!("No such name `{}`", name_or_id)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
($fun:ident, $getid:ident, $field:ident) => (
|
|
||||||
pub fn $fun(id: u32) -> IOResult<String> {
|
|
||||||
let data = unsafe {
|
|
||||||
$getid(id)
|
|
||||||
};
|
|
||||||
if !data.is_null() {
|
|
||||||
Ok(unsafe {
|
|
||||||
CStr::from_ptr(ptr::read(data).$field).to_string_lossy().into_owned()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(Error::new(ErrorKind::NotFound, format!("No such id `{}`", id)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_func!(getuid, getpwuid, getpwnam, pw_uid);
|
|
||||||
gen_func!(getgid, getgrgid, getgrnam, gr_gid);
|
|
||||||
gen_func!(uid2usr, getpwuid, pw_name);
|
|
||||||
gen_func!(gid2grp, getgrgid, gr_name);
|
|
|
@ -9,25 +9,25 @@ fn new_ucmd() -> UCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_passwd {
|
mod test_passgrp {
|
||||||
use super::passwd::*;
|
use super::uu_chown::entries::{usr2uid,grp2gid,uid2usr,gid2grp};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_getuid() {
|
fn test_usr2uid() {
|
||||||
assert_eq!(0, getuid("root").unwrap());
|
assert_eq!(0, usr2uid("root").unwrap());
|
||||||
assert!(getuid("88888888").is_err());
|
assert!(usr2uid("88888888").is_err());
|
||||||
assert!(getuid("auserthatdoesntexist").is_err());
|
assert!(usr2uid("auserthatdoesntexist").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_getgid() {
|
fn test_grp2gid() {
|
||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
assert_eq!(0, getgid("wheel").unwrap());
|
assert_eq!(0, grp2gid("wheel").unwrap());
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(0, getgid("root").unwrap());
|
assert_eq!(0, grp2gid("root").unwrap());
|
||||||
}
|
}
|
||||||
assert!(getgid("88888888").is_err());
|
assert!(grp2gid("88888888").is_err());
|
||||||
assert!(getgid("agroupthatdoesntexist").is_err());
|
assert!(grp2gid("agroupthatdoesntexist").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue