|
12 | 12 | """
|
13 | 13 |
|
14 | 14 | import functools
|
| 15 | +import posixpath |
15 | 16 | from glob import _Globber, _no_recurse_symlinks
|
16 |
| -from errno import ENOTDIR, ELOOP |
17 | 17 | from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
|
18 | 18 |
|
19 | 19 |
|
@@ -696,65 +696,34 @@ def resolve(self, strict=False):
|
696 | 696 | """
|
697 | 697 | if self._resolving:
|
698 | 698 | return self
|
699 |
| - path_root, parts = self._stack |
700 |
| - path = self.with_segments(path_root) |
701 |
| - try: |
702 |
| - path = path.absolute() |
703 |
| - except UnsupportedOperation: |
704 |
| - path_tail = [] |
705 |
| - else: |
706 |
| - path_root, path_tail = path._stack |
707 |
| - path_tail.reverse() |
708 |
| - |
709 |
| - # If the user has *not* overridden the `readlink()` method, then symlinks are unsupported |
710 |
| - # and (in non-strict mode) we can improve performance by not calling `stat()`. |
711 |
| - querying = strict or getattr(self.readlink, '_supported', True) |
712 |
| - link_count = 0 |
713 |
| - while parts: |
714 |
| - part = parts.pop() |
715 |
| - if not part or part == '.': |
716 |
| - continue |
717 |
| - if part == '..': |
718 |
| - if not path_tail: |
719 |
| - if path_root: |
720 |
| - # Delete '..' segment immediately following root |
721 |
| - continue |
722 |
| - elif path_tail[-1] != '..': |
723 |
| - # Delete '..' segment and its predecessor |
724 |
| - path_tail.pop() |
725 |
| - continue |
726 |
| - path_tail.append(part) |
727 |
| - if querying and part != '..': |
728 |
| - path = self.with_segments(path_root + self.parser.sep.join(path_tail)) |
| 699 | + |
| 700 | + def getcwd(): |
| 701 | + return str(self.with_segments().absolute()) |
| 702 | + |
| 703 | + if strict or getattr(self.readlink, '_supported', True): |
| 704 | + def lstat(path_str): |
| 705 | + path = self.with_segments(path_str) |
729 | 706 | path._resolving = True
|
730 |
| - try: |
731 |
| - st = path.stat(follow_symlinks=False) |
732 |
| - if S_ISLNK(st.st_mode): |
733 |
| - # Like Linux and macOS, raise OSError(errno.ELOOP) if too many symlinks are |
734 |
| - # encountered during resolution. |
735 |
| - link_count += 1 |
736 |
| - if link_count >= self._max_symlinks: |
737 |
| - raise OSError(ELOOP, "Too many symbolic links in path", self._raw_path) |
738 |
| - target_root, target_parts = path.readlink()._stack |
739 |
| - # If the symlink target is absolute (like '/etc/hosts'), set the current |
740 |
| - # path to its uppermost parent (like '/'). |
741 |
| - if target_root: |
742 |
| - path_root = target_root |
743 |
| - path_tail.clear() |
744 |
| - else: |
745 |
| - path_tail.pop() |
746 |
| - # Add the symlink target's reversed tail parts (like ['hosts', 'etc']) to |
747 |
| - # the stack of unresolved path parts. |
748 |
| - parts.extend(target_parts) |
749 |
| - continue |
750 |
| - elif parts and not S_ISDIR(st.st_mode): |
751 |
| - raise NotADirectoryError(ENOTDIR, "Not a directory", self._raw_path) |
752 |
| - except OSError: |
753 |
| - if strict: |
754 |
| - raise |
755 |
| - else: |
756 |
| - querying = False |
757 |
| - return self.with_segments(path_root + self.parser.sep.join(path_tail)) |
| 707 | + return path.lstat() |
| 708 | + |
| 709 | + def readlink(path_str): |
| 710 | + path = self.with_segments(path_str) |
| 711 | + path._resolving = True |
| 712 | + return str(path.readlink()) |
| 713 | + else: |
| 714 | + # If the user has *not* overridden the `readlink()` method, then |
| 715 | + # symlinks are unsupported and (in non-strict mode) we can improve |
| 716 | + # performance by not calling `path.lstat()`. |
| 717 | + def skip(path_str): |
| 718 | + # This exception will be internally consumed by `_realpath()`. |
| 719 | + raise OSError("Operation skipped.") |
| 720 | + |
| 721 | + lstat = readlink = skip |
| 722 | + |
| 723 | + return self.with_segments(posixpath._realpath( |
| 724 | + str(self), strict, self.parser.sep, |
| 725 | + getcwd=getcwd, lstat=lstat, readlink=readlink, |
| 726 | + maxlinks=self._max_symlinks)) |
758 | 727 |
|
759 | 728 | def symlink_to(self, target, target_is_directory=False):
|
760 | 729 | """
|
|
0 commit comments