Skip to content

Commit 5956b5d

Browse files
committed
fix test as dotdot resolves early on win32
1 parent 382e7c4 commit 5956b5d

File tree

1 file changed

+43
-42
lines changed

1 file changed

+43
-42
lines changed

Lib/test/test_tarfile.py

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import unittest.mock
1616
import tarfile
1717

18+
from functools import cache
1819
from test import archiver_tests
1920
from test import support
2021
from test.support import os_helper
@@ -2777,7 +2778,7 @@ def test_useful_error_message_when_modules_missing(self):
27772778
str(excinfo.exception),
27782779
)
27792780

2780-
@unittest.skipUnless(os_helper.can_symlink(), 'requires symlink support')
2781+
@os_helper.skip_unless_symlink
27812782
@unittest.skipUnless(hasattr(os, 'chmod'), "missing os.chmod")
27822783
@unittest.mock.patch('os.chmod')
27832784
def test_deferred_directory_attributes_update(self, mock_chmod):
@@ -3663,6 +3664,37 @@ class TestExtractionFilters(unittest.TestCase):
36633664
# The destination for the extraction, within `outerdir`
36643665
destdir = outerdir / 'dest'
36653666

3667+
@classmethod
3668+
def setUpClass(cls):
3669+
# Posix and Windows have different pathname resolution:
3670+
# either symlink or a '..' component resolve first.
3671+
# Let's see which we are on.
3672+
if os_helper.can_symlink():
3673+
testpath = os.path.join(TEMPDIR, 'resolution_test')
3674+
os.mkdir(testpath)
3675+
3676+
# testpath/current links to `.` which is all of:
3677+
# - `testpath`
3678+
# - `testpath/current`
3679+
# - `testpath/current/current`
3680+
# - etc.
3681+
os.symlink('.', os.path.join(testpath, 'current'))
3682+
3683+
# we'll test where `testpath/current/../file` ends up
3684+
with open(os.path.join(testpath, 'current', '..', 'file'), 'w'):
3685+
pass
3686+
3687+
if os.path.exists(os.path.join(testpath, 'file')):
3688+
# Windows collapses 'current\..' to '.' first, leaving
3689+
# 'testpath\file'
3690+
cls.dotdot_resolves_early = True
3691+
elif os.path.exists(os.path.join(testpath, '..', 'file')):
3692+
# Posix resolves 'current' to '.' first, leaving
3693+
# 'testpath/../file'
3694+
cls.dotdot_resolves_early = False
3695+
else:
3696+
raise AssertionError('Could not determine link resolution')
3697+
36663698
@contextmanager
36673699
def check_context(self, tar, filter, *, check_flag=True):
36683700
"""Extracts `tar` to `self.destdir` and allows checking the result
@@ -3809,23 +3841,21 @@ def test_parent_symlink(self):
38093841
arc.add('current', symlink_to='.')
38103842

38113843
# effectively points to ./../
3812-
arc.add('parent', symlink_to='current/..')
3844+
if self.dotdot_resolves_early:
3845+
arc.add('parent', symlink_to='current/../..')
3846+
else:
3847+
arc.add('parent', symlink_to='current/..')
38133848

38143849
arc.add('parent/evil')
38153850

38163851
if os_helper.can_symlink():
38173852
with self.check_context(arc.open(), 'fully_trusted'):
3818-
if self.raised_exception is not None:
3819-
# Windows will refuse to create a file that's a symlink to itself
3820-
# (and tarfile doesn't swallow that exception)
3821-
self.expect_exception(FileExistsError)
3822-
# The other cases will fail with this error too.
3823-
# Skip the rest of this test.
3824-
return
3853+
self.expect_file('current', symlink_to='.')
3854+
if self.dotdot_resolves_early:
3855+
self.expect_file('parent', symlink_to='current/../..')
38253856
else:
3826-
self.expect_file('current', symlink_to='.')
38273857
self.expect_file('parent', symlink_to='current/..')
3828-
self.expect_file('../evil')
3858+
self.expect_file('../evil')
38293859

38303860
with self.check_context(arc.open(), 'tar'):
38313861
self.expect_exception(
@@ -3927,35 +3957,6 @@ def test_parent_symlink2(self):
39273957
# Test interplaying symlinks
39283958
# Inspired by 'dirsymlink2b' in jwilk/traversal-archives
39293959

3930-
# Posix and Windows have different pathname resolution:
3931-
# either symlink or a '..' component resolve first.
3932-
# Let's see which we are on.
3933-
if os_helper.can_symlink():
3934-
testpath = os.path.join(TEMPDIR, 'resolution_test')
3935-
os.mkdir(testpath)
3936-
3937-
# testpath/current links to `.` which is all of:
3938-
# - `testpath`
3939-
# - `testpath/current`
3940-
# - `testpath/current/current`
3941-
# - etc.
3942-
os.symlink('.', os.path.join(testpath, 'current'))
3943-
3944-
# we'll test where `testpath/current/../file` ends up
3945-
with open(os.path.join(testpath, 'current', '..', 'file'), 'w'):
3946-
pass
3947-
3948-
if os.path.exists(os.path.join(testpath, 'file')):
3949-
# Windows collapses 'current\..' to '.' first, leaving
3950-
# 'testpath\file'
3951-
dotdot_resolves_early = True
3952-
elif os.path.exists(os.path.join(testpath, '..', 'file')):
3953-
# Posix resolves 'current' to '.' first, leaving
3954-
# 'testpath/../file'
3955-
dotdot_resolves_early = False
3956-
else:
3957-
raise AssertionError('Could not determine link resolution')
3958-
39593960
with ArchiveMaker() as arc:
39603961

39613962
# `current` links to `.` which is both the destination directory
@@ -3991,7 +3992,7 @@ def test_parent_symlink2(self):
39913992

39923993
with self.check_context(arc.open(), 'data'):
39933994
if os_helper.can_symlink():
3994-
if dotdot_resolves_early:
3995+
if self.dotdot_resolves_early:
39953996
# Fail when extracting a file outside destination
39963997
self.expect_exception(
39973998
tarfile.OutsideDestinationError,
@@ -4039,8 +4040,8 @@ def test_absolute_symlink(self):
40394040
tarfile.AbsoluteLinkError,
40404041
"'parent' is a link to an absolute path")
40414042

4042-
@unittest.skipUnless(os_helper.can_symlink(), 'requires symlink support')
40434043
@symlink_test
4044+
@os_helper.skip_unless_symlink
40444045
def test_symlink_target_sanitized_on_windows(self):
40454046
with ArchiveMaker() as arc:
40464047
arc.add('link', symlink_to="relative/test/path")

0 commit comments

Comments
 (0)