From 02b5edae05682c329f626a4f8ad5537870bfa817 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 18 Jul 2024 20:43:39 -0600 Subject: [PATCH] fileis(1): feature parity with C scrut(1) --- src/fileis.rs | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/fileis.rs b/src/fileis.rs index 70f62f6..9ad651e 100644 --- a/src/fileis.rs +++ b/src/fileis.rs @@ -19,6 +19,7 @@ use std::{ env::args, fs::metadata, + os::unix::fs::{ FileTypeExt, MetadataExt }, process::ExitCode, }; @@ -36,11 +37,11 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); - let mut sel: String; // selected options + let mut sel = String::from(""); // selected options let mut optind: usize = 1; // argv[0] while let Some(opt) = argv.getopt("bcdefgkprsuwxLS") { - if let Ok(optchr) = opt.opt() { sel.push(optchr); } + if let Ok(optchr) = opt.opt() { sel.push_str(optchr); } else { return usage(&argv[0]); } optind = opt.ind(); @@ -49,32 +50,38 @@ fn main() -> ExitCode { if optind == argv.len() { return usage(&argv[0]); } for arg in argv.iter().skip(optind) { - } + let fmeta; // file metadata + let fmode; // file mode; see chmod(1p) + let ftype; // file type -// do{ -// if (!fileis_exists(*argv)) -// return EXIT_FAILURE; -// -// for (size_t i = 0; sel[i] != '\0'; ++i) { -// if ((sel[i] == 'b' && !fileis_block(*argv)) -// || (sel[i] == 'c' && !fileis_char(*argv)) -// || (sel[i] == 'd' && !fileis_dir(*argv)) -// || (sel[i] != 'e') -// || (sel[i] == 'f' && !fileis_regular(*argv)) -// || (sel[i] == 'g' && !fileis_setgid(*argv)) -// || (sel[i] == 'k' && !fileis_vtx(*argv)) -// || (sel[i] == 'p' && !fileis_fifo(*argv)) -// || (sel[i] == 'r' && access(*argv, R_OK) != 0) -// || (sel[i] == 'u' && !fileis_setuid(*argv)) -// || (sel[i] == 'w' && access(*argv, W_OK) != 0) -// || (sel[i] == 'x' && access(*argv, X_OK) != 0) -// || (sel[i] == 'L' && !fileis_link(*argv)) -// || (sel[i] == 'S' && !fileis_socket(*argv)) -// ) { return EXIT_FAILURE; } -// } -// } while (*++argv != NULL); -// -// return EXIT_SUCCESS; + match metadata(arg) { + Ok(m) => fmeta = m, + _ => { return ExitCode::FAILURE; } // no perms or nonexistent + } + + fmode = fmeta.mode(); + ftype = fmeta.file_type(); + + for selection in sel.chars() { // run all selected tests + match selection { + 'b' if ftype.is_block_device() => (), + 'c' if ftype.is_char_device() => (), + 'e' => (), // exists or metadata would have errored + 'd' if fmeta.is_dir() => (), + 'f' if fmeta.is_file() => (), + 'g' if fmode & 0o2000 /* S_ISGID */ != 0 => (), // setgid + 'k' if fmode & 0o1000 /* S_ISVTX */ != 0 => (), // setvtx + 'p' if ftype.is_fifo() => (), + 'r' if fmode & 0o0400 /* S_IRUSR */ != 0 => (), // read access + 'u' if fmode & 0o4000 /* S_ISUID */ != 0 => (), // setuid + 'w' if fmode & 0o0200 /* S_IWUSR */ != 0 => (), // write access + 'x' if fmode & 0o0100 /* S_IXUSR */ != 0 => (), // exec access + 'L' if fmeta.is_symlink() => (), + 'S' if ftype.is_socket() => (), + _ => { return ExitCode::FAILURE; } + } + } + } ExitCode::SUCCESS }