Skip to content

bpo-47049: Fix incorrect shutil.copytree() behaviour with symlinks #31967

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

Closed

Conversation

vajdaz
Copy link

@vajdaz vajdaz commented Mar 17, 2022

shutil.copytree incorrectly does not copy symlink contents if called
with symlink=False and ignore_dangling_symlinks=True.

The wrong behaviour can be reproduced like this:

$ tree
.
└── a
    ├── a.txt
    └── b
        └── a.txt -> ../a.txt

$ python3 -c "import shutil;shutil.copytree('a/b', 'c', symlinks=False, ignore_dangling_symlinks=True)"

As a result directoy c will be created but it will remain empty.
Expected result is a file c/a.txt with the contents of a/b/a.txt.

https://bugs.python.org/issue47049

@vajdaz
Copy link
Author

vajdaz commented Apr 17, 2022

Something in the CLA signing check process changed (old checking service unavailable), and therefore the check fails although I signed the CLA. How can this be fixed? Do I have to do something, or does a a maintainer have to do something?

@MaxwellDupre
Copy link
Contributor

I have tested with test_shutil (and the example given) and it looks fine, but it looks like there are tests (in test_shutil) which are negative due to this bug.
Could you check to see if some tests need to be changed? Possibly test_copytree_dangling_symlinks.
If none then can you add a test for this change?

@vajdaz
Copy link
Author

vajdaz commented May 3, 2022

I have added a unit test to the fix. That revealed another issue. When dangling symlinks do exist in this situation, an error was thrown, because the ignore_dangling_symlinks argument of the copytree function was not propagated to recursive calls. This is fixed by the last commit, too.

vajdaz and others added 5 commits May 4, 2022 19:02
shutil.copytree incorrectly does not copy symlink contents if called
with symlink=False and ignore_dangling_symlinks=True.

The wrong behaviour can be reproduced like this:

$ tree
.
└── a
    ├── a.txt
    └── b
        └── a.txt -> ../a.txt

$ python3 -c "import shutil;shutil.copytree('a/b', 'c', symlinks=False, ignore_dangling_symlinks=True)"

As a result directoy c will be created but it will remain empty.
Expected result is a file c/a.txt with the contents of a/b/a.txt.
Co-authored-by: Oleg Iarygin <dralife@yandex.ru>
The test creates following filesystem structure:

src_dir
├── test.txt
└── subdir
    ├── doesnotexist.txt -> IDONOTEXIST
    └── test.txt -> ../test.txt

Then it uses copytree with symlinks=False and ignore_dangling_symlinks=True
As a result, in the destination file structure the symlink should become
a file and its contents should be the same as that of the original source
file that the symlink was pointing to. The symlink doesnotexist.txt
should be ignored, no error should occur, and no copy should appear in
the destination file tree.

The test revaled another issue with the _copytree implementation, which
was fixed, too.
@vajdaz vajdaz force-pushed the fix-copytree-symlink-plus-ignore-dangling branch from 4051578 to a60f119 Compare May 4, 2022 17:20
The unit test in the prevous commit did not test the case that failed
prior to the fix, it also succeeded with Python versions containing
the bug. Now it tests exaclty the same situation that is described in
issue 47049.
@vajdaz vajdaz force-pushed the fix-copytree-symlink-plus-ignore-dangling branch from a60f119 to f510c51 Compare May 4, 2022 17:59
@vajdaz
Copy link
Author

vajdaz commented May 24, 2022

@MaxwellDupre can you please have a look on this again?

Copy link
Contributor

@MaxwellDupre MaxwellDupre left a comment

Choose a reason for hiding this comment

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

LGTM: module and given tests run ok.
However, there is a lot of comments Lib/test/test_shutil.py esp lines 771-778. Most comment for tests are only a few lines.
You already hae ref'ed the Issue 47049 so people can go look that up if they want or check the PR.
Hence, you description lines 779 onwards could be a little shorter too.

vajdaz added 2 commits May 25, 2022 15:23
As a result of the code review the test comments were reduced.
@vajdaz
Copy link
Author

vajdaz commented May 25, 2022

LGTM: module and given tests run ok. However, there is a lot of comments Lib/test/test_shutil.py esp lines 771-778. Most comment for tests are only a few lines. You already hae ref'ed the Issue 47049 so people can go look that up if they want or check the PR. Hence, you description lines 779 onwards could be a little shorter too.
@MaxwellDupre I cut the comment.

@vajdaz
Copy link
Author

vajdaz commented Jun 21, 2022

ping @MaxwellDupre

Copy link
Contributor

@MaxwellDupre MaxwellDupre left a comment

Choose a reason for hiding this comment

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

Better but still a few extra words.

@vajdaz
Copy link
Author

vajdaz commented Jun 22, 2022

Better but still a few extra words.

@MaxwellDupre :) How about now?

@MaxwellDupre
Copy link
Contributor

Better, but I cant do anymore. I have already approved and now waiting core review.

@vajdaz
Copy link
Author

vajdaz commented Nov 16, 2022

Seems that this has been solved in #22937 and it is also a duplicate of #82704. Therefore I close this PR.

@dabuahoid
Copy link

The issue is still present in Python 3.12.6 and also an open case exists: #91205 (comment)

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

Successfully merging this pull request may close these issues.

7 participants