mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-02 14:07:46 +00:00
Merge pull request #1054 from ids1024/chmod
Make chmod use std where possible instead of libc; compile for Redox
This commit is contained in:
commit
f4f80f0231
1 changed files with 46 additions and 45 deletions
|
@ -9,6 +9,7 @@
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate walker;
|
extern crate walker;
|
||||||
|
|
||||||
|
@ -16,9 +17,9 @@ extern crate walker;
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::CString;
|
use std::fs;
|
||||||
use std::io::{self, Write};
|
use std::io::Write;
|
||||||
use std::mem;
|
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use walker::Walker;
|
use walker::Walker;
|
||||||
|
|
||||||
|
@ -74,16 +75,10 @@ pub fn uumain(mut args: Vec<String>) -> i32 {
|
||||||
let verbose = matches.opt_present("verbose");
|
let verbose = matches.opt_present("verbose");
|
||||||
let preserve_root = matches.opt_present("preserve-root");
|
let preserve_root = matches.opt_present("preserve-root");
|
||||||
let recursive = matches.opt_present("recursive");
|
let recursive = matches.opt_present("recursive");
|
||||||
let fmode = matches.opt_str("reference").and_then(|fref| {
|
let fmode = matches.opt_str("reference").and_then(|ref fref| {
|
||||||
let s = CString::new(fref).unwrap_or_else( |_| {
|
match fs::metadata(fref) {
|
||||||
crash!(1, "reference file name contains internal nul byte")
|
Ok(meta) => Some(meta.mode()),
|
||||||
});
|
Err(err) => crash!(1, "cannot stat attribues of '{}': {}", fref, err)
|
||||||
let mut stat : libc::stat = unsafe { mem::uninitialized() };
|
|
||||||
let statres = unsafe { libc::stat(s.as_ptr() as *const _, &mut stat as *mut libc::stat) };
|
|
||||||
if statres == 0 {
|
|
||||||
Some(stat.st_mode)
|
|
||||||
} else {
|
|
||||||
crash!(1, "cannot stat attribues of '{}': {}", matches.opt_str("reference").unwrap(), io::Error::last_os_error())
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let cmode =
|
let cmode =
|
||||||
|
@ -108,7 +103,7 @@ pub fn uumain(mut args: Vec<String>) -> i32 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve_root: bool, recursive: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
|
fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve_root: bool, recursive: bool, fmode: Option<u32>, cmode: Option<&String>) -> Result<(), i32> {
|
||||||
let mut r = Ok(());
|
let mut r = Ok(());
|
||||||
|
|
||||||
for filename in &files {
|
for filename in &files {
|
||||||
|
@ -157,28 +152,25 @@ fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
|
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<u32>, cmode: Option<&String>) -> Result<(), i32> {
|
||||||
// chmod is useless on Windows
|
// chmod is useless on Windows
|
||||||
// it doesn't set any permissions at all
|
// it doesn't set any permissions at all
|
||||||
// instead it just sets the readonly attribute on the file
|
// instead it just sets the readonly attribute on the file
|
||||||
Err(0)
|
Err(0)
|
||||||
}
|
}
|
||||||
#[cfg(unix)]
|
#[cfg(any(unix, target_os = "redox"))]
|
||||||
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
|
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<u32>, cmode: Option<&String>) -> Result<(), i32> {
|
||||||
let path = CString::new(name).unwrap_or_else(|e| panic!("{}", e));
|
let mut fperm = match fs::metadata(name) {
|
||||||
let mut stat: libc::stat = unsafe { mem::uninitialized() };
|
Ok(meta) => meta.mode() & 0o7777,
|
||||||
let statres = unsafe { libc::stat(path.as_ptr(), &mut stat as *mut libc::stat) };
|
Err(err) => {
|
||||||
let mut fperm =
|
|
||||||
if statres == 0 {
|
|
||||||
stat.st_mode & 0o7777
|
|
||||||
} else {
|
|
||||||
if !quiet {
|
if !quiet {
|
||||||
show_error!("{}", io::Error::last_os_error());
|
show_error!("{}", err);
|
||||||
}
|
}
|
||||||
return Err(1);
|
return Err(1);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
match fmode {
|
match fmode {
|
||||||
Some(mode) => try!(change_file(fperm, mode, file, &path, verbose, changes, quiet)),
|
Some(mode) => try!(change_file(fperm, mode, file, name, verbose, changes, quiet)),
|
||||||
None => {
|
None => {
|
||||||
for mode in cmode.unwrap().split(',') { // cmode is guaranteed to be Some in this case
|
for mode in cmode.unwrap().split(',') { // cmode is guaranteed to be Some in this case
|
||||||
let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||||
|
@ -190,7 +182,7 @@ fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
Ok(mode) => {
|
Ok(mode) => {
|
||||||
try!(change_file(fperm, mode, file, &path, verbose, changes, quiet));
|
try!(change_file(fperm, mode, file, name, verbose, changes, quiet));
|
||||||
fperm = mode;
|
fperm = mode;
|
||||||
}
|
}
|
||||||
Err(f) => {
|
Err(f) => {
|
||||||
|
@ -207,13 +199,13 @@ fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_numeric(fperm: libc::mode_t, mut mode: &str) -> Result<libc::mode_t, String> {
|
fn parse_numeric(fperm: u32, mut mode: &str) -> Result<u32, String> {
|
||||||
let (op, pos) = try!(parse_op(mode, Some('=')));
|
let (op, pos) = try!(parse_op(mode, Some('=')));
|
||||||
mode = mode[pos..].trim_left_matches('0');
|
mode = mode[pos..].trim_left_matches('0');
|
||||||
if mode.len() > 4 {
|
if mode.len() > 4 {
|
||||||
Err(format!("mode is too large ({} > 7777)", mode))
|
Err(format!("mode is too large ({} > 7777)", mode))
|
||||||
} else {
|
} else {
|
||||||
match libc::mode_t::from_str_radix(mode, 8) {
|
match u32::from_str_radix(mode, 8) {
|
||||||
Ok(change) => {
|
Ok(change) => {
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
'+' => fperm | change,
|
'+' => fperm | change,
|
||||||
|
@ -227,14 +219,23 @@ fn parse_numeric(fperm: libc::mode_t, mut mode: &str) -> Result<libc::mode_t, St
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_symbolic(mut fperm: libc::mode_t, mut mode: &str, file: &Path) -> Result<libc::mode_t, String> {
|
fn parse_symbolic(mut fperm: u32, mut mode: &str, file: &Path) -> Result<u32, String> {
|
||||||
|
#[cfg(unix)]
|
||||||
|
use libc::umask;
|
||||||
|
|
||||||
|
#[cfg(target_os = "redox")]
|
||||||
|
unsafe fn umask(_mask: u32) -> u32 {
|
||||||
|
// XXX Redox does not currently have umask
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
let (mask, pos) = parse_levels(mode);
|
let (mask, pos) = parse_levels(mode);
|
||||||
if pos == mode.len() {
|
if pos == mode.len() {
|
||||||
return Err(format!("invalid mode ({})", mode));
|
return Err(format!("invalid mode ({})", mode));
|
||||||
}
|
}
|
||||||
let respect_umask = pos == 0;
|
let respect_umask = pos == 0;
|
||||||
let last_umask = unsafe {
|
let last_umask = unsafe {
|
||||||
libc::umask(0)
|
umask(0)
|
||||||
};
|
};
|
||||||
mode = &mode[pos..];
|
mode = &mode[pos..];
|
||||||
while mode.len() > 0 {
|
while mode.len() > 0 {
|
||||||
|
@ -242,7 +243,7 @@ fn parse_symbolic(mut fperm: libc::mode_t, mut mode: &str, file: &Path) -> Resul
|
||||||
mode = &mode[pos..];
|
mode = &mode[pos..];
|
||||||
let (mut srwx, pos) = parse_change(mode, fperm, file);
|
let (mut srwx, pos) = parse_change(mode, fperm, file);
|
||||||
if respect_umask {
|
if respect_umask {
|
||||||
srwx &= !last_umask;
|
srwx &= !(last_umask as u32);
|
||||||
}
|
}
|
||||||
mode = &mode[pos..];
|
mode = &mode[pos..];
|
||||||
match op {
|
match op {
|
||||||
|
@ -253,12 +254,12 @@ fn parse_symbolic(mut fperm: libc::mode_t, mut mode: &str, file: &Path) -> Resul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::umask(last_umask);
|
umask(last_umask);
|
||||||
}
|
}
|
||||||
Ok(fperm)
|
Ok(fperm)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_levels(mode: &str) -> (libc::mode_t, usize) {
|
fn parse_levels(mode: &str) -> (u32, usize) {
|
||||||
let mut mask = 0;
|
let mut mask = 0;
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
for ch in mode.chars() {
|
for ch in mode.chars() {
|
||||||
|
@ -290,7 +291,7 @@ fn parse_op(mode: &str, default: Option<char>) -> Result<(char, usize), String>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_change(mode: &str, fperm: libc::mode_t, file: &Path) -> (libc::mode_t, usize) {
|
fn parse_change(mode: &str, fperm: u32, file: &Path) -> (u32, usize) {
|
||||||
let mut srwx = fperm & 0o7000;
|
let mut srwx = fperm & 0o7000;
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
for ch in mode.chars() {
|
for ch in mode.chars() {
|
||||||
|
@ -318,24 +319,24 @@ fn parse_change(mode: &str, fperm: libc::mode_t, file: &Path) -> (libc::mode_t,
|
||||||
(srwx, pos)
|
(srwx, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_file(fperm: libc::mode_t, mode: libc::mode_t, file: &Path, path: &CString, verbose: bool, changes: bool, quiet: bool) -> Result<(), i32> {
|
fn change_file(fperm: u32, mode: u32, file: &Path, path: &str, verbose: bool, changes: bool, quiet: bool) -> Result<(), i32> {
|
||||||
if fperm == mode {
|
if fperm == mode {
|
||||||
if verbose && !changes {
|
if verbose && !changes {
|
||||||
show_info!("mode of '{}' retained as {:o}", file.display(), fperm);
|
show_info!("mode of '{}' retained as {:o}", file.display(), fperm);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 {
|
} else if let Err(err) = fs::set_permissions(Path::new(path), fs::Permissions::from_mode(mode)) {
|
||||||
if verbose || changes {
|
|
||||||
show_info!("mode of '{}' changed from {:o} to {:o}", file.display(), fperm, mode);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
if !quiet {
|
if !quiet {
|
||||||
show_error!("{}", io::Error::last_os_error());
|
show_error!("{}", err);
|
||||||
}
|
}
|
||||||
if verbose {
|
if verbose {
|
||||||
show_info!("failed to change mode of file '{}' from {:o} to {:o}", file.display(), fperm, mode);
|
show_info!("failed to change mode of file '{}' from {:o} to {:o}", file.display(), fperm, mode);
|
||||||
}
|
}
|
||||||
return Err(1);
|
Err(1)
|
||||||
|
} else {
|
||||||
|
if verbose || changes {
|
||||||
|
show_info!("mode of '{}' changed from {:o} to {:o}", file.display(), fperm, mode);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue