`shutil.copytree()` incorrectly classifies relative symlinks as dangling
Nessuno ha ancora preso questa issue.
- Lingua principale
- Python
- Stelle
- 77.2k
- Fork
- 35.9k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
Bug report
Bug description:
Summary
shutil.copytree(..., symlinks=False, ignore_dangling_symlinks=True) tests a relative symlink target against the process current working directory rather than against the directory containing the symlink. Consequently, a valid relative symlink can be silently omitted from a successful copy, and a truly dangling symlink can still cause shutil.Error when the current working directory happens to contain a file with the same name as its target.
Affected code
Lib/shutil.py, _copytree():
linkto = os.readlink(srcname)
...
if not os.path.exists(linkto) and ignore_dangling_symlinks:
continue
os.readlink() returns the raw target. A relative target is interpreted by the operating system relative to the symlink's parent directory, but os.path.exists(linkto) interprets it relative to the process current working
directory.
Reproducer
import os
import shutil
import tempfile
with tempfile.TemporaryDirectory() as root:
src = os.path.join(root, "src")
dst = os.path.join(root, "dst")
os.mkdir(src)
with open(os.path.join(src, "target"), "w") as f:
f.write("data")
os.symlink("target", os.path.join(src, "link"))
old_cwd = os.getcwd()
try:
os.chdir(root) # root/target does not exist
shutil.copytree(src, dst, ignore_dangling_symlinks=True)
print("exception: none")
finally:
os.chdir(old_cwd)
print("source link exists?", os.path.lexists(os.path.join(src, "link")))
print("destination entries:", sorted(os.listdir(dst)))
print("destination link exists?", os.path.lexists(os.path.join(dst, "link")))
Actual output:
exception: none
source link exists? True
destination entries: ['target']
destination link exists? False
The source symlink is valid: src/link -> target resolves to src/target. With symlinks=False, the destination should contain a regular link file with the contents of src/target, in addition to target. Instead, the operation returns successfully with an incomplete destination tree.
The inverse case also fails: if src/link -> target is actually dangling but the current working directory contains target, it is not ignored and copytree() raises shutil.Error after creating the destination directory.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-156214
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia in Lib/shutil.py, in _copytree(), e esamina il PR collegato gh-156214 prima di apportare modifiche. Riproduci i casi di symlink relativi dell’issue, quindi aggiungi o aggiorna la copertura di regressione nei test shutil esistenti in modo che i link validi vengano copiati e i link pendenti vengano ignorati indipendentemente dalla directory di lavoro corrente.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python
- Ambito
- tooling
- Tipo di issue
- Bug
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Stato di attività
- Ferma
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 25/100