diff --git a/.vscode/cspell.dictionaries/jargon.wordlist.txt b/.vscode/cspell.dictionaries/jargon.wordlist.txt index e4c1592b475..16778da940d 100644 --- a/.vscode/cspell.dictionaries/jargon.wordlist.txt +++ b/.vscode/cspell.dictionaries/jargon.wordlist.txt @@ -219,6 +219,9 @@ nofield dtolnay Swatinem +preopened +dotdot + # * clippy uninlined nonminimal diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 063bd7af1ab..632d6ae591d 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1265,7 +1265,19 @@ fn depth_first_list( false, ), PathData::new( - path_data.path().join("..").into(), + // On WASI the sandbox may block access to ".." at the + // preopened root. Fall back to "." so the entry still + // appears with valid metadata instead of an error. + { + let dotdot = path_data.path().join(".."); + #[cfg(target_os = "wasi")] + let dotdot = if dotdot.metadata().is_err() { + path_data.path().into() + } else { + dotdot + }; + dotdot.into() + }, None, Some(OsStr::new("..").into()), config, diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index fbbba1a0a22..fe056008d58 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -7133,3 +7133,18 @@ fn test_ls_non_utf8_hidden() { scene.ucmd().succeeds().stdout_does_not_contain(".hidden"); } + +#[test] +#[cfg(target_os = "wasi")] +fn test_ls_a_dotdot_no_error_on_wasi() { + // On WASI the sandbox may block access to ".." at the preopened root. + // ls -a should still succeed and show ".." without an error message. + let scene = TestScenario::new(util_name!()); + scene + .ucmd() + .arg("-a") + .arg("-1") + .succeeds() + .stdout_contains("..") + .no_stderr(); +}