mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
cp: gnu "same-file" test case compatibility (#6190)
* cp: -b doesn't ignore "version control" env * cp: gnu "same-file" test compatibility fix
This commit is contained in:
parent
f78b408830
commit
a1717436a4
4 changed files with 1069 additions and 38 deletions
|
@ -29,8 +29,9 @@ use platform::copy_on_write;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError};
|
use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError};
|
||||||
use uucore::fs::{
|
use uucore::fs::{
|
||||||
are_hardlinks_to_same_file, canonicalize, is_symlink_loop, path_ends_with_terminator,
|
are_hardlinks_to_same_file, canonicalize, get_filename, is_symlink_loop,
|
||||||
paths_refer_to_same_file, FileInformation, MissingHandling, ResolveMode,
|
path_ends_with_terminator, paths_refer_to_same_file, FileInformation, MissingHandling,
|
||||||
|
ResolveMode,
|
||||||
};
|
};
|
||||||
use uucore::{backup_control, update_control};
|
use uucore::{backup_control, update_control};
|
||||||
// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
|
// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
|
||||||
|
@ -1468,16 +1469,23 @@ pub(crate) fn copy_attributes(
|
||||||
fn symlink_file(
|
fn symlink_file(
|
||||||
source: &Path,
|
source: &Path,
|
||||||
dest: &Path,
|
dest: &Path,
|
||||||
context: &str,
|
|
||||||
symlinked_files: &mut HashSet<FileInformation>,
|
symlinked_files: &mut HashSet<FileInformation>,
|
||||||
) -> CopyResult<()> {
|
) -> CopyResult<()> {
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
{
|
{
|
||||||
std::os::unix::fs::symlink(source, dest).context(context)?;
|
std::os::unix::fs::symlink(source, dest).context(format!(
|
||||||
|
"cannot create symlink {} to {}",
|
||||||
|
get_filename(dest).unwrap_or("invalid file name").quote(),
|
||||||
|
get_filename(source).unwrap_or("invalid file name").quote()
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
std::os::windows::fs::symlink_file(source, dest).context(context)?;
|
std::os::windows::fs::symlink_file(source, dest).context(format!(
|
||||||
|
"cannot create symlink {} to {}",
|
||||||
|
get_filename(dest).unwrap_or("invalid file name").quote(),
|
||||||
|
get_filename(source).unwrap_or("invalid file name").quote()
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
if let Ok(file_info) = FileInformation::from_path(dest, false) {
|
if let Ok(file_info) = FileInformation::from_path(dest, false) {
|
||||||
symlinked_files.insert(file_info);
|
symlinked_files.insert(file_info);
|
||||||
|
@ -1489,10 +1497,11 @@ fn context_for(src: &Path, dest: &Path) -> String {
|
||||||
format!("{} -> {}", src.quote(), dest.quote())
|
format!("{} -> {}", src.quote(), dest.quote())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements a simple backup copy for the destination file.
|
/// Implements a simple backup copy for the destination file .
|
||||||
|
/// if is_dest_symlink flag is set to true dest will be renamed to backup_path
|
||||||
/// TODO: for the backup, should this function be replaced by `copy_file(...)`?
|
/// TODO: for the backup, should this function be replaced by `copy_file(...)`?
|
||||||
fn backup_dest(dest: &Path, backup_path: &Path) -> CopyResult<PathBuf> {
|
fn backup_dest(dest: &Path, backup_path: &Path, is_dest_symlink: bool) -> CopyResult<PathBuf> {
|
||||||
if dest.is_symlink() {
|
if is_dest_symlink {
|
||||||
fs::rename(dest, backup_path)?;
|
fs::rename(dest, backup_path)?;
|
||||||
} else {
|
} else {
|
||||||
fs::copy(dest, backup_path)?;
|
fs::copy(dest, backup_path)?;
|
||||||
|
@ -1513,11 +1522,38 @@ fn is_forbidden_to_copy_to_same_file(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// TODO To match the behavior of GNU cp, we also need to check
|
// TODO To match the behavior of GNU cp, we also need to check
|
||||||
// that the file is a regular file.
|
// that the file is a regular file.
|
||||||
|
let source_is_symlink = source.is_symlink();
|
||||||
|
let dest_is_symlink = dest.is_symlink();
|
||||||
|
// only disable dereference if both source and dest is symlink and dereference flag is disabled
|
||||||
let dereference_to_compare =
|
let dereference_to_compare =
|
||||||
options.dereference(source_in_command_line) || !source.is_symlink();
|
options.dereference(source_in_command_line) || (!source_is_symlink || !dest_is_symlink);
|
||||||
paths_refer_to_same_file(source, dest, dereference_to_compare)
|
if !paths_refer_to_same_file(source, dest, dereference_to_compare) {
|
||||||
&& !(options.force() && options.backup != BackupMode::NoBackup)
|
return false;
|
||||||
&& !(dest.is_symlink() && options.backup != BackupMode::NoBackup)
|
}
|
||||||
|
if options.backup != BackupMode::NoBackup {
|
||||||
|
if options.force() && !source_is_symlink {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if source_is_symlink && !options.dereference {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if dest_is_symlink {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if !dest_is_symlink && !source_is_symlink && dest != source {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if options.copy_mode == CopyMode::Link {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if options.copy_mode == CopyMode::SymLink && dest_is_symlink {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if dest_is_symlink && source_is_symlink && !options.dereference {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Back up, remove, or leave intact the destination file, depending on the options.
|
/// Back up, remove, or leave intact the destination file, depending on the options.
|
||||||
|
@ -1526,6 +1562,7 @@ fn handle_existing_dest(
|
||||||
dest: &Path,
|
dest: &Path,
|
||||||
options: &Options,
|
options: &Options,
|
||||||
source_in_command_line: bool,
|
source_in_command_line: bool,
|
||||||
|
copied_files: &mut HashMap<FileInformation, PathBuf>,
|
||||||
) -> CopyResult<()> {
|
) -> CopyResult<()> {
|
||||||
// Disallow copying a file to itself, unless `--force` and
|
// Disallow copying a file to itself, unless `--force` and
|
||||||
// `--backup` are both specified.
|
// `--backup` are both specified.
|
||||||
|
@ -1537,6 +1574,7 @@ fn handle_existing_dest(
|
||||||
options.overwrite.verify(dest)?;
|
options.overwrite.verify(dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut is_dest_removed = false;
|
||||||
let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
|
let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
|
||||||
if let Some(backup_path) = backup_path {
|
if let Some(backup_path) = backup_path {
|
||||||
if paths_refer_to_same_file(source, &backup_path, true) {
|
if paths_refer_to_same_file(source, &backup_path, true) {
|
||||||
|
@ -1547,13 +1585,16 @@ fn handle_existing_dest(
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
} else {
|
} else {
|
||||||
backup_dest(dest, &backup_path)?;
|
is_dest_removed = dest.is_symlink();
|
||||||
|
backup_dest(dest, &backup_path, is_dest_removed)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match options.overwrite {
|
match options.overwrite {
|
||||||
// FIXME: print that the file was removed if --verbose is enabled
|
// FIXME: print that the file was removed if --verbose is enabled
|
||||||
OverwriteMode::Clobber(ClobberMode::Force) => {
|
OverwriteMode::Clobber(ClobberMode::Force) => {
|
||||||
if is_symlink_loop(dest) || fs::metadata(dest)?.permissions().readonly() {
|
if !is_dest_removed
|
||||||
|
&& (is_symlink_loop(dest) || fs::metadata(dest)?.permissions().readonly())
|
||||||
|
{
|
||||||
fs::remove_file(dest)?;
|
fs::remove_file(dest)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1574,7 +1615,19 @@ fn handle_existing_dest(
|
||||||
// `dest/src/f` and `dest/src/f` has the contents of
|
// `dest/src/f` and `dest/src/f` has the contents of
|
||||||
// `src/f`, we delete the existing file to allow the hard
|
// `src/f`, we delete the existing file to allow the hard
|
||||||
// linking.
|
// linking.
|
||||||
if options.preserve_hard_links() {
|
|
||||||
|
if options.preserve_hard_links()
|
||||||
|
// only try to remove dest file only if the current source
|
||||||
|
// is hardlink to a file that is already copied
|
||||||
|
&& copied_files.contains_key(
|
||||||
|
&FileInformation::from_path(
|
||||||
|
source,
|
||||||
|
options.dereference(source_in_command_line),
|
||||||
|
)
|
||||||
|
.context(format!("cannot stat {}", source.quote()))?,
|
||||||
|
)
|
||||||
|
&& !is_dest_removed
|
||||||
|
{
|
||||||
fs::remove_file(dest)?;
|
fs::remove_file(dest)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1700,7 +1753,7 @@ fn handle_copy_mode(
|
||||||
let backup_path =
|
let backup_path =
|
||||||
backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
|
backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
|
||||||
if let Some(backup_path) = backup_path {
|
if let Some(backup_path) = backup_path {
|
||||||
backup_dest(dest, &backup_path)?;
|
backup_dest(dest, &backup_path, dest.is_symlink())?;
|
||||||
fs::remove_file(dest)?;
|
fs::remove_file(dest)?;
|
||||||
}
|
}
|
||||||
if options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
|
if options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
|
||||||
|
@ -1714,7 +1767,11 @@ fn handle_copy_mode(
|
||||||
} else {
|
} else {
|
||||||
fs::hard_link(source, dest)
|
fs::hard_link(source, dest)
|
||||||
}
|
}
|
||||||
.context(context)?;
|
.context(format!(
|
||||||
|
"cannot create hard link {} to {}",
|
||||||
|
get_filename(dest).unwrap_or("invalid file name").quote(),
|
||||||
|
get_filename(source).unwrap_or("invalid file name").quote()
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
CopyMode::Copy => {
|
CopyMode::Copy => {
|
||||||
copy_helper(
|
copy_helper(
|
||||||
|
@ -1731,7 +1788,7 @@ fn handle_copy_mode(
|
||||||
if dest.exists() && options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
|
if dest.exists() && options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
|
||||||
fs::remove_file(dest)?;
|
fs::remove_file(dest)?;
|
||||||
}
|
}
|
||||||
symlink_file(source, dest, context, symlinked_files)?;
|
symlink_file(source, dest, symlinked_files)?;
|
||||||
}
|
}
|
||||||
CopyMode::Update => {
|
CopyMode::Update => {
|
||||||
if dest.exists() {
|
if dest.exists() {
|
||||||
|
@ -1860,8 +1917,10 @@ fn copy_file(
|
||||||
copied_files: &mut HashMap<FileInformation, PathBuf>,
|
copied_files: &mut HashMap<FileInformation, PathBuf>,
|
||||||
source_in_command_line: bool,
|
source_in_command_line: bool,
|
||||||
) -> CopyResult<()> {
|
) -> CopyResult<()> {
|
||||||
|
let source_is_symlink = source.is_symlink();
|
||||||
|
let dest_is_symlink = dest.is_symlink();
|
||||||
// Fail if dest is a dangling symlink or a symlink this program created previously
|
// Fail if dest is a dangling symlink or a symlink this program created previously
|
||||||
if dest.is_symlink() {
|
if dest_is_symlink {
|
||||||
if FileInformation::from_path(dest, false)
|
if FileInformation::from_path(dest, false)
|
||||||
.map(|info| symlinked_files.contains(&info))
|
.map(|info| symlinked_files.contains(&info))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
|
@ -1872,7 +1931,7 @@ fn copy_file(
|
||||||
dest.display()
|
dest.display()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let copy_contents = options.dereference(source_in_command_line) || !source.is_symlink();
|
let copy_contents = options.dereference(source_in_command_line) || !source_is_symlink;
|
||||||
if copy_contents
|
if copy_contents
|
||||||
&& !dest.exists()
|
&& !dest.exists()
|
||||||
&& !matches!(
|
&& !matches!(
|
||||||
|
@ -1898,6 +1957,7 @@ fn copy_file(
|
||||||
}
|
}
|
||||||
|
|
||||||
if are_hardlinks_to_same_file(source, dest)
|
if are_hardlinks_to_same_file(source, dest)
|
||||||
|
&& source != dest
|
||||||
&& matches!(
|
&& matches!(
|
||||||
options.overwrite,
|
options.overwrite,
|
||||||
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
||||||
|
@ -1913,19 +1973,37 @@ fn copy_file(
|
||||||
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
if are_hardlinks_to_same_file(source, dest)
|
if paths_refer_to_same_file(source, dest, true) && options.copy_mode == CopyMode::Link {
|
||||||
&& !options.force()
|
if source_is_symlink {
|
||||||
&& options.backup == BackupMode::NoBackup
|
if !dest_is_symlink {
|
||||||
&& source != dest
|
return Ok(());
|
||||||
|| (source == dest && options.copy_mode == CopyMode::Link)
|
}
|
||||||
{
|
if !options.dereference {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else if options.backup != BackupMode::NoBackup && !dest_is_symlink {
|
||||||
|
if source == dest {
|
||||||
|
if !options.force() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handle_existing_dest(source, dest, options, source_in_command_line, copied_files)?;
|
||||||
|
if are_hardlinks_to_same_file(source, dest) {
|
||||||
|
if options.copy_mode == CopyMode::Copy && options.backup != BackupMode::NoBackup {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if options.copy_mode == CopyMode::Link && (!source_is_symlink || !dest_is_symlink) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handle_existing_dest(source, dest, options, source_in_command_line)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.attributes_only
|
if options.attributes_only
|
||||||
&& source.is_symlink()
|
&& source_is_symlink
|
||||||
&& !matches!(
|
&& !matches!(
|
||||||
options.overwrite,
|
options.overwrite,
|
||||||
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
||||||
|
@ -1981,7 +2059,7 @@ fn copy_file(
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// TODO: implement something similar to gnu's lchown
|
// TODO: implement something similar to gnu's lchown
|
||||||
if !dest.is_symlink() {
|
if !dest_is_symlink {
|
||||||
// Here, to match GNU semantics, we quietly ignore an error
|
// Here, to match GNU semantics, we quietly ignore an error
|
||||||
// if a user does not have the correct ownership to modify
|
// if a user does not have the correct ownership to modify
|
||||||
// the permissions of a file.
|
// the permissions of a file.
|
||||||
|
@ -2130,7 +2208,7 @@ fn copy_link(
|
||||||
if dest.is_symlink() || dest.is_file() {
|
if dest.is_symlink() || dest.is_file() {
|
||||||
fs::remove_file(dest)?;
|
fs::remove_file(dest)?;
|
||||||
}
|
}
|
||||||
symlink_file(&link, dest, &context_for(&link, dest), symlinked_files)
|
symlink_file(&link, dest, symlinked_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate an error message if `target` is not the correct `target_type`
|
/// Generate an error message if `target` is not the correct `target_type`
|
||||||
|
|
|
@ -354,8 +354,13 @@ pub fn determine_backup_mode(matches: &ArgMatches) -> UResult<BackupMode> {
|
||||||
}
|
}
|
||||||
} else if matches.get_flag(arguments::OPT_BACKUP_NO_ARG) {
|
} else if matches.get_flag(arguments::OPT_BACKUP_NO_ARG) {
|
||||||
// the short form of this option, -b does not accept any argument.
|
// the short form of this option, -b does not accept any argument.
|
||||||
// Using -b is equivalent to using --backup=existing.
|
// if VERSION_CONTROL is not set then using -b is equivalent to
|
||||||
Ok(BackupMode::ExistingBackup)
|
// using --backup=existing.
|
||||||
|
if let Ok(method) = env::var("VERSION_CONTROL") {
|
||||||
|
match_method(&method, "$VERSION_CONTROL")
|
||||||
|
} else {
|
||||||
|
Ok(BackupMode::ExistingBackup)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// No option was present at all
|
// No option was present at all
|
||||||
Ok(BackupMode::NoBackup)
|
Ok(BackupMode::NoBackup)
|
||||||
|
@ -578,16 +583,16 @@ mod tests {
|
||||||
assert_eq!(result, BackupMode::SimpleBackup);
|
assert_eq!(result, BackupMode::SimpleBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -b ignores the "VERSION_CONTROL" environment variable
|
// -b doesn't ignores the "VERSION_CONTROL" environment variable
|
||||||
#[test]
|
#[test]
|
||||||
fn test_backup_mode_short_only_ignore_env() {
|
fn test_backup_mode_short_does_not_ignore_env() {
|
||||||
let _dummy = TEST_MUTEX.lock().unwrap();
|
let _dummy = TEST_MUTEX.lock().unwrap();
|
||||||
env::set_var(ENV_VERSION_CONTROL, "none");
|
env::set_var(ENV_VERSION_CONTROL, "numbered");
|
||||||
let matches = make_app().get_matches_from(vec!["command", "-b"]);
|
let matches = make_app().get_matches_from(vec!["command", "-b"]);
|
||||||
|
|
||||||
let result = determine_backup_mode(&matches).unwrap();
|
let result = determine_backup_mode(&matches).unwrap();
|
||||||
|
|
||||||
assert_eq!(result, BackupMode::ExistingBackup);
|
assert_eq!(result, BackupMode::NumberedBackup);
|
||||||
env::remove_var(ENV_VERSION_CONTROL);
|
env::remove_var(ENV_VERSION_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -770,6 +770,25 @@ pub mod sane_blksize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts the filename component from the given `file` path and returns it as an `Option<&str>`.
|
||||||
|
///
|
||||||
|
/// If the `file` path contains a filename, this function returns `Some(filename)` where `filename` is
|
||||||
|
/// the extracted filename as a string slice (`&str`). If the `file` path does not have a filename
|
||||||
|
/// component or if the filename is not valid UTF-8, it returns `None`.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `file`: A reference to a `Path` representing the file path from which to extract the filename.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// * `Some(filename)`: If a valid filename exists in the `file` path, where `filename` is the
|
||||||
|
/// extracted filename as a string slice (`&str`).
|
||||||
|
/// * `None`: If the `file` path does not contain a valid filename or if the filename is not valid UTF-8.
|
||||||
|
pub fn get_filename(file: &Path) -> Option<&str> {
|
||||||
|
file.file_name().and_then(|filename| filename.to_str())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
// Note this useful idiom: importing names from outer (for mod tests) scope.
|
// Note this useful idiom: importing names from outer (for mod tests) scope.
|
||||||
|
@ -1006,4 +1025,9 @@ mod tests {
|
||||||
assert_eq!(0x2000_0000, sane_blksize::sane_blksize(0x2000_0000));
|
assert_eq!(0x2000_0000, sane_blksize::sane_blksize(0x2000_0000));
|
||||||
assert_eq!(512, sane_blksize::sane_blksize(0x2000_0001));
|
assert_eq!(512, sane_blksize::sane_blksize(0x2000_0001));
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_get_file_name() {
|
||||||
|
let file_path = PathBuf::from("~/foo.txt");
|
||||||
|
assert!(matches!(get_filename(&file_path), Some("foo.txt")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// For the full copyright and license information, please view the LICENSE
|
// For the full copyright and license information, please view the LICENSE
|
||||||
// file that was distributed with this source code.
|
// file that was distributed with this source code.
|
||||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR procfs outfile uufs xattrs
|
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR procfs outfile uufs xattrs
|
||||||
|
// spell-checker:ignore bdfl hlsl
|
||||||
use crate::common::util::TestScenario;
|
use crate::common::util::TestScenario;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
use std::fs::set_permissions;
|
use std::fs::set_permissions;
|
||||||
|
@ -3886,3 +3886,927 @@ fn test_cp_no_dereference_attributes_only_with_symlink() {
|
||||||
"file2 content does not match expected"
|
"file2 content does not match expected"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
#[cfg(all(unix, not(target_os = "android")))]
|
||||||
|
#[cfg(test)]
|
||||||
|
/// contains the test for cp when the source and destination points to the same file
|
||||||
|
mod same_file {
|
||||||
|
|
||||||
|
use crate::common::util::TestScenario;
|
||||||
|
|
||||||
|
const FILE_NAME: &str = "foo";
|
||||||
|
const SYMLINK_NAME: &str = "symlink";
|
||||||
|
const CONTENTS: &str = "abcd";
|
||||||
|
|
||||||
|
// the following tests tries to copy a file to the symlink of the same file with
|
||||||
|
// various options
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink() {
|
||||||
|
for option in ["-d", "-f", "-df"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'foo' and 'symlink' are the same file");
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_rem_option() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["--rem", FILE_NAME, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_backup_option() {
|
||||||
|
for option in ["-b", "-bd", "-bf", "-bdf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "symlink~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.symlink_exists(backup));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(SYMLINK_NAME), CONTENTS,);
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_link_option() {
|
||||||
|
for option in ["-l", "-dl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cp: cannot create hard link 'symlink' to 'foo'");
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_options_link_and_force() {
|
||||||
|
for option in ["-fl", "-dfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_options_backup_and_link() {
|
||||||
|
for option in ["-bl", "-bdl", "-bfl", "-bdfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "symlink~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(backup));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_options_symlink() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-s", FILE_NAME, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cp: cannot create symlink 'symlink' to 'foo'");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_symlink_with_options_symlink_and_force() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-sf", FILE_NAME, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
// the following tests tries to copy a symlink to the file that symlink points to with
|
||||||
|
// various options
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_file() {
|
||||||
|
for option in ["-d", "-f", "-df", "--rem"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, SYMLINK_NAME, FILE_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'symlink' and 'foo' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_file_with_option_backup() {
|
||||||
|
for option in ["-b", "-bf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, SYMLINK_NAME, FILE_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'symlink' and 'foo' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_file_with_option_backup_without_deref() {
|
||||||
|
for option in ["-bd", "-bdf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "foo~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, SYMLINK_NAME, FILE_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(backup));
|
||||||
|
assert!(at.symlink_exists(FILE_NAME));
|
||||||
|
// this doesn't makes sense but this is how gnu does it
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(FILE_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(backup), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_file_with_options_link() {
|
||||||
|
for option in ["-l", "-dl", "-fl", "-bl", "-bfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, SYMLINK_NAME, FILE_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_file_with_option_symlink() {
|
||||||
|
for option in ["-s", "-sf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, SYMLINK_NAME, FILE_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'symlink' and 'foo' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following tests tries to copy a file to the same file with various options
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_file() {
|
||||||
|
for option in ["-d", "-f", "-df", "--rem"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, FILE_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'foo' and 'foo' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_file_with_backup() {
|
||||||
|
for option in ["-b", "-bd"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, FILE_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'foo' and 'foo' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_file_with_options_backup_and_no_deref() {
|
||||||
|
for option in ["-bf", "-bdf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "foo~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, FILE_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(at.read(backup), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_file_with_options_link() {
|
||||||
|
for option in ["-l", "-dl", "-fl", "-dfl", "-bl", "-bdl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "foo~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, FILE_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(!at.file_exists(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_file_with_options_link_and_backup_and_force() {
|
||||||
|
for option in ["-bfl", "-bdfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "foo~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, FILE_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(at.read(backup), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_file_with_options_symlink() {
|
||||||
|
for option in ["-s", "-sf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, FILE_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'foo' and 'foo' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following tests tries to copy a symlink that points to a file to a symlink
|
||||||
|
// that points to the same file with various options
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_no_deref() {
|
||||||
|
for option in ["-d", "-df"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&[option, symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_force() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-f", symlink1, symlink2])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'sl1' and 'sl2' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_rem() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&["--rem", symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert!(at.file_exists(symlink2));
|
||||||
|
assert_eq!(at.read(symlink2), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_backup() {
|
||||||
|
for option in ["-b", "-bf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
let backup = "sl2~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&[option, symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert!(at.file_exists(symlink2));
|
||||||
|
assert_eq!(at.read(symlink2), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_backup_and_no_deref() {
|
||||||
|
for option in ["-bd", "-bdf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
let backup = "sl2~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&[option, symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink2));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_link() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-l", symlink1, symlink2])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cannot create hard link 'sl2' to 'sl1'");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_force_link() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&["-fl", symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert!(at.file_exists(symlink2));
|
||||||
|
assert_eq!(at.read(symlink2), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_backup_and_link() {
|
||||||
|
for option in ["-bl", "-bfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
let backup = "sl2~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&[option, symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert!(at.file_exists(symlink2));
|
||||||
|
assert_eq!(at.read(symlink2), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_symlink() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-s", symlink1, symlink2])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cannot create symlink 'sl2' to 'sl1'");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_symlink_to_symlink_with_option_symlink_and_force() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let symlink1 = "sl1";
|
||||||
|
let symlink2 = "sl2";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, symlink1);
|
||||||
|
at.symlink_file(FILE_NAME, symlink2);
|
||||||
|
scene.ucmd().args(&["-sf", symlink1, symlink2]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(symlink1));
|
||||||
|
assert_eq!(symlink1, at.resolve_link(symlink2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following tests tries to copy file to a hardlink of the same file with
|
||||||
|
// various options
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_hardlink() {
|
||||||
|
for option in ["-d", "-f", "-df"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink = "hardlink";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.hard_link(FILE_NAME, hardlink);
|
||||||
|
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, hardlink])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'foo' and 'hardlink' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(hardlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_hardlink_with_option_rem() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink = "hardlink";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.hard_link(FILE_NAME, hardlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["--rem", FILE_NAME, hardlink])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(hardlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_hardlink_with_option_backup() {
|
||||||
|
for option in ["-b", "-bd", "-bf", "-bdf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink = "hardlink";
|
||||||
|
let backup = "hardlink~";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.hard_link(FILE_NAME, hardlink);
|
||||||
|
scene.ucmd().args(&[option, FILE_NAME, hardlink]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(hardlink));
|
||||||
|
assert!(at.file_exists(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_hardlink_with_option_link() {
|
||||||
|
for option in ["-l", "-dl", "-fl", "-dfl", "-bl", "-bdl", "-bfl", "-bdfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink = "hardlink";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.hard_link(FILE_NAME, hardlink);
|
||||||
|
scene.ucmd().args(&[option, FILE_NAME, hardlink]).succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(hardlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_file_to_hardlink_with_option_symlink() {
|
||||||
|
for option in ["-s", "-sf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink = "hardlink";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.hard_link(FILE_NAME, hardlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, FILE_NAME, hardlink])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("'foo' and 'hardlink' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(hardlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following tests tries to copy symlink to a hardlink of the same symlink with
|
||||||
|
// various options
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cp: 'hlsl' and 'symlink' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_force() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-f", hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cp: 'hlsl' and 'symlink' are the same file");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_no_deref() {
|
||||||
|
for option in ["-d", "-df"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_rem() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["--rem", hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert!(!at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(at.read(SYMLINK_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_backup() {
|
||||||
|
for option in ["-b", "-bf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "symlink~";
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert!(!at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert!(at.symlink_exists(backup));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
assert_eq!(at.read(SYMLINK_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_backup_and_no_deref() {
|
||||||
|
for option in ["-bd", "-bdf"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "symlink~";
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert!(at.symlink_exists(backup));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_link() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-l", hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cannot create hard link 'symlink' to 'hlsl'");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_link_and_no_deref() {
|
||||||
|
for option in ["-dl", "-dfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_link_and_force() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-fl", hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert!(!at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_link_and_backup() {
|
||||||
|
for option in ["-bl", "-bfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let backup = "symlink~";
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.file_exists(SYMLINK_NAME));
|
||||||
|
assert!(!at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert!(at.symlink_exists(backup));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(backup));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_options_backup_link_no_deref() {
|
||||||
|
for option in ["-bdl", "-bdfl"] {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&[option, hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_symlink() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-s", hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("cannot create symlink 'symlink' to 'hlsl'");
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_same_file_from_hard_link_of_symlink_to_symlink_with_option_symlink_and_force() {
|
||||||
|
let scene = TestScenario::new(util_name!());
|
||||||
|
let at = &scene.fixtures;
|
||||||
|
let hardlink_to_symlink = "hlsl";
|
||||||
|
at.write(FILE_NAME, CONTENTS);
|
||||||
|
at.symlink_file(FILE_NAME, SYMLINK_NAME);
|
||||||
|
at.hard_link(SYMLINK_NAME, hardlink_to_symlink);
|
||||||
|
scene
|
||||||
|
.ucmd()
|
||||||
|
.args(&["-sf", hardlink_to_symlink, SYMLINK_NAME])
|
||||||
|
.succeeds();
|
||||||
|
assert!(at.file_exists(FILE_NAME));
|
||||||
|
assert!(at.symlink_exists(SYMLINK_NAME));
|
||||||
|
assert!(at.symlink_exists(hardlink_to_symlink));
|
||||||
|
assert_eq!(hardlink_to_symlink, at.resolve_link(SYMLINK_NAME));
|
||||||
|
assert_eq!(FILE_NAME, at.resolve_link(hardlink_to_symlink));
|
||||||
|
assert_eq!(at.read(FILE_NAME), CONTENTS,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue