@@ -2389,20 +2389,32 @@ def extractall(self, path=".", members=None, *, numeric_owner=False,
23892389 tarinfo = self ._get_extract_tarinfo (member , filter_function , path )
23902390 if tarinfo is None :
23912391 continue
2392+ self ._extract_one (tarinfo , path , set_attrs = not tarinfo .isdir (),
2393+ numeric_owner = numeric_owner )
23922394 if tarinfo .isdir ():
23932395 # For directories, delay setting attributes until later,
23942396 # since permissions can interfere with extraction and
23952397 # extracting contents can reset mtime.
2396- directories .append (tarinfo )
2397- self ._extract_one (tarinfo , path , set_attrs = not tarinfo .isdir (),
2398- numeric_owner = numeric_owner )
2398+ # We also the keep the original inode and device, to detect
2399+ # if it was changed during extraction.
2400+ dirpath = os .path .join (path , tarinfo .name )
2401+ dirpath = self ._transform_destination_path (dirpath )
2402+ targetstat = os .stat (dirpath )
2403+ directories .append ((tarinfo , dirpath , targetstat .st_ino ,
2404+ targetstat .st_dev ))
23992405
24002406 # Reverse sort directories.
2401- directories .sort (key = lambda a : a .name , reverse = True )
2407+ directories .sort (key = lambda a : a [ 0 ] .name , reverse = True )
24022408
24032409 # Set correct owner, mtime and filemode on directories.
2404- for tarinfo in directories :
2405- dirpath = os .path .join (path , tarinfo .name )
2410+ for tarinfo , dirpath , original_ino , original_dev in directories :
2411+ dirstat = os .stat (dirpath )
2412+ if (dirstat .st_ino != original_ino or
2413+ dirstat .st_dev != original_dev ):
2414+ self ._dbg (1 , "tarfile: Directory renamed before its " \
2415+ "attributes could be extracted %r" % dirpath )
2416+ continue
2417+
24062418 try :
24072419 self .chown (tarinfo , dirpath , numeric_owner = numeric_owner )
24082420 self .utime (tarinfo , dirpath )
0 commit comments