python / cpython

The Python programming language
https://www.python.org
Other
63.36k stars 30.34k forks source link

Incorrect shutil.copytree() behaviour with symlinks #91205

Open 76c5dc72-c29b-4d12-862d-ff204cd56a78 opened 2 years ago

76c5dc72-c29b-4d12-862d-ff204cd56a78 commented 2 years ago
BPO 47049
Nosy @vajdaz
PRs
  • python/cpython#31967
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields: ```python assignee = None closed_at = None created_at = labels = ['type-bug', 'library', '3.11'] title = 'Incorrect shutil.copytree() behaviour with symlinks' updated_at = user = 'https://github.com/vajdaz' ``` bugs.python.org fields: ```python activity = actor = 'vajdaz' assignee = 'none' closed = False closed_date = None closer = None components = ['Library (Lib)'] creation = creator = 'vajdaz' dependencies = [] files = [] hgrepos = [] issue_num = 47049 keywords = ['patch'] message_count = 2.0 messages = ['415437', '416700'] nosy_count = 1.0 nosy_names = ['vajdaz'] pr_nums = ['31967'] priority = 'normal' resolution = None stage = 'patch review' status = 'open' superseder = None type = 'behavior' url = 'https://bugs.python.org/issue47049' versions = ['Python 3.11'] ```

    76c5dc72-c29b-4d12-862d-ff204cd56a78 commented 2 years ago

    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.

    76c5dc72-c29b-4d12-862d-ff204cd56a78 commented 2 years ago

    Because I am a first contributor, the automatic quality checks on GitHub have to be manually started by somebody. How can I reqest this and by whom?

    eakr9014 commented 10 months ago

    This still seems to be an issue even though the underlying PR was closed. Even though ignore_dangling_symlinks is passed to recursive calls of copy_tree now, the function will still incorrectly classify symlinks as dangling even if they aren't because it attempts to do a os.readlink relative to the current working directory, not the copied directory

    dabuahoid commented 1 month ago

    The issue is still present in Python 3.12.5 and must be fixed since copied data with enabled option symlinks=False and ignore_dangling_symlinks=True misses all resolved symbolic links file contents.

    dabuahoid commented 1 month ago

    Fix in shutil _copytree could look like:

    linkPath = linkto if os.path.isabs(linkto) else os.path.join(os.path.dirname(srcname), linkto)
    # ignore dangling symlink if the flag is on
    if not os.path.exists(linkPath) and ignore_dangling_symlinks: