From 5af152be2c9a01e9d60b3c6922fa012e3d159505 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 22:38:55 +0300 Subject: [PATCH 01/13] uucore/fs: add Not a directory cases handling, e.g. for trailing slashes --- src/uucore/src/lib/features/fs.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/fs.rs b/src/uucore/src/lib/features/fs.rs index 66838c749..2af6a77c9 100644 --- a/src/uucore/src/lib/features/fs.rs +++ b/src/uucore/src/lib/features/fs.rs @@ -22,11 +22,12 @@ use std::collections::VecDeque; use std::env; use std::ffi::{OsStr, OsString}; use std::fs; +use std::fs::read_dir; use std::hash::Hash; use std::io::{Error, ErrorKind, Result as IOResult}; #[cfg(unix)] use std::os::unix::{fs::MetadataExt, io::AsRawFd}; -use std::path::{Component, Path, PathBuf}; +use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR}; #[cfg(target_os = "windows")] use winapi_util::AsHandleRef; @@ -318,6 +319,11 @@ pub fn canonicalize>( ) -> IOResult { const SYMLINKS_TO_LOOK_FOR_LOOPS: i32 = 20; let original = original.as_ref(); + let has_to_be_directory = + (miss_mode == MissingHandling::Normal || miss_mode == MissingHandling::Existing) && { + let path_str = original.to_string_lossy(); + path_str.ends_with(MAIN_SEPARATOR) || path_str.ends_with('/') + }; let original = if original.is_absolute() { original.to_path_buf() } else { @@ -383,6 +389,24 @@ pub fn canonicalize>( _ => {} } } + // raise Not a directory if required + match miss_mode { + MissingHandling::Existing => { + if has_to_be_directory { + read_dir(&result)?; + } + } + MissingHandling::Normal => { + if result.exists() { + if has_to_be_directory { + read_dir(&result)?; + } + } else if let Some(parent) = result.parent() { + read_dir(parent)?; + } + } + _ => {} + } Ok(result) } From 1c6f71e0e1e4116bdc04a6f7c6baaa8426fbed80 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 22:40:00 +0300 Subject: [PATCH 02/13] tests/readlink: add tests for trailing slashes and canonicalize -e and -f usages --- tests/by-util/test_readlink.rs | 264 +++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index acb08a21d..8c7b935bd 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -80,3 +80,267 @@ fn test_symlink_to_itself_verbose() { .code_is(1) .stderr_contains("Too many levels of symbolic links"); } + +#[test] +fn test_trailing_slash_regular_file() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("regfile"); + scene + .ucmd() + .args(&["-ev", "./regfile/"]) + .fails() + .code_is(1) + .stderr_contains("Not a directory") + .no_stdout(); + scene + .ucmd() + .args(&["-e", "./regfile"]) + .succeeds() + .stdout_contains("regfile"); +} + +#[test] +fn test_trailing_slash_symlink_to_regular_file() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("regfile"); + at.relative_symlink_file("regfile", "link"); + scene + .ucmd() + .args(&["-ev", "./link/"]) + .fails() + .code_is(1) + .stderr_contains("Not a directory") + .no_stdout(); + scene + .ucmd() + .args(&["-e", "./link"]) + .succeeds() + .stdout_contains("regfile"); + scene + .ucmd() + .args(&["-ev", "./link/more"]) + .fails() + .code_is(1) + .stderr_contains("Not a directory") + .no_stdout(); +} + +#[test] +fn test_trailing_slash_directory() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("directory"); + for query in ["./directory", "./directory/"] { + scene + .ucmd() + .args(&["-e", query]) + .succeeds() + .stdout_contains("directory"); + } +} + +#[test] +fn test_trailing_slash_symlink_to_directory() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("directory"); + at.relative_symlink_dir("directory", "link"); + for query in ["./link", "./link/"] { + scene + .ucmd() + .args(&["-e", query]) + .succeeds() + .stdout_contains("directory"); + } + scene + .ucmd() + .args(&["-ev", "./link/more"]) + .fails() + .code_is(1) + .stderr_contains("No such file or directory"); +} + +#[test] +fn test_trailing_slash_symlink_to_missing() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("subdir"); + at.relative_symlink_file("missing", "link"); + at.relative_symlink_file("subdir/missing", "link2"); + for query in [ + "missing", + "./missing/", + "link", + "./link/", + "link/more", + "link2", + "./link2/", + "link2/more", + ] { + scene + .ucmd() + .args(&["-ev", query]) + .fails() + .code_is(1) + .stderr_contains("No such file or directory"); + } +} + +#[test] +fn test_canonicalize_trailing_slash_regfile() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("regfile"); + at.relative_symlink_file("regfile", "link1"); + for name in ["regfile", "link1"] { + scene + .ucmd() + .args(&["-f", name]) + .succeeds() + .stdout_contains("regfile"); + scene + .ucmd() + .args(&["-fv", &format!("./{}/", name)]) + .fails() + .code_is(1) + .stderr_contains("Not a directory"); + scene + .ucmd() + .args(&["-fv", &format!("{}/more", name)]) + .fails() + .code_is(1) + .stderr_contains("Not a directory"); + scene + .ucmd() + .args(&["-fv", &format!("./{}/more/", name)]) + .fails() + .code_is(1) + .stderr_contains("Not a directory"); + } +} + +#[test] +fn test_canonicalize_trailing_slash_subdir() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("subdir"); + at.relative_symlink_dir("subdir", "link2"); + for name in ["subdir", "link2"] { + scene + .ucmd() + .args(&["-f", name]) + .succeeds() + .stdout_contains("subdir"); + scene + .ucmd() + .args(&["-f", &format!("./{}/", name)]) + .succeeds() + .stdout_contains("subdir"); + scene + .ucmd() + .args(&["-f", &format!("{}/more", name)]) + .succeeds() + .stdout_contains(path_concat!("subdir", "more")); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/", name)]) + .succeeds() + .stdout_contains(path_concat!("subdir", "more")); + scene + .ucmd() + .args(&["-f", &format!("{}/more/more2", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/more2/", name)]) + .fails() + .code_is(1); + } +} + +#[test] +fn test_canonicalize_trailing_slash_missing() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.relative_symlink_file("missing", "link3"); + for name in ["missing", "link3"] { + scene + .ucmd() + .args(&["-f", name]) + .succeeds() + .stdout_contains("missing"); + scene + .ucmd() + .args(&["-f", &format!("./{}/", name)]) + .succeeds() + .stdout_contains("missing"); + scene + .ucmd() + .args(&["-f", &format!("{}/more", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/", name)]) + .fails() + .code_is(1); + } +} + +#[test] +fn test_canonicalize_trailing_slash_subdir_missing() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("subdir"); + at.relative_symlink_file("subdir/missing", "link4"); + for name in ["link4"] { + scene + .ucmd() + .args(&["-f", name]) + .succeeds() + .stdout_contains(path_concat!("subdir", "missing")); + scene + .ucmd() + .args(&["-f", &format!("./{}/", name)]) + .succeeds() + .stdout_contains(path_concat!("subdir", "missing")); + scene + .ucmd() + .args(&["-f", &format!("{}/more", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/", name)]) + .fails() + .code_is(1); + } +} + +#[test] +fn test_canonicalize_trailing_slash_symlink_loop() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.relative_symlink_file("link5", "link5"); + for name in ["link5"] { + scene.ucmd().args(&["-f", name]).fails().code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("{}/more", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/", name)]) + .fails() + .code_is(1); + } +} From 94860f8af6ed11ede2c1b305cc4679fb49b6f936 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 22:40:29 +0300 Subject: [PATCH 03/13] tests/realpath: add trailing slash usage tests --- tests/by-util/test_realpath.rs | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tests/by-util/test_realpath.rs b/tests/by-util/test_realpath.rs index 2f6bc0f7f..780110fbe 100644 --- a/tests/by-util/test_realpath.rs +++ b/tests/by-util/test_realpath.rs @@ -364,3 +364,92 @@ fn test_relative() { .succeeds() .stdout_is(".\nusr\n"); // spell-checker:disable-line } + +#[test] +fn test_realpath_trailing_slash() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("file"); + at.mkdir("dir"); + at.relative_symlink_file("file", "link_file"); + at.relative_symlink_dir("dir", "link_dir"); + at.relative_symlink_dir("no_dir", "link_no_dir"); + scene + .ucmd() + .arg("link_file") + .succeeds() + .stdout_contains(format!("{}file\n", std::path::MAIN_SEPARATOR)); + scene.ucmd().arg("link_file/").fails().code_is(1); + scene + .ucmd() + .arg("link_dir") + .succeeds() + .stdout_contains(format!("{}dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .arg("link_dir/") + .succeeds() + .stdout_contains(format!("{}dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .arg("link_no_dir") + .succeeds() + .stdout_contains(format!("{}no_dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .arg("link_no_dir/") + .succeeds() + .stdout_contains(format!("{}no_dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-e", "link_file"]) + .succeeds() + .stdout_contains(format!("{}file\n", std::path::MAIN_SEPARATOR)); + scene.ucmd().args(&["-e", "link_file/"]).fails().code_is(1); + scene + .ucmd() + .args(&["-e", "link_dir"]) + .succeeds() + .stdout_contains(format!("{}dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-e", "link_dir/"]) + .succeeds() + .stdout_contains(format!("{}dir\n", std::path::MAIN_SEPARATOR)); + scene.ucmd().args(&["-e", "link_no_dir"]).fails().code_is(1); + scene + .ucmd() + .args(&["-e", "link_no_dir/"]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-m", "link_file"]) + .succeeds() + .stdout_contains(format!("{}file\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-m", "link_file/"]) + .succeeds() + .stdout_contains(format!("{}file\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-m", "link_dir"]) + .succeeds() + .stdout_contains(format!("{}dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-m", "link_dir/"]) + .succeeds() + .stdout_contains(format!("{}dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-m", "link_no_dir"]) + .succeeds() + .stdout_contains(format!("{}no_dir\n", std::path::MAIN_SEPARATOR)); + scene + .ucmd() + .args(&["-m", "link_no_dir/"]) + .succeeds() + .stdout_contains(format!("{}no_dir\n", std::path::MAIN_SEPARATOR)); +} From df403334c01c9e57132c1e0c760ba8139b1d7d87 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 22:43:52 +0300 Subject: [PATCH 04/13] tests/readlink: add spell-checker ignore --- tests/by-util/test_readlink.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 8c7b935bd..a20015ae6 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -1,3 +1,4 @@ +// spell-checker:ignore regfile use crate::common::util::*; static GIBBERISH: &str = "supercalifragilisticexpialidocious"; From e826ab5f0fa101edd6e87fe51b54acf45b292404 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 22:44:56 +0300 Subject: [PATCH 05/13] tests/readlink: follow clippy advice --- tests/by-util/test_readlink.rs | 43 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index a20015ae6..7f8e0ea63 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -297,28 +297,27 @@ fn test_canonicalize_trailing_slash_subdir_missing() { let at = &scene.fixtures; at.mkdir("subdir"); at.relative_symlink_file("subdir/missing", "link4"); - for name in ["link4"] { - scene - .ucmd() - .args(&["-f", name]) - .succeeds() - .stdout_contains(path_concat!("subdir", "missing")); - scene - .ucmd() - .args(&["-f", &format!("./{}/", name)]) - .succeeds() - .stdout_contains(path_concat!("subdir", "missing")); - scene - .ucmd() - .args(&["-f", &format!("{}/more", name)]) - .fails() - .code_is(1); - scene - .ucmd() - .args(&["-f", &format!("./{}/more/", name)]) - .fails() - .code_is(1); - } + let name = "link4"; + scene + .ucmd() + .args(&["-f", name]) + .succeeds() + .stdout_contains(path_concat!("subdir", "missing")); + scene + .ucmd() + .args(&["-f", &format!("./{}/", name)]) + .succeeds() + .stdout_contains(path_concat!("subdir", "missing")); + scene + .ucmd() + .args(&["-f", &format!("{}/more", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/", name)]) + .fails() + .code_is(1); } #[test] From b74e2f9d9b4e7e9cec54ac95301508159f8ddf06 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 22:48:35 +0300 Subject: [PATCH 06/13] tests/readlink: follow clippy advice --- tests/by-util/test_readlink.rs | 37 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 7f8e0ea63..667d66d19 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -324,23 +324,22 @@ fn test_canonicalize_trailing_slash_subdir_missing() { fn test_canonicalize_trailing_slash_symlink_loop() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.relative_symlink_file("link5", "link5"); - for name in ["link5"] { - scene.ucmd().args(&["-f", name]).fails().code_is(1); - scene - .ucmd() - .args(&["-f", &format!("./{}/", name)]) - .fails() - .code_is(1); - scene - .ucmd() - .args(&["-f", &format!("{}/more", name)]) - .fails() - .code_is(1); - scene - .ucmd() - .args(&["-f", &format!("./{}/more/", name)]) - .fails() - .code_is(1); - } + let name = "link5"; + at.relative_symlink_file(name, name); + scene.ucmd().args(&["-f", name]).fails().code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("{}/more", name)]) + .fails() + .code_is(1); + scene + .ucmd() + .args(&["-f", &format!("./{}/more/", name)]) + .fails() + .code_is(1); } From a5e0a14415286229ef0a1677864e4d02cddd93e6 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 23:04:51 +0300 Subject: [PATCH 07/13] tests/readlink: fix Windows "Not a directory" error message --- tests/by-util/test_readlink.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 667d66d19..35951de31 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -3,6 +3,11 @@ use crate::common::util::*; static GIBBERISH: &str = "supercalifragilisticexpialidocious"; +#[cfg(not(windows))] +static NOT_A_DIRECTORY: &str = "Not a directory"; +#[cfg(windows)] +static NOT_A_DIRECTORY: &str = "The directory name is invalid."; + #[test] fn test_resolve() { let scene = TestScenario::new(util_name!()); @@ -92,7 +97,7 @@ fn test_trailing_slash_regular_file() { .args(&["-ev", "./regfile/"]) .fails() .code_is(1) - .stderr_contains("Not a directory") + .stderr_contains(NOT_A_DIRECTORY) .no_stdout(); scene .ucmd() @@ -112,7 +117,7 @@ fn test_trailing_slash_symlink_to_regular_file() { .args(&["-ev", "./link/"]) .fails() .code_is(1) - .stderr_contains("Not a directory") + .stderr_contains(NOT_A_DIRECTORY) .no_stdout(); scene .ucmd() @@ -124,7 +129,7 @@ fn test_trailing_slash_symlink_to_regular_file() { .args(&["-ev", "./link/more"]) .fails() .code_is(1) - .stderr_contains("Not a directory") + .stderr_contains(NOT_A_DIRECTORY) .no_stdout(); } @@ -206,19 +211,19 @@ fn test_canonicalize_trailing_slash_regfile() { .args(&["-fv", &format!("./{}/", name)]) .fails() .code_is(1) - .stderr_contains("Not a directory"); + .stderr_contains(NOT_A_DIRECTORY); scene .ucmd() .args(&["-fv", &format!("{}/more", name)]) .fails() .code_is(1) - .stderr_contains("Not a directory"); + .stderr_contains(NOT_A_DIRECTORY); scene .ucmd() .args(&["-fv", &format!("./{}/more/", name)]) .fails() .code_is(1) - .stderr_contains("Not a directory"); + .stderr_contains(NOT_A_DIRECTORY); } } From 38add34d31d3775b7f832ceb5bf66112b4c46aa1 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 23:31:45 +0300 Subject: [PATCH 08/13] tests/readlink: fix for Windows --- tests/by-util/test_readlink.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 35951de31..8583e5dea 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -126,10 +126,9 @@ fn test_trailing_slash_symlink_to_regular_file() { .stdout_contains("regfile"); scene .ucmd() - .args(&["-ev", "./link/more"]) + .args(&["-e", "./link/more"]) .fails() .code_is(1) - .stderr_contains(NOT_A_DIRECTORY) .no_stdout(); } From 6879ed7b34287eea6e971f33d1231e6dd34d698f Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Mon, 15 Aug 2022 23:33:41 +0300 Subject: [PATCH 09/13] tests/readlink: refactor added tests --- tests/by-util/test_readlink.rs | 90 ++++++++++++++++------------------ 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 8583e5dea..9356ea8a3 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -164,7 +164,8 @@ fn test_trailing_slash_symlink_to_directory() { .args(&["-ev", "./link/more"]) .fails() .code_is(1) - .stderr_contains("No such file or directory"); + .stderr_contains("No such file or directory") + .no_stdout(); } #[test] @@ -189,7 +190,8 @@ fn test_trailing_slash_symlink_to_missing() { .args(&["-ev", query]) .fails() .code_is(1) - .stderr_contains("No such file or directory"); + .stderr_contains("No such file or directory") + .no_stdout(); } } @@ -210,19 +212,22 @@ fn test_canonicalize_trailing_slash_regfile() { .args(&["-fv", &format!("./{}/", name)]) .fails() .code_is(1) - .stderr_contains(NOT_A_DIRECTORY); + .stderr_contains(NOT_A_DIRECTORY) + .no_stdout(); scene .ucmd() .args(&["-fv", &format!("{}/more", name)]) .fails() .code_is(1) - .stderr_contains(NOT_A_DIRECTORY); + .stderr_contains(NOT_A_DIRECTORY) + .no_stdout(); scene .ucmd() .args(&["-fv", &format!("./{}/more/", name)]) .fails() .code_is(1) - .stderr_contains(NOT_A_DIRECTORY); + .stderr_contains(NOT_A_DIRECTORY) + .no_stdout(); } } @@ -257,12 +262,14 @@ fn test_canonicalize_trailing_slash_subdir() { .ucmd() .args(&["-f", &format!("{}/more/more2", name)]) .fails() - .code_is(1); + .code_is(1) + .no_stdout(); scene .ucmd() .args(&["-f", &format!("./{}/more/more2/", name)]) .fails() - .code_is(1); + .code_is(1) + .no_stdout(); } } @@ -286,12 +293,14 @@ fn test_canonicalize_trailing_slash_missing() { .ucmd() .args(&["-f", &format!("{}/more", name)]) .fails() - .code_is(1); + .code_is(1) + .no_stdout(); scene .ucmd() .args(&["-f", &format!("./{}/more/", name)]) .fails() - .code_is(1); + .code_is(1) + .no_stdout(); } } @@ -301,49 +310,34 @@ fn test_canonicalize_trailing_slash_subdir_missing() { let at = &scene.fixtures; at.mkdir("subdir"); at.relative_symlink_file("subdir/missing", "link4"); - let name = "link4"; - scene - .ucmd() - .args(&["-f", name]) - .succeeds() - .stdout_contains(path_concat!("subdir", "missing")); - scene - .ucmd() - .args(&["-f", &format!("./{}/", name)]) - .succeeds() - .stdout_contains(path_concat!("subdir", "missing")); - scene - .ucmd() - .args(&["-f", &format!("{}/more", name)]) - .fails() - .code_is(1); - scene - .ucmd() - .args(&["-f", &format!("./{}/more/", name)]) - .fails() - .code_is(1); + for query in ["link4", "./link4/"] { + scene + .ucmd() + .args(&["-f", query]) + .succeeds() + .stdout_contains(path_concat!("subdir", "missing")); + } + for query in ["link4/more", "./link4/more/"] { + scene + .ucmd() + .args(&["-f", query]) + .fails() + .code_is(1) + .no_stdout(); + } } #[test] fn test_canonicalize_trailing_slash_symlink_loop() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - let name = "link5"; - at.relative_symlink_file(name, name); - scene.ucmd().args(&["-f", name]).fails().code_is(1); - scene - .ucmd() - .args(&["-f", &format!("./{}/", name)]) - .fails() - .code_is(1); - scene - .ucmd() - .args(&["-f", &format!("{}/more", name)]) - .fails() - .code_is(1); - scene - .ucmd() - .args(&["-f", &format!("./{}/more/", name)]) - .fails() - .code_is(1); + at.relative_symlink_file("link5", "link5"); + for query in ["link5", "./link5/", "link5/more", "./link5/more/"] { + scene + .ucmd() + .args(&["-f", query]) + .fails() + .code_is(1) + .no_stdout(); + } } From 391143fe5b260db2fa81acb539e8852c13370f51 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Tue, 16 Aug 2022 08:21:12 +0300 Subject: [PATCH 10/13] readlink: fix -n and -z no delimiter at the end --- src/uu/readlink/src/readlink.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/uu/readlink/src/readlink.rs b/src/uu/readlink/src/readlink.rs index c89752ad6..1d9efed84 100644 --- a/src/uu/readlink/src/readlink.rs +++ b/src/uu/readlink/src/readlink.rs @@ -36,7 +36,7 @@ const ARG_FILES: &str = "files"; pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().get_matches_from(args); - let mut no_newline = matches.contains_id(OPT_NO_NEWLINE); + let mut no_trailing_delimiter = matches.contains_id(OPT_NO_NEWLINE); let use_zero = matches.contains_id(OPT_ZERO); let silent = matches.contains_id(OPT_SILENT) || matches.contains_id(OPT_QUIET); let verbose = matches.contains_id(OPT_VERBOSE); @@ -66,9 +66,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { return Err(UUsageError::new(1, "missing operand")); } - if no_newline && files.len() > 1 && !silent { + if no_trailing_delimiter && files.len() > 1 && !silent { show_error!("ignoring --no-newline with multiple arguments"); - no_newline = false; + no_trailing_delimiter = false; } for f in &files { @@ -79,7 +79,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { canonicalize(&p, can_mode, res_mode) }; match path_result { - Ok(path) => show(&path, no_newline, use_zero).map_err_context(String::new)?, + Ok(path) => show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)?, Err(err) => { if verbose { return Err(USimpleError::new( @@ -167,12 +167,12 @@ pub fn uu_app<'a>() -> Command<'a> { ) } -fn show(path: &Path, no_newline: bool, use_zero: bool) -> std::io::Result<()> { +fn show(path: &Path, no_trailing_delimiter: bool, use_zero: bool) -> std::io::Result<()> { let path = path.to_str().unwrap(); - if use_zero { - print!("{}\0", path); - } else if no_newline { + if no_trailing_delimiter { print!("{}", path); + } else if use_zero { + print!("{}\0", path); } else { println!("{}", path); } From 5d4ad4de13c971a8eff5a08627340c8250564b91 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Tue, 16 Aug 2022 08:21:43 +0300 Subject: [PATCH 11/13] tests/readlink: add test for delimiters usage --- tests/by-util/test_readlink.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 9356ea8a3..5707913b2 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -341,3 +341,34 @@ fn test_canonicalize_trailing_slash_symlink_loop() { .no_stdout(); } } + +#[test] +#[cfg(not(windows))] +fn test_delimiters() { + new_ucmd!() + .args(&["--zero", "-n", "-m", "/a"]) + .succeeds() + .stdout_only("/a"); + new_ucmd!() + .args(&["-n", "-m", "/a"]) + .succeeds() + .stdout_only("/a"); + new_ucmd!() + .args(&["--zero", "-m", "/a"]) + .succeeds() + .stdout_only("/a\0"); + new_ucmd!() + .args(&["-m", "/a"]) + .succeeds() + .stdout_only("/a\n"); + new_ucmd!() + .args(&["--zero", "-n", "-m", "/a", "/a"]) + .succeeds() + .stderr_contains("ignoring --no-newline with multiple arguments") + .stdout_is("/a\0/a\0"); + new_ucmd!() + .args(&["-n", "-m", "/a", "/a"]) + .succeeds() + .stderr_contains("ignoring --no-newline with multiple arguments") + .stdout_is("/a\n/a\n"); +} From 9c97b700ecd7b51dcd2b658a6f291ef1498cb4a6 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Tue, 16 Aug 2022 08:25:02 +0300 Subject: [PATCH 12/13] readlink: reformat using rustfmt --- src/uu/readlink/src/readlink.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/uu/readlink/src/readlink.rs b/src/uu/readlink/src/readlink.rs index 1d9efed84..b2b2ec89b 100644 --- a/src/uu/readlink/src/readlink.rs +++ b/src/uu/readlink/src/readlink.rs @@ -79,7 +79,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { canonicalize(&p, can_mode, res_mode) }; match path_result { - Ok(path) => show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)?, + Ok(path) => { + show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)? + } Err(err) => { if verbose { return Err(USimpleError::new( From 0db17196ca55e37422701d957a709e0650201e64 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Tue, 16 Aug 2022 08:30:47 +0300 Subject: [PATCH 13/13] readlink: follow clippy advice, add semicolon --- src/uu/readlink/src/readlink.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/readlink/src/readlink.rs b/src/uu/readlink/src/readlink.rs index b2b2ec89b..ac72d055e 100644 --- a/src/uu/readlink/src/readlink.rs +++ b/src/uu/readlink/src/readlink.rs @@ -80,7 +80,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; match path_result { Ok(path) => { - show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)? + show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)?; } Err(err) => { if verbose {