1
Fork 0
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:
Knight 2016-08-14 13:22:42 +08:00
parent 799804e455
commit 40e01b94f3
4 changed files with 44 additions and 183 deletions

View file

@ -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"

View file

@ -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
}

View file

@ -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);

View file

@ -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]