@@ -3496,8 +3496,15 @@ def test_parent_symlink(self):
3496
3496
# Test interplaying symlinks
3497
3497
# Inspired by 'dirsymlink2a' in jwilk/traversal-archives
3498
3498
with ArchiveMaker () as arc :
3499
+
3500
+ # links to `.` which is both:
3501
+ # - the destination directory
3502
+ # - `current` itself
3499
3503
arc .add ('current' , symlink_to = '.' )
3504
+
3505
+ # effectively points to ./../
3500
3506
arc .add ('parent' , symlink_to = 'current/..' )
3507
+
3501
3508
arc .add ('parent/evil' )
3502
3509
3503
3510
if os_helper .can_symlink ():
@@ -3540,8 +3547,15 @@ def test_parent_symlink2(self):
3540
3547
# Test interplaying symlinks
3541
3548
# Inspired by 'dirsymlink2b' in jwilk/traversal-archives
3542
3549
with ArchiveMaker () as arc :
3550
+
3551
+ # links to `.` which is both:
3552
+ # - the destination directory
3553
+ # - `current` itself
3543
3554
arc .add ('current' , symlink_to = '.' )
3555
+
3556
+ # available as `./parent`, effectively points to `./../`
3544
3557
arc .add ('current/parent' , symlink_to = '..' )
3558
+
3545
3559
arc .add ('parent/evil' )
3546
3560
3547
3561
with self .check_context (arc .open (), 'fully_trusted' ):
@@ -3553,17 +3567,29 @@ def test_parent_symlink2(self):
3553
3567
self .expect_file ('current/' )
3554
3568
self .expect_file ('parent/evil' )
3555
3569
3556
- for filter in 'tar' , 'data' :
3557
- with self .check_context (arc .open (), filter ):
3558
- if os_helper .can_symlink ():
3559
- self .expect_exception (
3560
- tarfile .OutsideDestinationError ,
3561
- "'parent/evil' would be extracted to "
3562
- + """['"].*evil['"], which is outside """
3563
- + "the destination" )
3564
- else :
3565
- self .expect_file ('current/' )
3566
- self .expect_file ('parent/evil' )
3570
+ with self .check_context (arc .open (), 'tar' ):
3571
+ if os_helper .can_symlink ():
3572
+ # Fail when extracting a file outside destination
3573
+ self .expect_exception (
3574
+ tarfile .OutsideDestinationError ,
3575
+ "'parent/evil' would be extracted to "
3576
+ + """['"].*evil['"], which is outside """
3577
+ + "the destination" )
3578
+ else :
3579
+ self .expect_file ('current/' )
3580
+ self .expect_file ('parent/evil' )
3581
+
3582
+ with self .check_context (arc .open (), 'data' ):
3583
+ 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" )
3590
+ else :
3591
+ self .expect_file ('current/' )
3592
+ self .expect_file ('parent/evil' )
3567
3593
3568
3594
@symlink_test
3569
3595
def test_absolute_symlink (self ):
@@ -3593,12 +3619,30 @@ def test_absolute_symlink(self):
3593
3619
with self .check_context (arc .open (), 'data' ):
3594
3620
self .expect_exception (
3595
3621
tarfile .AbsoluteLinkError ,
3596
- "'parent' is a symlink to an absolute path" )
3622
+ "'parent' is a link to an absolute path" )
3623
+
3624
+ def test_absolute_hardlink (self ):
3625
+ # Test hardlink to an absolute path
3626
+ # Inspired by 'dirsymlink' in jwilk/traversal-archives
3627
+ with ArchiveMaker () as arc :
3628
+ arc .add ('parent' , hardlink_to = self .outerdir / 'foo' )
3629
+
3630
+ with self .check_context (arc .open (), 'fully_trusted' ):
3631
+ self .expect_exception (KeyError , ".*foo. not found" )
3632
+
3633
+ with self .check_context (arc .open (), 'tar' ):
3634
+ self .expect_exception (KeyError , ".*foo. not found" )
3635
+
3636
+ with self .check_context (arc .open (), 'data' ):
3637
+ self .expect_exception (
3638
+ tarfile .AbsoluteLinkError ,
3639
+ "'parent' is a link to an absolute path" )
3597
3640
3598
3641
@symlink_test
3599
3642
def test_sly_relative0 (self ):
3600
3643
# Inspired by 'relative0' in jwilk/traversal-archives
3601
3644
with ArchiveMaker () as arc :
3645
+ # points to `../../tmp/moo`
3602
3646
arc .add ('../moo' , symlink_to = '..//tmp/moo' )
3603
3647
3604
3648
try :
@@ -3651,10 +3695,15 @@ def test_sly_relative2(self):
3651
3695
3652
3696
@symlink_test
3653
3697
def test_deep_symlink (self ):
3698
+ # Test that symlinks and hardlinks inside a directory
3699
+ # point to the correct file (`target` of size 3).
3700
+ # If links aren't supported we get a copy of the file.
3654
3701
with ArchiveMaker () as arc :
3655
3702
arc .add ('targetdir/target' , size = 3 )
3703
+ # a hardlink's linkname is relative to the archive
3656
3704
arc .add ('linkdir/hardlink' , hardlink_to = os .path .join (
3657
3705
'targetdir' , 'target' ))
3706
+ # a symlink's linkname is relative to the link's directory
3658
3707
arc .add ('linkdir/symlink' , symlink_to = os .path .join (
3659
3708
'..' , 'targetdir' , 'target' ))
3660
3709
0 commit comments