Directory tree generator. This behaves exactly like walk(), except that it yields a 4-tuple dirpath, dirnames, filenames, dirfd `dirpath`, `dirnames` and `filenames` are identical to walk() output, and `dirfd` is a file descriptor referring to the direct
(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None)
| 429 | if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd: |
| 430 | |
| 431 | def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None): |
| 432 | """Directory tree generator. |
| 433 | |
| 434 | This behaves exactly like walk(), except that it yields a 4-tuple |
| 435 | |
| 436 | dirpath, dirnames, filenames, dirfd |
| 437 | |
| 438 | `dirpath`, `dirnames` and `filenames` are identical to walk() output, |
| 439 | and `dirfd` is a file descriptor referring to the directory `dirpath`. |
| 440 | |
| 441 | The advantage of fwalk() over walk() is that it's safe against symlink |
| 442 | races (when follow_symlinks is False). |
| 443 | |
| 444 | If dir_fd is not None, it should be a file descriptor open to a directory, |
| 445 | and top should be relative; top will then be relative to that directory. |
| 446 | (dir_fd is always supported for fwalk.) |
| 447 | |
| 448 | Caution: |
| 449 | Since fwalk() yields file descriptors, those are only valid until the |
| 450 | next iteration step, so you should dup() them if you want to keep them |
| 451 | for a longer period. |
| 452 | |
| 453 | Example: |
| 454 | |
| 455 | import os |
| 456 | for root, dirs, files, rootfd in os.fwalk('python/Lib/email'): |
| 457 | print(root, "consumes", end="") |
| 458 | print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files), |
| 459 | end="") |
| 460 | print("bytes in", len(files), "non-directory files") |
| 461 | if 'CVS' in dirs: |
| 462 | dirs.remove('CVS') # don't visit CVS directories |
| 463 | """ |
| 464 | sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd) |
| 465 | top = fspath(top) |
| 466 | # Note: To guard against symlink races, we use the standard |
| 467 | # lstat()/open()/fstat() trick. |
| 468 | if not follow_symlinks: |
| 469 | orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd) |
| 470 | topfd = open(top, O_RDONLY | O_NONBLOCK, dir_fd=dir_fd) |
| 471 | try: |
| 472 | if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and |
| 473 | path.samestat(orig_st, stat(topfd)))): |
| 474 | yield from _fwalk(topfd, top, isinstance(top, bytes), |
| 475 | topdown, onerror, follow_symlinks) |
| 476 | finally: |
| 477 | close(topfd) |
| 478 | |
| 479 | def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks): |
| 480 | # Note: This uses O(depth of the directory tree) file descriptors: if |