@@ -3546,14 +3546,44 @@ def test_parent_symlink(self):
3546
3546
def test_parent_symlink2 (self ):
3547
3547
# Test interplaying symlinks
3548
3548
# Inspired by 'dirsymlink2b' in jwilk/traversal-archives
3549
+
3550
+ # Posix and Windows have different pathname resolution:
3551
+ # either symlink or a '..' component resolve first.
3552
+ # Let's see which we are on.
3553
+ if os_helper .can_symlink ():
3554
+ testpath = os .path .join (TEMPDIR , 'resolution_test' )
3555
+ os .mkdir (testpath )
3556
+
3557
+ # testpath/current links to `.` which is all of:
3558
+ # - `testpath`
3559
+ # - `testpath/current`
3560
+ # - `testpath/current/current`
3561
+ # - etc.
3562
+ os .symlink ('.' , os .path .join (testpath , 'current' ))
3563
+
3564
+ # we'll test where `testpath/current/../file` ends up
3565
+ with open (os .path .join (testpath , 'current' , '..' , 'file' ), 'w' ):
3566
+ pass
3567
+
3568
+ if os .path .exists (os .path .join (testpath , 'file' )):
3569
+ # Windows collapses 'current\..' to '.' first, leaving
3570
+ # 'testpath\file'
3571
+ dotdot_resolves_early = True
3572
+ elif os .path .exists (os .path .join (testpath , '..' , 'file' )):
3573
+ # Posix resolves 'current' to '.' first, leaving
3574
+ # 'testpath/../file'
3575
+ dotdot_resolves_early = False
3576
+ else :
3577
+ raise AssertionError ('Could not determine link resolution' )
3578
+
3549
3579
with ArchiveMaker () as arc :
3550
3580
3551
- # links to `.` which is both:
3552
- # - the destination directory
3553
- # - `current` itself
3581
+ # `current` links to `.` which is both the destination directory
3582
+ # and `current` itself
3554
3583
arc .add ('current' , symlink_to = '.' )
3555
3584
3556
- # available as `./parent`, effectively points to `./../`
3585
+ # `current/parent` is also available as `./parent`,
3586
+ # and effectively points to `./../`
3557
3587
arc .add ('current/parent' , symlink_to = '..' )
3558
3588
3559
3589
arc .add ('parent/evil' )
@@ -3581,12 +3611,20 @@ def test_parent_symlink2(self):
3581
3611
3582
3612
with self .check_context (arc .open (), 'data' ):
3583
3613
if os_helper .can_symlink ():
3584
- # Fail as soon as we have a symlink outside the destination
3585
- self .expect_exception (
3586
- tarfile .LinkOutsideDestinationError ,
3587
- "'current/parent' would link to "
3588
- + """['"].*outerdir['"], which is outside """
3589
- + "the destination" )
3614
+ if dotdot_resolves_early :
3615
+ # Fail when extracting a file outside destination
3616
+ self .expect_exception (
3617
+ tarfile .OutsideDestinationError ,
3618
+ "'parent/evil' would be extracted to "
3619
+ + """['"].*evil['"], which is outside """
3620
+ + "the destination" )
3621
+ else :
3622
+ # Fail as soon as we have a symlink outside the destination
3623
+ self .expect_exception (
3624
+ tarfile .LinkOutsideDestinationError ,
3625
+ "'current/parent' would link to "
3626
+ + """['"].*outerdir['"], which is outside """
3627
+ + "the destination" )
3590
3628
else :
3591
3629
self .expect_file ('current/' )
3592
3630
self .expect_file ('parent/evil' )
0 commit comments