mirror of
https://github.com/uutils/coreutils
synced 2024-12-12 22:32:53 +00:00
cp: add support for -x/--one-file-system (#1840)
This commit is contained in:
parent
9132d32315
commit
c6927d97c8
5 changed files with 80 additions and 5 deletions
|
@ -347,6 +347,7 @@ tempfile = "= 3.1.0"
|
|||
time = "0.1"
|
||||
unindent = "0.1"
|
||||
uucore = { version=">=0.0.7", package="uucore", path="src/uucore", features=["entries"] }
|
||||
walkdir = "2.2"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
rust-users = { version="0.10", package="users" }
|
||||
|
|
|
@ -431,6 +431,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.arg(Arg::with_name(OPT_NO_DEREFERENCE_PRESERVE_LINKS)
|
||||
.short("d")
|
||||
.help("same as --no-dereference --preserve=links"))
|
||||
.arg(Arg::with_name(OPT_ONE_FILE_SYSTEM)
|
||||
.short("x")
|
||||
.long(OPT_ONE_FILE_SYSTEM)
|
||||
.help("stay on this file system"))
|
||||
|
||||
// TODO: implement the following args
|
||||
.arg(Arg::with_name(OPT_COPY_CONTENTS)
|
||||
|
@ -442,10 +446,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.takes_value(true)
|
||||
.value_name("WHEN")
|
||||
.help("NotImplemented: control creation of sparse files. See below"))
|
||||
.arg(Arg::with_name(OPT_ONE_FILE_SYSTEM)
|
||||
.short("x")
|
||||
.long(OPT_ONE_FILE_SYSTEM)
|
||||
.help("NotImplemented: stay on this file system"))
|
||||
.arg(Arg::with_name(OPT_CONTEXT)
|
||||
.long(OPT_CONTEXT)
|
||||
.takes_value(true)
|
||||
|
@ -563,6 +563,7 @@ impl Options {
|
|||
let not_implemented_opts = vec![
|
||||
OPT_COPY_CONTENTS,
|
||||
OPT_SPARSE,
|
||||
#[cfg(not(any(windows, unix)))]
|
||||
OPT_ONE_FILE_SYSTEM,
|
||||
OPT_CONTEXT,
|
||||
#[cfg(windows)]
|
||||
|
@ -937,7 +938,7 @@ fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult
|
|||
#[cfg(any(windows, target_os = "redox"))]
|
||||
let mut hard_links: Vec<(String, u64)> = vec![];
|
||||
|
||||
for path in WalkDir::new(root) {
|
||||
for path in WalkDir::new(root).same_file_system(options.one_file_system) {
|
||||
let p = or_continue!(path);
|
||||
let is_symlink = fs::symlink_metadata(p.path())?.file_type().is_symlink();
|
||||
let path = if (options.no_dereference || options.dereference) && is_symlink {
|
||||
|
|
|
@ -31,6 +31,12 @@ static TEST_COPY_FROM_FOLDER: &str = "hello_dir_with_file/";
|
|||
static TEST_COPY_FROM_FOLDER_FILE: &str = "hello_dir_with_file/hello_world.txt";
|
||||
static TEST_COPY_TO_FOLDER_NEW: &str = "hello_dir_new";
|
||||
static TEST_COPY_TO_FOLDER_NEW_FILE: &str = "hello_dir_new/hello_world.txt";
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
static TEST_MOUNT_COPY_FROM_FOLDER: &str = "dir_with_mount";
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
static TEST_MOUNT_MOUNTPOINT: &str = "mount";
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
static TEST_MOUNT_OTHER_FILESYSTEM_FILE: &str = "mount/DO_NOT_copy_me.txt";
|
||||
|
||||
#[test]
|
||||
fn test_cp_cp() {
|
||||
|
@ -1001,3 +1007,70 @@ fn test_cp_target_file_dev_null() {
|
|||
|
||||
assert!(at.file_exists(file2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
fn test_cp_one_file_system() {
|
||||
use crate::common::util::AtPath;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
// Test must be run as root (or with `sudo -E`)
|
||||
if scene.cmd("whoami").run().stdout != "root\n" {
|
||||
return;
|
||||
}
|
||||
|
||||
let at = scene.fixtures.clone();
|
||||
let at_src = AtPath::new(&at.plus(TEST_MOUNT_COPY_FROM_FOLDER));
|
||||
let at_dst = AtPath::new(&at.plus(TEST_COPY_TO_FOLDER_NEW));
|
||||
|
||||
// Prepare the mount
|
||||
at_src.mkdir(TEST_MOUNT_MOUNTPOINT);
|
||||
let mountpoint_path = &at_src.plus_as_string(TEST_MOUNT_MOUNTPOINT);
|
||||
|
||||
let _r = scene
|
||||
.cmd("mount")
|
||||
.arg("-t")
|
||||
.arg("tmpfs")
|
||||
.arg("-o")
|
||||
.arg("size=640k") // ought to be enough
|
||||
.arg("tmpfs")
|
||||
.arg(mountpoint_path)
|
||||
.run();
|
||||
assert!(_r.code == Some(0), _r.stderr);
|
||||
|
||||
at_src.touch(TEST_MOUNT_OTHER_FILESYSTEM_FILE);
|
||||
|
||||
// Begin testing -x flag
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("-rx")
|
||||
.arg(TEST_MOUNT_COPY_FROM_FOLDER)
|
||||
.arg(TEST_COPY_TO_FOLDER_NEW)
|
||||
.run();
|
||||
|
||||
// Ditch the mount before the asserts
|
||||
let _r = scene.cmd("umount").arg(mountpoint_path).run();
|
||||
assert!(_r.code == Some(0), _r.stderr);
|
||||
|
||||
assert!(result.success);
|
||||
assert!(!at_dst.file_exists(TEST_MOUNT_OTHER_FILESYSTEM_FILE));
|
||||
// Check if the other files were copied from the source folder hirerarchy
|
||||
for entry in WalkDir::new(at_src.as_string()) {
|
||||
let entry = entry.unwrap();
|
||||
let relative_src = entry
|
||||
.path()
|
||||
.strip_prefix(at_src.as_string())
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap();
|
||||
|
||||
let ft = entry.file_type();
|
||||
match (ft.is_dir(), ft.is_file(), ft.is_symlink()) {
|
||||
(true, _, _) => assert!(at_dst.dir_exists(relative_src)),
|
||||
(_, true, _) => assert!(at_dst.file_exists(relative_src)),
|
||||
(_, _, _) => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
0
tests/fixtures/cp/dir_with_mount/copy_me.txt
vendored
Normal file
0
tests/fixtures/cp/dir_with_mount/copy_me.txt
vendored
Normal file
0
tests/fixtures/cp/dir_with_mount/copy_me/copy_me.txt
vendored
Normal file
0
tests/fixtures/cp/dir_with_mount/copy_me/copy_me.txt
vendored
Normal file
Loading…
Reference in a new issue