Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(730)

Unified Diff: Lib/os.py

Issue 15177: Support os.walk(dir_fd=) and os.fwalk(dir_fd=)
Patch Set: Created 10 months, 4 weeks ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -331,7 +331,16 @@
__all__.extend(["makedirs", "removedirs", "renames"])
-def walk(top, topdown=True, onerror=None, followlinks=False):
+def _isdir_dir_fd(path, dir_fd):
+ """
+ A substitute for os.path.isdir that supports dir_fd.
+ """
+ try:
+ return st.S_ISDIR(stat(path, dir_fd=dir_fd).st_mode)
+ except FileNotFoundError:
+ return False
storchaka 2012/06/25 14:08:10 Should onerror handler be used?
larry 2012/06/25 15:04:13 I have a much better implementation, so this one i
+
+def walk(top=".", topdown=True, onerror=None, followlinks=False, *, dir_fd=None):
"""Directory tree generator.
For each directory in the directory tree rooted at top (including top
@@ -395,36 +404,57 @@
# always suppressed the exception then, rather than blow up for a
# minor reason when (say) a thousand readable directories are still
# left to visit. That logic is copied here.
+ #
+ # Note that listdir and error are globals in this module due
+ # to earlier import-*.
try:
- # Note that listdir and error are globals in this module due
- # to earlier import-*.
- names = listdir(top)
+ if dir_fd is None:
+ close_me = None
+ names = listdir(top)
+ else:
+ close_me = open(top, O_RDONLY, dir_fd=dir_fd)
+ names = listdir(close_me)
except error as err:
+ if close_me is not None:
+ close(close_me)
storchaka 2012/06/25 14:08:10 What if error happens on close?
larry 2012/06/25 15:04:13 Obviated by new implementation.
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
- for name in names:
- if isdir(join(top, name)):
- dirs.append(name)
- else:
- nondirs.append(name)
+ if close_me is not None:
+ for name in names:
+ # name is in directory referenced by close_me!
+ # don't bother joining with top here.
+ if _isdir_dir_fd(name, close_me):
+ dirs.append(name)
+ else:
+ nondirs.append(name)
+ close(close_me)
+ else:
+ for name in names:
+ new_path = join(top, name)
+ if isdir(new_path):
+ dirs.append(name)
+ else:
+ nondirs.append(name)
if topdown:
yield top, dirs, nondirs
for name in dirs:
new_path = join(top, name)
if followlinks or not islink(new_path):
storchaka 2012/06/25 14:08:10 st.S_ISLINK(stat(name, dir_fd=close_me).st_mode) ?
larry 2012/06/25 15:04:13 Obviated by new implementation.
- yield from walk(new_path, topdown, onerror, followlinks)
+ yield from walk(new_path, topdown, onerror, followlinks, dir_fd=dir_fd)
if not topdown:
yield top, dirs, nondirs
__all__.append("walk")
+if (listdir in supports_fd) and ({open, stat} <= supports_dir_fd):
+ supports_dir_fd.add(walk)
-if open in supports_dir_fd:
+if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:
- def fwalk(top, topdown=True, onerror=None, followlinks=False):
+ def fwalk(top=".", topdown=True, onerror=None, followlinks=False, *, dir_fd=None):
"""Directory tree generator.
This behaves exactly like walk(), except that it yields a 4-tuple
@@ -434,9 +464,13 @@
`dirpath`, `dirnames` and `filenames` are identical to walk() output,
and `dirfd` is a file descriptor referring to the directory `dirpath`.
- The advantage of walkfd() over walk() is that it's safe against symlink
+ The advantage of fwalk() over walk() is that it's safe against symlink
races (when followlinks is False).
+ If dir_fd is not None, it should be a file descriptor open to a directory,
+ and top should be relative; top will then be relative to that directory.
+ (dir_fd is always supported for fwalk.)
+
Caution:
Since fwalk() yields file descriptors, those are only valid until the
next iteration step, so you should dup() them if you want to keep them
@@ -455,11 +489,11 @@
"""
# Note: To guard against symlink races, we use the standard
# lstat()/open()/fstat() trick.
- orig_st = lstat(top)
- topfd = open(top, O_RDONLY)
+ orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
+ topfd = open(top, O_RDONLY, dir_fd=dir_fd)
try:
if (followlinks or (st.S_ISDIR(orig_st.st_mode) and
- path.samestat(orig_st, fstat(topfd)))):
+ path.samestat(orig_st, stat(topfd)))):
yield from _fwalk(topfd, top, topdown, onerror, followlinks)
finally:
close(topfd)
@@ -502,7 +536,7 @@
onerror(err)
return
try:
- if followlinks or path.samestat(orig_st, fstat(dirfd)):
+ if followlinks or path.samestat(orig_st, stat(dirfd)):
dirpath = path.join(toppath, name)
yield from _fwalk(dirfd, dirpath, topdown, onerror, followlinks)
finally:
« Doc/library/os.rst ('K') | « Doc/library/os.rst ('k') | Lib/test/test_os.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7