Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cp: correctly copy ancestor dirs in --parents mode #3894

Closed
wants to merge 3 commits into from

Conversation

jfinkels
Copy link
Collaborator

@jfinkels jfinkels commented Sep 3, 2022

Fix a bug where cp failed to copy ancestor directories when using
the --parents option. For example, before this commit:

$ mkdir -p a/b/c d
$ cp --parents a/b/c d
$ find d
d
d/c

After this commit

$ mkdir -p a/b/c d
$ cp --parents a/b/c d
$ find d
d
d/a
d/a/b
d/a/b/c

This commit also adds the correct messages for --verbose mode:

$ cp -r --parents --verbose a/b/c d
a -> d/a
a/b -> d/a/b
'a/b/c' -> 'd/a/b/c'

Fixes #3332.

.stdout_is("a -> d/a\na/b -> d/a/b\n'a/b/c' -> 'd/a/b/c'\n");
assert!(at.dir_exists("d/a/b/c"));
}

#[test]
#[ignore = "issue #3332"]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two tests below here that are currently ignored. They are marked as "issue #3332", but they are actually covering use cases that are slightly different than the one originally reported in that issue. Because they are slightly different use cases (and completely different code paths), I decided not to try to resolve them in this pull request.

@jfinkels
Copy link
Collaborator Author

jfinkels commented Sep 3, 2022

Okay there are some WIndows issues I need to resolve, but there is another failure reported in the GNU test suite that I want to explain.

The test case tests/cp/src-base-dot.sh claims to verify that

mkdir x y
cd y
cp --verbose -ab ../x/. .

succeeds, prints nothing to stdout, and is a no-op. However, it doesn't actually verify that the operation is a no-op, it only verifies that --verbose prints nothing. It just assumes that the directory x does not get copied into the directory y.

On the main branch, uutils cp will cause the directory x to be copied into the directory y, and nothing will be printed by --verbose (this is incorrect behavior). On this new branch, uutils cp will cause the directory x to be copied into the directory y but now --verbose will print the message ../x/. -> ./x (this is still incorrect behavior).

So the tests/cp/src-base-dot.sh test case was incorrectly passing on the main branch, and now it is correctly marked as a failure.

@sylvestre
Copy link
Contributor

nice:
Warning: Congrats! The gnu test tests/cp/cp-parents is no longer ERROR!

@sylvestre
Copy link
Contributor

Did you see
Error: GNU test failed: tests/cp/src-base-dot. tests/cp/src-base-dot is passing on 'main'. Maybe you have to rebase?

@jfinkels
Copy link
Collaborator Author

Did you see Error: GNU test failed: tests/cp/src-base-dot. tests/cp/src-base-dot is passing on 'main'. Maybe you have to rebase?

Yes, it is an expected failure. The explanation is in my comment above #3894 (comment) and I created a new issue for that here #3897

@sylvestre
Copy link
Contributor

sorry about that :(

@sylvestre
Copy link
Contributor

Seems that it broke a few tests ?


Error: GNU test failed: tests/cp/cp-i. tests/cp/cp-i is passing on 'main'. Maybe you have to rebase?
Error: GNU test failed: tests/cp/src-base-dot. tests/cp/src-base-dot is passing on 'main'. Maybe you have to rebase?

@jfinkels
Copy link
Collaborator Author

tests/cp/src-base-dot is an expected new failure, see my comments above. However, tests/cp/cp-i does seem to be an unexpected new failure, so I'll fix that.

@uutils uutils deleted a comment from github-actions bot Oct 10, 2022
@jfinkels jfinkels force-pushed the cp-parents-dir branch 2 times, most recently from 824ed12 to 15e9566 Compare October 10, 2022 15:12
Before this commit, `cp -a` would terminate with a non-zero status
code on Windows because there are no extended attributes (xattr) to
copy. However, the GNU documentation for cp states

> Try to preserve SELinux security context and extended attributes
> (xattr), but ignore any failure to do that and print no
> corresponding diagnostic.

so it seems reasonable to do nothing instead of exiting with an error
in this case.
@jfinkels
Copy link
Collaborator Author

I'm going to mark this as a draft pull request because there's still some weird behaviors of GNU cp that I haven't quite figure out yet. Specifically, I need to figure out how to get the quoting behavior for cp -v to work in both the cp-i.sh test case and the cp-parents.sh case.

@jfinkels jfinkels marked this pull request as draft October 10, 2022 17:23
Fix a bug where `cp` failed to copy ancestor directories when using
the `--parents` option. For example, before this commit:

    $ mkdir -p a/b/c d
    $ cp --parents a/b/c d
    $ find d
    d
    d/c

After this commit

    $ mkdir -p a/b/c d
    $ cp --parents a/b/c d
    $ find d
    d
    d/a
    d/a/b
    d/a/b/c

This commit also adds the correct messages for `--verbose` mode:

    $ cp -r --parents --verbose a/b/c d
    a -> d/a
    a/b -> d/a/b
    'a/b/c' -> 'd/a/b/c'

Fixes uutils#3332.
@jfinkels jfinkels marked this pull request as ready for review October 11, 2022 02:12
@jfinkels
Copy link
Collaborator Author

jfinkels commented Oct 11, 2022

Okay, this is ready for review again.

ancestors.push(p);
}
for p in ancestors.iter().rev().skip(1) {
println!("{} -> {}", p.display(), target.join(p).display());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ancestors are printed without quotes, so using context_for() is not appropriate here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a good idea to add that info as a comment in the code!

Copy link
Member

@tertsdiepraam tertsdiepraam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused, because the messages don't show up for me with this PR:

❯ touch x/y/z/foo
❯ mkdir bar
❯ cargo run --quiet -- cp --parents --verbose x/y/z/foo bar
'x/y/z/foo' -> 'test2/x/y/z/foo'
❯ rm -r bar/*
❯ cp --parents --verbose x/y/z/foo bar
x -> bar/x
x/y -> bar/x/y
x/y/z -> bar/x/y/z
'x/y/z/foo' -> 'bar/x/y/z/foo'

Also I think this PR does not have the right messages if a part of the subdirectories already. For example, below there is no line x -> bar/x:

❯ mkdir bar/x
❯ cp --parents --verbose x/y/z/foo bar
x/y -> bar/x/y
x/y/z -> bar/x/y/z
'x/y/z/foo' -> 'bar/x/y/z/foo'

(I might be wrong because I couldn't trigger the messages)

Comment on lines +1103 to +1106
let mut ancestors = vec![];
for p in parent.ancestors() {
ancestors.push(p);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this work?

Suggested change
let mut ancestors = vec![];
for p in parent.ancestors() {
ancestors.push(p);
}
let ancestors: Vec<_> = parent.ancestors().collect();

@jfinkels
Copy link
Collaborator Author

I'm going to close this and come back with a pull request that doesn't attempt to implement the --verbose behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cp-parents.sh: cp: recursive copy
3 participants