diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index 28d1aa702..f50b7e81b 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -395,6 +395,16 @@ fn directory(paths: &[String], b: &Behavior) -> UResult<()> { for path in paths.iter().map(Path::new) { // if the path already exist, don't try to create it again if !path.exists() { + // Special case to match GNU's behavior: + // install -d foo/. should work and just create foo/ + // std::fs::create_dir("foo/."); fails in pure Rust + // See also mkdir.rs for another occurrence of this + let path_to_create = if path.to_string_lossy().ends_with("/.") { + // Do a simple dance to strip the "/." + Path::new(path).components().collect::() + } else { + path.to_path_buf() + }; // Differently than the primary functionality // (MainFunction::Standard), the directory functionality should // create all ancestors (or components) of a directory @@ -404,15 +414,15 @@ fn directory(paths: &[String], b: &Behavior) -> UResult<()> { // target directory. All created ancestor directories will have // the default mode. Hence it is safe to use fs::create_dir_all // and then only modify the target's dir mode. - if let Err(e) = - fs::create_dir_all(path).map_err_context(|| path.maybe_quote().to_string()) + if let Err(e) = fs::create_dir_all(path_to_create.as_path()) + .map_err_context(|| path_to_create.as_path().maybe_quote().to_string()) { show!(e); continue; } if b.verbose { - println!("creating directory {}", path.quote()); + println!("creating directory {}", path_to_create.quote()); } } diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index c4ed0d617..1cbbdfe1c 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -1124,3 +1124,27 @@ fn test_install_missing_destination() { file_1 )); } + +#[test] +fn test_install_dir_dot() { + // To match tests/install/d-slashdot.sh + let scene = TestScenario::new(util_name!()); + + scene.ucmd().arg("-d").arg("dir1/.").succeeds(); + scene.ucmd().arg("-d").arg("dir2/..").succeeds(); + // Tests that we don't have dir3/. in the output + // but only 'dir3' + scene + .ucmd() + .arg("-d") + .arg("dir3/.") + .arg("-v") + .succeeds() + .stdout_contains("creating directory 'dir3'"); + + let at = &scene.fixtures; + + assert!(at.dir_exists("dir1")); + assert!(at.dir_exists("dir2")); + assert!(at.dir_exists("dir3")); +}