(path, dir_fd, onexc)
| 667 | |
| 668 | # version vulnerable to race conditions |
| 669 | def _rmtree_unsafe(path, dir_fd, onexc): |
| 670 | if dir_fd is not None: |
| 671 | raise NotImplementedError("dir_fd unavailable on this platform") |
| 672 | try: |
| 673 | st = os.lstat(path) |
| 674 | except OSError as err: |
| 675 | onexc(os.lstat, path, err) |
| 676 | return |
| 677 | try: |
| 678 | if _rmtree_islink(st): |
| 679 | # symlinks to directories are forbidden, see bug #1669 |
| 680 | raise OSError("Cannot call rmtree on a symbolic link") |
| 681 | except OSError as err: |
| 682 | onexc(os.path.islink, path, err) |
| 683 | # can't continue even if onexc hook returns |
| 684 | return |
| 685 | def onerror(err): |
| 686 | if not isinstance(err, FileNotFoundError): |
| 687 | onexc(os.scandir, err.filename, err) |
| 688 | results = os.walk(path, topdown=False, onerror=onerror, followlinks=os._walk_symlinks_as_files) |
| 689 | for dirpath, dirnames, filenames in results: |
| 690 | for name in dirnames: |
| 691 | fullname = os.path.join(dirpath, name) |
| 692 | try: |
| 693 | os.rmdir(fullname) |
| 694 | except FileNotFoundError: |
| 695 | continue |
| 696 | except OSError as err: |
| 697 | onexc(os.rmdir, fullname, err) |
| 698 | for name in filenames: |
| 699 | fullname = os.path.join(dirpath, name) |
| 700 | try: |
| 701 | os.unlink(fullname) |
| 702 | except FileNotFoundError: |
| 703 | continue |
| 704 | except OSError as err: |
| 705 | onexc(os.unlink, fullname, err) |
| 706 | try: |
| 707 | os.rmdir(path) |
| 708 | except FileNotFoundError: |
| 709 | pass |
| 710 | except OSError as err: |
| 711 | onexc(os.rmdir, path, err) |
| 712 | |
| 713 | # Version using fd-based APIs to protect against races |
| 714 | def _rmtree_safe_fd(path, dir_fd, onexc): |
nothing calls this directly
no test coverage detected
searching dependent graphs…