(stack, isbytes, topdown, onerror, follow_symlinks)
| 489 | _fwalk_close = 2 # args: dirfd |
| 490 | |
| 491 | def _fwalk(stack, isbytes, topdown, onerror, follow_symlinks): |
| 492 | # Note: This uses O(depth of the directory tree) file descriptors: if |
| 493 | # necessary, it can be adapted to only require O(1) FDs, see issue |
| 494 | # #13734. |
| 495 | |
| 496 | action, value = stack.pop() |
| 497 | if action == _fwalk_close: |
| 498 | close(value) |
| 499 | return |
| 500 | elif action == _fwalk_yield: |
| 501 | yield value |
| 502 | return |
| 503 | assert action == _fwalk_walk |
| 504 | isroot, dirfd, toppath, topname, entry = value |
| 505 | try: |
| 506 | if not follow_symlinks: |
| 507 | # Note: To guard against symlink races, we use the standard |
| 508 | # lstat()/open()/fstat() trick. |
| 509 | if entry is None: |
| 510 | orig_st = stat(topname, follow_symlinks=False, dir_fd=dirfd) |
| 511 | else: |
| 512 | orig_st = entry.stat(follow_symlinks=False) |
| 513 | topfd = open(topname, O_RDONLY | O_NONBLOCK, dir_fd=dirfd) |
| 514 | except OSError as err: |
| 515 | if isroot: |
| 516 | raise |
| 517 | if onerror is not None: |
| 518 | onerror(err) |
| 519 | return |
| 520 | stack.append((_fwalk_close, topfd)) |
| 521 | if not follow_symlinks: |
| 522 | if isroot and not st.S_ISDIR(orig_st.st_mode): |
| 523 | return |
| 524 | if not path.samestat(orig_st, stat(topfd)): |
| 525 | return |
| 526 | |
| 527 | scandir_it = scandir(topfd) |
| 528 | dirs = [] |
| 529 | nondirs = [] |
| 530 | entries = None if topdown or follow_symlinks else [] |
| 531 | for entry in scandir_it: |
| 532 | name = entry.name |
| 533 | if isbytes: |
| 534 | name = fsencode(name) |
| 535 | try: |
| 536 | if entry.is_dir(): |
| 537 | dirs.append(name) |
| 538 | if entries is not None: |
| 539 | entries.append(entry) |
| 540 | else: |
| 541 | nondirs.append(name) |
| 542 | except OSError: |
| 543 | try: |
| 544 | # Add dangling symlinks, ignore disappeared files |
| 545 | if entry.is_symlink(): |
| 546 | nondirs.append(name) |
| 547 | except OSError: |
| 548 | pass |
no test coverage detected