`shutil.copytree()` incorrectly classifies relative symlinks as dangling
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Python
- Estrellas
- 77.2k
- Forks
- 35.9k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
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
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Comienza en Lib/shutil.py, en _copytree(), e inspecciona el PR vinculado gh-156214 antes de hacer cambios. Reproduce los casos de symlinks relativos del issue y, después, añade o actualiza la cobertura de regresión en las pruebas existentes de shutil para que los enlaces válidos se copien y los enlaces colgantes se ignoren independientemente del directorio de trabajo actual.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- python
- Área
- tooling
- Tipo de issue
- Error
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Estado de actividad
- Estancado
- Claridad
- Bien especificado
- Aptitud para principiantes
- 25/100