Merge branch 'master' into ls/dereference-command-line

This commit is contained in:
Sylvestre Ledru
2021-04-17 10:30:42 +02:00
committed by GitHub
106 changed files with 2942 additions and 1382 deletions
+1
View File
@@ -22,6 +22,7 @@ search the issues to make sure no one else is working on it.
1. Make sure that the code coverage is covering all of the cases, including errors.
1. The code must be clippy-warning-free and rustfmt-compliant.
1. Don't hesitate to move common functions into uucore if they can be reused by other binaries.
1. Unsafe code should be documented with Safety comments.
## Commit messages
Generated
+15 -7
View File
@@ -1362,6 +1362,12 @@ dependencies = [
"maybe-uninit",
]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "strsim"
version = "0.8.0"
@@ -1388,9 +1394,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
dependencies = [
"proc-macro2",
"quote 1.0.9",
@@ -1610,7 +1616,8 @@ name = "uu_cat"
version = "0.0.6"
dependencies = [
"clap",
"quick-error",
"nix 0.20.0",
"thiserror",
"unix_socket",
"uucore",
"uucore_procs",
@@ -1816,7 +1823,7 @@ dependencies = [
"quickcheck",
"rand 0.7.3",
"rand_chacha",
"smallvec",
"smallvec 0.6.14",
"uucore",
"uucore_procs",
]
@@ -2285,10 +2292,11 @@ version = "0.0.6"
dependencies = [
"clap",
"fnv",
"itertools 0.8.2",
"itertools 0.10.0",
"rand 0.7.3",
"rayon",
"semver",
"smallvec 1.6.1",
"uucore",
"uucore_procs",
]
@@ -2316,7 +2324,7 @@ dependencies = [
name = "uu_stdbuf"
version = "0.0.6"
dependencies = [
"getopts",
"clap",
"tempfile",
"uu_stdbuf_libstdbuf",
"uucore",
@@ -2500,7 +2508,7 @@ dependencies = [
name = "uu_unlink"
version = "0.0.6"
dependencies = [
"getopts",
"clap",
"libc",
"uucore",
"uucore_procs",
+1
View File
@@ -111,6 +111,7 @@ fn basename(fullname: &str, suffix: &str) -> String {
}
}
#[allow(clippy::manual_strip)] // can be replaced with strip_suffix once the minimum rust version is 1.45
fn strip_suffix(name: &str, suffix: &str) -> String {
if name == suffix {
return name.to_owned();
+4 -1
View File
@@ -16,13 +16,16 @@ path = "src/cat.rs"
[dependencies]
clap = "2.33"
quick-error = "1.2.3"
thiserror = "1.0"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[target.'cfg(unix)'.dependencies]
unix_socket = "0.5.0"
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
nix = "0.20"
[[bin]]
name = "cat"
path = "src/main.rs"
+246 -172
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -286,7 +286,7 @@ impl Chgrper {
ret = match wrap_chgrp(path, &meta, self.dest_gid, follow, self.verbosity.clone()) {
Ok(n) => {
if n != "" {
if !n.is_empty() {
show_info!("{}", n);
}
0
+4 -4
View File
@@ -171,13 +171,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
// of a prefix '-' if it's associated with MODE
// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE"
pub fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
for i in 0..args.len() {
if args[i].starts_with("-") {
if let Some(second) = args[i].chars().nth(1) {
for arg in args {
if arg.starts_with('-') {
if let Some(second) = arg.chars().nth(1) {
match second {
'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
// TODO: use strip_prefix() once minimum rust version reaches 1.45.0
args[i] = args[i][1..args[i].len()].to_string();
*arg = arg[1..arg.len()].to_string();
return true;
}
_ => {}
+2 -2
View File
@@ -391,7 +391,7 @@ impl Chowner {
self.verbosity.clone(),
) {
Ok(n) => {
if n != "" {
if !n.is_empty() {
show_info!("{}", n);
}
0
@@ -446,7 +446,7 @@ impl Chowner {
self.verbosity.clone(),
) {
Ok(n) => {
if n != "" {
if !n.is_empty() {
show_info!("{}", n);
}
0
+7 -7
View File
@@ -104,7 +104,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
_ => {
let mut vector: Vec<&str> = Vec::new();
for (&k, v) in matches.args.iter() {
vector.push(k.clone());
vector.push(k);
vector.push(&v.vals[0].to_str().unwrap());
}
vector
@@ -133,7 +133,7 @@ fn set_context(root: &Path, options: &clap::ArgMatches) {
let userspec = match userspec_str {
Some(ref u) => {
let s: Vec<&str> = u.split(':').collect();
if s.len() != 2 || s.iter().any(|&spec| spec == "") {
if s.len() != 2 || s.iter().any(|&spec| spec.is_empty()) {
crash!(1, "invalid userspec: `{}`", u)
};
s
@@ -142,16 +142,16 @@ fn set_context(root: &Path, options: &clap::ArgMatches) {
};
let (user, group) = if userspec.is_empty() {
(&user_str[..], &group_str[..])
(user_str, group_str)
} else {
(&userspec[0][..], &userspec[1][..])
(userspec[0], userspec[1])
};
enter_chroot(root);
set_groups_from_str(&groups_str[..]);
set_main_group(&group[..]);
set_user(&user[..]);
set_groups_from_str(groups_str);
set_main_group(group);
set_user(user);
}
fn enter_chroot(root: &Path) {
+16 -14
View File
@@ -132,7 +132,9 @@ macro_rules! prompt_yes(
pub type CopyResult<T> = Result<T, Error>;
pub type Source = PathBuf;
pub type SourceSlice = Path;
pub type Target = PathBuf;
pub type TargetSlice = Path;
/// Specifies whether when overwrite files
#[derive(Clone, Eq, PartialEq)]
@@ -547,14 +549,13 @@ impl FromStr for Attribute {
}
fn add_all_attributes() -> Vec<Attribute> {
let mut attr = Vec::new();
use Attribute::*;
let mut attr = vec![Ownership, Timestamps, Context, Xattr, Links];
#[cfg(unix)]
attr.push(Attribute::Mode);
attr.push(Attribute::Ownership);
attr.push(Attribute::Timestamps);
attr.push(Attribute::Context);
attr.push(Attribute::Xattr);
attr.push(Attribute::Links);
attr.insert(0, Mode);
attr
}
@@ -665,7 +666,7 @@ impl TargetType {
///
/// Treat target as a dir if we have multiple sources or the target
/// exists and already is a directory
fn determine(sources: &[Source], target: &Target) -> TargetType {
fn determine(sources: &[Source], target: &TargetSlice) -> TargetType {
if sources.len() > 1 || target.is_dir() {
TargetType::Directory
} else {
@@ -714,7 +715,7 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<S
fn preserve_hardlinks(
hard_links: &mut Vec<(String, u64)>,
source: &std::path::PathBuf,
source: &std::path::Path,
dest: std::path::PathBuf,
found_hard_link: &mut bool,
) -> CopyResult<()> {
@@ -788,7 +789,7 @@ fn preserve_hardlinks(
/// Behavior depends on `options`, see [`Options`] for details.
///
/// [`Options`]: ./struct.Options.html
fn copy(sources: &[Source], target: &Target, options: &Options) -> CopyResult<()> {
fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResult<()> {
let target_type = TargetType::determine(sources, target);
verify_target_type(target, &target_type)?;
@@ -840,7 +841,7 @@ fn copy(sources: &[Source], target: &Target, options: &Options) -> CopyResult<()
fn construct_dest_path(
source_path: &Path,
target: &Target,
target: &TargetSlice,
target_type: &TargetType,
options: &Options,
) -> CopyResult<PathBuf> {
@@ -870,8 +871,8 @@ fn construct_dest_path(
}
fn copy_source(
source: &Source,
target: &Target,
source: &SourceSlice,
target: &TargetSlice,
target_type: &TargetType,
options: &Options,
) -> CopyResult<()> {
@@ -912,7 +913,7 @@ fn adjust_canonicalization(p: &Path) -> Cow<Path> {
///
/// Any errors encountered copying files in the tree will be logged but
/// will not cause a short-circuit.
fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult<()> {
fn copy_directory(root: &Path, target: &TargetSlice, options: &Options) -> CopyResult<()> {
if !options.recursive {
return Err(format!("omitting directory '{}'", root.display()).into());
}
@@ -1068,6 +1069,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
}
#[cfg(not(windows))]
#[allow(clippy::unnecessary_wraps)] // needed for windows version
fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
match std::os::unix::fs::symlink(source, dest).context(context) {
Ok(_) => Ok(()),
+31 -35
View File
@@ -406,7 +406,7 @@ fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
continue;
}
if !path.metadata().is_ok() {
if path.metadata().is_err() {
show_error!("{}: No such file or directory", filename);
continue;
}
@@ -487,7 +487,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.help("filter field columns from the input source")
.takes_value(true)
.allow_hyphen_values(true)
.value_name("LIST")
.value_name("LIST")
.display_order(4),
)
.arg(
@@ -535,40 +535,36 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
matches.value_of(options::CHARACTERS),
matches.value_of(options::FIELDS),
) {
(Some(byte_ranges), None, None) => {
list_to_ranges(&byte_ranges[..], complement).map(|ranges| {
Mode::Bytes(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
})
}
(None, Some(char_ranges), None) => {
list_to_ranges(&char_ranges[..], complement).map(|ranges| {
Mode::Characters(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
})
}
(Some(byte_ranges), None, None) => list_to_ranges(byte_ranges, complement).map(|ranges| {
Mode::Bytes(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
}),
(None, Some(char_ranges), None) => list_to_ranges(char_ranges, complement).map(|ranges| {
Mode::Characters(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
}),
(None, None, Some(field_ranges)) => {
list_to_ranges(&field_ranges[..], complement).and_then(|ranges| {
list_to_ranges(field_ranges, complement).and_then(|ranges| {
let out_delim = match matches.value_of(options::OUTPUT_DELIMITER) {
Some(s) => {
if s.is_empty() {
-5
View File
@@ -116,7 +116,6 @@ struct Options {
show_listed_fs: bool,
show_fs_type: bool,
show_inode_instead: bool,
print_grand_total: bool,
// block_size: usize,
human_readable_base: i64,
fs_selector: FsSelector,
@@ -286,7 +285,6 @@ impl Options {
show_listed_fs: false,
show_fs_type: false,
show_inode_instead: false,
print_grand_total: false,
// block_size: match env::var("BLOCKSIZE") {
// Ok(size) => size.parse().unwrap(),
// Err(_) => 512,
@@ -871,9 +869,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if matches.is_present(OPT_ALL) {
opt.show_all_fs = true;
}
if matches.is_present(OPT_TOTAL) {
opt.print_grand_total = true;
}
if matches.is_present(OPT_INODES) {
opt.show_inode_instead = true;
}
+17 -3
View File
@@ -15,7 +15,7 @@ use chrono::Local;
use std::collections::HashSet;
use std::env;
use std::fs;
use std::io::{stderr, Result, Write};
use std::io::{stderr, ErrorKind, Result, Write};
use std::iter;
#[cfg(not(windows))]
use std::os::unix::fs::MetadataExt;
@@ -296,7 +296,21 @@ fn du(
}
}
}
Err(error) => show_error!("{}", error),
Err(error) => match error.kind() {
ErrorKind::PermissionDenied => {
let description = format!(
"cannot access '{}'",
entry
.path()
.as_os_str()
.to_str()
.unwrap_or("<Un-printable path>")
);
let error_message = "Permission denied";
show_error_custom_description!(description, "{}", error_message)
}
_ => show_error!("{}", error),
},
},
Err(error) => show_error!("{}", error),
}
@@ -322,7 +336,7 @@ fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String {
}
}
if size == 0 {
return format!("0");
return "0".to_string();
}
format!("{}B", size)
}
+1 -1
View File
@@ -51,7 +51,7 @@ fn print_expr_error(expr_error: &str) -> ! {
crash!(2, "{}", expr_error)
}
fn evaluate_ast(maybe_ast: Result<Box<syntax_tree::ASTNode>, String>) -> Result<String, String> {
fn evaluate_ast(maybe_ast: Result<Box<syntax_tree::AstNode>, String>) -> Result<String, String> {
if maybe_ast.is_err() {
Err(maybe_ast.err().unwrap())
} else {
+18 -18
View File
@@ -17,10 +17,10 @@ use onig::{Regex, RegexOptions, Syntax};
use crate::tokens::Token;
type TokenStack = Vec<(usize, Token)>;
pub type OperandsList = Vec<Box<ASTNode>>;
pub type OperandsList = Vec<Box<AstNode>>;
#[derive(Debug)]
pub enum ASTNode {
pub enum AstNode {
Leaf {
token_idx: usize,
value: String,
@@ -31,7 +31,7 @@ pub enum ASTNode {
operands: OperandsList,
},
}
impl ASTNode {
impl AstNode {
fn debug_dump(&self) {
self.debug_dump_impl(1);
}
@@ -40,7 +40,7 @@ impl ASTNode {
print!("\t",);
}
match *self {
ASTNode::Leaf {
AstNode::Leaf {
ref token_idx,
ref value,
} => println!(
@@ -49,7 +49,7 @@ impl ASTNode {
token_idx,
self.evaluate()
),
ASTNode::Node {
AstNode::Node {
ref token_idx,
ref op_type,
ref operands,
@@ -67,23 +67,23 @@ impl ASTNode {
}
}
fn new_node(token_idx: usize, op_type: &str, operands: OperandsList) -> Box<ASTNode> {
Box::new(ASTNode::Node {
fn new_node(token_idx: usize, op_type: &str, operands: OperandsList) -> Box<AstNode> {
Box::new(AstNode::Node {
token_idx,
op_type: op_type.into(),
operands,
})
}
fn new_leaf(token_idx: usize, value: &str) -> Box<ASTNode> {
Box::new(ASTNode::Leaf {
fn new_leaf(token_idx: usize, value: &str) -> Box<AstNode> {
Box::new(AstNode::Leaf {
token_idx,
value: value.into(),
})
}
pub fn evaluate(&self) -> Result<String, String> {
match *self {
ASTNode::Leaf { ref value, .. } => Ok(value.clone()),
ASTNode::Node { ref op_type, .. } => match self.operand_values() {
AstNode::Leaf { ref value, .. } => Ok(value.clone()),
AstNode::Node { ref op_type, .. } => match self.operand_values() {
Err(reason) => Err(reason),
Ok(operand_values) => match op_type.as_ref() {
"+" => infix_operator_two_ints(
@@ -161,7 +161,7 @@ impl ASTNode {
}
}
pub fn operand_values(&self) -> Result<Vec<String>, String> {
if let ASTNode::Node { ref operands, .. } = *self {
if let AstNode::Node { ref operands, .. } = *self {
let mut out = Vec::with_capacity(operands.len());
for operand in operands {
match operand.evaluate() {
@@ -178,7 +178,7 @@ impl ASTNode {
pub fn tokens_to_ast(
maybe_tokens: Result<Vec<(usize, Token)>, String>,
) -> Result<Box<ASTNode>, String> {
) -> Result<Box<AstNode>, String> {
if maybe_tokens.is_err() {
Err(maybe_tokens.err().unwrap())
} else {
@@ -212,7 +212,7 @@ pub fn tokens_to_ast(
}
}
fn maybe_dump_ast(result: &Result<Box<ASTNode>, String>) {
fn maybe_dump_ast(result: &Result<Box<AstNode>, String>) {
use std::env;
if let Ok(debug_var) = env::var("EXPR_DEBUG_AST") {
if debug_var == "1" {
@@ -238,11 +238,11 @@ fn maybe_dump_rpn(rpn: &TokenStack) {
}
}
fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<ASTNode>, String> {
fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<AstNode>, String> {
match rpn.pop() {
None => Err("syntax error (premature end of expression)".to_owned()),
Some((token_idx, Token::Value { value })) => Ok(ASTNode::new_leaf(token_idx, &value)),
Some((token_idx, Token::Value { value })) => Ok(AstNode::new_leaf(token_idx, &value)),
Some((token_idx, Token::InfixOp { value, .. })) => {
maybe_ast_node(token_idx, &value, 2, rpn)
@@ -262,7 +262,7 @@ fn maybe_ast_node(
op_type: &str,
arity: usize,
rpn: &mut TokenStack,
) -> Result<Box<ASTNode>, String> {
) -> Result<Box<AstNode>, String> {
let mut operands = Vec::with_capacity(arity);
for _ in 0..arity {
match ast_from_rpn(rpn) {
@@ -271,7 +271,7 @@ fn maybe_ast_node(
}
}
operands.reverse();
Ok(ASTNode::new_node(token_idx, op_type, operands))
Ok(AstNode::new_node(token_idx, op_type, operands))
}
fn move_rest_of_ops_to_out(
+1 -1
View File
@@ -267,7 +267,7 @@ impl<'a> ParagraphStream<'a> {
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
l_slice[..colon_posn].chars().all(|x| match x as usize {
y if y < 33 || y > 126 => false,
y if !(33..=126).contains(&y) => false,
_ => true,
})
}
+1 -1
View File
@@ -66,7 +66,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.takes_value(true),
)
.arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
.get_matches_from(args.clone());
.get_matches_from(args);
let bytes = matches.is_present(options::BYTES);
let spaces = matches.is_present(options::SPACES);
+7 -7
View File
@@ -78,7 +78,7 @@ fn detect_algo<'a>(
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<dyn Digest>, 512),
"b2sum" => ("BLAKE2", Box::new(Blake2b::new(64)) as Box<dyn Digest>, 512),
"sha3sum" => match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(224) => (
"SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>,
@@ -128,7 +128,7 @@ fn detect_algo<'a>(
512,
),
"shake128sum" => match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => (
"SHAKE128",
Box::new(Shake128::new()) as Box<dyn Digest>,
@@ -139,7 +139,7 @@ fn detect_algo<'a>(
None => crash!(1, "--bits required for SHAKE-128"),
},
"shake256sum" => match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => (
"SHAKE256",
Box::new(Shake256::new()) as Box<dyn Digest>,
@@ -182,7 +182,7 @@ fn detect_algo<'a>(
}
if matches.is_present("sha3") {
match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(224) => set_or_crash(
"SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>,
@@ -226,7 +226,7 @@ fn detect_algo<'a>(
}
if matches.is_present("shake128") {
match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), bits),
Err(err) => crash!(1, "{}", err),
},
@@ -235,7 +235,7 @@ fn detect_algo<'a>(
}
if matches.is_present("shake256") {
match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), bits),
Err(err) => crash!(1, "{}", err),
},
@@ -253,7 +253,7 @@ fn detect_algo<'a>(
// TODO: return custom error type
fn parse_bit_num(arg: &str) -> Result<usize, ParseIntError> {
usize::from_str_radix(arg, 10)
arg.parse()
}
fn is_valid_bit_num(arg: String) -> Result<(), String> {
+1 -1
View File
@@ -625,7 +625,7 @@ mod tests {
assert_eq!(arg_outputs("head"), Ok("head".to_owned()));
}
#[test]
#[cfg(linux)]
#[cfg(target_os = "linux")]
fn test_arg_iterate_bad_encoding() {
let invalid = unsafe { std::str::from_utf8_unchecked(b"\x80\x81") };
// this arises from a conversion from OsString to &str
+36 -17
View File
@@ -23,9 +23,11 @@ use std::fs;
use std::fs::File;
use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::result::Result;
const DEFAULT_MODE: u32 = 0o755;
const DEFAULT_STRIP_PROGRAM: &str = "strip";
#[allow(dead_code)]
pub struct Behavior {
@@ -37,6 +39,8 @@ pub struct Behavior {
verbose: bool,
preserve_timestamps: bool,
compare: bool,
strip: bool,
strip_program: String,
}
#[derive(Clone, Eq, PartialEq)]
@@ -164,17 +168,15 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.help("apply access/modification times of SOURCE files to corresponding destination files")
)
.arg(
// TODO implement flag
Arg::with_name(OPT_STRIP)
.short("s")
.long(OPT_STRIP)
.help("(unimplemented) strip symbol tables")
.help("strip symbol tables (no action Windows)")
)
.arg(
// TODO implement flag
Arg::with_name(OPT_STRIP_PROGRAM)
.long(OPT_STRIP_PROGRAM)
.help("(unimplemented) program used to strip binaries")
.help("program used to strip binaries (no action Windows)")
.value_name("PROGRAM")
)
.arg(
@@ -266,10 +268,6 @@ fn check_unimplemented<'a>(matches: &ArgMatches) -> Result<(), &'a str> {
Err("-b")
} else if matches.is_present(OPT_CREATED) {
Err("-D")
} else if matches.is_present(OPT_STRIP) {
Err("--strip, -s")
} else if matches.is_present(OPT_STRIP_PROGRAM) {
Err("--strip-program")
} else if matches.is_present(OPT_SUFFIX) {
Err("--suffix, -S")
} else if matches.is_present(OPT_TARGET_DIRECTORY) {
@@ -304,7 +302,7 @@ fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
let specified_mode: Option<u32> = if matches.is_present(OPT_MODE) {
match matches.value_of(OPT_MODE) {
Some(x) => match mode::parse(&x[..], considering_dir) {
Some(x) => match mode::parse(x, considering_dir) {
Ok(y) => Some(y),
Err(err) => {
show_error!("Invalid mode string: {}", err);
@@ -339,6 +337,12 @@ fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
verbose: matches.is_present(OPT_VERBOSE),
preserve_timestamps: matches.is_present(OPT_PRESERVE_TIMESTAMPS),
compare: matches.is_present(OPT_COMPARE),
strip: matches.is_present(OPT_STRIP),
strip_program: String::from(
matches
.value_of(OPT_STRIP_PROGRAM)
.unwrap_or(DEFAULT_STRIP_PROGRAM),
),
})
}
@@ -425,7 +429,7 @@ fn standard(paths: Vec<String>, b: Behavior) -> i32 {
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) -> i32 {
fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i32 {
if !target_dir.is_dir() {
show_error!("target '{}' is not a directory", target_dir.display());
return 1;
@@ -449,7 +453,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) ->
continue;
}
let mut targetpath = target_dir.clone().to_path_buf();
let mut targetpath = target_dir.to_path_buf();
let filename = sourcepath.components().last().unwrap();
targetpath.push(filename);
@@ -474,7 +478,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) ->
/// _file_ must exist as a non-directory.
/// _target_ must be a non-directory
///
fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behavior) -> i32 {
fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> i32 {
if copy(file, &target, b).is_err() {
1
} else {
@@ -493,7 +497,7 @@ fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behavior) -> i32 {
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
fn copy(from: &Path, to: &Path, b: &Behavior) -> Result<(), ()> {
if b.compare && !need_copy(from, to, b) {
return Ok(());
}
@@ -521,6 +525,21 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
return Err(());
}
if b.strip && cfg!(not(windows)) {
match Command::new(&b.strip_program).arg(to).output() {
Ok(o) => {
if !o.status.success() {
crash!(
1,
"strip program failed: {}",
String::from_utf8(o.stderr).unwrap_or_default()
);
}
}
Err(e) => crash!(1, "strip program execution failed: {}", e),
}
}
if mode::chmod(&to, b.mode()).is_err() {
return Err(());
}
@@ -537,7 +556,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
};
let gid = meta.gid();
match wrap_chown(
to.as_path(),
to,
&meta,
Some(owner_id),
Some(gid),
@@ -563,7 +582,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
Ok(g) => g,
_ => crash!(1, "no such group: {}", b.group),
};
match wrap_chgrp(to.as_path(), &meta, group_id, false, Verbosity::Normal) {
match wrap_chgrp(to, &meta, group_id, false, Verbosity::Normal) {
Ok(n) => {
if !n.is_empty() {
show_info!("{}", n);
@@ -582,7 +601,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
let modified_time = FileTime::from_last_modification_time(&meta);
let accessed_time = FileTime::from_last_access_time(&meta);
match set_file_times(to.as_path(), accessed_time, modified_time) {
match set_file_times(to, accessed_time, modified_time) {
Ok(_) => {}
Err(e) => show_info!("{}", e),
}
@@ -611,7 +630,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
///
/// Crashes the program if a nonexistent owner or group is specified in _b_.
///
fn need_copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> bool {
fn need_copy(from: &Path, to: &Path, b: &Behavior) -> bool {
let from_meta = match fs::metadata(from) {
Ok(meta) => meta,
Err(_) => return true,

Some files were not shown because too many files have changed in this diff Show More