mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
cp: link-deref gnu test fix (#6378)
Co-authored-by: Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
This commit is contained in:
parent
b718f954e8
commit
2e16cbbd7a
3 changed files with 149 additions and 6 deletions
|
@ -337,10 +337,6 @@ pub(crate) fn copy_directory(
|
|||
copied_files: &mut HashMap<FileInformation, PathBuf>,
|
||||
source_in_command_line: bool,
|
||||
) -> CopyResult<()> {
|
||||
if !options.recursive {
|
||||
return Err(format!("-r not specified; omitting directory {}", root.quote()).into());
|
||||
}
|
||||
|
||||
// if no-dereference is enabled and this is a symlink, copy it as a file
|
||||
if !options.dereference(source_in_command_line) && root.is_symlink() {
|
||||
return copy_file(
|
||||
|
@ -355,6 +351,10 @@ pub(crate) fn copy_directory(
|
|||
);
|
||||
}
|
||||
|
||||
if !options.recursive {
|
||||
return Err(format!("-r not specified; omitting directory {}", root.quote()).into());
|
||||
}
|
||||
|
||||
// check if root is a prefix of target
|
||||
if path_has_prefix(target, root)? {
|
||||
return Err(format!(
|
||||
|
|
|
@ -977,7 +977,9 @@ impl Options {
|
|||
dereference: !(matches.get_flag(options::NO_DEREFERENCE)
|
||||
|| matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS)
|
||||
|| matches.get_flag(options::ARCHIVE)
|
||||
|| recursive)
|
||||
// cp normally follows the link only when not copying recursively or when
|
||||
// --link (-l) is used
|
||||
|| (recursive && CopyMode::from_matches(matches)!= CopyMode::Link ))
|
||||
|| matches.get_flag(options::DEREFERENCE),
|
||||
one_file_system: matches.get_flag(options::ONE_FILE_SYSTEM),
|
||||
parents: matches.get_flag(options::PARENTS),
|
||||
|
@ -2063,7 +2065,13 @@ fn copy_file(
|
|||
} else {
|
||||
fs::symlink_metadata(source)
|
||||
};
|
||||
result.context(context)?
|
||||
// this is just for gnu tests compatibility
|
||||
result.map_err(|err| {
|
||||
if err.to_string().contains("No such file or directory") {
|
||||
return format!("cannot stat {}: No such file or directory", source.quote());
|
||||
}
|
||||
err.to_string()
|
||||
})?
|
||||
};
|
||||
|
||||
let dest_permissions = calculate_dest_permissions(dest, &source_metadata, options, context)?;
|
||||
|
|
|
@ -5307,3 +5307,138 @@ mod same_file {
|
|||
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||
}
|
||||
}
|
||||
|
||||
// the following tests are for how the cp should behave when the source is a symlink
|
||||
// and link option is given
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
mod link_deref {
|
||||
|
||||
use crate::common::util::{AtPath, TestScenario};
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
const FILE: &str = "file";
|
||||
const FILE_LINK: &str = "file_link";
|
||||
const DIR: &str = "dir";
|
||||
const DIR_LINK: &str = "dir_link";
|
||||
const DANG_LINK: &str = "dang_link";
|
||||
const DST: &str = "dst";
|
||||
|
||||
fn setup_link_deref_tests(source: &str, at: &AtPath) {
|
||||
match source {
|
||||
FILE_LINK => {
|
||||
at.touch(FILE);
|
||||
at.symlink_file(FILE, FILE_LINK);
|
||||
}
|
||||
DIR_LINK => {
|
||||
at.mkdir(DIR);
|
||||
at.symlink_dir(DIR, DIR_LINK);
|
||||
}
|
||||
DANG_LINK => at.symlink_file("nowhere", DANG_LINK),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// cp --link shouldn't deref source if -P is given
|
||||
#[test]
|
||||
fn test_cp_symlink_as_source_with_link_and_no_deref() {
|
||||
for src in [FILE_LINK, DIR_LINK, DANG_LINK] {
|
||||
for r in [false, true] {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
setup_link_deref_tests(src, at);
|
||||
let mut args = vec!["--link", "-P", src, DST];
|
||||
if r {
|
||||
args.push("-R");
|
||||
};
|
||||
scene.ucmd().args(&args).succeeds().no_stderr();
|
||||
at.is_symlink(DST);
|
||||
let src_ino = at.symlink_metadata(src).ino();
|
||||
let dest_ino = at.symlink_metadata(DST).ino();
|
||||
assert_eq!(src_ino, dest_ino);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dereferencing should fail for dangling symlink.
|
||||
#[test]
|
||||
fn test_cp_dang_link_as_source_with_link() {
|
||||
for option in ["", "-L", "-H"] {
|
||||
for r in [false, true] {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
setup_link_deref_tests(DANG_LINK, at);
|
||||
let mut args = vec!["--link", DANG_LINK, DST];
|
||||
if r {
|
||||
args.push("-R");
|
||||
};
|
||||
if !option.is_empty() {
|
||||
args.push(option);
|
||||
}
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.fails()
|
||||
.stderr_contains("No such file or directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dereferencing should fail for the 'dir_link' without -R.
|
||||
#[test]
|
||||
fn test_cp_dir_link_as_source_with_link() {
|
||||
for option in ["", "-L", "-H"] {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
setup_link_deref_tests(DIR_LINK, at);
|
||||
let mut args = vec!["--link", DIR_LINK, DST];
|
||||
if !option.is_empty() {
|
||||
args.push(option);
|
||||
}
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.fails()
|
||||
.stderr_contains("cp: -r not specified; omitting directory");
|
||||
}
|
||||
}
|
||||
|
||||
// cp --link -R 'dir_link' should create a new directory.
|
||||
#[test]
|
||||
fn test_cp_dir_link_as_source_with_link_and_r() {
|
||||
for option in ["", "-L", "-H"] {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
setup_link_deref_tests(DIR_LINK, at);
|
||||
let mut args = vec!["--link", "-R", DIR_LINK, DST];
|
||||
if !option.is_empty() {
|
||||
args.push(option);
|
||||
}
|
||||
scene.ucmd().args(&args).succeeds();
|
||||
at.dir_exists(DST);
|
||||
}
|
||||
}
|
||||
|
||||
//cp --link 'file_link' should create a hard link to the target.
|
||||
#[test]
|
||||
fn test_cp_file_link_as_source_with_link() {
|
||||
for option in ["", "-L", "-H"] {
|
||||
for r in [false, true] {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
setup_link_deref_tests(FILE_LINK, at);
|
||||
let mut args = vec!["--link", "-R", FILE_LINK, DST];
|
||||
if !option.is_empty() {
|
||||
args.push(option);
|
||||
}
|
||||
if r {
|
||||
args.push("-R");
|
||||
}
|
||||
scene.ucmd().args(&args).succeeds();
|
||||
at.file_exists(DST);
|
||||
let src_ino = at.symlink_metadata(FILE).ino();
|
||||
let dest_ino = at.symlink_metadata(DST).ino();
|
||||
assert_eq!(src_ino, dest_ino);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue