ls: restore WASI ".." metadata fallback in collect_directory_entries (#11930)

* ls: restore WASI ".." metadata fallback in collect_directory_entries

The ls refactor in #9851 dropped the WASI guard added in #11633, so
`ls -al` at a preopened root once again fails with "Capabilities
insufficient" when stat'ing "..". Extract the logic into a small
`dotdot_path` helper and add a regression test covering `ls -al`.

* Update spell-checker ignore words in test_ls.rs
This commit is contained in:
Sylvestre Ledru
2026-04-22 14:07:02 +02:00
committed by GitHub
parent 444e383622
commit fd781df60a
2 changed files with 33 additions and 2 deletions
+15 -1
View File
@@ -1248,6 +1248,20 @@ pub fn list_with_output<O: LsOutput>(
Ok(())
}
/// Build the path for the ".." entry of `parent`.
///
/// On WASI the sandbox may block access to ".." at the preopened root,
/// so fall back to the parent path itself when its metadata can't be
/// read. On other targets this is just `parent/..`.
fn dotdot_path(parent: &Path) -> PathBuf {
let dotdot = parent.join("..");
#[cfg(target_os = "wasi")]
if dotdot.metadata().is_err() {
return parent.to_path_buf();
}
dotdot
}
fn collect_directory_entries<O: LsOutput>(
entries: &mut Vec<PathData>,
path_data: &PathData,
@@ -1266,7 +1280,7 @@ fn collect_directory_entries<O: LsOutput>(
false,
));
entries.push(PathData::new(
path_data.path().join("..").into(),
dotdot_path(path_data.path()).into(),
None,
Some(OsStr::new("..").into()),
config,
+18 -1
View File
@@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) READMECAREFULLY birthtime doesntexist oneline somebackup lrwx somefile somegroup somehiddenbackup somehiddenfile tabsize aaaaaaaa bbbb cccc dddddddd ncccc neee naaaaa nbcdef nfffff dired subdired tmpfs mdir COLORTERM mexe bcdef mfoo timefile
// spell-checker:ignore (words) fakeroot setcap drwxr bcdlps mdangling mentry awith acolons NOFILE
// spell-checker:ignore (words) fakeroot setcap drwxr bcdlps mdangling mentry awith acolons NOFILE NOTCAPABLE
#![allow(
clippy::similar_names,
clippy::too_many_lines,
@@ -7244,3 +7244,20 @@ fn test_ls_a_dotdot_no_error_on_wasi() {
.stdout_contains("..")
.no_stderr();
}
#[test]
#[cfg(target_os = "wasi")]
fn test_ls_al_no_capabilities_insufficient_on_wasi() {
// `ls -al` reads metadata for every entry including "..". Without the
// WASI fallback, stat on ".." at the preopened root returns
// ERRNO_NOTCAPABLE, which surfaces to the user as "Capabilities
// insufficient". Guard against that regression here.
let scene = TestScenario::new(util_name!());
let out = scene.ucmd().arg("-al").succeeds();
out.no_stderr();
assert!(
!out.stdout_str().contains("Capabilities insufficient"),
"ls -al stdout leaked a WASI capability error: {}",
out.stdout_str()
);
}