1+ import errno
12import sys
23import os
34import io
@@ -3691,34 +3692,55 @@ def test_modes(self):
36913692 arc .add ('read_group_only' , mode = '?---r-----' )
36923693 arc .add ('no_bits' , mode = '?---------' )
36933694 arc .add ('dir/' , mode = '?---rwsrwt' )
3695+ arc .add ('dir_all_bits/' , mode = '?rwsrwsrwt' )
36943696
3695- # On some systems, setting the sticky bit is a no-op.
3696- # Check if that's the case.
3697+ # On some systems, setting the uid, gid, and/or sticky bit is a no-ops.
3698+ # Check which bits we can set, so we can compare tarfile machinery to
3699+ # a simple chmod.
36973700 tmp_filename = os .path .join (TEMPDIR , "tmp.file" )
36983701 with open (tmp_filename , 'w' ):
36993702 pass
3700- os .chmod (tmp_filename , os .stat (tmp_filename ).st_mode | stat .S_ISVTX )
3701- have_sticky_files = (os .stat (tmp_filename ).st_mode & stat .S_ISVTX )
3702- os .unlink (tmp_filename )
3703+ try :
3704+ new_mode = (os .stat (tmp_filename ).st_mode
3705+ | stat .S_ISVTX | stat .S_ISGID | stat .S_ISUID )
3706+ try :
3707+ os .chmod (tmp_filename , new_mode )
3708+ except OSError as exc :
3709+ if exc .errno == getattr (errno , "EFTYPE" , 0 ):
3710+ # gh-108948: On FreeBSD, regular users cannot set
3711+ # the sticky bit.
3712+ self .skipTest ("chmod() failed with EFTYPE: "
3713+ "regular users cannot set sticky bit" )
3714+ else :
3715+ raise
3716+
3717+ got_mode = os .stat (tmp_filename ).st_mode
3718+ _t_file = 't' if (got_mode & stat .S_ISVTX ) else 'x'
3719+ _suid_file = 's' if (got_mode & stat .S_ISUID ) else 'x'
3720+ _sgid_file = 's' if (got_mode & stat .S_ISGID ) else 'x'
3721+ finally :
3722+ os .unlink (tmp_filename )
37033723
37043724 os .mkdir (tmp_filename )
3705- os .chmod (tmp_filename , os .stat (tmp_filename ).st_mode | stat .S_ISVTX )
3706- have_sticky_dirs = (os .stat (tmp_filename ).st_mode & stat .S_ISVTX )
3725+ new_mode = (os .stat (tmp_filename ).st_mode
3726+ | stat .S_ISVTX | stat .S_ISGID | stat .S_ISUID )
3727+ os .chmod (tmp_filename , new_mode )
3728+ got_mode = os .stat (tmp_filename ).st_mode
3729+ _t_dir = 't' if (got_mode & stat .S_ISVTX ) else 'x'
3730+ _suid_dir = 's' if (got_mode & stat .S_ISUID ) else 'x'
3731+ _sgid_dir = 's' if (got_mode & stat .S_ISGID ) else 'x'
37073732 os .rmdir (tmp_filename )
37083733
37093734 with self .check_context (arc .open (), 'fully_trusted' ):
3710- if have_sticky_files :
3711- self .expect_file ('all_bits' , mode = '?rwsrwsrwt' )
3712- else :
3713- self .expect_file ('all_bits' , mode = '?rwsrwsrwx' )
3735+ self .expect_file ('all_bits' ,
3736+ mode = f'?rw{ _suid_file } rw{ _sgid_file } rw{ _t_file } ' )
37143737 self .expect_file ('perm_bits' , mode = '?rwxrwxrwx' )
37153738 self .expect_file ('exec_group_other' , mode = '?rw-rwxrwx' )
37163739 self .expect_file ('read_group_only' , mode = '?---r-----' )
37173740 self .expect_file ('no_bits' , mode = '?---------' )
3718- if have_sticky_dirs :
3719- self .expect_file ('dir/' , mode = '?---rwsrwt' )
3720- else :
3721- self .expect_file ('dir/' , mode = '?---rwsrwx' )
3741+ self .expect_file ('dir/' , mode = f'?---rw{ _sgid_dir } rw{ _t_dir } ' )
3742+ self .expect_file ('dir_all_bits/' ,
3743+ mode = f'?rw{ _suid_dir } rw{ _sgid_dir } rw{ _t_dir } ' )
37223744
37233745 with self .check_context (arc .open (), 'tar' ):
37243746 self .expect_file ('all_bits' , mode = '?rwxr-xr-x' )
@@ -3727,6 +3749,7 @@ def test_modes(self):
37273749 self .expect_file ('read_group_only' , mode = '?---r-----' )
37283750 self .expect_file ('no_bits' , mode = '?---------' )
37293751 self .expect_file ('dir/' , mode = '?---r-xr-x' )
3752+ self .expect_file ('dir_all_bits/' , mode = '?rwxr-xr-x' )
37303753
37313754 with self .check_context (arc .open (), 'data' ):
37323755 normal_dir_mode = stat .filemode (stat .S_IMODE (
@@ -3737,6 +3760,7 @@ def test_modes(self):
37373760 self .expect_file ('read_group_only' , mode = '?rw-r-----' )
37383761 self .expect_file ('no_bits' , mode = '?rw-------' )
37393762 self .expect_file ('dir/' , mode = normal_dir_mode )
3763+ self .expect_file ('dir_all_bits/' , mode = normal_dir_mode )
37403764
37413765 def test_pipe (self ):
37423766 # Test handling of a special file
0 commit comments