From c674cf183923448a8e88eaaa60208eb47a8f5b21 Mon Sep 17 00:00:00 2001 From: Sudhakar Verma <10460978+sudhackar@users.noreply.github.com> Date: Thu, 19 Jun 2025 13:47:25 +0530 Subject: [PATCH] Merge pull request #8217 from sudhackar/ls-fix ls: follow symlinks for xattrs, fix #8216 --- .../cspell.dictionaries/jargon.wordlist.txt | 1 + src/uucore/src/lib/features/fsxattr.rs | 2 +- tests/by-util/test_ls.rs | 37 +++++++++++++++++++ util/gnu-patches/tests_ls_no_cap.patch | 8 ++-- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/.vscode/cspell.dictionaries/jargon.wordlist.txt b/.vscode/cspell.dictionaries/jargon.wordlist.txt index 6358f3c76..0fb10db68 100644 --- a/.vscode/cspell.dictionaries/jargon.wordlist.txt +++ b/.vscode/cspell.dictionaries/jargon.wordlist.txt @@ -68,6 +68,7 @@ kibi kibibytes libacl lcase +listxattr llistxattr lossily lstat diff --git a/src/uucore/src/lib/features/fsxattr.rs b/src/uucore/src/lib/features/fsxattr.rs index 1913b0669..1f1356ee5 100644 --- a/src/uucore/src/lib/features/fsxattr.rs +++ b/src/uucore/src/lib/features/fsxattr.rs @@ -79,7 +79,7 @@ pub fn apply_xattrs>( /// `true` if the file has extended attributes (indicating an ACL), `false` otherwise. pub fn has_acl>(file: P) -> bool { // don't use exacl here, it is doing more getxattr call then needed - xattr::list(file).is_ok_and(|acl| { + xattr::list_deref(file).is_ok_and(|acl| { // if we have extra attributes, we have an acl acl.count() > 0 }) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 58bd538e4..a8b0aa372 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -5716,3 +5716,40 @@ fn test_unknown_format_specifier() { .succeeds() .stdout_matches(&re_custom_format); } + +#[cfg(all(unix, not(target_os = "macos")))] +#[test] +fn test_acl_display_symlink() { + use std::process::Command; + + let (at, mut ucmd) = at_and_ucmd!(); + let dir_name = "dir"; + let link_name = "link"; + at.mkdir(dir_name); + + // calling the command directly. xattr requires some dev packages to be installed + // and it adds a complex dependency just for a test + match Command::new("setfacl") + .args(["-d", "-m", "u:bin:rwx", &at.plus_as_string(dir_name)]) + .status() + .map(|status| status.code()) + { + Ok(Some(0)) => {} + Ok(_) => { + println!("test skipped: setfacl failed"); + return; + } + Err(e) => { + println!("test skipped: setfacl failed with {e}"); + return; + } + } + + at.symlink_dir(dir_name, link_name); + + let re_with_acl = Regex::new(r"[a-z-]*\+ .*link").unwrap(); + ucmd.arg("-lLd") + .arg(link_name) + .succeeds() + .stdout_matches(&re_with_acl); +} diff --git a/util/gnu-patches/tests_ls_no_cap.patch b/util/gnu-patches/tests_ls_no_cap.patch index 8e36512ae..c2f48ca21 100644 --- a/util/gnu-patches/tests_ls_no_cap.patch +++ b/util/gnu-patches/tests_ls_no_cap.patch @@ -8,13 +8,13 @@ index 99f0563bc..f7b9e7885 100755 LS_COLORS=ca=1; export LS_COLORS -strace -e capget ls --color=always > /dev/null 2> out || fail=1 -$EGREP 'capget\(' out || skip_ "your ls doesn't call capget" -+strace -e llistxattr ls --color=always > /dev/null 2> out || fail=1 -+$EGREP 'llistxattr\(' out || skip_ "your ls doesn't call llistxattr" ++strace -e listxattr ls --color=always > /dev/null 2> out || fail=1 ++$EGREP 'listxattr\(' out || skip_ "your ls doesn't call listxattr" LS_COLORS=ca=:; export LS_COLORS -strace -e capget ls --color=always > /dev/null 2> out || fail=1 -$EGREP 'capget\(' out && fail=1 -+strace -e llistxattr ls --color=always > /dev/null 2> out || fail=1 -+$EGREP 'llistxattr\(' out && fail=1 ++strace -e listxattr ls --color=always > /dev/null 2> out || fail=1 ++$EGREP 'listxattr\(' out && fail=1 Exit $fail