pub fn uu_app() -> Commanddiff --git a/dev/src/uu_fmt/fmt.rs.html b/dev/src/uu_fmt/fmt.rs.html index fb6dabcb0..2e89b1a52 100644 --- a/dev/src/uu_fmt/fmt.rs.html +++ b/dev/src/uu_fmt/fmt.rs.html @@ -357,6 +357,41 @@ 357 358 359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394
// * This file is part of `fmt` from the uutils coreutils package.
// *
// * (c) kwantam <kwantam@gmail.com>
@@ -370,7 +405,7 @@
use std::cmp;
use std::fs::File;
use std::io::{stdin, stdout, Write};
-use std::io::{BufReader, BufWriter, Read};
+use std::io::{BufReader, BufWriter, Read, Stdout};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};
use uucore::{format_usage, help_about, help_usage, show_warning};
@@ -419,10 +454,16 @@
goal: usize,
tabwidth: usize,
}
-
-#[uucore::main]
-#[allow(clippy::cognitive_complexity)]
-pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+/// Parse the command line arguments and return the list of files and formatting options.
+///
+/// # Arguments
+///
+/// * `args` - Command line arguments.
+///
+/// # Returns
+///
+/// A tuple containing a vector of file names and a `FmtOptions` struct.
+fn parse_arguments(args: impl uucore::Args) -> UResult<(Vec<String>, FmtOptions)> {
let matches = uu_app().try_get_matches_from(args)?;
let mut files: Vec<String> = matches
@@ -536,39 +577,68 @@
files.push("-".to_owned());
}
+ Ok((files, fmt_opts))
+}
+
+/// Process the content of a file and format it according to the provided options.
+///
+/// # Arguments
+///
+/// * `file_name` - The name of the file to process. A value of "-" represents the standard input.
+/// * `fmt_opts` - A reference to a `FmtOptions` struct containing the formatting options.
+/// * `ostream` - A mutable reference to a `BufWriter` wrapping the standard output.
+///
+/// # Returns
+///
+/// A `UResult<()>` indicating success or failure.
+fn process_file(
+ file_name: &str,
+ fmt_opts: &FmtOptions,
+ ostream: &mut BufWriter<Stdout>,
+) -> UResult<()> {
+ let mut fp = match file_name {
+ "-" => BufReader::new(Box::new(stdin()) as Box<dyn Read + 'static>),
+ _ => match File::open(file_name) {
+ Ok(f) => BufReader::new(Box::new(f) as Box<dyn Read + 'static>),
+ Err(e) => {
+ show_warning!("{}: {}", file_name.maybe_quote(), e);
+ return Ok(());
+ }
+ },
+ };
+
+ let p_stream = ParagraphStream::new(fmt_opts, &mut fp);
+ for para_result in p_stream {
+ match para_result {
+ Err(s) => {
+ ostream
+ .write_all(s.as_bytes())
+ .map_err_context(|| "failed to write output".to_string())?;
+ ostream
+ .write_all(b"\n")
+ .map_err_context(|| "failed to write output".to_string())?;
+ }
+ Ok(para) => break_lines(¶, fmt_opts, ostream)
+ .map_err_context(|| "failed to write output".to_string())?,
+ }
+ }
+
+ // flush the output after each file
+ ostream
+ .flush()
+ .map_err_context(|| "failed to write output".to_string())?;
+
+ Ok(())
+}
+
+#[uucore::main]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+ let (files, fmt_opts) = parse_arguments(args)?;
+
let mut ostream = BufWriter::new(stdout());
- for i in files.iter().map(|x| &x[..]) {
- let mut fp = match i {
- "-" => BufReader::new(Box::new(stdin()) as Box<dyn Read + 'static>),
- _ => match File::open(i) {
- Ok(f) => BufReader::new(Box::new(f) as Box<dyn Read + 'static>),
- Err(e) => {
- show_warning!("{}: {}", i.maybe_quote(), e);
- continue;
- }
- },
- };
- let p_stream = ParagraphStream::new(&fmt_opts, &mut fp);
- for para_result in p_stream {
- match para_result {
- Err(s) => {
- ostream
- .write_all(s.as_bytes())
- .map_err_context(|| "failed to write output".to_string())?;
- ostream
- .write_all(b"\n")
- .map_err_context(|| "failed to write output".to_string())?;
- }
- Ok(para) => break_lines(¶, &fmt_opts, &mut ostream)
- .map_err_context(|| "failed to write output".to_string())?,
- }
- }
-
- // flush the output after each file
- ostream
- .flush()
- .map_err_context(|| "failed to write output".to_string())?;
+ for file_name in &files {
+ process_file(file_name, &fmt_opts, &mut ostream)?;
}
Ok(())
diff --git a/dev/src/uu_hashsum/hashsum.rs.html b/dev/src/uu_hashsum/hashsum.rs.html
index b8e7a5f0f..cfa794d39 100644
--- a/dev/src/uu_hashsum/hashsum.rs.html
+++ b/dev/src/uu_hashsum/hashsum.rs.html
@@ -721,6 +721,55 @@
721
722
723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
// * This file is part of the uutils coreutils package.
// *
// * (c) Alex Lyon <arcterus@mail.com>
@@ -773,71 +822,140 @@
zero: bool,
}
-#[allow(clippy::cognitive_complexity)]
+/// Creates a Blake2b hasher instance based on the specified length argument.
+///
+/// # Returns
+///
+/// Returns a tuple containing the algorithm name, the hasher instance, and the output length in bits.
+///
+/// # Panics
+///
+/// Panics if the length is not a multiple of 8 or if it is greater than 512.
+fn create_blake2b(matches: &ArgMatches) -> (&'static str, Box<dyn Digest>, usize) {
+ match matches.get_one::<usize>("length") {
+ Some(0) | None => ("BLAKE2", Box::new(Blake2b::new()) as Box<dyn Digest>, 512),
+ Some(length_in_bits) => {
+ if *length_in_bits > 512 {
+ crash!(1, "Invalid length (maximum digest length is 512 bits)")
+ }
+
+ if length_in_bits % 8 == 0 {
+ let length_in_bytes = length_in_bits / 8;
+ (
+ "BLAKE2",
+ Box::new(Blake2b::with_output_bytes(length_in_bytes)),
+ *length_in_bits,
+ )
+ } else {
+ crash!(1, "Invalid length (expected a multiple of 8)")
+ }
+ }
+ }
+}
+
+/// Creates a SHA3 hasher instance based on the specified bits argument.
+///
+/// # Returns
+///
+/// Returns a tuple containing the algorithm name, the hasher instance, and the output length in bits.
+///
+/// # Panics
+///
+/// Panics if an unsupported output size is provided, or if the `--bits` flag is missing.
+fn create_sha3(matches: &ArgMatches) -> (&'static str, Box<dyn Digest>, usize) {
+ match matches.get_one::<usize>("bits") {
+ Some(224) => (
+ "SHA3-224",
+ Box::new(Sha3_224::new()) as Box<dyn Digest>,
+ 224,
+ ),
+ Some(256) => (
+ "SHA3-256",
+ Box::new(Sha3_256::new()) as Box<dyn Digest>,
+ 256,
+ ),
+ Some(384) => (
+ "SHA3-384",
+ Box::new(Sha3_384::new()) as Box<dyn Digest>,
+ 384,
+ ),
+ Some(512) => (
+ "SHA3-512",
+ Box::new(Sha3_512::new()) as Box<dyn Digest>,
+ 512,
+ ),
+ Some(_) => crash!(
+ 1,
+ "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"
+ ),
+ None => crash!(1, "--bits required for SHA3"),
+ }
+}
+
+/// Creates a SHAKE-128 hasher instance based on the specified bits argument.
+///
+/// # Returns
+///
+/// Returns a tuple containing the algorithm name, the hasher instance, and the output length in bits.
+///
+/// # Panics
+///
+/// Panics if the `--bits` flag is missing.
+fn create_shake128(matches: &ArgMatches) -> (&'static str, Box<dyn Digest>, usize) {
+ match matches.get_one::<usize>("bits") {
+ Some(bits) => (
+ "SHAKE128",
+ Box::new(Shake128::new()) as Box<dyn Digest>,
+ *bits,
+ ),
+ None => crash!(1, "--bits required for SHAKE-128"),
+ }
+}
+
+/// Creates a SHAKE-256 hasher instance based on the specified bits argument.
+///
+/// # Returns
+///
+/// Returns a tuple containing the algorithm name, the hasher instance, and the output length in bits.
+///
+/// # Panics
+///
+/// Panics if the `--bits` flag is missing.
+fn create_shake256(matches: &ArgMatches) -> (&'static str, Box<dyn Digest>, usize) {
+ match matches.get_one::<usize>("bits") {
+ Some(bits) => (
+ "SHAKE256",
+ Box::new(Shake256::new()) as Box<dyn Digest>,
+ *bits,
+ ),
+ None => crash!(1, "--bits required for SHAKE-256"),
+ }
+}
+
+/// Detects the hash algorithm from the program name or command-line arguments.
+///
+/// # Arguments
+///
+/// * `program` - A string slice containing the program name.
+/// * `matches` - A reference to the `ArgMatches` object containing the command-line arguments.
+///
+/// # Returns
+///
+/// Returns a tuple containing the algorithm name, the hasher instance, and the output length in bits.
fn detect_algo(
program: &str,
matches: &ArgMatches,
) -> (&'static str, Box<dyn Digest + 'static>, usize) {
- let mut alg: Option<Box<dyn Digest>> = None;
- let mut name: &'static str = "";
- let mut output_bits = 0;
- match program {
+ let (name, alg, output_bits) = match program {
"md5sum" => ("MD5", Box::new(Md5::new()) as Box<dyn Digest>, 128),
"sha1sum" => ("SHA1", Box::new(Sha1::new()) as Box<dyn Digest>, 160),
"sha224sum" => ("SHA224", Box::new(Sha224::new()) as Box<dyn Digest>, 224),
"sha256sum" => ("SHA256", Box::new(Sha256::new()) as Box<dyn Digest>, 256),
"sha384sum" => ("SHA384", Box::new(Sha384::new()) as Box<dyn Digest>, 384),
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<dyn Digest>, 512),
- "b2sum" => match matches.get_one::<usize>("length") {
- // by default, blake2 uses 64 bytes (512 bits)
- // --length=0 falls back to default behavior
- Some(0) | None => ("BLAKE2", Box::new(Blake2b::new()) as Box<dyn Digest>, 512),
- Some(length_in_bits) => {
- if *length_in_bits > 512 {
- crash!(1, "Invalid length (maximum digest length is 512 bits)")
- }
-
- // blake2 output size must be a multiple of 8 bits
- if length_in_bits % 8 == 0 {
- let length_in_bytes = length_in_bits / 8;
- (
- "BLAKE2",
- Box::new(Blake2b::with_output_bytes(length_in_bytes)),
- *length_in_bits,
- )
- } else {
- crash!(1, "Invalid length (expected a multiple of 8)")
- }
- }
- },
+ "b2sum" => create_blake2b(matches),
"b3sum" => ("BLAKE3", Box::new(Blake3::new()) as Box<dyn Digest>, 256),
- "sha3sum" => match matches.get_one::<usize>("bits") {
- Some(224) => (
- "SHA3-224",
- Box::new(Sha3_224::new()) as Box<dyn Digest>,
- 224,
- ),
- Some(256) => (
- "SHA3-256",
- Box::new(Sha3_256::new()) as Box<dyn Digest>,
- 256,
- ),
- Some(384) => (
- "SHA3-384",
- Box::new(Sha3_384::new()) as Box<dyn Digest>,
- 384,
- ),
- Some(512) => (
- "SHA3-512",
- Box::new(Sha3_512::new()) as Box<dyn Digest>,
- 512,
- ),
- Some(_) => crash!(
- 1,
- "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"
- ),
- None => crash!(1, "--bits required for SHA3"),
- },
+ "sha3sum" => create_sha3(matches),
"sha3-224sum" => (
"SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>,
@@ -858,114 +976,94 @@
Box::new(Sha3_512::new()) as Box<dyn Digest>,
512,
),
- "shake128sum" => match matches.get_one::<usize>("bits") {
- Some(bits) => (
- "SHAKE128",
- Box::new(Shake128::new()) as Box<dyn Digest>,
- *bits,
- ),
+ "shake128sum" => create_shake128(matches),
+ "shake256sum" => create_shake256(matches),
+ _ => create_algorithm_from_flags(matches),
+ };
+ (name, alg, output_bits)
+}
+
+/// Creates a hasher instance based on the command-line flags.
+///
+/// # Arguments
+///
+/// * `matches` - A reference to the `ArgMatches` object containing the command-line arguments.
+///
+/// # Returns
+///
+/// Returns a tuple containing the algorithm name, the hasher instance, and the output length in bits.
+///
+/// # Panics
+///
+/// Panics if multiple hash algorithms are specified or if a required flag is missing.
+fn create_algorithm_from_flags(matches: &ArgMatches) -> (&'static str, Box<dyn Digest>, usize) {
+ let mut alg: Option<Box<dyn Digest>> = None;
+ let mut name: &'static str = "";
+ let mut output_bits = 0;
+ let mut set_or_crash = |n, val, bits| {
+ if alg.is_some() {
+ crash!(1, "You cannot combine multiple hash algorithms!");
+ };
+ name = n;
+ alg = Some(val);
+ output_bits = bits;
+ };
+
+ if matches.get_flag("md5") {
+ set_or_crash("MD5", Box::new(Md5::new()), 128);
+ }
+ if matches.get_flag("sha1") {
+ set_or_crash("SHA1", Box::new(Sha1::new()), 160);
+ }
+ if matches.get_flag("sha224") {
+ set_or_crash("SHA224", Box::new(Sha224::new()), 224);
+ }
+ if matches.get_flag("sha256") {
+ set_or_crash("SHA256", Box::new(Sha256::new()), 256);
+ }
+ if matches.get_flag("sha384") {
+ set_or_crash("SHA384", Box::new(Sha384::new()), 384);
+ }
+ if matches.get_flag("sha512") {
+ set_or_crash("SHA512", Box::new(Sha512::new()), 512);
+ }
+ if matches.get_flag("b2sum") {
+ set_or_crash("BLAKE2", Box::new(Blake2b::new()), 512);
+ }
+ if matches.get_flag("b3sum") {
+ set_or_crash("BLAKE3", Box::new(Blake3::new()), 256);
+ }
+ if matches.get_flag("sha3") {
+ let (n, val, bits) = create_sha3(matches);
+ set_or_crash(n, val, bits);
+ }
+ if matches.get_flag("sha3-224") {
+ set_or_crash("SHA3-224", Box::new(Sha3_224::new()), 224);
+ }
+ if matches.get_flag("sha3-256") {
+ set_or_crash("SHA3-256", Box::new(Sha3_256::new()), 256);
+ }
+ if matches.get_flag("sha3-384") {
+ set_or_crash("SHA3-384", Box::new(Sha3_384::new()), 384);
+ }
+ if matches.get_flag("sha3-512") {
+ set_or_crash("SHA3-512", Box::new(Sha3_512::new()), 512);
+ }
+ if matches.get_flag("shake128") {
+ match matches.get_one::<usize>("bits") {
+ Some(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), *bits),
None => crash!(1, "--bits required for SHAKE-128"),
- },
- "shake256sum" => match matches.get_one::<usize>("bits") {
- Some(bits) => (
- "SHAKE256",
- Box::new(Shake256::new()) as Box<dyn Digest>,
- *bits,
- ),
- None => crash!(1, "--bits required for SHAKE-256"),
- },
- _ => {
- {
- let mut set_or_crash = |n, val, bits| {
- if alg.is_some() {
- crash!(1, "You cannot combine multiple hash algorithms!")
- };
- name = n;
- alg = Some(val);
- output_bits = bits;
- };
- if matches.get_flag("md5") {
- set_or_crash("MD5", Box::new(Md5::new()), 128);
- }
- if matches.get_flag("sha1") {
- set_or_crash("SHA1", Box::new(Sha1::new()), 160);
- }
- if matches.get_flag("sha224") {
- set_or_crash("SHA224", Box::new(Sha224::new()), 224);
- }
- if matches.get_flag("sha256") {
- set_or_crash("SHA256", Box::new(Sha256::new()), 256);
- }
- if matches.get_flag("sha384") {
- set_or_crash("SHA384", Box::new(Sha384::new()), 384);
- }
- if matches.get_flag("sha512") {
- set_or_crash("SHA512", Box::new(Sha512::new()), 512);
- }
- if matches.get_flag("b2sum") {
- set_or_crash("BLAKE2", Box::new(Blake2b::new()), 512);
- }
- if matches.get_flag("b3sum") {
- set_or_crash("BLAKE3", Box::new(Blake3::new()), 256);
- }
- if matches.get_flag("sha3") {
- match matches.get_one::<usize>("bits") {
- Some(224) => set_or_crash(
- "SHA3-224",
- Box::new(Sha3_224::new()) as Box<dyn Digest>,
- 224,
- ),
- Some(256) => set_or_crash(
- "SHA3-256",
- Box::new(Sha3_256::new()) as Box<dyn Digest>,
- 256,
- ),
- Some(384) => set_or_crash(
- "SHA3-384",
- Box::new(Sha3_384::new()) as Box<dyn Digest>,
- 384,
- ),
- Some(512) => set_or_crash(
- "SHA3-512",
- Box::new(Sha3_512::new()) as Box<dyn Digest>,
- 512,
- ),
- Some(_) => crash!(
- 1,
- "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"
- ),
- None => crash!(1, "--bits required for SHA3"),
- }
- }
- if matches.get_flag("sha3-224") {
- set_or_crash("SHA3-224", Box::new(Sha3_224::new()), 224);
- }
- if matches.get_flag("sha3-256") {
- set_or_crash("SHA3-256", Box::new(Sha3_256::new()), 256);
- }
- if matches.get_flag("sha3-384") {
- set_or_crash("SHA3-384", Box::new(Sha3_384::new()), 384);
- }
- if matches.get_flag("sha3-512") {
- set_or_crash("SHA3-512", Box::new(Sha3_512::new()), 512);
- }
- if matches.get_flag("shake128") {
- match matches.get_one::<usize>("bits") {
- Some(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), *bits),
- None => crash!(1, "--bits required for SHAKE-128"),
- }
- }
- if matches.get_flag("shake256") {
- match matches.get_one::<usize>("bits") {
- Some(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), *bits),
- None => crash!(1, "--bits required for SHAKE-256"),
- }
- }
- }
- let alg = alg.unwrap_or_else(|| crash!(1, "You must specify hash algorithm!"));
- (name, alg, output_bits)
}
}
+ if matches.get_flag("shake256") {
+ match matches.get_one::<usize>("bits") {
+ Some(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), *bits),
+ None => crash!(1, "--bits required for SHAKE-256"),
+ }
+ }
+
+ let alg = alg.unwrap_or_else(|| crash!(1, "You must specify hash algorithm!"));
+ (name, alg, output_bits)
}
// TODO: return custom error type
diff --git a/dev/src/uu_install/install.rs.html b/dev/src/uu_install/install.rs.html
index 5d6e3df23..59ea6204b 100644
--- a/dev/src/uu_install/install.rs.html
+++ b/dev/src/uu_install/install.rs.html
@@ -867,6 +867,85 @@
867
868
869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
// * This file is part of the uutils coreutils package.
// *
// * (c) Ben Eills <ben@beneills.com>
@@ -1551,6 +1630,151 @@
Ok(())
}
+/// Perform backup before overwriting.
+///
+/// # Parameters
+///
+/// * `to` - The destination file path.
+/// * `b` - The behavior configuration.
+///
+/// # Returns
+///
+/// Returns an Option containing the backup path, or None if backup is not needed.
+///
+fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
+ if to.exists() {
+ if b.verbose {
+ println!("removed {}", to.quote());
+ }
+ let backup_path = backup_control::get_backup_path(b.backup_mode, to, &b.suffix);
+ if let Some(ref backup_path) = backup_path {
+ // TODO!!
+ if let Err(err) = fs::rename(to, backup_path) {
+ return Err(InstallError::BackupFailed(
+ to.to_path_buf(),
+ backup_path.to_path_buf(),
+ err,
+ )
+ .into());
+ }
+ }
+ Ok(backup_path)
+ } else {
+ Ok(None)
+ }
+}
+
+/// Copy a file from one path to another.
+///
+/// # Parameters
+///
+/// * `from` - The source file path.
+/// * `to` - The destination file path.
+///
+/// # Returns
+///
+/// Returns an empty Result or an error in case of failure.
+///
+fn copy_file(from: &Path, to: &Path) -> UResult<()> {
+ if from.as_os_str() == "/dev/null" {
+ /* workaround a limitation of fs::copy
+ * https://github.com/rust-lang/rust/issues/79390
+ */
+ if let Err(err) = File::create(to) {
+ return Err(
+ InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),
+ );
+ }
+ } else if let Err(err) = fs::copy(from, to) {
+ return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
+ }
+ Ok(())
+}
+
+/// Strip a file using an external program.
+///
+/// # Parameters
+///
+/// * `to` - The destination file path.
+/// * `b` - The behavior configuration.
+///
+/// # Returns
+///
+/// Returns an empty Result or an error in case of failure.
+///
+fn strip_file(to: &Path, b: &Behavior) -> UResult<()> {
+ match process::Command::new(&b.strip_program).arg(to).output() {
+ Ok(o) => {
+ if !o.status.success() {
+ // Follow GNU's behavior: if strip fails, removes the target
+ let _ = fs::remove_file(to);
+ return Err(InstallError::StripProgramFailed(
+ String::from_utf8(o.stderr).unwrap_or_default(),
+ )
+ .into());
+ }
+ }
+ Err(e) => {
+ // Follow GNU's behavior: if strip fails, removes the target
+ let _ = fs::remove_file(to);
+ return Err(InstallError::StripProgramFailed(e.to_string()).into());
+ }
+ }
+ Ok(())
+}
+
+/// Set ownership and permissions on the destination file.
+///
+/// # Parameters
+///
+/// * `to` - The destination file path.
+/// * `b` - The behavior configuration.
+///
+/// # Returns
+///
+/// Returns an empty Result or an error in case of failure.
+///
+fn set_ownership_and_permissions(to: &Path, b: &Behavior) -> UResult<()> {
+ // Silent the warning as we want to the error message
+ #[allow(clippy::question_mark)]
+ if mode::chmod(to, b.mode()).is_err() {
+ return Err(InstallError::ChmodFailed(to.to_path_buf()).into());
+ }
+
+ chown_optional_user_group(to, b)?;
+
+ Ok(())
+}
+
+/// Preserve timestamps on the destination file.
+///
+/// # Parameters
+///
+/// * `from` - The source file path.
+/// * `to` - The destination file path.
+///
+/// # Returns
+///
+/// Returns an empty Result or an error in case of failure.
+///
+fn preserve_timestamps(from: &Path, to: &Path) -> UResult<()> {
+ let meta = match fs::metadata(from) {
+ Ok(meta) => meta,
+ Err(e) => return Err(InstallError::MetadataFailed(e).into()),
+ };
+
+ let modified_time = FileTime::from_last_modification_time(&meta);
+ let accessed_time = FileTime::from_last_access_time(&meta);
+
+ match set_file_times(to, accessed_time, modified_time) {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ show_error!("{}", e);
+ Ok(())
+ }
+ }
+}
+
/// Copy one file to a new location, changing metadata.
///
/// Returns a Result type with the Err variant containing the error message.
@@ -1564,90 +1788,24 @@
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
-#[allow(clippy::cognitive_complexity)]
fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
if b.compare && !need_copy(from, to, b)? {
return Ok(());
}
// Declare the path here as we may need it for the verbose output below.
- let mut backup_path = None;
+ let backup_path = perform_backup(to, b)?;
- // Perform backup, if any, before overwriting 'to'
- //
- // The codes actually making use of the backup process don't seem to agree
- // on how best to approach the issue. (mv and ln, for example)
- if to.exists() {
- if b.verbose {
- println!("removed {}", to.quote());
- }
- backup_path = backup_control::get_backup_path(b.backup_mode, to, &b.suffix);
- if let Some(ref backup_path) = backup_path {
- // TODO!!
- if let Err(err) = fs::rename(to, backup_path) {
- return Err(InstallError::BackupFailed(
- to.to_path_buf(),
- backup_path.to_path_buf(),
- err,
- )
- .into());
- }
- }
+ copy_file(from, to)?;
+
+ #[cfg(not(windows))]
+ if b.strip {
+ strip_file(to, b)?;
}
- if from.as_os_str() == "/dev/null" {
- /* workaround a limitation of fs::copy
- * https://github.com/rust-lang/rust/issues/79390
- */
- if let Err(err) = File::create(to) {
- return Err(
- InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),
- );
- }
- } else if let Err(err) = fs::copy(from, to) {
- return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
- }
-
- if b.strip && cfg!(not(windows)) {
- match process::Command::new(&b.strip_program).arg(to).output() {
- Ok(o) => {
- if !o.status.success() {
- // Follow GNU's behavior: if strip fails, removes the target
- let _ = fs::remove_file(to);
- return Err(InstallError::StripProgramFailed(
- String::from_utf8(o.stderr).unwrap_or_default(),
- )
- .into());
- }
- }
- Err(e) => {
- // Follow GNU's behavior: if strip fails, removes the target
- let _ = fs::remove_file(to);
- return Err(InstallError::StripProgramFailed(e.to_string()).into());
- }
- }
- }
-
- // Silent the warning as we want to the error message
- #[allow(clippy::question_mark)]
- if mode::chmod(to, b.mode()).is_err() {
- return Err(InstallError::ChmodFailed(to.to_path_buf()).into());
- }
-
- chown_optional_user_group(to, b)?;
+ set_ownership_and_permissions(to, b)?;
if b.preserve_timestamps {
- let meta = match fs::metadata(from) {
- Ok(meta) => meta,
- Err(e) => return Err(InstallError::MetadataFailed(e).into()),
- };
-
- let modified_time = FileTime::from_last_modification_time(&meta);
- let accessed_time = FileTime::from_last_access_time(&meta);
-
- match set_file_times(to, accessed_time, modified_time) {
- Ok(_) => {}
- Err(e) => show_error!("{}", e),
- }
+ preserve_timestamps(from, to)?;
}
if b.verbose {
diff --git a/dev/src/uu_stat/stat.rs.html b/dev/src/uu_stat/stat.rs.html
index 617a36a3e..d5b2e7da2 100644
--- a/dev/src/uu_stat/stat.rs.html
+++ b/dev/src/uu_stat/stat.rs.html
@@ -933,6 +933,110 @@
933
934
935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
@@ -1140,7 +1244,16 @@
default_dev_tokens: Vec<Token>,
}
-#[allow(clippy::cognitive_complexity)]
+/// Prints a formatted output based on the provided output type, flags, width, and precision.
+///
+/// # Arguments
+///
+/// * `output` - A reference to the OutputType enum containing the value to be printed.
+/// * `flags` - A Flags struct containing formatting flags.
+/// * `width` - The width of the field for the printed output.
+/// * `precision` - An Option containing the precision value.
+///
+/// This function delegates the printing process to more specialized functions depending on the output type.
fn print_it(output: &OutputType, flags: Flags, width: usize, precision: Option<usize>) {
// If the precision is given as just '.', the precision is taken to be zero.
// A negative precision is taken as if the precision were omitted.
@@ -1171,71 +1284,166 @@
// A sign (+ or -) should always be placed before a number produced by a signed conversion.
// By default, a sign is used only for negative numbers.
// A + overrides a space if both are used.
-
- let padding_char = if flags.zero && !flags.left && precision.is_none() {
- Padding::Zero
- } else {
- Padding::Space
- };
+ let padding_char = determine_padding_char(&flags, &precision);
match output {
- OutputType::Str(s) => {
- let s = match precision {
- Some(p) if p < s.len() => &s[..p],
- _ => s,
- };
- pad_and_print(s, flags.left, width, Padding::Space);
- }
- OutputType::Integer(num) => {
- let num = num.to_string();
- let arg = if flags.group {
- group_num(&num)
- } else {
- Cow::Borrowed(num.as_str())
- };
- let prefix = if flags.sign {
- "+"
- } else if flags.space {
- " "
- } else {
- ""
- };
- let extended = format!(
- "{prefix}{arg:0>precision$}",
- precision = precision.unwrap_or(0)
- );
- pad_and_print(&extended, flags.left, width, padding_char);
- }
- OutputType::Unsigned(num) => {
- let num = num.to_string();
- let s = if flags.group {
- group_num(&num)
- } else {
- Cow::Borrowed(num.as_str())
- };
- let s = format!("{s:0>precision$}", precision = precision.unwrap_or(0));
- pad_and_print(&s, flags.left, width, padding_char);
- }
+ OutputType::Str(s) => print_str(s, &flags, width, precision),
+ OutputType::Integer(num) => print_integer(*num, &flags, width, precision, padding_char),
+ OutputType::Unsigned(num) => print_unsigned(*num, &flags, width, precision, padding_char),
OutputType::UnsignedOct(num) => {
- let prefix = if flags.alter { "0" } else { "" };
- let s = format!(
- "{prefix}{num:0>precision$o}",
- precision = precision.unwrap_or(0)
- );
- pad_and_print(&s, flags.left, width, padding_char);
+ print_unsigned_oct(*num, &flags, width, precision, padding_char);
}
OutputType::UnsignedHex(num) => {
- let prefix = if flags.alter { "0x" } else { "" };
- let s = format!(
- "{prefix}{num:0>precision$x}",
- precision = precision.unwrap_or(0)
- );
- pad_and_print(&s, flags.left, width, padding_char);
+ print_unsigned_hex(*num, &flags, width, precision, padding_char);
}
OutputType::Unknown => print!("?"),
}
}
+/// Determines the padding character based on the provided flags and precision.
+///
+/// # Arguments
+///
+/// * `flags` - A reference to the Flags struct containing formatting flags.
+/// * `precision` - An Option containing the precision value.
+///
+/// # Returns
+///
+/// * Padding - An instance of the Padding enum representing the padding character.
+fn determine_padding_char(flags: &Flags, precision: &Option<usize>) -> Padding {
+ if flags.zero && !flags.left && precision.is_none() {
+ Padding::Zero
+ } else {
+ Padding::Space
+ }
+}
+
+/// Prints a string value based on the provided flags, width, and precision.
+///
+/// # Arguments
+///
+/// * `s` - The string to be printed.
+/// * `flags` - A reference to the Flags struct containing formatting flags.
+/// * `width` - The width of the field for the printed string.
+/// * `precision` - An Option containing the precision value.
+fn print_str(s: &str, flags: &Flags, width: usize, precision: Option<usize>) {
+ let s = match precision {
+ Some(p) if p < s.len() => &s[..p],
+ _ => s,
+ };
+ pad_and_print(s, flags.left, width, Padding::Space);
+}
+
+/// Prints an integer value based on the provided flags, width, and precision.
+///
+/// # Arguments
+///
+/// * `num` - The integer value to be printed.
+/// * `flags` - A reference to the Flags struct containing formatting flags.
+/// * `width` - The width of the field for the printed integer.
+/// * `precision` - An Option containing the precision value.
+/// * `padding_char` - The padding character as determined by `determine_padding_char`.
+fn print_integer(
+ num: i64,
+ flags: &Flags,
+ width: usize,
+ precision: Option<usize>,
+ padding_char: Padding,
+) {
+ let num = num.to_string();
+ let arg = if flags.group {
+ group_num(&num)
+ } else {
+ Cow::Borrowed(num.as_str())
+ };
+ let prefix = if flags.sign {
+ "+"
+ } else if flags.space {
+ " "
+ } else {
+ ""
+ };
+ let extended = format!(
+ "{prefix}{arg:0>precision$}",
+ precision = precision.unwrap_or(0)
+ );
+ pad_and_print(&extended, flags.left, width, padding_char);
+}
+
+/// Prints an unsigned integer value based on the provided flags, width, and precision.
+///
+/// # Arguments
+///
+/// * `num` - The unsigned integer value to be printed.
+/// * `flags` - A reference to the Flags struct containing formatting flags.
+/// * `width` - The width of the field for the printed unsigned integer.
+/// * `precision` - An Option containing the precision value.
+/// * `padding_char` - The padding character as determined by `determine_padding_char`.
+fn print_unsigned(
+ num: u64,
+ flags: &Flags,
+ width: usize,
+ precision: Option<usize>,
+ padding_char: Padding,
+) {
+ let num = num.to_string();
+ let s = if flags.group {
+ group_num(&num)
+ } else {
+ Cow::Borrowed(num.as_str())
+ };
+ let s = format!("{s:0>precision$}", precision = precision.unwrap_or(0));
+ pad_and_print(&s, flags.left, width, padding_char);
+}
+
+/// Prints an unsigned octal integer value based on the provided flags, width, and precision.
+///
+/// # Arguments
+///
+/// * `num` - The unsigned octal integer value to be printed.
+/// * `flags` - A reference to the Flags struct containing formatting flags.
+/// * `width` - The width of the field for the printed unsigned octal integer.
+/// * `precision` - An Option containing the precision value.
+/// * `padding_char` - The padding character as determined by `determine_padding_char`.
+fn print_unsigned_oct(
+ num: u32,
+ flags: &Flags,
+ width: usize,
+ precision: Option<usize>,
+ padding_char: Padding,
+) {
+ let prefix = if flags.alter { "0" } else { "" };
+ let s = format!(
+ "{prefix}{num:0>precision$o}",
+ precision = precision.unwrap_or(0)
+ );
+ pad_and_print(&s, flags.left, width, padding_char);
+}
+
+/// Prints an unsigned hexadecimal integer value based on the provided flags, width, and precision.
+///
+/// # Arguments
+///
+/// * `num` - The unsigned hexadecimal integer value to be printed.
+/// * `flags` - A reference to the Flags struct containing formatting flags.
+/// * `width` - The width of the field for the printed unsigned hexadecimal integer.
+/// * `precision` - An Option containing the precision value.
+/// * `padding_char` - The padding character as determined by `determine_padding_char`.
+fn print_unsigned_hex(
+ num: u64,
+ flags: &Flags,
+ width: usize,
+ precision: Option<usize>,
+ padding_char: Padding,
+) {
+ let prefix = if flags.alter { "0x" } else { "" };
+ let s = format!(
+ "{prefix}{num:0>precision$x}",
+ precision = precision.unwrap_or(0)
+ );
+ pad_and_print(&s, flags.left, width, padding_char);
+}
+
impl Stater {
fn generate_tokens(format_str: &str, use_printf: bool) -> UResult<Vec<Token>> {
let mut tokens = Vec::new();
diff --git a/dev/uu_fmt/fn.uu_app.html b/dev/uu_fmt/fn.uu_app.html
index 663fb860b..0bdef4273 100644
--- a/dev/uu_fmt/fn.uu_app.html
+++ b/dev/uu_fmt/fn.uu_app.html
@@ -1 +1 @@
-uu_app in uu_fmt - Rust
\ No newline at end of file
+uu_app in uu_fmt - Rust
\ No newline at end of file
diff --git a/dev/uu_fmt/fn.uumain.html b/dev/uu_fmt/fn.uumain.html
index aaa304924..cc1049a2d 100644
--- a/dev/uu_fmt/fn.uumain.html
+++ b/dev/uu_fmt/fn.uumain.html
@@ -1 +1 @@
-uumain in uu_fmt - Rust
\ No newline at end of file
+uumain in uu_fmt - Rust
\ No newline at end of file
diff --git a/dev/uu_fmt/index.html b/dev/uu_fmt/index.html
index 6fba6125d..fb78fd92f 100644
--- a/dev/uu_fmt/index.html
+++ b/dev/uu_fmt/index.html
@@ -1 +1 @@
-uu_fmt - Rust
\ No newline at end of file
+uu_fmt - Rust
\ No newline at end of file
diff --git a/dev/uu_hashsum/fn.uu_app_b3sum.html b/dev/uu_hashsum/fn.uu_app_b3sum.html
index aa883ff80..a4d2cbf78 100644
--- a/dev/uu_hashsum/fn.uu_app_b3sum.html
+++ b/dev/uu_hashsum/fn.uu_app_b3sum.html
@@ -1 +1 @@
-uu_app_b3sum in uu_hashsum - Rust Function uu_hashsum::uu_app_b3sum
source · pub fn uu_app_b3sum() -> Command
\ No newline at end of file
+uu_app_b3sum in uu_hashsum - Rust Function uu_hashsum::uu_app_b3sum
source · pub fn uu_app_b3sum() -> Command
\ No newline at end of file
diff --git a/dev/uu_hashsum/fn.uu_app_bits.html b/dev/uu_hashsum/fn.uu_app_bits.html
index 191cd9dc9..4417acc3b 100644
--- a/dev/uu_hashsum/fn.uu_app_bits.html
+++ b/dev/uu_hashsum/fn.uu_app_bits.html
@@ -1 +1 @@
-uu_app_bits in uu_hashsum - Rust Function uu_hashsum::uu_app_bits
source · pub fn uu_app_bits() -> Command
\ No newline at end of file
+uu_app_bits in uu_hashsum - Rust Function uu_hashsum::uu_app_bits
source · pub fn uu_app_bits() -> Command
\ No newline at end of file
diff --git a/dev/uu_hashsum/fn.uu_app_common.html b/dev/uu_hashsum/fn.uu_app_common.html
index f3b59412e..69a7dc931 100644
--- a/dev/uu_hashsum/fn.uu_app_common.html
+++ b/dev/uu_hashsum/fn.uu_app_common.html
@@ -1 +1 @@
-uu_app_common in uu_hashsum - Rust Function uu_hashsum::uu_app_common
source · pub fn uu_app_common() -> Command
\ No newline at end of file
+uu_app_common in uu_hashsum - Rust Function uu_hashsum::uu_app_common
source · pub fn uu_app_common() -> Command
\ No newline at end of file
diff --git a/dev/uu_hashsum/fn.uu_app_custom.html b/dev/uu_hashsum/fn.uu_app_custom.html
index 3fdc5179a..3bc68993e 100644
--- a/dev/uu_hashsum/fn.uu_app_custom.html
+++ b/dev/uu_hashsum/fn.uu_app_custom.html
@@ -1 +1 @@
-uu_app_custom in uu_hashsum - Rust Function uu_hashsum::uu_app_custom
source · pub fn uu_app_custom() -> Command
\ No newline at end of file
+uu_app_custom in uu_hashsum - Rust Function uu_hashsum::uu_app_custom
source · pub fn uu_app_custom() -> Command
\ No newline at end of file
diff --git a/dev/uu_hashsum/fn.uu_app_length.html b/dev/uu_hashsum/fn.uu_app_length.html
index 71034ed05..5a305b52b 100644
--- a/dev/uu_hashsum/fn.uu_app_length.html
+++ b/dev/uu_hashsum/fn.uu_app_length.html
@@ -1 +1 @@
-uu_app_length in uu_hashsum - Rust Function uu_hashsum::uu_app_length
source · pub fn uu_app_length() -> Command
\ No newline at end of file
+uu_app_length in uu_hashsum - Rust Function uu_hashsum::uu_app_length
source · pub fn uu_app_length() -> Command
\ No newline at end of file
diff --git a/dev/uu_hashsum/fn.uumain.html b/dev/uu_hashsum/fn.uumain.html
index 9f9a226bd..a47f5907a 100644
--- a/dev/uu_hashsum/fn.uumain.html
+++ b/dev/uu_hashsum/fn.uumain.html
@@ -1 +1 @@
-uumain in uu_hashsum - Rust Function uu_hashsum::uumain
source · pub fn uumain(args: impl Args) -> i32
\ No newline at end of file
+uumain in uu_hashsum - Rust Function uu_hashsum::uumain
source · pub fn uumain(args: impl Args) -> i32
\ No newline at end of file
diff --git a/dev/uu_hashsum/index.html b/dev/uu_hashsum/index.html
index 5f46be8a2..309f6ecf7 100644
--- a/dev/uu_hashsum/index.html
+++ b/dev/uu_hashsum/index.html
@@ -1 +1 @@
-uu_hashsum - Rust
\ No newline at end of file
+uu_hashsum - Rust
\ No newline at end of file
diff --git a/dev/uu_install/index.html b/dev/uu_install/index.html
index 0c0c52ef1..021e86a0d 100644
--- a/dev/uu_install/index.html
+++ b/dev/uu_install/index.html
@@ -1 +1 @@
-uu_install - Rust
\ No newline at end of file
+uu_install - Rust
\ No newline at end of file
diff --git a/dev/uu_stat/fn.uu_app.html b/dev/uu_stat/fn.uu_app.html
index e7c29d526..cee80f30f 100644
--- a/dev/uu_stat/fn.uu_app.html
+++ b/dev/uu_stat/fn.uu_app.html
@@ -1 +1 @@
-uu_app in uu_stat - Rust
\ No newline at end of file
+uu_app in uu_stat - Rust
\ No newline at end of file
diff --git a/dev/uu_stat/fn.uumain.html b/dev/uu_stat/fn.uumain.html
index af358213e..dad483454 100644
--- a/dev/uu_stat/fn.uumain.html
+++ b/dev/uu_stat/fn.uumain.html
@@ -1 +1 @@
-uumain in uu_stat - Rust
\ No newline at end of file
+uumain in uu_stat - Rust
\ No newline at end of file
diff --git a/dev/uu_stat/index.html b/dev/uu_stat/index.html
index dc6795edb..5ba2fd4c5 100644
--- a/dev/uu_stat/index.html
+++ b/dev/uu_stat/index.html
@@ -1 +1 @@
-uu_stat - Rust
\ No newline at end of file
+uu_stat - Rust
\ No newline at end of file