Skip to content
Prev Previous commit
Next Next commit
Use DirEntry.stat() where possible.
  • Loading branch information
barneygale committed May 30, 2024
commit aee87db34504dd05682fcbe3ad5d0661337f27ab
18 changes: 11 additions & 7 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,24 +636,28 @@ def onerror(err):

# Version using fd-based APIs to protect against races
def _rmtree_safe_fd(stack, onexc):
func, dir_fd, name, path = stack.pop()
func, dir_fd, name, path, entry = stack.pop()
try:
if func is os.close:
os.close(dir_fd)
elif func is os.rmdir:
os.rmdir(name, dir_fd=dir_fd)
else:
assert func is os.lstat
orig_st = os.lstat(name, dir_fd=dir_fd)
if entry is None:
orig_st = os.lstat(name, dir_fd=dir_fd)
else:
orig_st = entry.stat(follow_symlinks=False)

func = os.open # For error reporting.
fd = os.open(name, os.O_RDONLY | os.O_NONBLOCK, dir_fd=dir_fd)
try:
func = os.path.islink # For error reporting.
if not os.path.samestat(orig_st, os.fstat(fd)):
raise OSError("Cannot call rmtree on a symbolic link")
stack.append((os.rmdir, dir_fd, name, path))
stack.append((os.rmdir, dir_fd, name, path, None))
finally:
stack.append((os.close, fd, name, path))
stack.append((os.close, fd, name, path, None))

func = os.scandir # For error reporting.
with os.scandir(fd) as scandir_it:
Expand All @@ -665,7 +669,7 @@ def _rmtree_safe_fd(stack, onexc):
except OSError:
is_dir = False
if is_dir:
stack.append((os.lstat, fd, entry.name, fullname))
stack.append((os.lstat, fd, entry.name, fullname, entry))
else:
try:
os.unlink(entry.name, dir_fd=fd)
Expand Down Expand Up @@ -733,13 +737,13 @@ def onexc(*args):
path = os.fsdecode(path)
# Note: To guard against symlink races, we use the standard
# lstat()/open()/fstat() trick.
Comment thread
barneygale marked this conversation as resolved.
Outdated
stack = [(os.lstat, dir_fd, path, path)]
stack = [(os.lstat, dir_fd, path, path, None)]
try:
while stack:
_rmtree_safe_fd(stack, onexc)
finally:
while stack:
func, dir_fd, name, path = stack.pop()
func, dir_fd, name, path, entry = stack.pop()
if func is os.close:
os.close(dir_fd)
else:
Expand Down