@@ -1511,6 +1511,34 @@ def test_sparse_file_10_pax_size(self):
15111511 self .assertEqual (tar .getnames (), ["sparse" , "last" ])
15121512 self .assertEqual (tar .extractfile ("last" ).read (), data )
15131513
1514+ def test_pax_size_with_gnu_longname (self ):
1515+ # gh-159435: a GNU long-name header between a pax header and its
1516+ # member must not make the member header get read a second time.
1517+ long_name = "long-name-" * 12 + "file.txt"
1518+
1519+ def header (name , type , size ):
1520+ info = tarfile .TarInfo (name )
1521+ info .type = type
1522+ info .size = size
1523+ return info .tobuf (tarfile .USTAR_FORMAT )
1524+
1525+ def padded (data ):
1526+ return data + b"\0 " * (- len (data ) % tarfile .BLOCKSIZE )
1527+
1528+ pax_record = b"9 size=5\n "
1529+ buf = header ("././@PaxHeader" , tarfile .XHDTYPE , len (pax_record ))
1530+ buf += padded (pax_record )
1531+ longname = long_name .encode () + b"\0 "
1532+ buf += header ("././@LongLink" , tarfile .GNUTYPE_LONGNAME , len (longname ))
1533+ buf += padded (longname )
1534+ buf += header ("member-short" , tarfile .REGTYPE , 5 ) + padded (b"hello" )
1535+ buf += header ("next.txt" , tarfile .REGTYPE , 3 ) + padded (b"bye" )
1536+ buf += b"\0 " * (tarfile .BLOCKSIZE * 2 )
1537+
1538+ with tarfile .open (fileobj = io .BytesIO (buf )) as tar :
1539+ self .assertEqual (tar .getnames (), [long_name , "next.txt" ])
1540+ self .assertEqual (tar .extractfile ("next.txt" ).read (), b"bye" )
1541+
15141542 @staticmethod
15151543 def _fs_supports_holes ():
15161544 # Return True if the platform knows the st_blocks stat attribute and
0 commit comments