mirror of
https://github.com/uutils/coreutils
synced 2024-12-14 15:22:38 +00:00
ln: Implement -L -P to make tests/ln/hard-to-sym.sh work
This commit is contained in:
parent
3ea6720d46
commit
06c2aea1b4
3 changed files with 94 additions and 11 deletions
|
@ -36,6 +36,7 @@ pub struct Settings {
|
||||||
suffix: String,
|
suffix: String,
|
||||||
symbolic: bool,
|
symbolic: bool,
|
||||||
relative: bool,
|
relative: bool,
|
||||||
|
logical: bool,
|
||||||
target_dir: Option<String>,
|
target_dir: Option<String>,
|
||||||
no_target_dir: bool,
|
no_target_dir: bool,
|
||||||
no_dereference: bool,
|
no_dereference: bool,
|
||||||
|
@ -121,9 +122,12 @@ const USAGE: &str = "\
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const FORCE: &str = "force";
|
pub const FORCE: &str = "force";
|
||||||
|
//pub const DIRECTORY: &str = "directory";
|
||||||
pub const INTERACTIVE: &str = "interactive";
|
pub const INTERACTIVE: &str = "interactive";
|
||||||
pub const NO_DEREFERENCE: &str = "no-dereference";
|
pub const NO_DEREFERENCE: &str = "no-dereference";
|
||||||
pub const SYMBOLIC: &str = "symbolic";
|
pub const SYMBOLIC: &str = "symbolic";
|
||||||
|
pub const LOGICAL: &str = "logical";
|
||||||
|
pub const PHYSICAL: &str = "physical";
|
||||||
pub const TARGET_DIRECTORY: &str = "target-directory";
|
pub const TARGET_DIRECTORY: &str = "target-directory";
|
||||||
pub const NO_TARGET_DIRECTORY: &str = "no-target-directory";
|
pub const NO_TARGET_DIRECTORY: &str = "no-target-directory";
|
||||||
pub const RELATIVE: &str = "relative";
|
pub const RELATIVE: &str = "relative";
|
||||||
|
@ -152,6 +156,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let symbolic = matches.is_present(options::SYMBOLIC);
|
||||||
|
|
||||||
let overwrite_mode = if matches.is_present(options::FORCE) {
|
let overwrite_mode = if matches.is_present(options::FORCE) {
|
||||||
OverwriteMode::Force
|
OverwriteMode::Force
|
||||||
} else if matches.is_present(options::INTERACTIVE) {
|
} else if matches.is_present(options::INTERACTIVE) {
|
||||||
|
@ -163,11 +169,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let backup_mode = backup_control::determine_backup_mode(&matches)?;
|
let backup_mode = backup_control::determine_backup_mode(&matches)?;
|
||||||
let backup_suffix = backup_control::determine_backup_suffix(&matches);
|
let backup_suffix = backup_control::determine_backup_suffix(&matches);
|
||||||
|
|
||||||
|
// When we have "-L" or "-L -P", false otherwise
|
||||||
|
let logical = matches.is_present(options::LOGICAL);
|
||||||
|
|
||||||
let settings = Settings {
|
let settings = Settings {
|
||||||
overwrite: overwrite_mode,
|
overwrite: overwrite_mode,
|
||||||
backup: backup_mode,
|
backup: backup_mode,
|
||||||
suffix: backup_suffix,
|
suffix: backup_suffix,
|
||||||
symbolic: matches.is_present(options::SYMBOLIC),
|
symbolic,
|
||||||
|
logical,
|
||||||
relative: matches.is_present(options::RELATIVE),
|
relative: matches.is_present(options::RELATIVE),
|
||||||
target_dir: matches
|
target_dir: matches
|
||||||
.value_of(options::TARGET_DIRECTORY)
|
.value_of(options::TARGET_DIRECTORY)
|
||||||
|
@ -188,9 +198,12 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.infer_long_args(true)
|
.infer_long_args(true)
|
||||||
.arg(backup_control::arguments::backup())
|
.arg(backup_control::arguments::backup())
|
||||||
.arg(backup_control::arguments::backup_no_args())
|
.arg(backup_control::arguments::backup_no_args())
|
||||||
// TODO: opts.arg(
|
/*.arg(
|
||||||
// Arg::new(("d", "directory", "allow users with appropriate privileges to attempt \
|
Arg::new(options::DIRECTORY)
|
||||||
// to make hard links to directories");
|
.short('d')
|
||||||
|
.long(options::DIRECTORY)
|
||||||
|
.help("allow users with appropriate privileges to attempt to make hard links to directories")
|
||||||
|
)*/
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FORCE)
|
Arg::new(options::FORCE)
|
||||||
.short('f')
|
.short('f')
|
||||||
|
@ -212,15 +225,24 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
symbolic link to a directory",
|
symbolic link to a directory",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
// TODO: opts.arg(
|
.arg(
|
||||||
// Arg::new(("L", "logical", "dereference TARGETs that are symbolic links");
|
Arg::new(options::LOGICAL)
|
||||||
//
|
.short('L')
|
||||||
// TODO: opts.arg(
|
.long(options::LOGICAL)
|
||||||
// Arg::new(("P", "physical", "make hard links directly to symbolic links");
|
.help("dereference TARGETs that are symbolic links")
|
||||||
|
.overrides_with(options::PHYSICAL),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
// Not implemented yet
|
||||||
|
Arg::new(options::PHYSICAL)
|
||||||
|
.short('P')
|
||||||
|
.long(options::PHYSICAL)
|
||||||
|
.help("make hard links directly to symbolic links"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::SYMBOLIC)
|
Arg::new(options::SYMBOLIC)
|
||||||
.short('s')
|
.short('s')
|
||||||
.long("symbolic")
|
.long(options::SYMBOLIC)
|
||||||
.help("make symbolic links instead of hard links")
|
.help("make symbolic links instead of hard links")
|
||||||
// override added for https://github.com/uutils/coreutils/issues/2359
|
// override added for https://github.com/uutils/coreutils/issues/2359
|
||||||
.overrides_with(options::SYMBOLIC),
|
.overrides_with(options::SYMBOLIC),
|
||||||
|
@ -446,7 +468,15 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> {
|
||||||
if settings.symbolic {
|
if settings.symbolic {
|
||||||
symlink(&source, dst)?;
|
symlink(&source, dst)?;
|
||||||
} else {
|
} else {
|
||||||
fs::hard_link(&source, dst)?;
|
let p = if settings.logical && is_symlink(&source) {
|
||||||
|
// if we want to have an hard link,
|
||||||
|
// source is a symlink and -L is passed
|
||||||
|
// we want to resolve the symlink to create the hardlink
|
||||||
|
std::fs::canonicalize(&source)?
|
||||||
|
} else {
|
||||||
|
source.to_path_buf()
|
||||||
|
};
|
||||||
|
fs::hard_link(&p, dst)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.verbose {
|
if settings.verbose {
|
||||||
|
|
|
@ -650,3 +650,55 @@ fn test_backup_force() {
|
||||||
// we should have the same content as b as we had time to do a backup
|
// we should have the same content as b as we had time to do a backup
|
||||||
assert_eq!(at.read("b~"), "b2\n");
|
assert_eq!(at.read("b~"), "b2\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hard_logical() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let file_a = "file1";
|
||||||
|
let link = "symlink1";
|
||||||
|
let target = "hard-to-a";
|
||||||
|
let target2 = "hard-to-a2";
|
||||||
|
at.touch(file_a);
|
||||||
|
at.symlink_file(file_a, link);
|
||||||
|
|
||||||
|
ucmd.args(&["-P", "-L", link, target]);
|
||||||
|
assert!(!at.is_symlink(target));
|
||||||
|
|
||||||
|
ucmd.args(&["-P", "-L", "-s", link, target2]);
|
||||||
|
assert!(!at.is_symlink(target2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hard_logical_non_exit_fail() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
|
||||||
|
let file_a = "/no-such-dir";
|
||||||
|
let link = "hard-to-dangle";
|
||||||
|
|
||||||
|
scene.ucmd().args(&["-s", file_a]);
|
||||||
|
assert!(!at.is_symlink("no-such-dir"));
|
||||||
|
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-L", "no-such-dir", link])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("failed to link 'no-such-dir'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hard_logical_dir_fail() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let dir = "d";
|
||||||
|
at.mkdir(dir);
|
||||||
|
let target = "link-to-dir";
|
||||||
|
|
||||||
|
scene.ucmd().args(&["-s", dir, target]);
|
||||||
|
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-L", target, "hard-to-dir-link"])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("failed to link 'link-to-dir'");
|
||||||
|
}
|
||||||
|
|
|
@ -198,3 +198,4 @@ sed -i -e "s/provoked error./provoked error\ncat pat |sort -u > pat/" tests/misc
|
||||||
|
|
||||||
# Update the GNU error message to match ours
|
# Update the GNU error message to match ours
|
||||||
sed -i -e "s/ln: 'f' and 'f' are the same file/ln: failed to link 'f' to 'f': Same file/g" tests/ln/hard-backup.sh
|
sed -i -e "s/ln: 'f' and 'f' are the same file/ln: failed to link 'f' to 'f': Same file/g" tests/ln/hard-backup.sh
|
||||||
|
sed -i -e "s/failed to access 'no-such-dir'\":/failed to link 'no-such-dir'\"/" -e "s/link-to-dir: hard link not allowed for directory/failed to link 'link-to-dir' to/" -e "s|link-to-dir/: hard link not allowed for directory|failed to link 'link-to-dir/' to|" tests/ln/hard-to-sym.sh
|
Loading…
Reference in a new issue