1+ import errno
12import sys
23import os
34import io
@@ -3651,34 +3652,55 @@ def test_modes(self):
36513652 arc .add ('read_group_only' , mode = '?---r-----' )
36523653 arc .add ('no_bits' , mode = '?---------' )
36533654 arc .add ('dir/' , mode = '?---rwsrwt' )
3655+ arc .add ('dir_all_bits/' , mode = '?rwsrwsrwt' )
36543656
3655- # On some systems, setting the sticky bit is a no-op.
3656- # Check if that's the case.
3657+ # On some systems, setting the uid, gid, and/or sticky bit is a no-ops.
3658+ # Check which bits we can set, so we can compare tarfile machinery to
3659+ # a simple chmod.
36573660 tmp_filename = os .path .join (TEMPDIR , "tmp.file" )
36583661 with open (tmp_filename , 'w' ):
36593662 pass
3660- os .chmod (tmp_filename , os .stat (tmp_filename ).st_mode | stat .S_ISVTX )
3661- have_sticky_files = (os .stat (tmp_filename ).st_mode & stat .S_ISVTX )
3662- os .unlink (tmp_filename )
3663+ try :
3664+ new_mode = (os .stat (tmp_filename ).st_mode
3665+ | stat .S_ISVTX | stat .S_ISGID | stat .S_ISUID )
3666+ try :
3667+ os .chmod (tmp_filename , new_mode )
3668+ except OSError as exc :
3669+ if exc .errno == getattr (errno , "EFTYPE" , 0 ):
3670+ # gh-108948: On FreeBSD, regular users cannot set
3671+ # the sticky bit.
3672+ self .skipTest ("chmod() failed with EFTYPE: "
3673+ "regular users cannot set sticky bit" )
3674+ else :
3675+ raise
3676+
3677+ got_mode = os .stat (tmp_filename ).st_mode
3678+ _t_file = 't' if (got_mode & stat .S_ISVTX ) else 'x'
3679+ _suid_file = 's' if (got_mode & stat .S_ISUID ) else 'x'
3680+ _sgid_file = 's' if (got_mode & stat .S_ISGID ) else 'x'
3681+ finally :
3682+ os .unlink (tmp_filename )
36633683
36643684 os .mkdir (tmp_filename )
3665- os .chmod (tmp_filename , os .stat (tmp_filename ).st_mode | stat .S_ISVTX )
3666- have_sticky_dirs = (os .stat (tmp_filename ).st_mode & stat .S_ISVTX )
3685+ new_mode = (os .stat (tmp_filename ).st_mode
3686+ | stat .S_ISVTX | stat .S_ISGID | stat .S_ISUID )
3687+ os .chmod (tmp_filename , new_mode )
3688+ got_mode = os .stat (tmp_filename ).st_mode
3689+ _t_dir = 't' if (got_mode & stat .S_ISVTX ) else 'x'
3690+ _suid_dir = 's' if (got_mode & stat .S_ISUID ) else 'x'
3691+ _sgid_dir = 's' if (got_mode & stat .S_ISGID ) else 'x'
36673692 os .rmdir (tmp_filename )
36683693
36693694 with self .check_context (arc .open (), 'fully_trusted' ):
3670- if have_sticky_files :
3671- self .expect_file ('all_bits' , mode = '?rwsrwsrwt' )
3672- else :
3673- self .expect_file ('all_bits' , mode = '?rwsrwsrwx' )
3695+ self .expect_file ('all_bits' ,
3696+ mode = f'?rw{ _suid_file } rw{ _sgid_file } rw{ _t_file } ' )
36743697 self .expect_file ('perm_bits' , mode = '?rwxrwxrwx' )
36753698 self .expect_file ('exec_group_other' , mode = '?rw-rwxrwx' )
36763699 self .expect_file ('read_group_only' , mode = '?---r-----' )
36773700 self .expect_file ('no_bits' , mode = '?---------' )
3678- if have_sticky_dirs :
3679- self .expect_file ('dir/' , mode = '?---rwsrwt' )
3680- else :
3681- self .expect_file ('dir/' , mode = '?---rwsrwx' )
3701+ self .expect_file ('dir/' , mode = f'?---rw{ _sgid_dir } rw{ _t_dir } ' )
3702+ self .expect_file ('dir_all_bits/' ,
3703+ mode = f'?rw{ _suid_dir } rw{ _sgid_dir } rw{ _t_dir } ' )
36823704
36833705 with self .check_context (arc .open (), 'tar' ):
36843706 self .expect_file ('all_bits' , mode = '?rwxr-xr-x' )
@@ -3687,6 +3709,7 @@ def test_modes(self):
36873709 self .expect_file ('read_group_only' , mode = '?---r-----' )
36883710 self .expect_file ('no_bits' , mode = '?---------' )
36893711 self .expect_file ('dir/' , mode = '?---r-xr-x' )
3712+ self .expect_file ('dir_all_bits/' , mode = '?rwxr-xr-x' )
36903713
36913714 with self .check_context (arc .open (), 'data' ):
36923715 normal_dir_mode = stat .filemode (stat .S_IMODE (
@@ -3697,6 +3720,7 @@ def test_modes(self):
36973720 self .expect_file ('read_group_only' , mode = '?rw-r-----' )
36983721 self .expect_file ('no_bits' , mode = '?rw-------' )
36993722 self .expect_file ('dir/' , mode = normal_dir_mode )
3723+ self .expect_file ('dir_all_bits/' , mode = normal_dir_mode )
37003724
37013725 def test_pipe (self ):
37023726 # Test handling of a special file
0 commit comments