bpo-46245: Add optional parameter dir_fd in shutil.rmtree() (GH-30365)

This commit is contained in:
Serhiy Storchaka 2022-03-09 14:29:33 +02:00 committed by GitHub
parent 5eb03b1b51
commit 02fbaf4887
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 7 deletions

View file

@ -684,9 +684,14 @@ _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
os.scandir in os.supports_fd and
os.stat in os.supports_follow_symlinks)
def rmtree(path, ignore_errors=False, onerror=None):
def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None):
"""Recursively delete a directory tree.
If dir_fd is not None, it should be a file descriptor open to a directory;
path will then be relative to that directory.
dir_fd may not be implemented on your platform.
If it is unavailable, using it will raise a NotImplementedError.
If ignore_errors is set, errors are ignored; otherwise, if onerror
is set, it is called to handle the error with arguments (func,
path, exc_info) where func is platform and implementation dependent;
@ -695,7 +700,7 @@ def rmtree(path, ignore_errors=False, onerror=None):
is false and onerror is None, an exception is raised.
"""
sys.audit("shutil.rmtree", path)
sys.audit("shutil.rmtree", path, dir_fd)
if ignore_errors:
def onerror(*args):
pass
@ -709,12 +714,12 @@ def rmtree(path, ignore_errors=False, onerror=None):
# Note: To guard against symlink races, we use the standard
# lstat()/open()/fstat() trick.
try:
orig_st = os.lstat(path)
orig_st = os.lstat(path, dir_fd=dir_fd)
except Exception:
onerror(os.lstat, path, sys.exc_info())
return
try:
fd = os.open(path, os.O_RDONLY)
fd = os.open(path, os.O_RDONLY, dir_fd=dir_fd)
fd_closed = False
except Exception:
onerror(os.open, path, sys.exc_info())
@ -725,7 +730,7 @@ def rmtree(path, ignore_errors=False, onerror=None):
try:
os.close(fd)
fd_closed = True
os.rmdir(path)
os.rmdir(path, dir_fd=dir_fd)
except OSError:
onerror(os.rmdir, path, sys.exc_info())
else:
@ -738,6 +743,8 @@ def rmtree(path, ignore_errors=False, onerror=None):
if not fd_closed:
os.close(fd)
else:
if dir_fd is not None:
raise NotImplementedError("dir_fd unavailable on this platform")
try:
if _rmtree_islink(path):
# symlinks to directories are forbidden, see bug #1669