diff --git a/Cargo.toml b/Cargo.toml index 54cb21bd..b51b1d85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "findutils" version = "0.11.0" homepage = "https://github.com/uutils/findutils" repository = "https://github.com/uutils/findutils" -edition = "2021" +edition = "2024" rust-version = "1.88.0" license = "MIT" readme = "README.md" diff --git a/benches/find_bench.rs b/benches/find_bench.rs index 69082faa..9a42f059 100644 --- a/benches/find_bench.rs +++ b/benches/find_bench.rs @@ -14,8 +14,8 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::time::SystemTime; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use findutils::find::{find_main, Dependencies}; +use criterion::{Criterion, black_box, criterion_group, criterion_main}; +use findutils::find::{Dependencies, find_main}; /// `Dependencies` implementation that throws output away. A fixed `now` keeps /// time-based matchers (`-newer`, `-mtime`, …) deterministic across runs. diff --git a/benches/locate_bench.rs b/benches/locate_bench.rs index 2c4c4737..f18c9949 100644 --- a/benches/locate_bench.rs +++ b/benches/locate_bench.rs @@ -16,7 +16,7 @@ mod bench { use std::path::{Path, PathBuf}; - use criterion::{black_box, criterion_group, Criterion}; + use criterion::{Criterion, black_box, criterion_group}; use findutils::locate::locate_main; use findutils::updatedb::updatedb_main; diff --git a/benches/updatedb_bench.rs b/benches/updatedb_bench.rs index 20ed69c2..86e15f02 100644 --- a/benches/updatedb_bench.rs +++ b/benches/updatedb_bench.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, black_box, criterion_group, criterion_main}; use findutils::updatedb::updatedb_main; /// Run `updatedb` end-to-end. `args` are the arguments after the program name. diff --git a/benches/xargs_bench.rs b/benches/xargs_bench.rs index 2be2a057..a2c814c3 100644 --- a/benches/xargs_bench.rs +++ b/benches/xargs_bench.rs @@ -12,7 +12,7 @@ use std::path::PathBuf; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, black_box, criterion_group, criterion_main}; use findutils::xargs::xargs_main; /// Run `xargs` end-to-end. `args` are the arguments after the program name. diff --git a/src/find/matchers/delete.rs b/src/find/matchers/delete.rs index 354db309..b9cc1153 100644 --- a/src/find/matchers/delete.rs +++ b/src/find/matchers/delete.rs @@ -8,7 +8,7 @@ */ use std::fs; -use std::io::{self, stderr, Write}; +use std::io::{self, Write, stderr}; use super::{Matcher, MatcherIO, WalkEntry}; @@ -57,7 +57,7 @@ impl Matcher for DeleteMatcher { #[cfg(test)] mod tests { - use std::fs::{create_dir, File}; + use std::fs::{File, create_dir}; use tempfile::Builder; use super::*; diff --git a/src/find/matchers/empty.rs b/src/find/matchers/empty.rs index 9770dffe..ef035e0b 100644 --- a/src/find/matchers/empty.rs +++ b/src/find/matchers/empty.rs @@ -6,7 +6,7 @@ use std::{ fs::read_dir, - io::{stderr, Write}, + io::{Write, stderr}, }; use super::{Matcher, MatcherIO, WalkEntry}; diff --git a/src/find/matchers/entry.rs b/src/find/matchers/entry.rs index 649413d3..2d44e6bd 100644 --- a/src/find/matchers/entry.rs +++ b/src/find/matchers/entry.rs @@ -239,14 +239,14 @@ impl WalkEntry { } Err(e) if e.is_not_found() => { // Detect broken symlinks and replace them with explicit entries - if let (Some(path), Some(depth)) = (e.path(), e.depth()) { - if let Ok(meta) = path.symlink_metadata() { - return Ok(Self { - inner: Entry::Explicit(path.into(), depth), - follow: Follow::Never, - meta: Ok(meta).into(), - }); - } + if let (Some(path), Some(depth)) = (e.path(), e.depth()) + && let Ok(meta) = path.symlink_metadata() + { + return Ok(Self { + inner: Entry::Explicit(path.into(), depth), + follow: Follow::Never, + meta: Ok(meta).into(), + }); } Err(e) diff --git a/src/find/matchers/exec.rs b/src/find/matchers/exec.rs index f1170046..51bb3c77 100644 --- a/src/find/matchers/exec.rs +++ b/src/find/matchers/exec.rs @@ -7,7 +7,7 @@ use std::cell::RefCell; use std::error::Error; use std::ffi::{OsStr, OsString}; -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; use std::path::Path; use std::process::Command; diff --git a/src/find/matchers/fs.rs b/src/find/matchers/fs.rs index f8ae47b6..79894620 100644 --- a/src/find/matchers/fs.rs +++ b/src/find/matchers/fs.rs @@ -28,7 +28,7 @@ pub struct Cache { #[cfg(unix)] use std::{ cell::RefCell, - io::{stderr, Write}, + io::{Write, stderr}, path::Path, }; @@ -54,10 +54,10 @@ pub fn get_file_system_type(path: &Path, cache: &RefCell>) -> URes /// This is only supported on Unix. #[cfg(unix)] pub fn fs_type_for_dev(dev_id: String, cache: &RefCell>) -> UResult { - if let Some(cache) = cache.borrow().as_ref() { - if cache.dev_id == dev_id { - return Ok(cache.fs_type.clone()); - } + if let Some(cache) = cache.borrow().as_ref() + && cache.dev_id == dev_id + { + return Ok(cache.fs_type.clone()); } let fs_list = uucore::fsext::read_fs_list()?; @@ -148,9 +148,9 @@ mod tests { fn test_fs_matcher() { use crate::find::{ matchers::{ - fs::{get_file_system_type, Cache}, - tests::get_dir_entry_for, Matcher, + fs::{Cache, get_file_system_type}, + tests::get_dir_entry_for, }, tests::FakeDependencies, }; diff --git a/src/find/matchers/group.rs b/src/find/matchers/group.rs index 7b35c86c..9b241fe6 100644 --- a/src/find/matchers/group.rs +++ b/src/find/matchers/group.rs @@ -93,7 +93,7 @@ mod tests { #[test] #[cfg(unix)] fn test_group_matcher() { - use crate::find::matchers::{group::GroupMatcher, tests::get_dir_entry_for, Matcher}; + use crate::find::matchers::{Matcher, group::GroupMatcher, tests::get_dir_entry_for}; use crate::find::tests::FakeDependencies; use chrono::Local; use nix::unistd::{Gid, Group}; diff --git a/src/find/matchers/lname.rs b/src/find/matchers/lname.rs index d41b83eb..cd9aa2e9 100644 --- a/src/find/matchers/lname.rs +++ b/src/find/matchers/lname.rs @@ -4,7 +4,7 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; use std::path::PathBuf; use super::glob::Pattern; diff --git a/src/find/matchers/ls.rs b/src/find/matchers/ls.rs index 8e662faa..a7bd1f3d 100644 --- a/src/find/matchers/ls.rs +++ b/src/find/matchers/ls.rs @@ -6,7 +6,7 @@ use chrono::DateTime; use std::{ fs::File, - io::{stderr, Write}, + io::{Write, stderr}, }; use super::{Matcher, MatcherIO, StdoutErrors, WalkEntry}; @@ -87,12 +87,11 @@ impl Ls { now_utc.format("%b %e %H:%M") }; let mut path = file_info.path().to_string_lossy().into_owned(); - if file_info.file_type().is_symlink() { - if let Ok(target) = std::fs::read_link(file_info.path()) { + if file_info.file_type().is_symlink() + && let Ok(target) = std::fs::read_link(file_info.path()) { path.push_str(" -> "); path.push_str(&target.to_string_lossy()); } - } match writeln!( out, diff --git a/src/find/matchers/mod.rs b/src/find/matchers/mod.rs index dde6f8b2..2dacda74 100644 --- a/src/find/matchers/mod.rs +++ b/src/find/matchers/mod.rs @@ -34,7 +34,7 @@ mod user; use self::access::AccessMatcher; use self::delete::DeleteMatcher; use self::empty::EmptyMatcher; -use self::exec::{check_path_for_relative_entries, MultiExecMatcher, SingleExecMatcher}; +use self::exec::{MultiExecMatcher, SingleExecMatcher, check_path_for_relative_entries}; use self::group::{GroupMatcher, NoGroupMatcher}; use self::lname::LinkNameMatcher; use self::logical_matchers::{ @@ -65,7 +65,7 @@ use std::{ cell::Cell, error::Error, fs::{File, Metadata}, - io::{stderr, Write}, + io::{Write, stderr}, path::{Path, PathBuf}, rc::Rc, str::FromStr, @@ -356,14 +356,14 @@ fn convert_arg_to_comparable_value( value_as_string: &str, ) -> Result> { let re = Regex::new(r"^([-+]?)[-+]?(\d+)$")?; - if let Some(groups) = re.captures(value_as_string) { - if let Ok(val) = groups[2].parse::() { - return Ok(match &groups[1] { - "+" => ComparableValue::MoreThan(val), - "-" => ComparableValue::LessThan(val), - _ => ComparableValue::EqualTo(val), - }); - } + if let Some(groups) = re.captures(value_as_string) + && let Ok(val) = groups[2].parse::() + { + return Ok(match &groups[1] { + "+" => ComparableValue::MoreThan(val), + "-" => ComparableValue::LessThan(val), + _ => ComparableValue::EqualTo(val), + }); } Err(From::from(format!( "Expected a decimal integer (with optional + or - prefix) argument \ @@ -380,17 +380,17 @@ fn convert_arg_to_comparable_value_and_suffix( // accepts one more optional '+' (so "++5c" and "-+5c" are valid, but "+-5c" // and "--5c" are not), which `\+?` reproduces. let re = Regex::new(r"^([-+]?)\+?(\d+)(.*)$")?; - if let Some(groups) = re.captures(value_as_string) { - if let Ok(val) = groups[2].parse::() { - return Ok(( - match &groups[1] { - "+" => ComparableValue::MoreThan(val), - "-" => ComparableValue::LessThan(val), - _ => ComparableValue::EqualTo(val), - }, - groups[3].to_string(), - )); - } + if let Some(groups) = re.captures(value_as_string) + && let Ok(val) = groups[2].parse::() + { + return Ok(( + match &groups[1] { + "+" => ComparableValue::MoreThan(val), + "-" => ComparableValue::LessThan(val), + _ => ComparableValue::EqualTo(val), + }, + groups[3].to_string(), + )); } Err(From::from(format!( "Expected a decimal integer (with optional + or - prefix) and \ @@ -1247,8 +1247,8 @@ fn build_matcher_tree( #[cfg(test)] mod tests { use super::*; - use crate::find::tests::fix_up_slashes; use crate::find::tests::FakeDependencies; + use crate::find::tests::fix_up_slashes; /// Helper function for tests to get a [WalkEntry] object. root should /// probably be a string starting with `test_data/` (cargo's tests run with @@ -1330,10 +1330,13 @@ mod tests { for arg in &["-not", "!"] { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&[arg], &mut config) { - assert!(e.to_string().contains("expected an expression")); - } else { - panic!("parsing argument lists that end in -not should fail"); + match build_top_level_matcher(&[arg], &mut config) { + Err(e) => { + assert!(e.to_string().contains("expected an expression")); + } + _ => { + panic!("parsing argument lists that end in -not should fail"); + } } } } @@ -1368,10 +1371,13 @@ mod tests { for arg in &["-iname", "-name", "-type"] { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&[arg], &mut config) { - assert_eq!(e.to_string(), format!("missing argument to `{arg}'")); - } else { - panic!("parsing argument lists that end in -not should fail"); + match build_top_level_matcher(&[arg], &mut config) { + Err(e) => { + assert_eq!(e.to_string(), format!("missing argument to `{arg}'")); + } + _ => { + panic!("parsing argument lists that end in -not should fail"); + } } } } @@ -1381,10 +1387,13 @@ mod tests { for arg in &["-or", "-o"] { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&[arg, "-true"], &mut config) { - assert!(e.to_string().contains("you have used a binary operator")); - } else { - panic!("parsing argument list that begins with -or should fail"); + match build_top_level_matcher(&[arg, "-true"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("you have used a binary operator")); + } + _ => { + panic!("parsing argument list that begins with -or should fail"); + } } } } @@ -1394,10 +1403,13 @@ mod tests { for arg in &["-or", "-o"] { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-true", arg], &mut config) { - assert!(e.to_string().contains("expected an expression")); - } else { - panic!("parsing argument list that ends with -or should fail"); + match build_top_level_matcher(&["-true", arg], &mut config) { + Err(e) => { + assert!(e.to_string().contains("expected an expression")); + } + _ => { + panic!("parsing argument list that ends with -or should fail"); + } } } } @@ -1408,16 +1420,19 @@ mod tests { for arg in ["-and", "-a"] { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&[arg, "-true"], &mut config) { - assert_eq!( - e.to_string(), - format!( - "invalid expression; you have used a binary operator \ + match build_top_level_matcher(&[arg, "-true"], &mut config) { + Err(e) => { + assert_eq!( + e.to_string(), + format!( + "invalid expression; you have used a binary operator \ '{arg}' with nothing before it." - ) - ); - } else { - panic!("parsing argument list that begins with {arg} should fail"); + ) + ); + } + _ => { + panic!("parsing argument list that begins with {arg} should fail"); + } } } } @@ -1426,10 +1441,13 @@ mod tests { fn build_top_level_matcher_and_without_expr2() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-true", "-a"], &mut config) { - assert!(e.to_string().contains("expected an expression")); - } else { - panic!("parsing argument list that ends with -or should fail"); + match build_top_level_matcher(&["-true", "-a"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("expected an expression")); + } + _ => { + panic!("parsing argument list that ends with -or should fail"); + } } } @@ -1530,16 +1548,22 @@ mod tests { fn build_top_level_matcher_list_without_expr1() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&[",", "-true"], &mut config) { - assert!(e.to_string().contains("you have used a binary operator")); - } else { - panic!("parsing argument list that begins with , should fail"); + match build_top_level_matcher(&[",", "-true"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("you have used a binary operator")); + } + _ => { + panic!("parsing argument list that begins with , should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-true", "-o", ",", "-true"], &mut config) { - assert!(e.to_string().contains("you have used a binary operator")); - } else { - panic!("parsing argument list that contains '-o ,' should fail"); + match build_top_level_matcher(&["-true", "-o", ",", "-true"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("you have used a binary operator")); + } + _ => { + panic!("parsing argument list that contains '-o ,' should fail"); + } } } @@ -1547,10 +1571,13 @@ mod tests { fn build_top_level_matcher_list_without_expr2() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-true", ","], &mut config) { - assert!(e.to_string().contains("expected an expression")); - } else { - panic!("parsing argument list that ends with , should fail"); + match build_top_level_matcher(&["-true", ","], &mut config) { + Err(e) => { + assert!(e.to_string().contains("expected an expression")); + } + _ => { + panic!("parsing argument list that ends with , should fail"); + } } } @@ -1558,10 +1585,13 @@ mod tests { fn build_top_level_matcher_not_enough_brackets() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-true", "("], &mut config) { - assert!(e.to_string().contains("I was expecting to find a ')'")); - } else { - panic!("parsing argument list with not enough closing brackets should fail"); + match build_top_level_matcher(&["-true", "("], &mut config) { + Err(e) => { + assert!(e.to_string().contains("I was expecting to find a ')'")); + } + _ => { + panic!("parsing argument list with not enough closing brackets should fail"); + } } } @@ -1569,13 +1599,16 @@ mod tests { fn build_top_level_matcher_too_many_brackets() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher( + match build_top_level_matcher( &["-type", "f", "(", "-name", "*.txt", ")", ")"], &mut config, ) { - assert_eq!(e.to_string(), "you have too many ')'"); - } else { - panic!("parsing argument list with too many closing brackets should fail"); + Err(e) => { + assert_eq!(e.to_string(), "you have too many ')'"); + } + _ => { + panic!("parsing argument list with too many closing brackets should fail"); + } } } @@ -1657,10 +1690,13 @@ mod tests { fn build_top_level_matcher_expression_empty_parentheses() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-true", "(", ")"], &mut config) { - assert!(e.to_string().contains("empty parentheses are not allowed")); - } else { - panic!("parsing argument list with empty parentheses in an expression should fail"); + match build_top_level_matcher(&["-true", "(", ")"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("empty parentheses are not allowed")); + } + _ => { + panic!("parsing argument list with empty parentheses in an expression should fail"); + } } } @@ -1813,13 +1849,16 @@ mod tests { fn build_top_level_matcher_bad_ctime_value() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-ctime", "-123."], &mut config) { - assert!( - e.to_string().contains("Expected a decimal integer"), - "bad description: {e}" - ); - } else { - panic!("parsing a bad ctime value should fail"); + match build_top_level_matcher(&["-ctime", "-123."], &mut config) { + Err(e) => { + assert!( + e.to_string().contains("Expected a decimal integer"), + "bad description: {e}" + ); + } + _ => { + panic!("parsing a bad ctime value should fail"); + } } } @@ -1827,46 +1866,69 @@ mod tests { fn build_top_level_exec_not_enough_args() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-exec"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and no executable or semi-colon should fail"); + match build_top_level_matcher(&["-exec"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!( + "parsing argument list with exec and no executable or semi-colon should fail" + ); + } } - if let Err(e) = build_top_level_matcher(&["-exec", ";"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and no executable should fail"); + match build_top_level_matcher(&["-exec", ";"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing argument list with exec and no executable should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-exec", "foo"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and no executable should fail"); + match build_top_level_matcher(&["-exec", "foo"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing argument list with exec and no executable should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-exec", "+"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and no executable should fail"); + match build_top_level_matcher(&["-exec", "+"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing argument list with exec and no executable should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-exec", "foo", "+"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and no brackets should fail"); + match build_top_level_matcher(&["-exec", "foo", "+"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing argument list with exec and no brackets should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-exec", "{}", "+"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and no executable should fail"); + match build_top_level_matcher(&["-exec", "{}", "+"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing argument list with exec and no executable should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-exec", "foo", "{}", "foo", "+"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing argument list with exec and + not following {{}} should fail"); + match build_top_level_matcher(&["-exec", "foo", "{}", "foo", "+"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing argument list with exec and + not following {{}} should fail"); + } } } @@ -1888,22 +1950,31 @@ mod tests { fn build_top_level_ok_not_enough_args() { // -ok follows the same validation rules as -exec for missing arguments. let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-ok"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing -ok with no executable or semicolon should fail"); + match build_top_level_matcher(&["-ok"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing -ok with no executable or semicolon should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-ok", ";"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing -ok with no executable should fail"); + match build_top_level_matcher(&["-ok", ";"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing -ok with no executable should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-ok", "foo"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("parsing -ok without terminating ';' should fail"); + match build_top_level_matcher(&["-ok", "foo"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("parsing -ok without terminating ';' should fail"); + } } } @@ -1948,12 +2019,13 @@ mod tests { #[test] fn build_top_level_multi_exec_too_many_holders() { let mut config = Config::default(); - if let Err(e) = - build_top_level_matcher(&["-exec", "foo", "{}", "foo", "{}", "+", ";"], &mut config) - { - assert!(e.to_string().contains("Only one instance of {}")); - } else { - panic!("parsing argument list with more than one {{}} for + should fail"); + match build_top_level_matcher(&["-exec", "foo", "{}", "foo", "{}", "+", ";"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("Only one instance of {}")); + } + _ => { + panic!("parsing argument list with more than one {{}} for + should fail"); + } } } @@ -1981,16 +2053,22 @@ mod tests { #[cfg(unix)] fn build_top_level_matcher_perm_bad() { let mut config = Config::default(); - if let Err(e) = build_top_level_matcher(&["-perm", "foo"], &mut config) { - assert_eq!(e.to_string(), "invalid mode 'foo'"); - } else { - panic!("-perm with bad mode pattern should fail"); + match build_top_level_matcher(&["-perm", "foo"], &mut config) { + Err(e) => { + assert_eq!(e.to_string(), "invalid mode 'foo'"); + } + _ => { + panic!("-perm with bad mode pattern should fail"); + } } - if let Err(e) = build_top_level_matcher(&["-perm"], &mut config) { - assert!(e.to_string().contains("missing argument")); - } else { - panic!("-perm with no mode pattern should fail"); + match build_top_level_matcher(&["-perm"], &mut config) { + Err(e) => { + assert!(e.to_string().contains("missing argument")); + } + _ => { + panic!("-perm with no mode pattern should fail"); + } } } diff --git a/src/find/matchers/perm.rs b/src/find/matchers/perm.rs index 93ba4471..0643eb11 100644 --- a/src/find/matchers/perm.rs +++ b/src/find/matchers/perm.rs @@ -9,7 +9,7 @@ //! even try. use std::error::Error; -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; #[cfg(unix)] use uucore::mode::{parse_numeric, parse_symbolic}; @@ -40,7 +40,7 @@ impl ComparisonType { #[cfg(unix)] mod parsing { - use super::{parse_numeric, parse_symbolic, ComparisonType}; + use super::{ComparisonType, parse_numeric, parse_symbolic}; pub fn split_comparison_type(pattern: &str) -> (ComparisonType, &str) { let mut chars = pattern.chars(); diff --git a/src/find/matchers/printer.rs b/src/find/matchers/printer.rs index 511f882c..14859acf 100644 --- a/src/find/matchers/printer.rs +++ b/src/find/matchers/printer.rs @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT. use std::fs::File; -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; use super::{Matcher, MatcherIO, StdoutErrors, WalkEntry}; @@ -95,8 +95,8 @@ impl Matcher for Printer { mod tests { use super::*; use crate::find::matchers::tests::get_dir_entry_for; - use crate::find::tests::fix_up_slashes; use crate::find::tests::FakeDependencies; + use crate::find::tests::fix_up_slashes; #[test] fn prints_newline() { diff --git a/src/find/matchers/printf.rs b/src/find/matchers/printf.rs index f0a5b7f6..f2943906 100644 --- a/src/find/matchers/printf.rs +++ b/src/find/matchers/printf.rs @@ -7,11 +7,11 @@ use std::borrow::Cow; use std::error::Error; use std::fs::{self, File}; -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; use std::path::{Path, PathBuf}; use std::time::SystemTime; -use chrono::{format::StrftimeItems, DateTime, Local}; +use chrono::{DateTime, Local, format::StrftimeItems}; use super::{FileType, Matcher, MatcherIO, StdoutErrors, WalkEntry, WalkError}; @@ -717,11 +717,11 @@ mod tests { use super::*; use crate::find::matchers::tests::get_dir_entry_for; - use crate::find::tests::fix_up_slashes; use crate::find::tests::FakeDependencies; + use crate::find::tests::fix_up_slashes; #[cfg(unix)] - use std::os::unix::fs::{symlink, PermissionsExt}; + use std::os::unix::fs::{PermissionsExt, symlink}; #[cfg(windows)] use std::os::windows::fs::{symlink_dir, symlink_file}; diff --git a/src/find/matchers/size.rs b/src/find/matchers/size.rs index af2909f7..01cd188e 100644 --- a/src/find/matchers/size.rs +++ b/src/find/matchers/size.rs @@ -5,7 +5,7 @@ // https://opensource.org/licenses/MIT. use std::error::Error; -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; use std::str::FromStr; use super::{ComparableValue, Matcher, MatcherIO, WalkEntry}; @@ -143,13 +143,16 @@ mod tests { #[test] fn size_matcher_bad_unit() { - if let Err(e) = SizeMatcher::new(ComparableValue::EqualTo(2), "xyz") { - assert!( - e.to_string().contains("Invalid suffix") && e.to_string().contains("xyz"), - "bad description: {e}" - ); - } else { - panic!("parsing a unit string should fail"); + match SizeMatcher::new(ComparableValue::EqualTo(2), "xyz") { + Err(e) => { + assert!( + e.to_string().contains("Invalid suffix") && e.to_string().contains("xyz"), + "bad description: {e}" + ); + } + _ => { + panic!("parsing a unit string should fail"); + } } } diff --git a/src/find/matchers/time.rs b/src/find/matchers/time.rs index e440d22b..4b58d75a 100644 --- a/src/find/matchers/time.rs +++ b/src/find/matchers/time.rs @@ -6,7 +6,7 @@ use std::error::Error; use std::fs::{self, Metadata}; -use std::io::{stderr, Write}; +use std::io::{Write, stderr}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use chrono::{DateTime, Local, Timelike}; diff --git a/src/find/matchers/type_matcher.rs b/src/find/matchers/type_matcher.rs index 46a68966..52c72a71 100644 --- a/src/find/matchers/type_matcher.rs +++ b/src/find/matchers/type_matcher.rs @@ -26,7 +26,9 @@ fn parse(type_string: &str, mode: &str) -> Result> { "D" => { #[cfg(not(target_os = "solaris"))] { - return Err(From::from(format!("{mode} D is not supported because Solaris doors are not supported on the platform find was compiled on."))); + return Err(From::from(format!( + "{mode} D is not supported because Solaris doors are not supported on the platform find was compiled on." + ))); } #[cfg(target_os = "solaris")] { @@ -38,12 +40,12 @@ fn parse(type_string: &str, mode: &str) -> Result> { "" => { return Err(From::from(format!( "Arguments to {mode} should contain at least one letter" - ))) + ))); } _ => { return Err(From::from(format!( "Unrecognised type argument {type_string}" - ))) + ))); } }; Ok(file_type) @@ -107,7 +109,9 @@ fn type_creator(type_string: &str, mode: &str) -> Result, Box< if type_string.contains(',') { for part in type_string.split(',') { if part.is_empty() { - return Err(From::from(format!("Last file type in list argument to {mode} is missing, i.e., list is ending on: ','"))); + return Err(From::from(format!( + "Last file type in list argument to {mode} is missing, i.e., list is ending on: ','" + ))); } let file_type = parse(part, mode)?; if !file_types.insert(file_type) { diff --git a/src/find/matchers/user.rs b/src/find/matchers/user.rs index 92ce2216..fabc041d 100644 --- a/src/find/matchers/user.rs +++ b/src/find/matchers/user.rs @@ -91,7 +91,7 @@ mod tests { #[test] #[cfg(unix)] fn test_user_matcher() { - use crate::find::matchers::{tests::get_dir_entry_for, user::UserMatcher, Matcher}; + use crate::find::matchers::{Matcher, tests::get_dir_entry_for, user::UserMatcher}; use crate::find::tests::FakeDependencies; use chrono::Local; use nix::unistd::{Uid, User}; diff --git a/src/find/mod.rs b/src/find/mod.rs index c68e4133..4b0e35e5 100644 --- a/src/find/mod.rs +++ b/src/find/mod.rs @@ -13,7 +13,7 @@ use std::cell::RefCell; use std::error::Error; #[cfg(unix)] use std::io::IsTerminal; -use std::io::{self, stderr, stdout, BufRead, BufReader, Write}; +use std::io::{self, BufRead, BufReader, Write, stderr, stdout}; use std::path::PathBuf; use std::rc::Rc; use std::time::SystemTime; @@ -511,10 +511,9 @@ pub fn program_name() -> &'static str { && path .extension() .is_some_and(|ext| ext.eq_ignore_ascii_case("exe")) + && let Some(stem) = path.file_stem().and_then(std::ffi::OsStr::to_str) { - if let Some(stem) = path.file_stem().and_then(std::ffi::OsStr::to_str) { - return stem; - } + return stem; } name } @@ -558,8 +557,8 @@ mod tests { #[cfg(windows)] use std::os::windows::fs::symlink_file; - use crate::find::matchers::time::ChangeTime; use crate::find::matchers::MatcherIO; + use crate::find::matchers::time::ChangeTime; use super::*; @@ -1304,9 +1303,10 @@ mod tests { let rc = find_main(&["find", "./test_data/simple/subdir", arg, time], &deps); assert_eq!(rc, 0); - assert!(deps - .get_output_as_string() - .contains("./test_data/simple/subdir")); + assert!( + deps.get_output_as_string() + .contains("./test_data/simple/subdir") + ); assert!(deps.get_output_as_string().contains("ABBBC")); } } diff --git a/src/locate/mod.rs b/src/locate/mod.rs index 17c0e566..baab281c 100644 --- a/src/locate/mod.rs +++ b/src/locate/mod.rs @@ -7,13 +7,13 @@ use std::{ env, ffi::{CStr, CString}, fs::{self, File}, - io::{self, stderr, BufRead, BufReader, Read, Write}, + io::{self, BufRead, BufReader, Read, Write, stderr}, path::{Path, PathBuf}, str::FromStr, }; use chrono::{DateTime, Local, TimeDelta}; -use clap::{self, crate_version, value_parser, Arg, ArgAction, ArgMatches, Command, Id}; +use clap::{self, Arg, ArgAction, ArgMatches, Command, Id, crate_version, value_parser}; use itertools::Itertools; use onig::{Regex, RegexOptions, Syntax}; use thiserror::Error; @@ -614,20 +614,20 @@ fn do_locate(args: &[&str]) -> LocateResult<()> { .filter_map(|p| DbReader::new(p.as_path()).ok()) { // if we can get the mtime of the file, check it against the current time - if let Ok(metadata) = fs::metadata(&dbreader.path) { - if let Ok(time) = metadata.modified() { - let modified: DateTime = time.into(); - let now = Local::now(); - let delta = now - modified; - if is_db_too_old(delta, config.max_age) { - eprintln!( - "{}: warning: database ‘{}’ is more than {} days old (actual age is {:.1} days)", - args[0], - dbreader.path.to_string_lossy(), - config.max_age, - delta.num_seconds() as f64 / (60 * 60 * 24) as f64 - ); - } + if let Ok(metadata) = fs::metadata(&dbreader.path) + && let Ok(time) = metadata.modified() + { + let modified: DateTime = time.into(); + let now = Local::now(); + let delta = now - modified; + if is_db_too_old(delta, config.max_age) { + eprintln!( + "{}: warning: database ‘{}’ is more than {} days old (actual age is {:.1} days)", + args[0], + dbreader.path.to_string_lossy(), + config.max_age, + delta.num_seconds() as f64 / (60 * 60 * 24) as f64 + ); } } @@ -705,7 +705,7 @@ mod tests { use chrono::TimeDelta; - use super::{is_db_too_old, path_exists, DbReader, Statistics}; + use super::{DbReader, Statistics, is_db_too_old, path_exists}; /// A writer that always fails, to emulate stdout with no space left /// (`> /dev/full`) or a closed pipe. diff --git a/src/testing/commandline/main.rs b/src/testing/commandline/main.rs index 428e42f9..2a3836f3 100644 --- a/src/testing/commandline/main.rs +++ b/src/testing/commandline/main.rs @@ -6,7 +6,7 @@ use std::env; use std::fs::{self, File, OpenOptions}; -use std::io::{stdin, stdout, Read, Write}; +use std::io::{Read, Write, stdin, stdout}; use std::path::PathBuf; fn usage() -> ! { diff --git a/src/updatedb/mod.rs b/src/updatedb/mod.rs index 6568cff1..54fff284 100644 --- a/src/updatedb/mod.rs +++ b/src/updatedb/mod.rs @@ -6,17 +6,17 @@ use std::{ cell::RefCell, fmt::Display, fs::OpenOptions, - io::{stderr, BufRead, BufReader, BufWriter, Write}, + io::{BufRead, BufReader, BufWriter, Write, stderr}, path::PathBuf, rc::Rc, str::FromStr, time::SystemTime, }; -use clap::{crate_version, value_parser, Arg, ArgAction, ArgMatches, Command}; -use uucore::error::{strip_errno, UResult, USimpleError}; +use clap::{Arg, ArgAction, ArgMatches, Command, crate_version, value_parser}; +use uucore::error::{UResult, USimpleError, strip_errno}; -use crate::find::{find_main, Dependencies}; +use crate::find::{Dependencies, find_main}; pub use crate::locate::DEFAULT_DB_PATH; diff --git a/src/xargs/mod.rs b/src/xargs/mod.rs index 5b67446b..56619933 100644 --- a/src/xargs/mod.rs +++ b/src/xargs/mod.rs @@ -14,7 +14,7 @@ use std::{ process::{Command, Stdio}, }; -use clap::{crate_version, error::ErrorKind, Arg, ArgAction}; +use clap::{Arg, ArgAction, crate_version, error::ErrorKind}; use uucore::error::strip_errno; mod options { @@ -927,43 +927,46 @@ fn validate_positive_usize(s: &str) -> Result { } fn normalize_options(options: Options, matches: &clap::ArgMatches) -> Options { - let (max_args, max_lines, replace) = - match (options.max_args, options.max_lines, &options.replace) { - // These 3 options are mutually exclusive. - // But `max_args=1` and `replace` do not actually conflict, so no warning. - (None | Some(1), None, Some(_)) => { - // If `replace`, all matches in initial args should be replaced with extra args read from stdin. - // It is possible to have multiple matches and multiple extra args, and the Cartesian product is desired. - // To be specific, we process extra args one by one, and replace all matches with the same extra arg in each time. - (Some(1), None, options.replace) - } - (Some(_), None, None) | (None, Some(_), None) | (None, None, None) => { - (options.max_args, options.max_lines, None) - } - _ => { - eprintln!( + let (max_args, max_lines, replace) = match ( + options.max_args, + options.max_lines, + &options.replace, + ) { + // These 3 options are mutually exclusive. + // But `max_args=1` and `replace` do not actually conflict, so no warning. + (None | Some(1), None, Some(_)) => { + // If `replace`, all matches in initial args should be replaced with extra args read from stdin. + // It is possible to have multiple matches and multiple extra args, and the Cartesian product is desired. + // To be specific, we process extra args one by one, and replace all matches with the same extra arg in each time. + (Some(1), None, options.replace) + } + (Some(_), None, None) | (None, Some(_), None) | (None, None, None) => { + (options.max_args, options.max_lines, None) + } + _ => { + eprintln!( "WARNING: -L, -n and -I/-i are mutually exclusive, but more than one were given; \ only the last option will be used" ); - let lines_index = matches - .indices_of(options::MAX_LINES) - .and_then(|mut v| v.next_back()); - let args_index = matches - .indices_of(options::MAX_ARGS) - .and_then(|mut v| v.next_back()); - let replace_index = [options::REPLACE, options::REPLACE_I] - .iter() - .flat_map(|o| matches.indices_of(o).and_then(|mut v| v.next_back())) - .max(); - if lines_index > args_index && lines_index > replace_index { - (None, options.max_lines, None) - } else if args_index > lines_index && args_index > replace_index { - (options.max_args, None, None) - } else { - (Some(1), None, options.replace) - } + let lines_index = matches + .indices_of(options::MAX_LINES) + .and_then(|mut v| v.next_back()); + let args_index = matches + .indices_of(options::MAX_ARGS) + .and_then(|mut v| v.next_back()); + let replace_index = [options::REPLACE, options::REPLACE_I] + .iter() + .flat_map(|o| matches.indices_of(o).and_then(|mut v| v.next_back())) + .max(); + if lines_index > args_index && lines_index > replace_index { + (None, options.max_lines, None) + } else if args_index > lines_index && args_index > replace_index { + (options.max_args, None, None) + } else { + (Some(1), None, options.replace) } - }; + } + }; let delimiter = match (options.delimiter, options.null) { (Some(delimiter), true) => { @@ -1389,12 +1392,16 @@ mod tests { let max_chars = count_osstr_chars_for_exec(OsStr::new("abc")) + count_osstr_chars_for_exec(OsStr::new("a")); let mut limiter = MaxCharsCommandSizeLimiter::new(max_chars); - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_hard("abcd"), empty_cursor()) - .is_err()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_hard("abcd"), empty_cursor()) + .is_err() + ); assert!(limiter.try_arg(make_arg_hard("a"), empty_cursor()).is_ok()); } @@ -1402,12 +1409,16 @@ mod tests { #[test] fn test_chars_limiter_windows() { let mut limiter = MaxCharsCommandSizeLimiter::new(6); - assert!(limiter - .try_arg(make_arg_hard("abcde"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_hard("ab de"), empty_cursor()) - .is_err()); + assert!( + limiter + .try_arg(make_arg_hard("abcde"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_hard("ab de"), empty_cursor()) + .is_err() + ); } #[test] @@ -1429,13 +1440,17 @@ mod tests { let mut limiter = MaxCharsCommandSizeLimiter::new(count_osstr_chars_for_exec(OsStr::new("abc"))); - assert!(limiter - .try_arg(make_arg_hard("abc"), reject_cursor) - .is_err()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), reject_cursor) + .is_err() + ); // Ensure the limiter didn't update before trying the cursor. - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); } #[test] @@ -1443,19 +1458,27 @@ mod tests { let mut limiter = MaxArgsCommandSizeLimiter::new(2); // Should not count initial arguments. for _ in 1..3 { - assert!(limiter - .try_arg(make_arg_init("abc"), empty_cursor()) - .is_ok()); + assert!( + limiter + .try_arg(make_arg_init("abc"), empty_cursor()) + .is_ok() + ); } - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_err()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_err() + ); } #[test] @@ -1466,42 +1489,62 @@ mod tests { }; let mut limiter = MaxArgsCommandSizeLimiter::new(1); - assert!(limiter - .try_arg(make_arg_hard("abc"), reject_cursor) - .is_err()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), reject_cursor) + .is_err() + ); // Ensure the limiter didn't update before trying the cursor. - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); } #[test] fn test_lines_limiter() { let mut limiter = MaxLinesCommandSizeLimiter::new(2); - assert!(limiter - .try_arg(make_arg_soft("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_soft("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_soft("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_soft("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); - assert!(limiter - .try_arg(make_arg_soft("abc"), empty_cursor()) - .is_err()); - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_err()); + assert!( + limiter + .try_arg(make_arg_soft("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_soft("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_soft("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_soft("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); + assert!( + limiter + .try_arg(make_arg_soft("abc"), empty_cursor()) + .is_err() + ); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_err() + ); } #[test] @@ -1512,13 +1555,17 @@ mod tests { }; let mut limiter = MaxLinesCommandSizeLimiter::new(1); - assert!(limiter - .try_arg(make_arg_hard("abc"), reject_cursor) - .is_err()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), reject_cursor) + .is_err() + ); // Ensure the limiter didn't update before trying the cursor. - assert!(limiter - .try_arg(make_arg_hard("abc"), empty_cursor()) - .is_ok()); + assert!( + limiter + .try_arg(make_arg_hard("abc"), empty_cursor()) + .is_ok() + ); } #[test] diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 3b70eaff..b58a279d 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -12,7 +12,7 @@ pub mod test_helpers; // Set UUTESTS_BINARY_PATH before any tests run. The value is only used by // TestScenario::new() to satisfy its internal setup; tests that need a // specific binary pass it explicitly via TestScenario::cmd(BINARY_PATH). -#[ctor::ctor(unsafe)] -fn init() { - std::env::set_var("UUTESTS_BINARY_PATH", env!("CARGO_BIN_EXE_find")); +#[ctor::ctor] +unsafe fn init() { + unsafe { std::env::set_var("UUTESTS_BINARY_PATH", env!("CARGO_BIN_EXE_find")) }; } diff --git a/tests/common/test_helpers.rs b/tests/common/test_helpers.rs index a1cf9d8c..7a6d6468 100644 --- a/tests/common/test_helpers.rs +++ b/tests/common/test_helpers.rs @@ -11,8 +11,8 @@ use std::io::{Cursor, Read, Write}; use std::path::Path; use std::time::SystemTime; -use findutils::find::matchers::{Follow, MatcherIO, WalkEntry}; use findutils::find::Dependencies; +use findutils::find::matchers::{Follow, MatcherIO, WalkEntry}; /// A copy of `find::tests::FakeDependencies`. /// TODO: find out how to share #[cfg(test)] functions/structs between unit diff --git a/tests/exec_unit_tests.rs b/tests/exec_unit_tests.rs index e37ad2a6..1cf0448e 100644 --- a/tests/exec_unit_tests.rs +++ b/tests/exec_unit_tests.rs @@ -15,7 +15,7 @@ use std::path::Path; use tempfile::Builder; use common::test_helpers::{ - fix_up_slashes, get_dir_entry_for, path_to_testing_commandline, FakeDependencies, + FakeDependencies, fix_up_slashes, get_dir_entry_for, path_to_testing_commandline, }; use findutils::find::matchers::exec::{MultiExecMatcher, SingleExecMatcher}; use findutils::find::matchers::{Matcher, MatcherIO}; diff --git a/tests/find_exec_tests.rs b/tests/find_exec_tests.rs index 7b2b9f51..1cddf7d0 100644 --- a/tests/find_exec_tests.rs +++ b/tests/find_exec_tests.rs @@ -14,7 +14,7 @@ use std::fs::File; use std::io::Read; use tempfile::Builder; -use common::test_helpers::{fix_up_slashes, path_to_testing_commandline, FakeDependencies}; +use common::test_helpers::{FakeDependencies, fix_up_slashes, path_to_testing_commandline}; use findutils::find::find_main; mod common; diff --git a/tests/test_find.rs b/tests/test_find.rs index efe25b77..d4d6c3ac 100644 --- a/tests/test_find.rs +++ b/tests/test_find.rs @@ -1624,7 +1624,7 @@ fn find_ls_shows_allocated_blocks_and_link_target() { #[test] #[cfg(unix)] fn find_ls_unmapped_owner_renders_numeric_id() { - use nix::unistd::{chown, Gid, Uid}; + use nix::unistd::{Gid, Uid, chown}; let temp_dir = Builder::new().prefix("find_ls_unmapped").tempdir().unwrap(); let file = temp_dir.path().join("orphan");