gh-135034: Normalize link targets in tarfile, add `os.path.realpath(s… · Yhg1s/cpython@3612d8f (original) (raw)
`@@ -29,7 +29,7 @@
`
29
29
`"abspath","curdir","pardir","sep","pathsep","defpath","altsep",
`
30
30
`"extsep","devnull","realpath","supports_unicode_filenames","relpath",
`
31
31
`"samefile", "sameopenfile", "samestat", "commonpath", "isjunction",
`
32
``
`-
"isdevdrive"]
`
``
32
`+
"isdevdrive", "ALLOW_MISSING"]
`
33
33
``
34
34
`def _get_bothseps(path):
`
35
35
`if isinstance(path, bytes):
`
`@@ -601,9 +601,10 @@ def abspath(path):
`
601
601
`from nt import _findfirstfile, _getfinalpathname, readlink as _nt_readlink
`
602
602
`except ImportError:
`
603
603
`# realpath is a no-op on systems without _getfinalpathname support.
`
604
``
`-
realpath = abspath
`
``
604
`+
def realpath(path, *, strict=False):
`
``
605
`+
return abspath(path)
`
605
606
`else:
`
606
``
`-
def _readlink_deep(path):
`
``
607
`+
def _readlink_deep(path, ignored_error=OSError):
`
607
608
`# These error codes indicate that we should stop reading links and
`
608
609
`# return the path we currently have.
`
609
610
`# 1: ERROR_INVALID_FUNCTION
`
`@@ -636,7 +637,7 @@ def _readlink_deep(path):
`
636
637
`path = old_path
`
637
638
`break
`
638
639
`path = normpath(join(dirname(old_path), path))
`
639
``
`-
except OSError as ex:
`
``
640
`+
except ignored_error as ex:
`
640
641
`if ex.winerror in allowed_winerror:
`
641
642
`break
`
642
643
`raise
`
`@@ -645,7 +646,7 @@ def _readlink_deep(path):
`
645
646
`break
`
646
647
`return path
`
647
648
``
648
``
`-
def _getfinalpathname_nonstrict(path):
`
``
649
`+
def _getfinalpathname_nonstrict(path, ignored_error=OSError):
`
649
650
`# These error codes indicate that we should stop resolving the path
`
650
651
`# and return the value we currently have.
`
651
652
`# 1: ERROR_INVALID_FUNCTION
`
`@@ -673,25 +674,26 @@ def _getfinalpathname_nonstrict(path):
`
673
674
`try:
`
674
675
`path = _getfinalpathname(path)
`
675
676
`return join(path, tail) if tail else path
`
676
``
`-
except OSError as ex:
`
``
677
`+
except ignored_error as ex:
`
677
678
`if ex.winerror not in allowed_winerror:
`
678
679
`raise
`
679
680
`try:
`
680
681
`# The OS could not resolve this path fully, so we attempt
`
681
682
`# to follow the link ourselves. If we succeed, join the tail
`
682
683
`# and return.
`
683
``
`-
new_path = _readlink_deep(path)
`
``
684
`+
new_path = _readlink_deep(path,
`
``
685
`+
ignored_error=ignored_error)
`
684
686
`if new_path != path:
`
685
687
`return join(new_path, tail) if tail else new_path
`
686
``
`-
except OSError:
`
``
688
`+
except ignored_error:
`
687
689
`# If we fail to readlink(), let's keep traversing
`
688
690
`pass
`
689
691
`# If we get these errors, try to get the real name of the file without accessing it.
`
690
692
`if ex.winerror in (1, 5, 32, 50, 87, 1920, 1921):
`
691
693
`try:
`
692
694
`name = _findfirstfile(path)
`
693
695
`path, _ = split(path)
`
694
``
`-
except OSError:
`
``
696
`+
except ignored_error:
`
695
697
`path, name = split(path)
`
696
698
`else:
`
697
699
`path, name = split(path)
`
`@@ -721,24 +723,32 @@ def realpath(path, *, strict=False):
`
721
723
`if normcase(path) == devnull:
`
722
724
`return '\\.\NUL'
`
723
725
`had_prefix = path.startswith(prefix)
`
``
726
+
``
727
`+
if strict is ALLOW_MISSING:
`
``
728
`+
ignored_error = FileNotFoundError
`
``
729
`+
strict = True
`
``
730
`+
elif strict:
`
``
731
`+
ignored_error = ()
`
``
732
`+
else:
`
``
733
`+
ignored_error = OSError
`
``
734
+
724
735
`if not had_prefix and not isabs(path):
`
725
736
`path = join(cwd, path)
`
726
737
`try:
`
727
738
`path = _getfinalpathname(path)
`
728
739
`initial_winerror = 0
`
729
740
`except ValueError as ex:
`
730
741
`# gh-106242: Raised for embedded null characters
`
731
``
`-
In strict mode, we convert into an OSError.
`
``
742
`+
In strict modes, we convert into an OSError.
`
732
743
`# Non-strict mode returns the path as-is, since we've already
`
733
744
`# made it absolute.
`
734
745
`if strict:
`
735
746
`raise OSError(str(ex)) from None
`
736
747
`path = normpath(path)
`
737
``
`-
except OSError as ex:
`
738
``
`-
if strict:
`
739
``
`-
raise
`
``
748
`+
except ignored_error as ex:
`
740
749
`initial_winerror = ex.winerror
`
741
``
`-
path = _getfinalpathname_nonstrict(path)
`
``
750
`+
path = _getfinalpathname_nonstrict(path,
`
``
751
`+
ignored_error=ignored_error)
`
742
752
`# The path returned by _getfinalpathname will always start with \?\ -
`
743
753
`# strip off that prefix unless it was already provided on the original
`
744
754
`# path.
`