Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' into gh-73991-rmtree
  • Loading branch information
barneygale committed Jun 2, 2024
commit bdd12556b8bcd053bcfa866ecda374a4b28d1519
79 changes: 42 additions & 37 deletions Lib/os.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,8 @@ def renames(old, new):

__all__.extend(["makedirs", "removedirs", "renames"])

# Private sentinel that can be passed to os.walk() to classify all symlinks as
# files, and walk into every path classified as a directory (potentially after
# user modification in topdown mode). Used by pathlib.Path.walk().
# Private sentinel that makes walk() classify all symlinks and junctions as
# regular files.
_walk_symlinks_as_files = object()

def walk(top, topdown=True, onerror=None, followlinks=False):
Expand Down Expand Up @@ -501,11 +500,38 @@ def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
# necessary, it can be adapted to only require O(1) FDs, see issue
# #13734.

action, value = stack.pop()
if action == _fwalk_close:
close(value)
return
elif action == _fwalk_yield:
yield value
return
assert action == _fwalk_walk
isroot, dirfd, toppath, topname, entry = value
try:
scandir_it = scandir(topfd)
except OSError as error:
error.filename = toppath
raise
if not follow_symlinks:
# Note: To guard against symlink races, we use the standard
# lstat()/open()/fstat() trick.
if entry is None:
orig_st = stat(topname, follow_symlinks=False, dir_fd=dirfd)
else:
orig_st = entry.stat(follow_symlinks=False)
topfd = open(topname, O_RDONLY | O_NONBLOCK, dir_fd=dirfd)
except OSError as err:
if isroot:
raise
if onerror is not None:
onerror(err)
return
stack.append((_fwalk_close, topfd))
if not follow_symlinks:
if isroot and not st.S_ISDIR(orig_st.st_mode):
return
if not path.samestat(orig_st, stat(topfd)):
return

scandir_it = scandir(topfd)
dirs = []
nondirs = []
entries = None if topdown or follow_symlinks else []
Expand Down Expand Up @@ -533,36 +559,15 @@ def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks):
else:
stack.append((_fwalk_yield, (toppath, dirs, nondirs, topfd)))

for name in dirs if entries is None else zip(dirs, entries):
try:
if not follow_symlinks:
if topdown:
orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
else:
assert entries is not None
name, entry = name
orig_st = entry.stat(follow_symlinks=False)
dirfd = open(name, O_RDONLY | O_NONBLOCK, dir_fd=topfd)
except OSError as err:
if onerror is not None:
onerror(err)
continue
try:
if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
dirpath = path.join(toppath, name)
yield from _fwalk(dirfd, dirpath, isbytes,
topdown, onerror, follow_symlinks)
finally:
try:
close(dirfd)
except OSError as err:
err.filename = path.join(toppath, name)
if onerror is not None:
onerror(err)
continue

if not topdown:
yield toppath, dirs, nondirs, topfd
toppath = path.join(toppath, toppath[:0]) # Add trailing slash.
if entries is None:
stack.extend(
(_fwalk_walk, (False, topfd, toppath + name, name, None))
for name in dirs[::-1])
else:
stack.extend(
(_fwalk_walk, (False, topfd, toppath + name, name, entry))
for name, entry in zip(dirs[::-1], entries[::-1]))

__all__.append("fwalk")

Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.