From d62163e54b129f639ef661ca02820501bfd0e6e4 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Wed, 2 Apr 2025 14:16:29 +0530 Subject: [PATCH 01/15] Implemented namei command --- Cargo.lock | 9 + Cargo.toml | 4 +- src/uu/namei/Cargo.toml | 15 ++ src/uu/namei/namei.md | 7 + src/uu/namei/src/main.rs | 1 + src/uu/namei/src/namei.rs | 414 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 src/uu/namei/Cargo.toml create mode 100644 src/uu/namei/namei.md create mode 100644 src/uu/namei/src/main.rs create mode 100644 src/uu/namei/src/namei.rs diff --git a/Cargo.lock b/Cargo.lock index 6b715314..04e06d7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1142,6 +1142,7 @@ dependencies = [ "uu_mcookie", "uu_mesg", "uu_mountpoint", + "uu_namei", "uu_renice", "uu_rev", "uu_setsid", @@ -1283,6 +1284,14 @@ dependencies = [ "uucore", ] +[[package]] +name = "uu_namei" +version = "0.0.1" +dependencies = [ + "clap", + "uucore", +] + [[package]] name = "uu_renice" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index 3798c367..cba88077 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ feat_common_core = [ "renice", "rev", "setsid", + "namei", ] [workspace.dependencies] @@ -67,7 +68,7 @@ sysinfo = "0.34" tempfile = "3.9.0" textwrap = { version = "0.16.0", features = ["terminal_size"] } thiserror = "2.0" -uucore = "0.0.30" +uucore = { version = "0.0.30", features = ["entries"] } xattr = "1.3.1" [dependencies] @@ -98,6 +99,7 @@ mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", pa renice = { optional = true, version = "0.0.1", package = "uu_renice", path = "src/uu/renice" } rev = { optional = true, version = "0.0.1", package = "uu_rev", path = "src/uu/rev" } setsid = { optional = true, version = "0.0.1", package = "uu_setsid", path ="src/uu/setsid" } +namei = { optional = true, version = "0.0.1", package = "uu_namei", path ="src/uu/namei" } [dev-dependencies] # dmesg test require fixed-boot-time feature turned on. diff --git a/src/uu/namei/Cargo.toml b/src/uu/namei/Cargo.toml new file mode 100644 index 00000000..351086d4 --- /dev/null +++ b/src/uu/namei/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "uu_namei" +version = "0.0.1" +edition = "2021" + +[dependencies] +uucore = { workspace = true } +clap = { workspace = true } + +[lib] +path = "src/namei.rs" + +[[bin]] +name = "namei" +path = "src/main.rs" diff --git a/src/uu/namei/namei.md b/src/uu/namei/namei.md new file mode 100644 index 00000000..44e8dd3c --- /dev/null +++ b/src/uu/namei/namei.md @@ -0,0 +1,7 @@ +# namei + +``` +namei [options] ... +``` + +Follow a pathname until a terminal point is found. \ No newline at end of file diff --git a/src/uu/namei/src/main.rs b/src/uu/namei/src/main.rs new file mode 100644 index 00000000..ab7b609a --- /dev/null +++ b/src/uu/namei/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_namei); \ No newline at end of file diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs new file mode 100644 index 00000000..94051ace --- /dev/null +++ b/src/uu/namei/src/namei.rs @@ -0,0 +1,414 @@ +// This file is part of the uutils util-linux package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use clap::{crate_version, Arg, ArgAction, Command}; +use std::env; +use std::str::FromStr; +use std::{cmp::max, fs, os::unix::fs::MetadataExt, path::Path}; +use uucore::entries::{gid2grp, uid2usr}; +use uucore::{error::UResult, format_usage, help_about, help_usage}; + +const ABOUT: &str = help_about!("namei.md"); +const USAGE: &str = help_usage!("namei.md"); + +const MAXSYMLINKS: usize = 256; + +mod options { + pub const LONG: &str = "long"; + pub const MODES: &str = "modes"; + pub const NOSYMLINKS: &str = "nosymlinks"; + pub const OWNERS: &str = "owners"; + pub const VERTICAL: &str = "vertical"; + pub const MOUNTPOINTS: &str = "mountpoints"; + pub const CONTEXT: &str = "context"; + pub const PATHNAMES: &str = "pathnames"; +} + +struct OutputOptions { + long: bool, + modes: bool, + nosymlinks: bool, + owners: bool, + vertical: bool, + mountpoints: bool, + context: bool, +} + +pub fn uu_app() -> Command { + Command::new(uucore::util_name()) + .version(crate_version!()) + .about(ABOUT) + .override_usage(format_usage(USAGE)) + .arg( + Arg::new(options::PATHNAMES) + .value_name("PATH") + .help("Paths to follow") + .hide(true) + .index(1) + .action(ArgAction::Set) + .required(true) + .num_args(1..), + ) + .arg( + Arg::new(options::LONG) + .short('l') + .long("long") + .help("use a long listing format (-m -o -v)") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new(options::MODES) + .short('m') + .long("modes") + .help("show the mode bits of each file") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new(options::NOSYMLINKS) + .short('n') + .long("nosymlinks") + .help("don't follow symlinks") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new(options::OWNERS) + .short('o') + .long("owners") + .help("show owner and group name of each file") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new(options::VERTICAL) + .short('v') + .long("vertical") + .help("vertical align of modes and owners") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new(options::MOUNTPOINTS) + .short('x') + .long("mountpoints") + .help("show mount point directories with a 'D'") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new(options::CONTEXT) + .short('Z') + .long("context") + .help("print any security context of each file") + .action(ArgAction::SetTrue), + ) +} + +fn max_owner_length(path: &Path) -> usize { + let mut max_length = 0; + + for entry in path.ancestors() { + if let Err(_e) = entry.metadata() { + continue; + } + let metadata = entry.metadata().unwrap(); + let uid = metadata.uid(); + + let owner = uid2usr(uid).unwrap(); + let max_entry_length = owner.len(); + max_length = max(max_entry_length, max_length); + } + + return max_length; +} + +fn max_group_length(path: &Path) -> usize { + let mut max_length = 0; + + for entry in path.ancestors() { + if let Err(_e) = entry.metadata() { + continue; + } + let metadata = entry.metadata().unwrap(); + let gid = metadata.gid(); + + let group = gid2grp(gid).unwrap(); + let max_entry_length = group.len(); + max_length = max(max_entry_length, max_length); + } + + return max_length; +} + +fn get_file_name(input: &str) -> &str { + let stripped = input.trim_end_matches('/'); + if stripped.is_empty() { + return "/"; + } + stripped.rsplit('/').next().unwrap_or("/") +} + +fn is_mount_point(input_path: &Path) -> bool { + let canonical_path = input_path.canonicalize().unwrap().into_os_string(); + let path = Path::new(&canonical_path); + if let Some(parent) = path.parent() { + let metadata = fs::metadata(path).unwrap(); + if let Err(_e) = fs::metadata(parent) { + return false; + } + let parent_metadata = fs::metadata(parent).unwrap(); + return metadata.dev() != parent_metadata.dev(); + } else { + return true; + } +} + +fn get_prefix( + level: usize, + path: &Path, + output_opts: &OutputOptions, + maximum_owner_length: usize, + maximum_group_length: usize, +) -> String { + let mut prefix = String::new(); + + if !output_opts.vertical { + let mut st = String::from(" "); + st.push_str(&" ".repeat(level * 2)); + prefix.push_str(&st); + } + + if let Err(_e) = fs::metadata(path) { + let mut blanks = 1 + level * 2; + if output_opts.modes { + blanks += 9; + } + if output_opts.owners { + blanks += maximum_owner_length + maximum_group_length + 2; + } + if output_opts.vertical { + blanks += 1; + } + if !output_opts.context { + blanks += 1; + } + prefix = " ".repeat(blanks); + return prefix; + } + + let metadata = fs::metadata(path).unwrap(); + + let mode = metadata.mode(); + + let file_type = match mode & 0o170000 { + 0o100000 => '-', // Regular file + 0o040000 if output_opts.mountpoints && is_mount_point(path) => 'D', // Directory + 0o040000 => 'd', // Directory + 0o120000 => 'l', // Symbolic link + 0o020000 => 'c', // Character device + 0o060000 => 'b', // Block device + 0o010000 => 'p', // FIFO + 0o140000 => 's', // Socket + _ => '?', // Unknown + }; + + if path.is_symlink() { + prefix.push('l'); + } else { + prefix.push(file_type); + } + + if output_opts.modes || output_opts.long { + let permissions = [ + (mode & 0o400, 'r'), + (mode & 0o200, 'w'), + (mode & 0o100, 'x'), // Owner + (mode & 0o040, 'r'), + (mode & 0o020, 'w'), + (mode & 0o010, 'x'), // Group + (mode & 0o004, 'r'), + (mode & 0o002, 'w'), + (mode & 0o001, 'x'), // Others + ]; + let mut perm_string = String::new(); + for &(bit, ch) in &permissions { + perm_string.push(if bit != 0 { ch } else { '-' }); + } + if mode & 0o4000 != 0 { + // Set UID + perm_string.replace_range( + 2..3, + if perm_string.chars().nth(3) == Some('x') { + "s" + } else { + "S" + }, + ); + } + if mode & 0o2000 != 0 { + // Set GID + perm_string.replace_range( + 5..6, + if perm_string.chars().nth(6) == Some('x') { + "s" + } else { + "S" + }, + ); + } + if mode & 0o1000 != 0 { + // Sticky Bit + perm_string.replace_range( + 8..9, + if perm_string.chars().nth(9) == Some('x') { + "t" + } else { + "T" + }, + ); + } + + prefix.push_str(&perm_string); + } + prefix.push_str(" "); + + if output_opts.owners { + let uid = metadata.uid(); + let gid = metadata.gid(); + let mut owner = uid2usr(uid).unwrap(); + let str1 = " ".repeat(maximum_owner_length - owner.len() + 1); + owner = format!("{}{}", owner, str1); + let mut group = gid2grp(gid).unwrap(); + let str2 = " ".repeat(maximum_group_length - group.len() + 1); + group = format!("{}{}", group, str2); + + prefix = format!("{}{}{}", prefix, owner, group); + } + + if output_opts.vertical { + let mut st = String::new(); + st.push_str(&" ".repeat(level * 2)); + prefix.push_str(&st); + } + + return prefix; +} + +fn print_files( + level: usize, + path: &Path, + output_opts: &OutputOptions, + maximum_owner_length: usize, + maximum_group_length: usize, +) { + if let Some(pt) = path.parent() { + print_files( + level, + pt, + output_opts, + maximum_owner_length, + maximum_group_length, + ); + } + + let prefix = get_prefix( + level, + path, + output_opts, + maximum_owner_length, + maximum_group_length, + ); + + let symlinksuffix = if path.is_symlink() { + let mut suffix = String::from_str(" -> ").unwrap(); + let target = fs::read_link(path).unwrap(); + suffix.push_str(target.to_str().unwrap()); + suffix + } else { + String::new() + }; + + match fs::metadata(path) { + Err(e) => println!( + "{}{} - {}", + prefix, + get_file_name(path.to_str().unwrap()), + e + ), + _ => println!( + "{}{}{}", + prefix, + get_file_name(path.to_str().unwrap()), + symlinksuffix + ), + } + + if !output_opts.nosymlinks && path.is_symlink() && level < MAXSYMLINKS - 1 { + let target_pathbuf = fs::read_link(path).unwrap(); + if target_pathbuf.is_relative() { + let target_pathrel = Path::new(target_pathbuf.to_str().unwrap()); + let symlink_dir = path.parent().unwrap(); + let joindir = symlink_dir.join(target_pathrel); + let target_path = joindir.as_path(); + print_files( + level + 1, + target_path, + &output_opts, + maximum_owner_length, + maximum_group_length, + ); + } else { + let osstr = fs::read_link(path).unwrap().into_os_string(); + print_files( + level + 1, + Path::new(&osstr), + &output_opts, + maximum_owner_length, + maximum_group_length, + ); + } + } +} + +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; + + let pathlist = matches.get_many::(options::PATHNAMES); + + let output_opts = OutputOptions { + long: matches.get_flag(options::LONG), + modes: matches.get_flag(options::MODES) || matches.get_flag(options::LONG), + nosymlinks: matches.get_flag(options::NOSYMLINKS), + owners: matches.get_flag(options::OWNERS) || matches.get_flag(options::LONG), + vertical: matches.get_flag(options::VERTICAL) || matches.get_flag(options::LONG), + mountpoints: matches.get_flag(options::MOUNTPOINTS), + context: matches.get_flag(options::CONTEXT), + }; + + if let Some(paths) = pathlist { + for path_str in paths { + let path = Path::new(path_str); + println!("f: {}", path.to_str().unwrap()); + let maximum_owner_length = if output_opts.owners { + max_owner_length(path) + } else { + 0 + }; + let maximum_group_length = if output_opts.owners { + max_group_length(path) + } else { + 0 + }; + print_files( + 0, + path, + &output_opts, + maximum_owner_length, + maximum_group_length, + ); + } + } else { + // Handle the case where path is not provided + } + + Ok(()) +} From 8e47a48fe098820f0d38d7769018e1afeba01495 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury <54467781+cdebanil@users.noreply.github.com> Date: Wed, 2 Apr 2025 16:02:49 +0530 Subject: [PATCH 02/15] Update namei.rs Removed two unnecessary lines --- src/uu/namei/src/namei.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 94051ace..dc0f1c45 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -406,9 +406,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { maximum_group_length, ); } - } else { - // Handle the case where path is not provided } + // Handling the case where path is not provided is not necessary + // because in path arguments have been made necessary in clap so + // it will automatically show an error in stdout Ok(()) } From 8b5fbb55d991497c2f4dc7dab8b38c81077a0013 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Thu, 3 Apr 2025 20:38:44 +0530 Subject: [PATCH 03/15] added selinux support --- Cargo.lock | 313 ++++++++++++++++++++++++++++++++------ src/uu/namei/Cargo.toml | 4 + src/uu/namei/src/main.rs | 2 +- src/uu/namei/src/namei.rs | 71 ++++++--- 4 files changed, 328 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04e06d7b..38410f73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,19 +76,53 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "bindgen" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "clap 3.2.25", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "which", +] + [[package]] name = "bindgen" version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cexpr", "clang-sys", "itertools", @@ -97,11 +131,17 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 2.1.1", "shlex", "syn", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.0" @@ -199,6 +239,21 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "strsim 0.10.0", + "termcolor", + "textwrap", +] + [[package]] name = "clap" version = "4.5.35" @@ -216,8 +271,8 @@ checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" dependencies = [ "anstream", "anstyle", - "clap_lex", - "strsim", + "clap_lex 0.7.4", + "strsim 0.11.1", "terminal_size", ] @@ -227,7 +282,16 @@ version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" dependencies = [ - "clap", + "clap 4.5.35", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", ] [[package]] @@ -242,7 +306,7 @@ version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "724842fa9b144f9b89b3f3d371a89f3455eea660361d13a554f68f8ae5d6c13a" dependencies = [ - "clap", + "clap 4.5.35", "roff", ] @@ -317,6 +381,19 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -330,7 +407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -367,18 +444,48 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + [[package]] name = "iana-time-zone" version = "0.1.62" @@ -403,6 +510,16 @@ dependencies = [ "cc", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.8.0" @@ -410,7 +527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -444,6 +561,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.171" @@ -457,7 +586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -506,7 +635,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cfg-if", "cfg_aliases", "libc", @@ -576,7 +705,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" dependencies = [ - "bitflags", + "bitflags 2.9.0", ] [[package]] @@ -594,6 +723,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "parse-zoneinfo" version = "0.3.1" @@ -614,6 +749,12 @@ dependencies = [ "regex", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "phf" version = "0.11.3" @@ -702,7 +843,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags", + "bitflags 2.9.0", "hex", "procfs-core", "rustix 0.38.44", @@ -714,7 +855,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags", + "bitflags 2.9.0", "hex", ] @@ -784,6 +925,12 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +[[package]] +name = "reference-counted-singleton" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5daffa8f5ca827e146485577fa9dba9bd9c6921e06e954ab8f6408c10f753086" + [[package]] name = "regex" version = "1.11.1" @@ -828,6 +975,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -840,11 +993,11 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -853,11 +1006,11 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ - "bitflags", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys 0.9.3", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -881,6 +1034,32 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "selinux" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd525eeb189eb26c8471463186bba87644e3d8a9c7ae392adaf9ec45ede574bc" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "reference-counted-singleton", + "selinux-sys", + "thiserror 1.0.69", +] + +[[package]] +name = "selinux-sys" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223e5015ef798b00c3303373a9fe471e91ac455a863b00d3511fe2772b4af864" +dependencies = [ + "bindgen 0.60.1", + "cc", + "dunce", + "walkdir", +] + [[package]] name = "serde" version = "1.0.219" @@ -907,7 +1086,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap", + "indexmap 2.8.0", "itoa", "memchr", "ryu", @@ -932,7 +1111,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95f44699de6c620259d5a4fe55dc9e6a1a98af93f935567f82bf02fad5c2295d" dependencies = [ - "bindgen", + "bindgen 0.71.1", "cc", "dunce", "walkdir", @@ -954,6 +1133,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -1000,7 +1185,16 @@ dependencies = [ "getrandom", "once_cell", "rustix 1.0.3", - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", ] [[package]] @@ -1025,13 +1219,33 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1112,7 +1326,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" name = "util-linux" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "clap_complete", "clap_mangen", "dns-lookup", @@ -1154,7 +1368,7 @@ dependencies = [ name = "uu_blockdev" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "linux-raw-sys 0.9.3", "regex", "sysinfo", @@ -1165,11 +1379,11 @@ dependencies = [ name = "uu_chcpu" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "libc", "rangemap", "syscall-numbers", - "thiserror", + "thiserror 2.0.12", "uucore", ] @@ -1177,7 +1391,7 @@ dependencies = [ name = "uu_ctrlaltdel" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "uucore", ] @@ -1186,7 +1400,7 @@ name = "uu_dmesg" version = "0.0.1" dependencies = [ "chrono", - "clap", + "clap 4.5.35", "parse_datetime", "regex", "serde", @@ -1198,7 +1412,7 @@ dependencies = [ name = "uu_fsfreeze" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "linux-raw-sys 0.9.3", "regex", "sysinfo", @@ -1209,7 +1423,7 @@ dependencies = [ name = "uu_last" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "dns-lookup", "uucore", ] @@ -1218,7 +1432,7 @@ dependencies = [ name = "uu_lscpu" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "regex", "serde", "serde_json", @@ -1230,7 +1444,7 @@ dependencies = [ name = "uu_lsipc" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "errno", "libc", "smartcols-sys", @@ -1241,7 +1455,7 @@ dependencies = [ name = "uu_lslocks" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "serde", "serde_json", "uucore", @@ -1251,7 +1465,7 @@ dependencies = [ name = "uu_lsmem" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "serde", "serde_json", "uucore", @@ -1261,7 +1475,7 @@ dependencies = [ name = "uu_mcookie" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "md-5", "rand 0.9.0", "uucore", @@ -1271,7 +1485,7 @@ dependencies = [ name = "uu_mesg" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "nix", "uucore", ] @@ -1280,7 +1494,7 @@ dependencies = [ name = "uu_mountpoint" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "uucore", ] @@ -1288,7 +1502,8 @@ dependencies = [ name = "uu_namei" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", + "selinux", "uucore", ] @@ -1296,7 +1511,7 @@ dependencies = [ name = "uu_renice" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "libc", "uucore", ] @@ -1305,7 +1520,7 @@ dependencies = [ name = "uu_rev" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "uucore", ] @@ -1313,7 +1528,7 @@ dependencies = [ name = "uu_setsid" version = "0.0.1" dependencies = [ - "clap", + "clap 4.5.35", "libc", "uucore", ] @@ -1326,7 +1541,7 @@ checksum = "71f4e82877d06de779c611a3d54720f56f1e68b228fb30a5b6c66ef07e68263d" dependencies = [ "chrono", "chrono-tz", - "clap", + "clap 4.5.35", "dns-lookup", "glob", "iana-time-zone", @@ -1439,6 +1654,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + [[package]] name = "wild" version = "2.2.1" @@ -1470,7 +1697,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1701,7 +1928,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags", + "bitflags 2.9.0", ] [[package]] diff --git a/src/uu/namei/Cargo.toml b/src/uu/namei/Cargo.toml index 351086d4..34b0fd18 100644 --- a/src/uu/namei/Cargo.toml +++ b/src/uu/namei/Cargo.toml @@ -6,6 +6,10 @@ edition = "2021" [dependencies] uucore = { workspace = true } clap = { workspace = true } +selinux = { version = "0.1", optional = true } + +[features] +selinux = ["dep:selinux"] [lib] path = "src/namei.rs" diff --git a/src/uu/namei/src/main.rs b/src/uu/namei/src/main.rs index ab7b609a..df3fa7f9 100644 --- a/src/uu/namei/src/main.rs +++ b/src/uu/namei/src/main.rs @@ -1 +1 @@ -uucore::bin!(uu_namei); \ No newline at end of file +uucore::bin!(uu_namei); diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index dc0f1c45..a79d111b 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -4,6 +4,8 @@ // file that was distributed with this source code. use clap::{crate_version, Arg, ArgAction, Command}; +#[cfg(feature = "selinux")] +use selinux::SecurityContext; use std::env; use std::str::FromStr; use std::{cmp::max, fs, os::unix::fs::MetadataExt, path::Path}; @@ -22,8 +24,10 @@ mod options { pub const OWNERS: &str = "owners"; pub const VERTICAL: &str = "vertical"; pub const MOUNTPOINTS: &str = "mountpoints"; - pub const CONTEXT: &str = "context"; pub const PATHNAMES: &str = "pathnames"; + + #[cfg(feature = "selinux")] + pub const CONTEXT: &str = "context"; } struct OutputOptions { @@ -33,11 +37,13 @@ struct OutputOptions { owners: bool, vertical: bool, mountpoints: bool, + + #[cfg(feature = "selinux")] context: bool, } pub fn uu_app() -> Command { - Command::new(uucore::util_name()) + let cmd = Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) .override_usage(format_usage(USAGE)) @@ -92,14 +98,19 @@ pub fn uu_app() -> Command { .long("mountpoints") .help("show mount point directories with a 'D'") .action(ArgAction::SetTrue), - ) - .arg( - Arg::new(options::CONTEXT) - .short('Z') - .long("context") - .help("print any security context of each file") - .action(ArgAction::SetTrue), - ) + ); + + #[cfg(feature = "selinux")] + return cmd.arg( + Arg::new(options::CONTEXT) + .short('Z') + .long("context") + .help("print any security context of each file") + .action(ArgAction::SetTrue), + ); + + #[cfg(not(feature = "selinux"))] + return cmd; } fn max_owner_length(path: &Path) -> usize { @@ -117,7 +128,7 @@ fn max_owner_length(path: &Path) -> usize { max_length = max(max_entry_length, max_length); } - return max_length; + max_length } fn max_group_length(path: &Path) -> usize { @@ -135,7 +146,7 @@ fn max_group_length(path: &Path) -> usize { max_length = max(max_entry_length, max_length); } - return max_length; + max_length } fn get_file_name(input: &str) -> &str { @@ -155,9 +166,9 @@ fn is_mount_point(input_path: &Path) -> bool { return false; } let parent_metadata = fs::metadata(parent).unwrap(); - return metadata.dev() != parent_metadata.dev(); + metadata.dev() != parent_metadata.dev() } else { - return true; + true } } @@ -187,9 +198,12 @@ fn get_prefix( if output_opts.vertical { blanks += 1; } + + #[cfg(feature = "selinux")] if !output_opts.context { blanks += 1; } + prefix = " ".repeat(blanks); return prefix; } @@ -268,7 +282,7 @@ fn get_prefix( prefix.push_str(&perm_string); } - prefix.push_str(" "); + prefix.push(' '); if output_opts.owners { let uid = metadata.uid(); @@ -283,13 +297,32 @@ fn get_prefix( prefix = format!("{}{}{}", prefix, owner, group); } + #[cfg(feature = "selinux")] + if output_opts.context { + let context_not_available_string: String = '?'.to_string(); + match SecurityContext::of_path(path, !output_opts.nosymlinks, false) { + Err(_r) => prefix.push_str(context_not_available_string.as_str()), + Ok(None) => prefix.push_str(context_not_available_string.as_str()), + Ok(Some(cntxt)) => { + let context = cntxt.as_bytes(); + let context = context.strip_suffix(&[0]).unwrap_or(context); + prefix.push_str( + String::from_utf8(context.to_vec()) + .unwrap_or_else(|_e| String::from_utf8_lossy(context).into_owned()) + .as_str(), + ) + } + } + prefix.push_str(" "); + } + if output_opts.vertical { let mut st = String::new(); st.push_str(&" ".repeat(level * 2)); prefix.push_str(&st); } - return prefix; + prefix } fn print_files( @@ -351,7 +384,7 @@ fn print_files( print_files( level + 1, target_path, - &output_opts, + output_opts, maximum_owner_length, maximum_group_length, ); @@ -360,7 +393,7 @@ fn print_files( print_files( level + 1, Path::new(&osstr), - &output_opts, + output_opts, maximum_owner_length, maximum_group_length, ); @@ -381,6 +414,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { owners: matches.get_flag(options::OWNERS) || matches.get_flag(options::LONG), vertical: matches.get_flag(options::VERTICAL) || matches.get_flag(options::LONG), mountpoints: matches.get_flag(options::MOUNTPOINTS), + + #[cfg(feature = "selinux")] context: matches.get_flag(options::CONTEXT), }; From ef34c966bf918cd23f8525f43f4ad1d7251a6607 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sat, 5 Apr 2025 14:39:36 +0530 Subject: [PATCH 04/15] Added tests --- src/uu/namei/src/namei.rs | 19 ++++--- tests/by-util/test_namei.rs | 110 ++++++++++++++++++++++++++++++++++++ tests/tests.rs | 4 ++ 3 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 tests/by-util/test_namei.rs diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index a79d111b..3c09c727 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -7,6 +7,7 @@ use clap::{crate_version, Arg, ArgAction, Command}; #[cfg(feature = "selinux")] use selinux::SecurityContext; use std::env; +use std::process; use std::str::FromStr; use std::{cmp::max, fs, os::unix::fs::MetadataExt, path::Path}; use uucore::entries::{gid2grp, uid2usr}; @@ -52,8 +53,7 @@ pub fn uu_app() -> Command { .value_name("PATH") .help("Paths to follow") .hide(true) - .index(1) - .action(ArgAction::Set) + .action(ArgAction::Append) .required(true) .num_args(1..), ) @@ -360,12 +360,15 @@ fn print_files( }; match fs::metadata(path) { - Err(e) => println!( - "{}{} - {}", - prefix, - get_file_name(path.to_str().unwrap()), - e - ), + Err(e) => { + eprintln!( + "{}{} - {}", + prefix, + get_file_name(path.to_str().unwrap()), + e + ); + process::exit(1); + } _ => println!( "{}{}{}", prefix, diff --git a/tests/by-util/test_namei.rs b/tests/by-util/test_namei.rs new file mode 100644 index 00000000..79fa5602 --- /dev/null +++ b/tests/by-util/test_namei.rs @@ -0,0 +1,110 @@ +// This file is part of the uutils util-linux package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use regex::Regex; + +use crate::common::util::TestScenario; + +#[test] +fn test_invalid_arg() { + new_ucmd!().arg("--definitely-invalid").fails().code_is(1); +} + +#[test] +fn test_fails_on_non_existing_path() { + new_ucmd!() + .arg("/non/existing") + .fails() + .code_is(1) + .stderr_contains("No such file or directory"); +} + +#[test] +fn test_fails_on_no_permission() { + let (at, mut ucmd) = at_and_ucmd!(); + at.mkdir("noperms"); + at.make_file("noperms/testfile"); + at.set_mode("noperms", 0); + let argmnt = at.plus_as_string("noperms/testfile"); + ucmd.arg(argmnt) + .fails() + .code_is(1) + .stderr_contains("Permission denied"); +} + +#[test] +fn test_long_arg() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch(at.plus_as_string("test-long")); + + #[cfg(not(windows))] + let regex = r" *[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} [a-z0-9_\.][a-z0-9_\-\.]*[$]? [a-z0-9_\.][a-z0-9_\-\.]*[$]? .*"; + #[cfg(windows)] + let regex = r"[-dl](r[w-]x){3}.*"; + + let re = &Regex::new(regex).unwrap(); + + let args = vec!["-l", "--long"]; + for arg in args { + let result = scene.ucmd().arg(arg).arg(at.as_string()).succeeds(); + result.stdout_matches(re); + } +} + +#[test] +fn test_modes_arg() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch(at.plus_as_string("test-modes")); + + #[cfg(not(windows))] + let regex = r" +[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} .*"; + + let re = &Regex::new(regex).unwrap(); + + let args = vec!["-m", "--modes"]; + for arg in args { + let result = scene.ucmd().arg(arg).arg(at.as_string()).succeeds(); + result.stdout_matches(re); + } +} + +#[test] +fn test_owners_arg() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch(at.plus_as_string("test-owners")); + + #[cfg(not(windows))] + let regex = + r" +[-bcCdDlMnpPsStTx?] [a-z0-9_\.][a-z0-9_\-\.]*[$]? [a-z0-9_\.][a-z0-9_\-\.]*[$]? .*"; + + let re = &Regex::new(regex).unwrap(); + + let args = vec!["-o", "--owners"]; + for arg in args { + let result = scene.ucmd().arg(arg).arg(at.as_string()).succeeds(); + result.stdout_matches(re); + } +} + +#[test] +fn test_vertical_arg() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch(at.plus_as_string("test-vertical")); + + #[cfg(not(windows))] + let regex = r"[-bcCdDlMnpPsStTx?] +.*"; + + let re = &Regex::new(regex).unwrap(); + + let args = vec!["-v", "--vertical"]; + for arg in args { + let result = scene.ucmd().arg(arg).arg(at.as_string()).succeeds(); + result.stdout_matches(re); + } +} diff --git a/tests/tests.rs b/tests/tests.rs index 0fb3ed14..ce74cb10 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -60,3 +60,7 @@ mod test_fsfreeze; #[cfg(feature = "mcookie")] #[path = "by-util/test_mcookie.rs"] mod test_mcookie; + +#[cfg(feature = "namei")] +#[path = "by-util/test_namei.rs"] +mod test_namei; From 47f0e23c92803d0e756c506b73a320adcdf6357f Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sun, 6 Apr 2025 16:39:51 +0530 Subject: [PATCH 05/15] added windows functionality --- src/uu/namei/src/namei.rs | 349 +++++++++++++++++++++++++----------- tests/by-util/test_namei.rs | 8 +- 2 files changed, 246 insertions(+), 111 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 3c09c727..749a55ec 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -6,10 +6,17 @@ use clap::{crate_version, Arg, ArgAction, Command}; #[cfg(feature = "selinux")] use selinux::SecurityContext; +#[cfg(unix)] +use std::cmp::max; use std::env; +#[cfg(not(target_os = "windows"))] +use std::fs::Metadata; +#[cfg(unix)] +use std::os::unix::fs::MetadataExt; use std::process; use std::str::FromStr; -use std::{cmp::max, fs, os::unix::fs::MetadataExt, path::Path}; +use std::{fs, path::Path}; +#[cfg(unix)] use uucore::entries::{gid2grp, uid2usr}; use uucore::{error::UResult, format_usage, help_about, help_usage}; @@ -22,11 +29,15 @@ mod options { pub const LONG: &str = "long"; pub const MODES: &str = "modes"; pub const NOSYMLINKS: &str = "nosymlinks"; - pub const OWNERS: &str = "owners"; pub const VERTICAL: &str = "vertical"; - pub const MOUNTPOINTS: &str = "mountpoints"; pub const PATHNAMES: &str = "pathnames"; + #[cfg(unix)] + pub const OWNERS: &str = "owners"; + + #[cfg(not(target_os = "windows"))] + pub const MOUNTPOINTS: &str = "mountpoints"; + #[cfg(feature = "selinux")] pub const CONTEXT: &str = "context"; } @@ -35,10 +46,14 @@ struct OutputOptions { long: bool, modes: bool, nosymlinks: bool, - owners: bool, vertical: bool, + + #[cfg(not(target_os = "windows"))] mountpoints: bool, + #[cfg(unix)] + owners: bool, + #[cfg(feature = "selinux")] context: bool, } @@ -78,30 +93,34 @@ pub fn uu_app() -> Command { .help("don't follow symlinks") .action(ArgAction::SetTrue), ) - .arg( - Arg::new(options::OWNERS) - .short('o') - .long("owners") - .help("show owner and group name of each file") - .action(ArgAction::SetTrue), - ) .arg( Arg::new(options::VERTICAL) .short('v') .long("vertical") .help("vertical align of modes and owners") .action(ArgAction::SetTrue), - ) - .arg( - Arg::new(options::MOUNTPOINTS) - .short('x') - .long("mountpoints") - .help("show mount point directories with a 'D'") - .action(ArgAction::SetTrue), ); + #[cfg(not(target_os = "windows"))] + let cmd = cmd.arg( + Arg::new(options::MOUNTPOINTS) + .short('x') + .long("mountpoints") + .help("show mount point directories with a 'D'") + .action(ArgAction::SetTrue), + ); + + #[cfg(unix)] + let cmd = cmd.arg( + Arg::new(options::OWNERS) + .short('o') + .long("owners") + .help("show owner and group name of each file") + .action(ArgAction::SetTrue), + ); + #[cfg(feature = "selinux")] - return cmd.arg( + let cmd = cmd.arg( Arg::new(options::CONTEXT) .short('Z') .long("context") @@ -109,11 +128,15 @@ pub fn uu_app() -> Command { .action(ArgAction::SetTrue), ); - #[cfg(not(feature = "selinux"))] - return cmd; + cmd } -fn max_owner_length(path: &Path) -> usize { +#[cfg(unix)] +fn max_owner_length(path: &Path, owners_output: bool) -> usize { + if owners_output { + return 0; + } + let mut max_length = 0; for entry in path.ancestors() { @@ -130,8 +153,12 @@ fn max_owner_length(path: &Path) -> usize { max_length } +#[cfg(unix)] +fn max_group_length(path: &Path, owners_output: bool) -> usize { + if owners_output { + return 0; + } -fn max_group_length(path: &Path) -> usize { let mut max_length = 0; for entry in path.ancestors() { @@ -149,6 +176,7 @@ fn max_group_length(path: &Path) -> usize { max_length } +#[cfg(not(target_os = "windows"))] fn get_file_name(input: &str) -> &str { let stripped = input.trim_end_matches('/'); if stripped.is_empty() { @@ -157,6 +185,66 @@ fn get_file_name(input: &str) -> &str { stripped.rsplit('/').next().unwrap_or("/") } +#[cfg(target_os = "windows")] +fn get_file_name(input: &str) -> &str { + if !input.contains('\\') { + return input; + } else { + let stripped = input.trim_end_matches('\\'); + if stripped.is_empty() { + return ":"; + } + if !stripped.contains('\\') { + return stripped; + } + return stripped.rsplit('\\').next().unwrap_or("\\"); + } +} + +#[cfg(unix)] +fn get_file_type(path: &Path, outputmountpoints: bool) -> char { + if path.is_symlink() { + return 'l'; + } + if outputmountpoints && is_mount_point(path) { + return 'D'; + } + + let metadata = fs::metadata(path).unwrap(); + + let mode = metadata.mode(); + + let file_type = match mode & 0o170000 { + 0o100000 => '-', // Regular file + 0o040000 => 'd', // Directory + 0o020000 => 'c', // Character device + 0o060000 => 'b', // Block device + 0o010000 => 'p', // FIFO + 0o140000 => 's', // Socket + _ => '?', // Unknown + }; + + file_type +} + +#[cfg(not(unix))] +fn get_file_type(path: &Path, _outputmountpoints: bool) -> char { + let filetype = fs::metadata(path).unwrap().file_type(); + + let file_type = if filetype.is_dir() { + 'd' + } else if filetype.is_file() { + '-' + } else if filetype.is_symlink() { + 'l' + } else { + '?' + }; + + file_type +} + +#[cfg(not(target_os = "windows"))] fn is_mount_point(input_path: &Path) -> bool { let canonical_path = input_path.canonicalize().unwrap().into_os_string(); let path = Path::new(&canonical_path); @@ -172,6 +260,108 @@ fn is_mount_point(input_path: &Path) -> bool { } } +#[cfg(unix)] +fn get_permissions(path: &Path) -> String { + let mode = metadata.mode(); + + let permissions = [ + (mode & 0o400, 'r'), + (mode & 0o200, 'w'), + (mode & 0o100, 'x'), // Owner + (mode & 0o040, 'r'), + (mode & 0o020, 'w'), + (mode & 0o010, 'x'), // Group + (mode & 0o004, 'r'), + (mode & 0o002, 'w'), + (mode & 0o001, 'x'), // Others + ]; + let mut perm_string = String::new(); + for &(bit, ch) in &permissions { + perm_string.push(if bit != 0 { ch } else { '-' }); + } + if mode & 0o4000 != 0 { + // Set UID + perm_string.replace_range( + 2..3, + if perm_string.chars().nth(3) == Some('x') { + "s" + } else { + "S" + }, + ); + } + if mode & 0o2000 != 0 { + // Set GID + perm_string.replace_range( + 5..6, + if perm_string.chars().nth(6) == Some('x') { + "s" + } else { + "S" + }, + ); + } + if mode & 0o1000 != 0 { + // Sticky Bit + perm_string.replace_range( + 8..9, + if perm_string.chars().nth(9) == Some('x') { + "t" + } else { + "T" + }, + ); + } + + perm_string +} + +#[cfg(not(unix))] +fn get_permissions(path: &Path) -> String { + let metadata = fs::metadata(path).unwrap(); + let file_type = metadata.file_type(); + + // NOTE: Windows doesn't give full Unix-style permissions + // We're faking it: check readonly bit to infer write access + let readonly = metadata.permissions().readonly(); + + // Use PATHEXT environment variable to figure out if file is executable + let executable = if file_type.is_file() { + match path.extension().and_then(|e| e.to_str()) { + Some(e) => { + let ext = e.to_ascii_lowercase(); + let pathext = env::var("PATHEXT").unwrap_or_default(); + pathext + .split(';') + .filter_map(|e| e.strip_prefix('.')) // ".EXE" -> "EXE" + .any(|e| e.eq_ignore_ascii_case(&ext)) + } + None => false, + } + } else { + false + }; + + let mut perm_string = String::new(); + + let mut rwx = if readonly { + "r-".to_string() + } else { + "rw".to_string() + }; + if executable { + rwx.push('x'); + } else { + rwx.push('-'); + } + + perm_string.push_str(rwx.as_str()); + perm_string.push_str(rwx.as_str()); + perm_string.push_str(rwx.as_str()); + + perm_string +} + fn get_prefix( level: usize, path: &Path, @@ -179,6 +369,12 @@ fn get_prefix( maximum_owner_length: usize, maximum_group_length: usize, ) -> String { + // Avoid unused variable warnings on non-Unix platforms + #[cfg(not(unix))] + { + let _ = (maximum_owner_length, maximum_group_length); + } + let mut prefix = String::new(); if !output_opts.vertical { @@ -192,6 +388,7 @@ fn get_prefix( if output_opts.modes { blanks += 9; } + #[cfg(unix)] if output_opts.owners { blanks += maximum_owner_length + maximum_group_length + 2; } @@ -208,82 +405,20 @@ fn get_prefix( return prefix; } - let metadata = fs::metadata(path).unwrap(); - - let mode = metadata.mode(); - - let file_type = match mode & 0o170000 { - 0o100000 => '-', // Regular file - 0o040000 if output_opts.mountpoints && is_mount_point(path) => 'D', // Directory - 0o040000 => 'd', // Directory - 0o120000 => 'l', // Symbolic link - 0o020000 => 'c', // Character device - 0o060000 => 'b', // Block device - 0o010000 => 'p', // FIFO - 0o140000 => 's', // Socket - _ => '?', // Unknown - }; - - if path.is_symlink() { - prefix.push('l'); - } else { - prefix.push(file_type); - } + let mountpoints = false; + #[cfg(not(target_os = "windows"))] + let mountpoints = output_opts.mountpoints; + + prefix.push(get_file_type(path, mountpoints)); if output_opts.modes || output_opts.long { - let permissions = [ - (mode & 0o400, 'r'), - (mode & 0o200, 'w'), - (mode & 0o100, 'x'), // Owner - (mode & 0o040, 'r'), - (mode & 0o020, 'w'), - (mode & 0o010, 'x'), // Group - (mode & 0o004, 'r'), - (mode & 0o002, 'w'), - (mode & 0o001, 'x'), // Others - ]; - let mut perm_string = String::new(); - for &(bit, ch) in &permissions { - perm_string.push(if bit != 0 { ch } else { '-' }); - } - if mode & 0o4000 != 0 { - // Set UID - perm_string.replace_range( - 2..3, - if perm_string.chars().nth(3) == Some('x') { - "s" - } else { - "S" - }, - ); - } - if mode & 0o2000 != 0 { - // Set GID - perm_string.replace_range( - 5..6, - if perm_string.chars().nth(6) == Some('x') { - "s" - } else { - "S" - }, - ); - } - if mode & 0o1000 != 0 { - // Sticky Bit - perm_string.replace_range( - 8..9, - if perm_string.chars().nth(9) == Some('x') { - "t" - } else { - "T" - }, - ); - } - + let perm_string = get_permissions(path); prefix.push_str(&perm_string); } + prefix.push(' '); + #[cfg(unix)] if output_opts.owners { let uid = metadata.uid(); let gid = metadata.gid(); @@ -414,10 +549,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { long: matches.get_flag(options::LONG), modes: matches.get_flag(options::MODES) || matches.get_flag(options::LONG), nosymlinks: matches.get_flag(options::NOSYMLINKS), - owners: matches.get_flag(options::OWNERS) || matches.get_flag(options::LONG), vertical: matches.get_flag(options::VERTICAL) || matches.get_flag(options::LONG), + + #[cfg(not(target_os = "windows"))] mountpoints: matches.get_flag(options::MOUNTPOINTS), + #[cfg(unix)] + owners: matches.get_flag(options::OWNERS) || matches.get_flag(options::LONG), + #[cfg(feature = "selinux")] context: matches.get_flag(options::CONTEXT), }; @@ -426,16 +565,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { for path_str in paths { let path = Path::new(path_str); println!("f: {}", path.to_str().unwrap()); - let maximum_owner_length = if output_opts.owners { - max_owner_length(path) - } else { - 0 - }; - let maximum_group_length = if output_opts.owners { - max_group_length(path) - } else { - 0 - }; + + let maximum_owner_length = 0; + let maximum_group_length = 0; + + #[cfg(unix)] + let maximum_owner_length = max_owner_length(path, output_opts.owners); + #[cfg(unix)] + let maximum_group_length = max_group_length(path, output_opts.owners); + print_files( 0, path, @@ -445,9 +583,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ); } } - // Handling the case where path is not provided is not necessary - // because in path arguments have been made necessary in clap so - // it will automatically show an error in stdout Ok(()) } diff --git a/tests/by-util/test_namei.rs b/tests/by-util/test_namei.rs index 79fa5602..1fb36def 100644 --- a/tests/by-util/test_namei.rs +++ b/tests/by-util/test_namei.rs @@ -21,6 +21,7 @@ fn test_fails_on_non_existing_path() { .stderr_contains("No such file or directory"); } +#[cfg(unix)] #[test] fn test_fails_on_no_permission() { let (at, mut ucmd) = at_and_ucmd!(); @@ -40,9 +41,9 @@ fn test_long_arg() { let at = &scene.fixtures; at.touch(at.plus_as_string("test-long")); - #[cfg(not(windows))] + #[cfg(unix)] let regex = r" *[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} [a-z0-9_\.][a-z0-9_\-\.]*[$]? [a-z0-9_\.][a-z0-9_\-\.]*[$]? .*"; - #[cfg(windows)] + #[cfg(target_os="windows")] let regex = r"[-dl](r[w-]x){3}.*"; let re = &Regex::new(regex).unwrap(); @@ -60,7 +61,6 @@ fn test_modes_arg() { let at = &scene.fixtures; at.touch(at.plus_as_string("test-modes")); - #[cfg(not(windows))] let regex = r" +[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} .*"; let re = &Regex::new(regex).unwrap(); @@ -72,6 +72,7 @@ fn test_modes_arg() { } } +#[cfg(unix)] #[test] fn test_owners_arg() { let scene = TestScenario::new(util_name!()); @@ -97,7 +98,6 @@ fn test_vertical_arg() { let at = &scene.fixtures; at.touch(at.plus_as_string("test-vertical")); - #[cfg(not(windows))] let regex = r"[-bcCdDlMnpPsStTx?] +.*"; let re = &Regex::new(regex).unwrap(); From 753fc8f0da3d21eef99da3e80b367fe244152781 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sun, 6 Apr 2025 16:49:18 +0530 Subject: [PATCH 06/15] added windows functionality --- src/uu/namei/src/namei.rs | 18 ++++++++---------- tests/by-util/test_namei.rs | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 749a55ec..53c5a18f 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -34,10 +34,10 @@ mod options { #[cfg(unix)] pub const OWNERS: &str = "owners"; - + #[cfg(not(target_os = "windows"))] pub const MOUNTPOINTS: &str = "mountpoints"; - + #[cfg(feature = "selinux")] pub const CONTEXT: &str = "context"; } @@ -109,7 +109,7 @@ pub fn uu_app() -> Command { .help("show mount point directories with a 'D'") .action(ArgAction::SetTrue), ); - + #[cfg(unix)] let cmd = cmd.arg( Arg::new(options::OWNERS) @@ -188,7 +188,7 @@ fn get_file_name(input: &str) -> &str { #[cfg(target_os = "windows")] fn get_file_name(input: &str) -> &str { if !input.contains('\\') { - return input; + input } else { let stripped = input.trim_end_matches('\\'); if stripped.is_empty() { @@ -197,7 +197,7 @@ fn get_file_name(input: &str) -> &str { if !stripped.contains('\\') { return stripped; } - return stripped.rsplit('\\').next().unwrap_or("\\"); + stripped.rsplit('\\').next().unwrap_or("\\") } } @@ -231,7 +231,7 @@ fn get_file_type(path: &Path, outputmountpoints: bool) -> char { fn get_file_type(path: &Path, _outputmountpoints: bool) -> char { let filetype = fs::metadata(path).unwrap().file_type(); - let file_type = if filetype.is_dir() { + if filetype.is_dir() { 'd' } else if filetype.is_file() { '-' @@ -239,9 +239,7 @@ fn get_file_type(path: &Path, _outputmountpoints: bool) -> char { 'l' } else { '?' - }; - - file_type + } } #[cfg(not(target_os = "windows"))] @@ -408,7 +406,7 @@ fn get_prefix( let mountpoints = false; #[cfg(not(target_os = "windows"))] let mountpoints = output_opts.mountpoints; - + prefix.push(get_file_type(path, mountpoints)); if output_opts.modes || output_opts.long { diff --git a/tests/by-util/test_namei.rs b/tests/by-util/test_namei.rs index 1fb36def..48b7c946 100644 --- a/tests/by-util/test_namei.rs +++ b/tests/by-util/test_namei.rs @@ -43,7 +43,7 @@ fn test_long_arg() { #[cfg(unix)] let regex = r" *[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} [a-z0-9_\.][a-z0-9_\-\.]*[$]? [a-z0-9_\.][a-z0-9_\-\.]*[$]? .*"; - #[cfg(target_os="windows")] + #[cfg(target_os = "windows")] let regex = r"[-dl](r[w-]x){3}.*"; let re = &Regex::new(regex).unwrap(); From 0798804856281ee230dae6df6269249129b2884f Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sun, 6 Apr 2025 16:59:12 +0530 Subject: [PATCH 07/15] fix some failing test --- src/uu/namei/src/namei.rs | 30 +++++++++++++++--------------- tests/by-util/test_namei.rs | 6 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 53c5a18f..848568eb 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -6,17 +6,17 @@ use clap::{crate_version, Arg, ArgAction, Command}; #[cfg(feature = "selinux")] use selinux::SecurityContext; -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] use std::cmp::max; use std::env; #[cfg(not(target_os = "windows"))] use std::fs::Metadata; -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] use std::os::unix::fs::MetadataExt; use std::process; use std::str::FromStr; use std::{fs, path::Path}; -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] use uucore::entries::{gid2grp, uid2usr}; use uucore::{error::UResult, format_usage, help_about, help_usage}; @@ -32,7 +32,7 @@ mod options { pub const VERTICAL: &str = "vertical"; pub const PATHNAMES: &str = "pathnames"; - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] pub const OWNERS: &str = "owners"; #[cfg(not(target_os = "windows"))] @@ -51,7 +51,7 @@ struct OutputOptions { #[cfg(not(target_os = "windows"))] mountpoints: bool, - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] owners: bool, #[cfg(feature = "selinux")] @@ -110,7 +110,7 @@ pub fn uu_app() -> Command { .action(ArgAction::SetTrue), ); - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] let cmd = cmd.arg( Arg::new(options::OWNERS) .short('o') @@ -131,7 +131,7 @@ pub fn uu_app() -> Command { cmd } -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] fn max_owner_length(path: &Path, owners_output: bool) -> usize { if owners_output { return 0; @@ -153,7 +153,7 @@ fn max_owner_length(path: &Path, owners_output: bool) -> usize { max_length } -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] fn max_group_length(path: &Path, owners_output: bool) -> usize { if owners_output { return 0; @@ -201,7 +201,7 @@ fn get_file_name(input: &str) -> &str { } } -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] fn get_file_type(path: &Path, outputmountpoints: bool) -> char { if path.is_symlink() { return 'l'; @@ -258,7 +258,7 @@ fn is_mount_point(input_path: &Path) -> bool { } } -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] fn get_permissions(path: &Path) -> String { let mode = metadata.mode(); @@ -386,7 +386,7 @@ fn get_prefix( if output_opts.modes { blanks += 9; } - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] if output_opts.owners { blanks += maximum_owner_length + maximum_group_length + 2; } @@ -416,7 +416,7 @@ fn get_prefix( prefix.push(' '); - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] if output_opts.owners { let uid = metadata.uid(); let gid = metadata.gid(); @@ -552,7 +552,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { #[cfg(not(target_os = "windows"))] mountpoints: matches.get_flag(options::MOUNTPOINTS), - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] owners: matches.get_flag(options::OWNERS) || matches.get_flag(options::LONG), #[cfg(feature = "selinux")] @@ -567,9 +567,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let maximum_owner_length = 0; let maximum_group_length = 0; - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] let maximum_owner_length = max_owner_length(path, output_opts.owners); - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] let maximum_group_length = max_group_length(path, output_opts.owners); print_files( diff --git a/tests/by-util/test_namei.rs b/tests/by-util/test_namei.rs index 48b7c946..9eb2f95b 100644 --- a/tests/by-util/test_namei.rs +++ b/tests/by-util/test_namei.rs @@ -21,7 +21,7 @@ fn test_fails_on_non_existing_path() { .stderr_contains("No such file or directory"); } -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] #[test] fn test_fails_on_no_permission() { let (at, mut ucmd) = at_and_ucmd!(); @@ -41,7 +41,7 @@ fn test_long_arg() { let at = &scene.fixtures; at.touch(at.plus_as_string("test-long")); - #[cfg(unix)] + #[cfg(not(target_os = "windows"))] let regex = r" *[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} [a-z0-9_\.][a-z0-9_\-\.]*[$]? [a-z0-9_\.][a-z0-9_\-\.]*[$]? .*"; #[cfg(target_os = "windows")] let regex = r"[-dl](r[w-]x){3}.*"; @@ -72,7 +72,7 @@ fn test_modes_arg() { } } -#[cfg(unix)] +#[cfg(not(target_os = "windows"))] #[test] fn test_owners_arg() { let scene = TestScenario::new(util_name!()); From 9d1aca5c1300a292b80300932e44e6cfa45feee7 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sun, 6 Apr 2025 18:14:37 +0530 Subject: [PATCH 08/15] fix some errors --- src/uu/namei/src/namei.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 848568eb..9512d0c0 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -9,8 +9,8 @@ use selinux::SecurityContext; #[cfg(not(target_os = "windows"))] use std::cmp::max; use std::env; -#[cfg(not(target_os = "windows"))] -use std::fs::Metadata; +// #[cfg(not(target_os = "windows"))] +// use std::fs::Metadata; #[cfg(not(target_os = "windows"))] use std::os::unix::fs::MetadataExt; use std::process; @@ -214,7 +214,7 @@ fn get_file_type(path: &Path, outputmountpoints: bool) -> char { let mode = metadata.mode(); - let file_type = match mode & 0o170000 { + match mode & 0o170000 { 0o100000 => '-', // Regular file 0o040000 => 'd', // Directory 0o020000 => 'c', // Character device @@ -222,9 +222,7 @@ fn get_file_type(path: &Path, outputmountpoints: bool) -> char { 0o010000 => 'p', // FIFO 0o140000 => 's', // Socket _ => '?', // Unknown - }; - - file_type + } } #[cfg(not(unix))] @@ -260,6 +258,7 @@ fn is_mount_point(input_path: &Path) -> bool { #[cfg(not(target_os = "windows"))] fn get_permissions(path: &Path) -> String { + let metadata = fs::metadata(path).unwrap(); let mode = metadata.mode(); let permissions = [ @@ -403,6 +402,7 @@ fn get_prefix( return prefix; } + #[cfg(target_os = "windows")] let mountpoints = false; #[cfg(not(target_os = "windows"))] let mountpoints = output_opts.mountpoints; @@ -418,6 +418,7 @@ fn get_prefix( #[cfg(not(target_os = "windows"))] if output_opts.owners { + let metadata = fs::metadata(path).unwrap(); let uid = metadata.uid(); let gid = metadata.gid(); let mut owner = uid2usr(uid).unwrap(); @@ -564,7 +565,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let path = Path::new(path_str); println!("f: {}", path.to_str().unwrap()); + #[cfg(target_os = "windows")] let maximum_owner_length = 0; + #[cfg(target_os = "windows")] let maximum_group_length = 0; #[cfg(not(target_os = "windows"))] From 7863e364471b49547fe429d43deb9c25752a1362 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sun, 6 Apr 2025 18:22:08 +0530 Subject: [PATCH 09/15] fix failing tests --- src/uu/namei/src/namei.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 9512d0c0..996da6ec 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -132,11 +132,7 @@ pub fn uu_app() -> Command { } #[cfg(not(target_os = "windows"))] -fn max_owner_length(path: &Path, owners_output: bool) -> usize { - if owners_output { - return 0; - } - +fn max_owner_length(path: &Path) -> usize { let mut max_length = 0; for entry in path.ancestors() { @@ -154,11 +150,7 @@ fn max_owner_length(path: &Path, owners_output: bool) -> usize { max_length } #[cfg(not(target_os = "windows"))] -fn max_group_length(path: &Path, owners_output: bool) -> usize { - if owners_output { - return 0; - } - +fn max_group_length(path: &Path) -> usize { let mut max_length = 0; for entry in path.ancestors() { @@ -571,9 +563,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let maximum_group_length = 0; #[cfg(not(target_os = "windows"))] - let maximum_owner_length = max_owner_length(path, output_opts.owners); + let maximum_owner_length = max_owner_length(path); #[cfg(not(target_os = "windows"))] - let maximum_group_length = max_group_length(path, output_opts.owners); + let maximum_group_length = max_group_length(path); print_files( 0, From b20a0f3ba9473bcc996168baa566a5fc7a344401 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Sun, 6 Apr 2025 18:56:21 +0530 Subject: [PATCH 10/15] fix windows test fail issue --- tests/by-util/test_namei.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/by-util/test_namei.rs b/tests/by-util/test_namei.rs index 9eb2f95b..dcd56d2f 100644 --- a/tests/by-util/test_namei.rs +++ b/tests/by-util/test_namei.rs @@ -14,11 +14,15 @@ fn test_invalid_arg() { #[test] fn test_fails_on_non_existing_path() { - new_ucmd!() - .arg("/non/existing") - .fails() - .code_is(1) - .stderr_contains("No such file or directory"); + let (at, mut ucmd) = at_and_ucmd!(); + let argmnt = at.plus_as_string("nonexisting"); + + #[cfg(target_os = "windows")] + let err = "The system cannot find the file specified"; + #[cfg(not(target_os = "windows"))] + let err = "No such file or directory"; + + ucmd.arg(argmnt).fails().code_is(1).stderr_contains(err); } #[cfg(not(target_os = "windows"))] @@ -44,7 +48,7 @@ fn test_long_arg() { #[cfg(not(target_os = "windows"))] let regex = r" *[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} [a-z0-9_\.][a-z0-9_\-\.]*[$]? [a-z0-9_\.][a-z0-9_\-\.]*[$]? .*"; #[cfg(target_os = "windows")] - let regex = r"[-dl](r[w-]x){3}.*"; + let regex = r"[-dl]([r-][w-][x-]){3} .*"; let re = &Regex::new(regex).unwrap(); From 8165700a31c6e0e10051b2806d2814465a7dabf2 Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury <54467781+cdebanil@users.noreply.github.com> Date: Mon, 7 Apr 2025 22:08:34 +0530 Subject: [PATCH 11/15] fix typo in Cargo.toml --- src/uu/namei/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/namei/Cargo.toml b/src/uu/namei/Cargo.toml index 34b0fd18..b9a4b764 100644 --- a/src/uu/namei/Cargo.toml +++ b/src/uu/namei/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] uucore = { workspace = true } clap = { workspace = true } -selinux = { version = "0.1", optional = true } +selinux = { version = "0.5.1", optional = true } [features] selinux = ["dep:selinux"] From 74f330a6800df1a728b4044beeb0822faeb0e42c Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Wed, 9 Apr 2025 16:19:07 +0530 Subject: [PATCH 12/15] fix error on relative paths --- Cargo.lock | 334 +++++++++++--------------------------- src/uu/namei/src/namei.rs | 78 +++++++-- 2 files changed, 161 insertions(+), 251 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82afbce6..5f93e54a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,53 +76,19 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "bindgen" -version = "0.60.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "clap 3.2.25", - "env_logger", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "which", -] - [[package]] name = "bindgen" version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.0", + "bitflags", "cexpr", "clang-sys", "itertools", @@ -131,17 +97,11 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 2.1.1", + "rustc-hash", "shlex", "syn", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.9.0" @@ -239,21 +199,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "strsim 0.10.0", - "termcolor", - "textwrap", -] - [[package]] name = "clap" version = "4.5.35" @@ -271,8 +216,8 @@ checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.4", - "strsim 0.11.1", + "clap_lex", + "strsim", "terminal_size", ] @@ -282,16 +227,7 @@ version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" dependencies = [ - "clap 4.5.35", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", + "clap", ] [[package]] @@ -306,7 +242,7 @@ version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "724842fa9b144f9b89b3f3d371a89f3455eea660361d13a554f68f8ae5d6c13a" dependencies = [ - "clap 4.5.35", + "clap", "roff", ] @@ -381,19 +317,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -444,48 +367,18 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "humantime" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" - [[package]] name = "iana-time-zone" version = "0.1.62" @@ -510,16 +403,6 @@ dependencies = [ "cc", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.8.0" @@ -527,7 +410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", ] [[package]] @@ -561,18 +444,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.171" @@ -601,6 +472,16 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.27" @@ -635,7 +516,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -705,7 +586,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" dependencies = [ - "bitflags 2.9.0", + "bitflags", ] [[package]] @@ -724,10 +605,27 @@ dependencies = [ ] [[package]] -name = "os_str_bytes" -version = "6.6.1" +name = "parking_lot" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] [[package]] name = "parse-zoneinfo" @@ -749,12 +647,6 @@ dependencies = [ "regex", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "phf" version = "0.11.3" @@ -843,7 +735,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags 2.9.0", + "bitflags", "hex", "procfs-core", "rustix 0.38.44", @@ -855,7 +747,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.9.0", + "bitflags", "hex", ] @@ -926,10 +818,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" [[package]] -name = "reference-counted-singleton" -version = "0.1.5" +name = "redox_syscall" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5daffa8f5ca827e146485577fa9dba9bd9c6921e06e954ab8f6408c10f753086" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +dependencies = [ + "bitflags", +] [[package]] name = "regex" @@ -975,12 +870,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -993,7 +882,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1006,7 +895,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ - "bitflags 2.9.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.9.3", @@ -1034,27 +923,33 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "selinux" -version = "0.1.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd525eeb189eb26c8471463186bba87644e3d8a9c7ae392adaf9ec45ede574bc" +checksum = "e37f432dfe840521abd9a72fefdf88ed7ad0f43bbea7d9d1d3d80383e9f4ad13" dependencies = [ - "bitflags 1.3.2", + "bitflags", "libc", "once_cell", - "reference-counted-singleton", + "parking_lot", "selinux-sys", - "thiserror 1.0.69", + "thiserror", ] [[package]] name = "selinux-sys" -version = "0.5.3" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223e5015ef798b00c3303373a9fe471e91ac455a863b00d3511fe2772b4af864" +checksum = "280da3df1236da180be5ac50a893b26a1d3c49e3a44acb2d10d1f082523ff916" dependencies = [ - "bindgen 0.60.1", + "bindgen", "cc", "dunce", "walkdir", @@ -1086,7 +981,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap 2.8.0", + "indexmap", "itoa", "memchr", "ryu", @@ -1105,13 +1000,19 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + [[package]] name = "smartcols-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95f44699de6c620259d5a4fe55dc9e6a1a98af93f935567f82bf02fad5c2295d" dependencies = [ - "bindgen 0.71.1", + "bindgen", "cc", "dunce", "walkdir", @@ -1133,12 +1034,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -1185,16 +1080,7 @@ dependencies = [ "getrandom", "once_cell", "rustix 1.0.3", - "windows-sys 0.52.0", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", + "windows-sys 0.59.0", ] [[package]] @@ -1219,33 +1105,13 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "thiserror-impl", ] [[package]] @@ -1326,7 +1192,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" name = "util-linux" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "clap_complete", "clap_mangen", "dns-lookup", @@ -1368,7 +1234,7 @@ dependencies = [ name = "uu_blockdev" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "linux-raw-sys 0.9.3", "regex", "sysinfo", @@ -1379,11 +1245,11 @@ dependencies = [ name = "uu_chcpu" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "libc", "rangemap", "syscall-numbers", - "thiserror 2.0.12", + "thiserror", "uucore", ] @@ -1391,7 +1257,7 @@ dependencies = [ name = "uu_ctrlaltdel" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "uucore", ] @@ -1400,7 +1266,7 @@ name = "uu_dmesg" version = "0.0.1" dependencies = [ "chrono", - "clap 4.5.35", + "clap", "parse_datetime", "regex", "serde", @@ -1412,7 +1278,7 @@ dependencies = [ name = "uu_fsfreeze" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "linux-raw-sys 0.9.3", "regex", "sysinfo", @@ -1423,7 +1289,7 @@ dependencies = [ name = "uu_last" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "dns-lookup", "uucore", ] @@ -1432,7 +1298,7 @@ dependencies = [ name = "uu_lscpu" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "regex", "serde", "serde_json", @@ -1444,7 +1310,7 @@ dependencies = [ name = "uu_lsipc" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "errno", "libc", "smartcols-sys", @@ -1455,7 +1321,7 @@ dependencies = [ name = "uu_lslocks" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "serde", "serde_json", "uucore", @@ -1465,7 +1331,7 @@ dependencies = [ name = "uu_lsmem" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "serde", "serde_json", "uucore", @@ -1475,7 +1341,7 @@ dependencies = [ name = "uu_mcookie" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "md-5", "rand 0.9.0", "uucore", @@ -1485,7 +1351,7 @@ dependencies = [ name = "uu_mesg" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "nix", "uucore", ] @@ -1494,7 +1360,7 @@ dependencies = [ name = "uu_mountpoint" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "uucore", ] @@ -1502,7 +1368,7 @@ dependencies = [ name = "uu_namei" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "selinux", "uucore", ] @@ -1511,7 +1377,7 @@ dependencies = [ name = "uu_renice" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "libc", "uucore", ] @@ -1520,7 +1386,7 @@ dependencies = [ name = "uu_rev" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "uucore", ] @@ -1528,7 +1394,7 @@ dependencies = [ name = "uu_setsid" version = "0.0.1" dependencies = [ - "clap 4.5.35", + "clap", "libc", "uucore", ] @@ -1541,7 +1407,7 @@ checksum = "71f4e82877d06de779c611a3d54720f56f1e68b228fb30a5b6c66ef07e68263d" dependencies = [ "chrono", "chrono-tz", - "clap 4.5.35", + "clap", "dns-lookup", "glob", "iana-time-zone", @@ -1654,18 +1520,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "wild" version = "2.2.1" @@ -1928,7 +1782,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags", ] [[package]] diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 996da6ec..157b9cc8 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -451,23 +451,26 @@ fn get_prefix( prefix } -fn print_files( +fn tokenize_relative_path(path: &str, cwd: &str) -> Vec { + let mut result = Vec::new(); + let mut current = String::from(cwd); + + for part in path.split('/') { + current.push('/'); + current.push_str(part); + result.push(current.clone()); + } + + result +} + +fn print_file( level: usize, path: &Path, output_opts: &OutputOptions, maximum_owner_length: usize, maximum_group_length: usize, ) { - if let Some(pt) = path.parent() { - print_files( - level, - pt, - output_opts, - maximum_owner_length, - maximum_group_length, - ); - } - let prefix = get_prefix( level, path, @@ -530,6 +533,59 @@ fn print_files( } } +fn print_files( + level: usize, + path: &Path, + output_opts: &OutputOptions, + maximum_owner_length: usize, + maximum_group_length: usize, +) { + if path.is_absolute() { + if let Some(pt) = path.parent() { + print_files( + level, + pt, + output_opts, + maximum_owner_length, + maximum_group_length, + ); + } + print_file( + level, + path, + output_opts, + maximum_owner_length, + maximum_group_length, + ); + } + + if path.is_relative() { + match env::current_dir() { + Ok(pt) => { + if let Some(cwd) = pt.to_str() { + if path.to_str().is_none() { + eprintln!("Invalid Path (Non-unicode)"); + } else { + let paths = tokenize_relative_path(path.to_str().unwrap(), cwd); + for path_string in &paths { + let p = Path::new(path_string); + + print_file( + level, + p, + output_opts, + maximum_owner_length, + maximum_group_length, + ); + } + } + } + } + Err(e) => eprintln!("{}", e), + } + } +} + #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; From 95e5dfa621c74e2138114e6581e9de2905e3e98d Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Thu, 10 Apr 2025 09:02:41 +0530 Subject: [PATCH 13/15] fixed an issue where output was different from GNU namei --- src/uu/namei/src/namei.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index 157b9cc8..fcd34fd2 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -456,9 +456,11 @@ fn tokenize_relative_path(path: &str, cwd: &str) -> Vec { let mut current = String::from(cwd); for part in path.split('/') { - current.push('/'); - current.push_str(part); - result.push(current.clone()); + if part.len() != 0 { + current.push('/'); + current.push_str(part); + result.push(current.clone()); + } } result From 6d1f759d9bc5903b589bab20a4cbae47d994f1dc Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Thu, 10 Apr 2025 10:50:13 +0530 Subject: [PATCH 14/15] small change --- src/uu/namei/src/namei.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index fcd34fd2..b6ee7bc7 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -455,9 +455,14 @@ fn tokenize_relative_path(path: &str, cwd: &str) -> Vec { let mut result = Vec::new(); let mut current = String::from(cwd); - for part in path.split('/') { + #[cfg(not(target_os = "windows"))] + let sep = '/'; + #[cfg(target_os = "windows")] + let sep = '\\'; + + for part in path.split(sep) { if part.len() != 0 { - current.push('/'); + current.push(sep); current.push_str(part); result.push(current.clone()); } From c44ec54c03c89232a8784a4f439d398f1f3fb57b Mon Sep 17 00:00:00 2001 From: Debanil Chowdhury Date: Thu, 10 Apr 2025 10:53:12 +0530 Subject: [PATCH 15/15] ran cargo fmt and cargo clippy --- src/uu/namei/src/namei.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/namei/src/namei.rs b/src/uu/namei/src/namei.rs index b6ee7bc7..2ed6d119 100644 --- a/src/uu/namei/src/namei.rs +++ b/src/uu/namei/src/namei.rs @@ -461,7 +461,7 @@ fn tokenize_relative_path(path: &str, cwd: &str) -> Vec { let sep = '\\'; for part in path.split(sep) { - if part.len() != 0 { + if !part.is_empty() { current.push(sep); current.push_str(part); result.push(current.clone());