17db96d56Sopenharmony_ciimport sys 27db96d56Sopenharmony_ciimport os 37db96d56Sopenharmony_ciimport io 47db96d56Sopenharmony_cifrom hashlib import sha256 57db96d56Sopenharmony_cifrom contextlib import contextmanager 67db96d56Sopenharmony_cifrom random import Random 77db96d56Sopenharmony_ciimport pathlib 87db96d56Sopenharmony_ciimport shutil 97db96d56Sopenharmony_ciimport re 107db96d56Sopenharmony_ciimport warnings 117db96d56Sopenharmony_ciimport stat 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciimport unittest 147db96d56Sopenharmony_ciimport unittest.mock 157db96d56Sopenharmony_ciimport tarfile 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_cifrom test import support 187db96d56Sopenharmony_cifrom test.support import os_helper 197db96d56Sopenharmony_cifrom test.support import script_helper 207db96d56Sopenharmony_cifrom test.support import warnings_helper 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_ci# Check for our compression modules. 237db96d56Sopenharmony_citry: 247db96d56Sopenharmony_ci import gzip 257db96d56Sopenharmony_ciexcept ImportError: 267db96d56Sopenharmony_ci gzip = None 277db96d56Sopenharmony_citry: 287db96d56Sopenharmony_ci import zlib 297db96d56Sopenharmony_ciexcept ImportError: 307db96d56Sopenharmony_ci zlib = None 317db96d56Sopenharmony_citry: 327db96d56Sopenharmony_ci import bz2 337db96d56Sopenharmony_ciexcept ImportError: 347db96d56Sopenharmony_ci bz2 = None 357db96d56Sopenharmony_citry: 367db96d56Sopenharmony_ci import lzma 377db96d56Sopenharmony_ciexcept ImportError: 387db96d56Sopenharmony_ci lzma = None 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_cidef sha256sum(data): 417db96d56Sopenharmony_ci return sha256(data).hexdigest() 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ciTEMPDIR = os.path.abspath(os_helper.TESTFN) + "-tardir" 447db96d56Sopenharmony_citarextdir = TEMPDIR + '-extract-test' 457db96d56Sopenharmony_citarname = support.findfile("testtar.tar") 467db96d56Sopenharmony_cigzipname = os.path.join(TEMPDIR, "testtar.tar.gz") 477db96d56Sopenharmony_cibz2name = os.path.join(TEMPDIR, "testtar.tar.bz2") 487db96d56Sopenharmony_cixzname = os.path.join(TEMPDIR, "testtar.tar.xz") 497db96d56Sopenharmony_citmpname = os.path.join(TEMPDIR, "tmp.tar") 507db96d56Sopenharmony_cidotlessname = os.path.join(TEMPDIR, "testtar") 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_cisha256_regtype = ( 537db96d56Sopenharmony_ci "e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce" 547db96d56Sopenharmony_ci) 557db96d56Sopenharmony_cisha256_sparse = ( 567db96d56Sopenharmony_ci "4f05a776071146756345ceee937b33fc5644f5a96b9780d1c7d6a32cdf164d7b" 577db96d56Sopenharmony_ci) 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ciclass TarTest: 617db96d56Sopenharmony_ci tarname = tarname 627db96d56Sopenharmony_ci suffix = '' 637db96d56Sopenharmony_ci open = io.FileIO 647db96d56Sopenharmony_ci taropen = tarfile.TarFile.taropen 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci @property 677db96d56Sopenharmony_ci def mode(self): 687db96d56Sopenharmony_ci return self.prefix + self.suffix 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci@support.requires_gzip() 717db96d56Sopenharmony_ciclass GzipTest: 727db96d56Sopenharmony_ci tarname = gzipname 737db96d56Sopenharmony_ci suffix = 'gz' 747db96d56Sopenharmony_ci open = gzip.GzipFile if gzip else None 757db96d56Sopenharmony_ci taropen = tarfile.TarFile.gzopen 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci@support.requires_bz2() 787db96d56Sopenharmony_ciclass Bz2Test: 797db96d56Sopenharmony_ci tarname = bz2name 807db96d56Sopenharmony_ci suffix = 'bz2' 817db96d56Sopenharmony_ci open = bz2.BZ2File if bz2 else None 827db96d56Sopenharmony_ci taropen = tarfile.TarFile.bz2open 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci@support.requires_lzma() 857db96d56Sopenharmony_ciclass LzmaTest: 867db96d56Sopenharmony_ci tarname = xzname 877db96d56Sopenharmony_ci suffix = 'xz' 887db96d56Sopenharmony_ci open = lzma.LZMAFile if lzma else None 897db96d56Sopenharmony_ci taropen = tarfile.TarFile.xzopen 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ciclass ReadTest(TarTest): 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci prefix = "r:" 957db96d56Sopenharmony_ci 967db96d56Sopenharmony_ci def setUp(self): 977db96d56Sopenharmony_ci self.tar = tarfile.open(self.tarname, mode=self.mode, 987db96d56Sopenharmony_ci encoding="iso8859-1") 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci def tearDown(self): 1017db96d56Sopenharmony_ci self.tar.close() 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ciclass UstarReadTest(ReadTest, unittest.TestCase): 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci def test_fileobj_regular_file(self): 1077db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/regtype") 1087db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as fobj: 1097db96d56Sopenharmony_ci data = fobj.read() 1107db96d56Sopenharmony_ci self.assertEqual(len(data), tarinfo.size, 1117db96d56Sopenharmony_ci "regular file extraction failed") 1127db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_regtype, 1137db96d56Sopenharmony_ci "regular file extraction failed") 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci def test_fileobj_readlines(self): 1167db96d56Sopenharmony_ci self.tar.extract("ustar/regtype", TEMPDIR, filter='data') 1177db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/regtype") 1187db96d56Sopenharmony_ci with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1: 1197db96d56Sopenharmony_ci lines1 = fobj1.readlines() 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as fobj: 1227db96d56Sopenharmony_ci fobj2 = io.TextIOWrapper(fobj) 1237db96d56Sopenharmony_ci lines2 = fobj2.readlines() 1247db96d56Sopenharmony_ci self.assertEqual(lines1, lines2, 1257db96d56Sopenharmony_ci "fileobj.readlines() failed") 1267db96d56Sopenharmony_ci self.assertEqual(len(lines2), 114, 1277db96d56Sopenharmony_ci "fileobj.readlines() failed") 1287db96d56Sopenharmony_ci self.assertEqual(lines2[83], 1297db96d56Sopenharmony_ci "I will gladly admit that Python is not the fastest " 1307db96d56Sopenharmony_ci "running scripting language.\n", 1317db96d56Sopenharmony_ci "fileobj.readlines() failed") 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci def test_fileobj_iter(self): 1347db96d56Sopenharmony_ci self.tar.extract("ustar/regtype", TEMPDIR, filter='data') 1357db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/regtype") 1367db96d56Sopenharmony_ci with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1: 1377db96d56Sopenharmony_ci lines1 = fobj1.readlines() 1387db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as fobj2: 1397db96d56Sopenharmony_ci lines2 = list(io.TextIOWrapper(fobj2)) 1407db96d56Sopenharmony_ci self.assertEqual(lines1, lines2, 1417db96d56Sopenharmony_ci "fileobj.__iter__() failed") 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci def test_fileobj_seek(self): 1447db96d56Sopenharmony_ci self.tar.extract("ustar/regtype", TEMPDIR, 1457db96d56Sopenharmony_ci filter='data') 1467db96d56Sopenharmony_ci with open(os.path.join(TEMPDIR, "ustar/regtype"), "rb") as fobj: 1477db96d56Sopenharmony_ci data = fobj.read() 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/regtype") 1507db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as fobj: 1517db96d56Sopenharmony_ci text = fobj.read() 1527db96d56Sopenharmony_ci fobj.seek(0) 1537db96d56Sopenharmony_ci self.assertEqual(0, fobj.tell(), 1547db96d56Sopenharmony_ci "seek() to file's start failed") 1557db96d56Sopenharmony_ci fobj.seek(2048, 0) 1567db96d56Sopenharmony_ci self.assertEqual(2048, fobj.tell(), 1577db96d56Sopenharmony_ci "seek() to absolute position failed") 1587db96d56Sopenharmony_ci fobj.seek(-1024, 1) 1597db96d56Sopenharmony_ci self.assertEqual(1024, fobj.tell(), 1607db96d56Sopenharmony_ci "seek() to negative relative position failed") 1617db96d56Sopenharmony_ci fobj.seek(1024, 1) 1627db96d56Sopenharmony_ci self.assertEqual(2048, fobj.tell(), 1637db96d56Sopenharmony_ci "seek() to positive relative position failed") 1647db96d56Sopenharmony_ci s = fobj.read(10) 1657db96d56Sopenharmony_ci self.assertEqual(s, data[2048:2058], 1667db96d56Sopenharmony_ci "read() after seek failed") 1677db96d56Sopenharmony_ci fobj.seek(0, 2) 1687db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, fobj.tell(), 1697db96d56Sopenharmony_ci "seek() to file's end failed") 1707db96d56Sopenharmony_ci self.assertEqual(fobj.read(), b"", 1717db96d56Sopenharmony_ci "read() at file's end did not return empty string") 1727db96d56Sopenharmony_ci fobj.seek(-tarinfo.size, 2) 1737db96d56Sopenharmony_ci self.assertEqual(0, fobj.tell(), 1747db96d56Sopenharmony_ci "relative seek() to file's end failed") 1757db96d56Sopenharmony_ci fobj.seek(512) 1767db96d56Sopenharmony_ci s1 = fobj.readlines() 1777db96d56Sopenharmony_ci fobj.seek(512) 1787db96d56Sopenharmony_ci s2 = fobj.readlines() 1797db96d56Sopenharmony_ci self.assertEqual(s1, s2, 1807db96d56Sopenharmony_ci "readlines() after seek failed") 1817db96d56Sopenharmony_ci fobj.seek(0) 1827db96d56Sopenharmony_ci self.assertEqual(len(fobj.readline()), fobj.tell(), 1837db96d56Sopenharmony_ci "tell() after readline() failed") 1847db96d56Sopenharmony_ci fobj.seek(512) 1857db96d56Sopenharmony_ci self.assertEqual(len(fobj.readline()) + 512, fobj.tell(), 1867db96d56Sopenharmony_ci "tell() after seek() and readline() failed") 1877db96d56Sopenharmony_ci fobj.seek(0) 1887db96d56Sopenharmony_ci line = fobj.readline() 1897db96d56Sopenharmony_ci self.assertEqual(fobj.read(), data[len(line):], 1907db96d56Sopenharmony_ci "read() after readline() failed") 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci def test_fileobj_text(self): 1937db96d56Sopenharmony_ci with self.tar.extractfile("ustar/regtype") as fobj: 1947db96d56Sopenharmony_ci fobj = io.TextIOWrapper(fobj) 1957db96d56Sopenharmony_ci data = fobj.read().encode("iso8859-1") 1967db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_regtype) 1977db96d56Sopenharmony_ci try: 1987db96d56Sopenharmony_ci fobj.seek(100) 1997db96d56Sopenharmony_ci except AttributeError: 2007db96d56Sopenharmony_ci # Issue #13815: seek() complained about a missing 2017db96d56Sopenharmony_ci # flush() method. 2027db96d56Sopenharmony_ci self.fail("seeking failed in text mode") 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci # Test if symbolic and hard links are resolved by extractfile(). The 2057db96d56Sopenharmony_ci # test link members each point to a regular member whose data is 2067db96d56Sopenharmony_ci # supposed to be exported. 2077db96d56Sopenharmony_ci def _test_fileobj_link(self, lnktype, regtype): 2087db96d56Sopenharmony_ci with self.tar.extractfile(lnktype) as a, \ 2097db96d56Sopenharmony_ci self.tar.extractfile(regtype) as b: 2107db96d56Sopenharmony_ci self.assertEqual(a.name, b.name) 2117db96d56Sopenharmony_ci 2127db96d56Sopenharmony_ci def test_fileobj_link1(self): 2137db96d56Sopenharmony_ci self._test_fileobj_link("ustar/lnktype", "ustar/regtype") 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci def test_fileobj_link2(self): 2167db96d56Sopenharmony_ci self._test_fileobj_link("./ustar/linktest2/lnktype", 2177db96d56Sopenharmony_ci "ustar/linktest1/regtype") 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci def test_fileobj_symlink1(self): 2207db96d56Sopenharmony_ci self._test_fileobj_link("ustar/symtype", "ustar/regtype") 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_ci def test_fileobj_symlink2(self): 2237db96d56Sopenharmony_ci self._test_fileobj_link("./ustar/linktest2/symtype", 2247db96d56Sopenharmony_ci "ustar/linktest1/regtype") 2257db96d56Sopenharmony_ci 2267db96d56Sopenharmony_ci def test_issue14160(self): 2277db96d56Sopenharmony_ci self._test_fileobj_link("symtype2", "ustar/regtype") 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci def test_add_dir_getmember(self): 2307db96d56Sopenharmony_ci # bpo-21987 2317db96d56Sopenharmony_ci self.add_dir_and_getmember('bar') 2327db96d56Sopenharmony_ci self.add_dir_and_getmember('a'*101) 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci @unittest.skipUnless(hasattr(os, "getuid") and hasattr(os, "getgid"), 2357db96d56Sopenharmony_ci "Missing getuid or getgid implementation") 2367db96d56Sopenharmony_ci def add_dir_and_getmember(self, name): 2377db96d56Sopenharmony_ci def filter(tarinfo): 2387db96d56Sopenharmony_ci tarinfo.uid = tarinfo.gid = 100 2397db96d56Sopenharmony_ci return tarinfo 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_ci with os_helper.temp_cwd(): 2427db96d56Sopenharmony_ci with tarfile.open(tmpname, 'w') as tar: 2437db96d56Sopenharmony_ci tar.format = tarfile.USTAR_FORMAT 2447db96d56Sopenharmony_ci try: 2457db96d56Sopenharmony_ci os.mkdir(name) 2467db96d56Sopenharmony_ci tar.add(name, filter=filter) 2477db96d56Sopenharmony_ci finally: 2487db96d56Sopenharmony_ci os.rmdir(name) 2497db96d56Sopenharmony_ci with tarfile.open(tmpname) as tar: 2507db96d56Sopenharmony_ci self.assertEqual( 2517db96d56Sopenharmony_ci tar.getmember(name), 2527db96d56Sopenharmony_ci tar.getmember(name + '/') 2537db96d56Sopenharmony_ci ) 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ciclass GzipUstarReadTest(GzipTest, UstarReadTest): 2567db96d56Sopenharmony_ci pass 2577db96d56Sopenharmony_ci 2587db96d56Sopenharmony_ciclass Bz2UstarReadTest(Bz2Test, UstarReadTest): 2597db96d56Sopenharmony_ci pass 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ciclass LzmaUstarReadTest(LzmaTest, UstarReadTest): 2627db96d56Sopenharmony_ci pass 2637db96d56Sopenharmony_ci 2647db96d56Sopenharmony_ci 2657db96d56Sopenharmony_ciclass ListTest(ReadTest, unittest.TestCase): 2667db96d56Sopenharmony_ci 2677db96d56Sopenharmony_ci # Override setUp to use default encoding (UTF-8) 2687db96d56Sopenharmony_ci def setUp(self): 2697db96d56Sopenharmony_ci self.tar = tarfile.open(self.tarname, mode=self.mode) 2707db96d56Sopenharmony_ci 2717db96d56Sopenharmony_ci def test_list(self): 2727db96d56Sopenharmony_ci tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') 2737db96d56Sopenharmony_ci with support.swap_attr(sys, 'stdout', tio): 2747db96d56Sopenharmony_ci self.tar.list(verbose=False) 2757db96d56Sopenharmony_ci out = tio.detach().getvalue() 2767db96d56Sopenharmony_ci self.assertIn(b'ustar/conttype', out) 2777db96d56Sopenharmony_ci self.assertIn(b'ustar/regtype', out) 2787db96d56Sopenharmony_ci self.assertIn(b'ustar/lnktype', out) 2797db96d56Sopenharmony_ci self.assertIn(b'ustar' + (b'/12345' * 40) + b'67/longname', out) 2807db96d56Sopenharmony_ci self.assertIn(b'./ustar/linktest2/symtype', out) 2817db96d56Sopenharmony_ci self.assertIn(b'./ustar/linktest2/lnktype', out) 2827db96d56Sopenharmony_ci # Make sure it puts trailing slash for directory 2837db96d56Sopenharmony_ci self.assertIn(b'ustar/dirtype/', out) 2847db96d56Sopenharmony_ci self.assertIn(b'ustar/dirtype-with-size/', out) 2857db96d56Sopenharmony_ci # Make sure it is able to print unencodable characters 2867db96d56Sopenharmony_ci def conv(b): 2877db96d56Sopenharmony_ci s = b.decode(self.tar.encoding, 'surrogateescape') 2887db96d56Sopenharmony_ci return s.encode('ascii', 'backslashreplace') 2897db96d56Sopenharmony_ci self.assertIn(conv(b'ustar/umlauts-\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out) 2907db96d56Sopenharmony_ci self.assertIn(conv(b'misc/regtype-hpux-signed-chksum-' 2917db96d56Sopenharmony_ci b'\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out) 2927db96d56Sopenharmony_ci self.assertIn(conv(b'misc/regtype-old-v7-signed-chksum-' 2937db96d56Sopenharmony_ci b'\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out) 2947db96d56Sopenharmony_ci self.assertIn(conv(b'pax/bad-pax-\xe4\xf6\xfc'), out) 2957db96d56Sopenharmony_ci self.assertIn(conv(b'pax/hdrcharset-\xe4\xf6\xfc'), out) 2967db96d56Sopenharmony_ci # Make sure it prints files separated by one newline without any 2977db96d56Sopenharmony_ci # 'ls -l'-like accessories if verbose flag is not being used 2987db96d56Sopenharmony_ci # ... 2997db96d56Sopenharmony_ci # ustar/conttype 3007db96d56Sopenharmony_ci # ustar/regtype 3017db96d56Sopenharmony_ci # ... 3027db96d56Sopenharmony_ci self.assertRegex(out, br'ustar/conttype ?\r?\n' 3037db96d56Sopenharmony_ci br'ustar/regtype ?\r?\n') 3047db96d56Sopenharmony_ci # Make sure it does not print the source of link without verbose flag 3057db96d56Sopenharmony_ci self.assertNotIn(b'link to', out) 3067db96d56Sopenharmony_ci self.assertNotIn(b'->', out) 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci def test_list_verbose(self): 3097db96d56Sopenharmony_ci tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') 3107db96d56Sopenharmony_ci with support.swap_attr(sys, 'stdout', tio): 3117db96d56Sopenharmony_ci self.tar.list(verbose=True) 3127db96d56Sopenharmony_ci out = tio.detach().getvalue() 3137db96d56Sopenharmony_ci # Make sure it prints files separated by one newline with 'ls -l'-like 3147db96d56Sopenharmony_ci # accessories if verbose flag is being used 3157db96d56Sopenharmony_ci # ... 3167db96d56Sopenharmony_ci # ?rw-r--r-- tarfile/tarfile 7011 2003-01-06 07:19:43 ustar/conttype 3177db96d56Sopenharmony_ci # ?rw-r--r-- tarfile/tarfile 7011 2003-01-06 07:19:43 ustar/regtype 3187db96d56Sopenharmony_ci # ... 3197db96d56Sopenharmony_ci self.assertRegex(out, (br'\?rw-r--r-- tarfile/tarfile\s+7011 ' 3207db96d56Sopenharmony_ci br'\d{4}-\d\d-\d\d\s+\d\d:\d\d:\d\d ' 3217db96d56Sopenharmony_ci br'ustar/\w+type ?\r?\n') * 2) 3227db96d56Sopenharmony_ci # Make sure it prints the source of link with verbose flag 3237db96d56Sopenharmony_ci self.assertIn(b'ustar/symtype -> regtype', out) 3247db96d56Sopenharmony_ci self.assertIn(b'./ustar/linktest2/symtype -> ../linktest1/regtype', out) 3257db96d56Sopenharmony_ci self.assertIn(b'./ustar/linktest2/lnktype link to ' 3267db96d56Sopenharmony_ci b'./ustar/linktest1/regtype', out) 3277db96d56Sopenharmony_ci self.assertIn(b'gnu' + (b'/123' * 125) + b'/longlink link to gnu' + 3287db96d56Sopenharmony_ci (b'/123' * 125) + b'/longname', out) 3297db96d56Sopenharmony_ci self.assertIn(b'pax' + (b'/123' * 125) + b'/longlink link to pax' + 3307db96d56Sopenharmony_ci (b'/123' * 125) + b'/longname', out) 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci def test_list_members(self): 3337db96d56Sopenharmony_ci tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') 3347db96d56Sopenharmony_ci def members(tar): 3357db96d56Sopenharmony_ci for tarinfo in tar.getmembers(): 3367db96d56Sopenharmony_ci if 'reg' in tarinfo.name: 3377db96d56Sopenharmony_ci yield tarinfo 3387db96d56Sopenharmony_ci with support.swap_attr(sys, 'stdout', tio): 3397db96d56Sopenharmony_ci self.tar.list(verbose=False, members=members(self.tar)) 3407db96d56Sopenharmony_ci out = tio.detach().getvalue() 3417db96d56Sopenharmony_ci self.assertIn(b'ustar/regtype', out) 3427db96d56Sopenharmony_ci self.assertNotIn(b'ustar/conttype', out) 3437db96d56Sopenharmony_ci 3447db96d56Sopenharmony_ci 3457db96d56Sopenharmony_ciclass GzipListTest(GzipTest, ListTest): 3467db96d56Sopenharmony_ci pass 3477db96d56Sopenharmony_ci 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ciclass Bz2ListTest(Bz2Test, ListTest): 3507db96d56Sopenharmony_ci pass 3517db96d56Sopenharmony_ci 3527db96d56Sopenharmony_ci 3537db96d56Sopenharmony_ciclass LzmaListTest(LzmaTest, ListTest): 3547db96d56Sopenharmony_ci pass 3557db96d56Sopenharmony_ci 3567db96d56Sopenharmony_ci 3577db96d56Sopenharmony_ciclass CommonReadTest(ReadTest): 3587db96d56Sopenharmony_ci 3597db96d56Sopenharmony_ci def test_is_tarfile_erroneous(self): 3607db96d56Sopenharmony_ci with open(tmpname, "wb"): 3617db96d56Sopenharmony_ci pass 3627db96d56Sopenharmony_ci 3637db96d56Sopenharmony_ci # is_tarfile works on filenames 3647db96d56Sopenharmony_ci self.assertFalse(tarfile.is_tarfile(tmpname)) 3657db96d56Sopenharmony_ci 3667db96d56Sopenharmony_ci # is_tarfile works on path-like objects 3677db96d56Sopenharmony_ci self.assertFalse(tarfile.is_tarfile(pathlib.Path(tmpname))) 3687db96d56Sopenharmony_ci 3697db96d56Sopenharmony_ci # is_tarfile works on file objects 3707db96d56Sopenharmony_ci with open(tmpname, "rb") as fobj: 3717db96d56Sopenharmony_ci self.assertFalse(tarfile.is_tarfile(fobj)) 3727db96d56Sopenharmony_ci 3737db96d56Sopenharmony_ci # is_tarfile works on file-like objects 3747db96d56Sopenharmony_ci self.assertFalse(tarfile.is_tarfile(io.BytesIO(b"invalid"))) 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci def test_is_tarfile_valid(self): 3777db96d56Sopenharmony_ci # is_tarfile works on filenames 3787db96d56Sopenharmony_ci self.assertTrue(tarfile.is_tarfile(self.tarname)) 3797db96d56Sopenharmony_ci 3807db96d56Sopenharmony_ci # is_tarfile works on path-like objects 3817db96d56Sopenharmony_ci self.assertTrue(tarfile.is_tarfile(pathlib.Path(self.tarname))) 3827db96d56Sopenharmony_ci 3837db96d56Sopenharmony_ci # is_tarfile works on file objects 3847db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 3857db96d56Sopenharmony_ci self.assertTrue(tarfile.is_tarfile(fobj)) 3867db96d56Sopenharmony_ci 3877db96d56Sopenharmony_ci # is_tarfile works on file-like objects 3887db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 3897db96d56Sopenharmony_ci self.assertTrue(tarfile.is_tarfile(io.BytesIO(fobj.read()))) 3907db96d56Sopenharmony_ci 3917db96d56Sopenharmony_ci def test_is_tarfile_keeps_position(self): 3927db96d56Sopenharmony_ci # Test for issue44289: tarfile.is_tarfile() modifies 3937db96d56Sopenharmony_ci # file object's current position 3947db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 3957db96d56Sopenharmony_ci tarfile.is_tarfile(fobj) 3967db96d56Sopenharmony_ci self.assertEqual(fobj.tell(), 0) 3977db96d56Sopenharmony_ci 3987db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 3997db96d56Sopenharmony_ci file_like = io.BytesIO(fobj.read()) 4007db96d56Sopenharmony_ci tarfile.is_tarfile(file_like) 4017db96d56Sopenharmony_ci self.assertEqual(file_like.tell(), 0) 4027db96d56Sopenharmony_ci 4037db96d56Sopenharmony_ci def test_empty_tarfile(self): 4047db96d56Sopenharmony_ci # Test for issue6123: Allow opening empty archives. 4057db96d56Sopenharmony_ci # This test checks if tarfile.open() is able to open an empty tar 4067db96d56Sopenharmony_ci # archive successfully. Note that an empty tar archive is not the 4077db96d56Sopenharmony_ci # same as an empty file! 4087db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode.replace("r", "w")): 4097db96d56Sopenharmony_ci pass 4107db96d56Sopenharmony_ci try: 4117db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 4127db96d56Sopenharmony_ci tar.getnames() 4137db96d56Sopenharmony_ci except tarfile.ReadError: 4147db96d56Sopenharmony_ci self.fail("tarfile.open() failed on empty archive") 4157db96d56Sopenharmony_ci else: 4167db96d56Sopenharmony_ci self.assertListEqual(tar.getmembers(), []) 4177db96d56Sopenharmony_ci finally: 4187db96d56Sopenharmony_ci tar.close() 4197db96d56Sopenharmony_ci 4207db96d56Sopenharmony_ci def test_non_existent_tarfile(self): 4217db96d56Sopenharmony_ci # Test for issue11513: prevent non-existent gzipped tarfiles raising 4227db96d56Sopenharmony_ci # multiple exceptions. 4237db96d56Sopenharmony_ci with self.assertRaisesRegex(FileNotFoundError, "xxx"): 4247db96d56Sopenharmony_ci tarfile.open("xxx", self.mode) 4257db96d56Sopenharmony_ci 4267db96d56Sopenharmony_ci def test_null_tarfile(self): 4277db96d56Sopenharmony_ci # Test for issue6123: Allow opening empty archives. 4287db96d56Sopenharmony_ci # This test guarantees that tarfile.open() does not treat an empty 4297db96d56Sopenharmony_ci # file as an empty tar archive. 4307db96d56Sopenharmony_ci with open(tmpname, "wb"): 4317db96d56Sopenharmony_ci pass 4327db96d56Sopenharmony_ci self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, self.mode) 4337db96d56Sopenharmony_ci self.assertRaises(tarfile.ReadError, tarfile.open, tmpname) 4347db96d56Sopenharmony_ci 4357db96d56Sopenharmony_ci def test_ignore_zeros(self): 4367db96d56Sopenharmony_ci # Test TarFile's ignore_zeros option. 4377db96d56Sopenharmony_ci # generate 512 pseudorandom bytes 4387db96d56Sopenharmony_ci data = Random(0).randbytes(512) 4397db96d56Sopenharmony_ci for char in (b'\0', b'a'): 4407db96d56Sopenharmony_ci # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a') 4417db96d56Sopenharmony_ci # are ignored correctly. 4427db96d56Sopenharmony_ci with self.open(tmpname, "w") as fobj: 4437db96d56Sopenharmony_ci fobj.write(char * 1024) 4447db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("foo") 4457db96d56Sopenharmony_ci tarinfo.size = len(data) 4467db96d56Sopenharmony_ci fobj.write(tarinfo.tobuf()) 4477db96d56Sopenharmony_ci fobj.write(data) 4487db96d56Sopenharmony_ci 4497db96d56Sopenharmony_ci tar = tarfile.open(tmpname, mode="r", ignore_zeros=True) 4507db96d56Sopenharmony_ci try: 4517db96d56Sopenharmony_ci self.assertListEqual(tar.getnames(), ["foo"], 4527db96d56Sopenharmony_ci "ignore_zeros=True should have skipped the %r-blocks" % 4537db96d56Sopenharmony_ci char) 4547db96d56Sopenharmony_ci finally: 4557db96d56Sopenharmony_ci tar.close() 4567db96d56Sopenharmony_ci 4577db96d56Sopenharmony_ci def test_premature_end_of_archive(self): 4587db96d56Sopenharmony_ci for size in (512, 600, 1024, 1200): 4597db96d56Sopenharmony_ci with tarfile.open(tmpname, "w:") as tar: 4607db96d56Sopenharmony_ci t = tarfile.TarInfo("foo") 4617db96d56Sopenharmony_ci t.size = 1024 4627db96d56Sopenharmony_ci tar.addfile(t, io.BytesIO(b"a" * 1024)) 4637db96d56Sopenharmony_ci 4647db96d56Sopenharmony_ci with open(tmpname, "r+b") as fobj: 4657db96d56Sopenharmony_ci fobj.truncate(size) 4667db96d56Sopenharmony_ci 4677db96d56Sopenharmony_ci with tarfile.open(tmpname) as tar: 4687db96d56Sopenharmony_ci with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): 4697db96d56Sopenharmony_ci for t in tar: 4707db96d56Sopenharmony_ci pass 4717db96d56Sopenharmony_ci 4727db96d56Sopenharmony_ci with tarfile.open(tmpname) as tar: 4737db96d56Sopenharmony_ci t = tar.next() 4747db96d56Sopenharmony_ci 4757db96d56Sopenharmony_ci with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): 4767db96d56Sopenharmony_ci tar.extract(t, TEMPDIR, filter='data') 4777db96d56Sopenharmony_ci 4787db96d56Sopenharmony_ci with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): 4797db96d56Sopenharmony_ci tar.extractfile(t).read() 4807db96d56Sopenharmony_ci 4817db96d56Sopenharmony_ci def test_length_zero_header(self): 4827db96d56Sopenharmony_ci # bpo-39017 (CVE-2019-20907): reading a zero-length header should fail 4837db96d56Sopenharmony_ci # with an exception 4847db96d56Sopenharmony_ci with self.assertRaisesRegex(tarfile.ReadError, "file could not be opened successfully"): 4857db96d56Sopenharmony_ci with tarfile.open(support.findfile('recursion.tar')) as tar: 4867db96d56Sopenharmony_ci pass 4877db96d56Sopenharmony_ci 4887db96d56Sopenharmony_ciclass MiscReadTestBase(CommonReadTest): 4897db96d56Sopenharmony_ci def requires_name_attribute(self): 4907db96d56Sopenharmony_ci pass 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci def test_no_name_argument(self): 4937db96d56Sopenharmony_ci self.requires_name_attribute() 4947db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 4957db96d56Sopenharmony_ci self.assertIsInstance(fobj.name, str) 4967db96d56Sopenharmony_ci with tarfile.open(fileobj=fobj, mode=self.mode) as tar: 4977db96d56Sopenharmony_ci self.assertIsInstance(tar.name, str) 4987db96d56Sopenharmony_ci self.assertEqual(tar.name, os.path.abspath(fobj.name)) 4997db96d56Sopenharmony_ci 5007db96d56Sopenharmony_ci def test_no_name_attribute(self): 5017db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 5027db96d56Sopenharmony_ci data = fobj.read() 5037db96d56Sopenharmony_ci fobj = io.BytesIO(data) 5047db96d56Sopenharmony_ci self.assertRaises(AttributeError, getattr, fobj, "name") 5057db96d56Sopenharmony_ci tar = tarfile.open(fileobj=fobj, mode=self.mode) 5067db96d56Sopenharmony_ci self.assertIsNone(tar.name) 5077db96d56Sopenharmony_ci 5087db96d56Sopenharmony_ci def test_empty_name_attribute(self): 5097db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 5107db96d56Sopenharmony_ci data = fobj.read() 5117db96d56Sopenharmony_ci fobj = io.BytesIO(data) 5127db96d56Sopenharmony_ci fobj.name = "" 5137db96d56Sopenharmony_ci with tarfile.open(fileobj=fobj, mode=self.mode) as tar: 5147db96d56Sopenharmony_ci self.assertIsNone(tar.name) 5157db96d56Sopenharmony_ci 5167db96d56Sopenharmony_ci def test_int_name_attribute(self): 5177db96d56Sopenharmony_ci # Issue 21044: tarfile.open() should handle fileobj with an integer 5187db96d56Sopenharmony_ci # 'name' attribute. 5197db96d56Sopenharmony_ci fd = os.open(self.tarname, os.O_RDONLY) 5207db96d56Sopenharmony_ci with open(fd, 'rb') as fobj: 5217db96d56Sopenharmony_ci self.assertIsInstance(fobj.name, int) 5227db96d56Sopenharmony_ci with tarfile.open(fileobj=fobj, mode=self.mode) as tar: 5237db96d56Sopenharmony_ci self.assertIsNone(tar.name) 5247db96d56Sopenharmony_ci 5257db96d56Sopenharmony_ci def test_bytes_name_attribute(self): 5267db96d56Sopenharmony_ci self.requires_name_attribute() 5277db96d56Sopenharmony_ci tarname = os.fsencode(self.tarname) 5287db96d56Sopenharmony_ci with open(tarname, 'rb') as fobj: 5297db96d56Sopenharmony_ci self.assertIsInstance(fobj.name, bytes) 5307db96d56Sopenharmony_ci with tarfile.open(fileobj=fobj, mode=self.mode) as tar: 5317db96d56Sopenharmony_ci self.assertIsInstance(tar.name, bytes) 5327db96d56Sopenharmony_ci self.assertEqual(tar.name, os.path.abspath(fobj.name)) 5337db96d56Sopenharmony_ci 5347db96d56Sopenharmony_ci def test_pathlike_name(self): 5357db96d56Sopenharmony_ci tarname = pathlib.Path(self.tarname) 5367db96d56Sopenharmony_ci with tarfile.open(tarname, mode=self.mode) as tar: 5377db96d56Sopenharmony_ci self.assertIsInstance(tar.name, str) 5387db96d56Sopenharmony_ci self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname))) 5397db96d56Sopenharmony_ci with self.taropen(tarname) as tar: 5407db96d56Sopenharmony_ci self.assertIsInstance(tar.name, str) 5417db96d56Sopenharmony_ci self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname))) 5427db96d56Sopenharmony_ci with tarfile.TarFile.open(tarname, mode=self.mode) as tar: 5437db96d56Sopenharmony_ci self.assertIsInstance(tar.name, str) 5447db96d56Sopenharmony_ci self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname))) 5457db96d56Sopenharmony_ci if self.suffix == '': 5467db96d56Sopenharmony_ci with tarfile.TarFile(tarname, mode='r') as tar: 5477db96d56Sopenharmony_ci self.assertIsInstance(tar.name, str) 5487db96d56Sopenharmony_ci self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname))) 5497db96d56Sopenharmony_ci 5507db96d56Sopenharmony_ci def test_illegal_mode_arg(self): 5517db96d56Sopenharmony_ci with open(tmpname, 'wb'): 5527db96d56Sopenharmony_ci pass 5537db96d56Sopenharmony_ci with self.assertRaisesRegex(ValueError, 'mode must be '): 5547db96d56Sopenharmony_ci tar = self.taropen(tmpname, 'q') 5557db96d56Sopenharmony_ci with self.assertRaisesRegex(ValueError, 'mode must be '): 5567db96d56Sopenharmony_ci tar = self.taropen(tmpname, 'rw') 5577db96d56Sopenharmony_ci with self.assertRaisesRegex(ValueError, 'mode must be '): 5587db96d56Sopenharmony_ci tar = self.taropen(tmpname, '') 5597db96d56Sopenharmony_ci 5607db96d56Sopenharmony_ci def test_fileobj_with_offset(self): 5617db96d56Sopenharmony_ci # Skip the first member and store values from the second member 5627db96d56Sopenharmony_ci # of the testtar. 5637db96d56Sopenharmony_ci tar = tarfile.open(self.tarname, mode=self.mode) 5647db96d56Sopenharmony_ci try: 5657db96d56Sopenharmony_ci tar.next() 5667db96d56Sopenharmony_ci t = tar.next() 5677db96d56Sopenharmony_ci name = t.name 5687db96d56Sopenharmony_ci offset = t.offset 5697db96d56Sopenharmony_ci with tar.extractfile(t) as f: 5707db96d56Sopenharmony_ci data = f.read() 5717db96d56Sopenharmony_ci finally: 5727db96d56Sopenharmony_ci tar.close() 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci # Open the testtar and seek to the offset of the second member. 5757db96d56Sopenharmony_ci with self.open(self.tarname) as fobj: 5767db96d56Sopenharmony_ci fobj.seek(offset) 5777db96d56Sopenharmony_ci 5787db96d56Sopenharmony_ci # Test if the tarfile starts with the second member. 5797db96d56Sopenharmony_ci with tar.open(self.tarname, mode="r:", fileobj=fobj) as tar: 5807db96d56Sopenharmony_ci t = tar.next() 5817db96d56Sopenharmony_ci self.assertEqual(t.name, name) 5827db96d56Sopenharmony_ci # Read to the end of fileobj and test if seeking back to the 5837db96d56Sopenharmony_ci # beginning works. 5847db96d56Sopenharmony_ci tar.getmembers() 5857db96d56Sopenharmony_ci self.assertEqual(tar.extractfile(t).read(), data, 5867db96d56Sopenharmony_ci "seek back did not work") 5877db96d56Sopenharmony_ci 5887db96d56Sopenharmony_ci def test_fail_comp(self): 5897db96d56Sopenharmony_ci # For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file. 5907db96d56Sopenharmony_ci self.assertRaises(tarfile.ReadError, tarfile.open, tarname, self.mode) 5917db96d56Sopenharmony_ci with open(tarname, "rb") as fobj: 5927db96d56Sopenharmony_ci self.assertRaises(tarfile.ReadError, tarfile.open, 5937db96d56Sopenharmony_ci fileobj=fobj, mode=self.mode) 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci def test_v7_dirtype(self): 5967db96d56Sopenharmony_ci # Test old style dirtype member (bug #1336623): 5977db96d56Sopenharmony_ci # Old V7 tars create directory members using an AREGTYPE 5987db96d56Sopenharmony_ci # header with a "/" appended to the filename field. 5997db96d56Sopenharmony_ci tarinfo = self.tar.getmember("misc/dirtype-old-v7") 6007db96d56Sopenharmony_ci self.assertEqual(tarinfo.type, tarfile.DIRTYPE, 6017db96d56Sopenharmony_ci "v7 dirtype failed") 6027db96d56Sopenharmony_ci 6037db96d56Sopenharmony_ci def test_xstar_type(self): 6047db96d56Sopenharmony_ci # The xstar format stores extra atime and ctime fields inside the 6057db96d56Sopenharmony_ci # space reserved for the prefix field. The prefix field must be 6067db96d56Sopenharmony_ci # ignored in this case, otherwise it will mess up the name. 6077db96d56Sopenharmony_ci try: 6087db96d56Sopenharmony_ci self.tar.getmember("misc/regtype-xstar") 6097db96d56Sopenharmony_ci except KeyError: 6107db96d56Sopenharmony_ci self.fail("failed to find misc/regtype-xstar (mangled prefix?)") 6117db96d56Sopenharmony_ci 6127db96d56Sopenharmony_ci def test_check_members(self): 6137db96d56Sopenharmony_ci for tarinfo in self.tar: 6147db96d56Sopenharmony_ci self.assertEqual(int(tarinfo.mtime), 0o7606136617, 6157db96d56Sopenharmony_ci "wrong mtime for %s" % tarinfo.name) 6167db96d56Sopenharmony_ci if not tarinfo.name.startswith("ustar/"): 6177db96d56Sopenharmony_ci continue 6187db96d56Sopenharmony_ci self.assertEqual(tarinfo.uname, "tarfile", 6197db96d56Sopenharmony_ci "wrong uname for %s" % tarinfo.name) 6207db96d56Sopenharmony_ci 6217db96d56Sopenharmony_ci def test_find_members(self): 6227db96d56Sopenharmony_ci self.assertEqual(self.tar.getmembers()[-1].name, "misc/eof", 6237db96d56Sopenharmony_ci "could not find all members") 6247db96d56Sopenharmony_ci 6257db96d56Sopenharmony_ci @unittest.skipUnless(hasattr(os, "link"), 6267db96d56Sopenharmony_ci "Missing hardlink implementation") 6277db96d56Sopenharmony_ci @os_helper.skip_unless_symlink 6287db96d56Sopenharmony_ci def test_extract_hardlink(self): 6297db96d56Sopenharmony_ci # Test hardlink extraction (e.g. bug #857297). 6307db96d56Sopenharmony_ci with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar: 6317db96d56Sopenharmony_ci tar.extract("ustar/regtype", TEMPDIR, filter='data') 6327db96d56Sopenharmony_ci self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/regtype")) 6337db96d56Sopenharmony_ci 6347db96d56Sopenharmony_ci tar.extract("ustar/lnktype", TEMPDIR, filter='data') 6357db96d56Sopenharmony_ci self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/lnktype")) 6367db96d56Sopenharmony_ci with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f: 6377db96d56Sopenharmony_ci data = f.read() 6387db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_regtype) 6397db96d56Sopenharmony_ci 6407db96d56Sopenharmony_ci tar.extract("ustar/symtype", TEMPDIR, filter='data') 6417db96d56Sopenharmony_ci self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/symtype")) 6427db96d56Sopenharmony_ci with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f: 6437db96d56Sopenharmony_ci data = f.read() 6447db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_regtype) 6457db96d56Sopenharmony_ci 6467db96d56Sopenharmony_ci @os_helper.skip_unless_working_chmod 6477db96d56Sopenharmony_ci def test_extractall(self): 6487db96d56Sopenharmony_ci # Test if extractall() correctly restores directory permissions 6497db96d56Sopenharmony_ci # and times (see issue1735). 6507db96d56Sopenharmony_ci tar = tarfile.open(tarname, encoding="iso8859-1") 6517db96d56Sopenharmony_ci DIR = os.path.join(TEMPDIR, "extractall") 6527db96d56Sopenharmony_ci os.mkdir(DIR) 6537db96d56Sopenharmony_ci try: 6547db96d56Sopenharmony_ci directories = [t for t in tar if t.isdir()] 6557db96d56Sopenharmony_ci tar.extractall(DIR, directories, filter='fully_trusted') 6567db96d56Sopenharmony_ci for tarinfo in directories: 6577db96d56Sopenharmony_ci path = os.path.join(DIR, tarinfo.name) 6587db96d56Sopenharmony_ci if sys.platform != "win32": 6597db96d56Sopenharmony_ci # Win32 has no support for fine grained permissions. 6607db96d56Sopenharmony_ci self.assertEqual(tarinfo.mode & 0o777, 6617db96d56Sopenharmony_ci os.stat(path).st_mode & 0o777, 6627db96d56Sopenharmony_ci tarinfo.name) 6637db96d56Sopenharmony_ci def format_mtime(mtime): 6647db96d56Sopenharmony_ci if isinstance(mtime, float): 6657db96d56Sopenharmony_ci return "{} ({})".format(mtime, mtime.hex()) 6667db96d56Sopenharmony_ci else: 6677db96d56Sopenharmony_ci return "{!r} (int)".format(mtime) 6687db96d56Sopenharmony_ci file_mtime = os.path.getmtime(path) 6697db96d56Sopenharmony_ci errmsg = "tar mtime {0} != file time {1} of path {2!a}".format( 6707db96d56Sopenharmony_ci format_mtime(tarinfo.mtime), 6717db96d56Sopenharmony_ci format_mtime(file_mtime), 6727db96d56Sopenharmony_ci path) 6737db96d56Sopenharmony_ci self.assertEqual(tarinfo.mtime, file_mtime, errmsg) 6747db96d56Sopenharmony_ci finally: 6757db96d56Sopenharmony_ci tar.close() 6767db96d56Sopenharmony_ci os_helper.rmtree(DIR) 6777db96d56Sopenharmony_ci 6787db96d56Sopenharmony_ci @os_helper.skip_unless_working_chmod 6797db96d56Sopenharmony_ci def test_extract_directory(self): 6807db96d56Sopenharmony_ci dirtype = "ustar/dirtype" 6817db96d56Sopenharmony_ci DIR = os.path.join(TEMPDIR, "extractdir") 6827db96d56Sopenharmony_ci os.mkdir(DIR) 6837db96d56Sopenharmony_ci try: 6847db96d56Sopenharmony_ci with tarfile.open(tarname, encoding="iso8859-1") as tar: 6857db96d56Sopenharmony_ci tarinfo = tar.getmember(dirtype) 6867db96d56Sopenharmony_ci tar.extract(tarinfo, path=DIR, filter='fully_trusted') 6877db96d56Sopenharmony_ci extracted = os.path.join(DIR, dirtype) 6887db96d56Sopenharmony_ci self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime) 6897db96d56Sopenharmony_ci if sys.platform != "win32": 6907db96d56Sopenharmony_ci self.assertEqual(os.stat(extracted).st_mode & 0o777, 0o755) 6917db96d56Sopenharmony_ci finally: 6927db96d56Sopenharmony_ci os_helper.rmtree(DIR) 6937db96d56Sopenharmony_ci 6947db96d56Sopenharmony_ci def test_extractall_pathlike_name(self): 6957db96d56Sopenharmony_ci DIR = pathlib.Path(TEMPDIR) / "extractall" 6967db96d56Sopenharmony_ci with os_helper.temp_dir(DIR), \ 6977db96d56Sopenharmony_ci tarfile.open(tarname, encoding="iso8859-1") as tar: 6987db96d56Sopenharmony_ci directories = [t for t in tar if t.isdir()] 6997db96d56Sopenharmony_ci tar.extractall(DIR, directories, filter='fully_trusted') 7007db96d56Sopenharmony_ci for tarinfo in directories: 7017db96d56Sopenharmony_ci path = DIR / tarinfo.name 7027db96d56Sopenharmony_ci self.assertEqual(os.path.getmtime(path), tarinfo.mtime) 7037db96d56Sopenharmony_ci 7047db96d56Sopenharmony_ci def test_extract_pathlike_name(self): 7057db96d56Sopenharmony_ci dirtype = "ustar/dirtype" 7067db96d56Sopenharmony_ci DIR = pathlib.Path(TEMPDIR) / "extractall" 7077db96d56Sopenharmony_ci with os_helper.temp_dir(DIR), \ 7087db96d56Sopenharmony_ci tarfile.open(tarname, encoding="iso8859-1") as tar: 7097db96d56Sopenharmony_ci tarinfo = tar.getmember(dirtype) 7107db96d56Sopenharmony_ci tar.extract(tarinfo, path=DIR, filter='fully_trusted') 7117db96d56Sopenharmony_ci extracted = DIR / dirtype 7127db96d56Sopenharmony_ci self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime) 7137db96d56Sopenharmony_ci 7147db96d56Sopenharmony_ci def test_init_close_fobj(self): 7157db96d56Sopenharmony_ci # Issue #7341: Close the internal file object in the TarFile 7167db96d56Sopenharmony_ci # constructor in case of an error. For the test we rely on 7177db96d56Sopenharmony_ci # the fact that opening an empty file raises a ReadError. 7187db96d56Sopenharmony_ci empty = os.path.join(TEMPDIR, "empty") 7197db96d56Sopenharmony_ci with open(empty, "wb") as fobj: 7207db96d56Sopenharmony_ci fobj.write(b"") 7217db96d56Sopenharmony_ci 7227db96d56Sopenharmony_ci try: 7237db96d56Sopenharmony_ci tar = object.__new__(tarfile.TarFile) 7247db96d56Sopenharmony_ci try: 7257db96d56Sopenharmony_ci tar.__init__(empty) 7267db96d56Sopenharmony_ci except tarfile.ReadError: 7277db96d56Sopenharmony_ci self.assertTrue(tar.fileobj.closed) 7287db96d56Sopenharmony_ci else: 7297db96d56Sopenharmony_ci self.fail("ReadError not raised") 7307db96d56Sopenharmony_ci finally: 7317db96d56Sopenharmony_ci os_helper.unlink(empty) 7327db96d56Sopenharmony_ci 7337db96d56Sopenharmony_ci def test_parallel_iteration(self): 7347db96d56Sopenharmony_ci # Issue #16601: Restarting iteration over tarfile continued 7357db96d56Sopenharmony_ci # from where it left off. 7367db96d56Sopenharmony_ci with tarfile.open(self.tarname) as tar: 7377db96d56Sopenharmony_ci for m1, m2 in zip(tar, tar): 7387db96d56Sopenharmony_ci self.assertEqual(m1.offset, m2.offset) 7397db96d56Sopenharmony_ci self.assertEqual(m1.get_info(), m2.get_info()) 7407db96d56Sopenharmony_ci 7417db96d56Sopenharmony_ci @unittest.skipIf(zlib is None, "requires zlib") 7427db96d56Sopenharmony_ci def test_zlib_error_does_not_leak(self): 7437db96d56Sopenharmony_ci # bpo-39039: tarfile.open allowed zlib exceptions to bubble up when 7447db96d56Sopenharmony_ci # parsing certain types of invalid data 7457db96d56Sopenharmony_ci with unittest.mock.patch("tarfile.TarInfo.fromtarfile") as mock: 7467db96d56Sopenharmony_ci mock.side_effect = zlib.error 7477db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError): 7487db96d56Sopenharmony_ci tarfile.open(self.tarname) 7497db96d56Sopenharmony_ci 7507db96d56Sopenharmony_ci def test_next_on_empty_tarfile(self): 7517db96d56Sopenharmony_ci fd = io.BytesIO() 7527db96d56Sopenharmony_ci tf = tarfile.open(fileobj=fd, mode="w") 7537db96d56Sopenharmony_ci tf.close() 7547db96d56Sopenharmony_ci 7557db96d56Sopenharmony_ci fd.seek(0) 7567db96d56Sopenharmony_ci with tarfile.open(fileobj=fd, mode="r|") as tf: 7577db96d56Sopenharmony_ci self.assertEqual(tf.next(), None) 7587db96d56Sopenharmony_ci 7597db96d56Sopenharmony_ci fd.seek(0) 7607db96d56Sopenharmony_ci with tarfile.open(fileobj=fd, mode="r") as tf: 7617db96d56Sopenharmony_ci self.assertEqual(tf.next(), None) 7627db96d56Sopenharmony_ci 7637db96d56Sopenharmony_ciclass MiscReadTest(MiscReadTestBase, unittest.TestCase): 7647db96d56Sopenharmony_ci test_fail_comp = None 7657db96d56Sopenharmony_ci 7667db96d56Sopenharmony_ciclass GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase): 7677db96d56Sopenharmony_ci pass 7687db96d56Sopenharmony_ci 7697db96d56Sopenharmony_ciclass Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase): 7707db96d56Sopenharmony_ci def requires_name_attribute(self): 7717db96d56Sopenharmony_ci self.skipTest("BZ2File have no name attribute") 7727db96d56Sopenharmony_ci 7737db96d56Sopenharmony_ciclass LzmaMiscReadTest(LzmaTest, MiscReadTestBase, unittest.TestCase): 7747db96d56Sopenharmony_ci def requires_name_attribute(self): 7757db96d56Sopenharmony_ci self.skipTest("LZMAFile have no name attribute") 7767db96d56Sopenharmony_ci 7777db96d56Sopenharmony_ci 7787db96d56Sopenharmony_ciclass StreamReadTest(CommonReadTest, unittest.TestCase): 7797db96d56Sopenharmony_ci 7807db96d56Sopenharmony_ci prefix="r|" 7817db96d56Sopenharmony_ci 7827db96d56Sopenharmony_ci def test_read_through(self): 7837db96d56Sopenharmony_ci # Issue #11224: A poorly designed _FileInFile.read() method 7847db96d56Sopenharmony_ci # caused seeking errors with stream tar files. 7857db96d56Sopenharmony_ci for tarinfo in self.tar: 7867db96d56Sopenharmony_ci if not tarinfo.isreg(): 7877db96d56Sopenharmony_ci continue 7887db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as fobj: 7897db96d56Sopenharmony_ci while True: 7907db96d56Sopenharmony_ci try: 7917db96d56Sopenharmony_ci buf = fobj.read(512) 7927db96d56Sopenharmony_ci except tarfile.StreamError: 7937db96d56Sopenharmony_ci self.fail("simple read-through using " 7947db96d56Sopenharmony_ci "TarFile.extractfile() failed") 7957db96d56Sopenharmony_ci if not buf: 7967db96d56Sopenharmony_ci break 7977db96d56Sopenharmony_ci 7987db96d56Sopenharmony_ci def test_fileobj_regular_file(self): 7997db96d56Sopenharmony_ci tarinfo = self.tar.next() # get "regtype" (can't use getmember) 8007db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as fobj: 8017db96d56Sopenharmony_ci data = fobj.read() 8027db96d56Sopenharmony_ci self.assertEqual(len(data), tarinfo.size, 8037db96d56Sopenharmony_ci "regular file extraction failed") 8047db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_regtype, 8057db96d56Sopenharmony_ci "regular file extraction failed") 8067db96d56Sopenharmony_ci 8077db96d56Sopenharmony_ci def test_provoke_stream_error(self): 8087db96d56Sopenharmony_ci tarinfos = self.tar.getmembers() 8097db96d56Sopenharmony_ci with self.tar.extractfile(tarinfos[0]) as f: # read the first member 8107db96d56Sopenharmony_ci self.assertRaises(tarfile.StreamError, f.read) 8117db96d56Sopenharmony_ci 8127db96d56Sopenharmony_ci def test_compare_members(self): 8137db96d56Sopenharmony_ci tar1 = tarfile.open(tarname, encoding="iso8859-1") 8147db96d56Sopenharmony_ci try: 8157db96d56Sopenharmony_ci tar2 = self.tar 8167db96d56Sopenharmony_ci 8177db96d56Sopenharmony_ci while True: 8187db96d56Sopenharmony_ci t1 = tar1.next() 8197db96d56Sopenharmony_ci t2 = tar2.next() 8207db96d56Sopenharmony_ci if t1 is None: 8217db96d56Sopenharmony_ci break 8227db96d56Sopenharmony_ci self.assertIsNotNone(t2, "stream.next() failed.") 8237db96d56Sopenharmony_ci 8247db96d56Sopenharmony_ci if t2.islnk() or t2.issym(): 8257db96d56Sopenharmony_ci with self.assertRaises(tarfile.StreamError): 8267db96d56Sopenharmony_ci tar2.extractfile(t2) 8277db96d56Sopenharmony_ci continue 8287db96d56Sopenharmony_ci 8297db96d56Sopenharmony_ci v1 = tar1.extractfile(t1) 8307db96d56Sopenharmony_ci v2 = tar2.extractfile(t2) 8317db96d56Sopenharmony_ci if v1 is None: 8327db96d56Sopenharmony_ci continue 8337db96d56Sopenharmony_ci self.assertIsNotNone(v2, "stream.extractfile() failed") 8347db96d56Sopenharmony_ci self.assertEqual(v1.read(), v2.read(), 8357db96d56Sopenharmony_ci "stream extraction failed") 8367db96d56Sopenharmony_ci finally: 8377db96d56Sopenharmony_ci tar1.close() 8387db96d56Sopenharmony_ci 8397db96d56Sopenharmony_ciclass GzipStreamReadTest(GzipTest, StreamReadTest): 8407db96d56Sopenharmony_ci pass 8417db96d56Sopenharmony_ci 8427db96d56Sopenharmony_ciclass Bz2StreamReadTest(Bz2Test, StreamReadTest): 8437db96d56Sopenharmony_ci pass 8447db96d56Sopenharmony_ci 8457db96d56Sopenharmony_ciclass LzmaStreamReadTest(LzmaTest, StreamReadTest): 8467db96d56Sopenharmony_ci pass 8477db96d56Sopenharmony_ci 8487db96d56Sopenharmony_ci 8497db96d56Sopenharmony_ciclass DetectReadTest(TarTest, unittest.TestCase): 8507db96d56Sopenharmony_ci def _testfunc_file(self, name, mode): 8517db96d56Sopenharmony_ci try: 8527db96d56Sopenharmony_ci tar = tarfile.open(name, mode) 8537db96d56Sopenharmony_ci except tarfile.ReadError as e: 8547db96d56Sopenharmony_ci self.fail() 8557db96d56Sopenharmony_ci else: 8567db96d56Sopenharmony_ci tar.close() 8577db96d56Sopenharmony_ci 8587db96d56Sopenharmony_ci def _testfunc_fileobj(self, name, mode): 8597db96d56Sopenharmony_ci try: 8607db96d56Sopenharmony_ci with open(name, "rb") as f: 8617db96d56Sopenharmony_ci tar = tarfile.open(name, mode, fileobj=f) 8627db96d56Sopenharmony_ci except tarfile.ReadError as e: 8637db96d56Sopenharmony_ci self.fail() 8647db96d56Sopenharmony_ci else: 8657db96d56Sopenharmony_ci tar.close() 8667db96d56Sopenharmony_ci 8677db96d56Sopenharmony_ci def _test_modes(self, testfunc): 8687db96d56Sopenharmony_ci if self.suffix: 8697db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError): 8707db96d56Sopenharmony_ci tarfile.open(tarname, mode="r:" + self.suffix) 8717db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError): 8727db96d56Sopenharmony_ci tarfile.open(tarname, mode="r|" + self.suffix) 8737db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError): 8747db96d56Sopenharmony_ci tarfile.open(self.tarname, mode="r:") 8757db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError): 8767db96d56Sopenharmony_ci tarfile.open(self.tarname, mode="r|") 8777db96d56Sopenharmony_ci testfunc(self.tarname, "r") 8787db96d56Sopenharmony_ci testfunc(self.tarname, "r:" + self.suffix) 8797db96d56Sopenharmony_ci testfunc(self.tarname, "r:*") 8807db96d56Sopenharmony_ci testfunc(self.tarname, "r|" + self.suffix) 8817db96d56Sopenharmony_ci testfunc(self.tarname, "r|*") 8827db96d56Sopenharmony_ci 8837db96d56Sopenharmony_ci def test_detect_file(self): 8847db96d56Sopenharmony_ci self._test_modes(self._testfunc_file) 8857db96d56Sopenharmony_ci 8867db96d56Sopenharmony_ci def test_detect_fileobj(self): 8877db96d56Sopenharmony_ci self._test_modes(self._testfunc_fileobj) 8887db96d56Sopenharmony_ci 8897db96d56Sopenharmony_ciclass GzipDetectReadTest(GzipTest, DetectReadTest): 8907db96d56Sopenharmony_ci pass 8917db96d56Sopenharmony_ci 8927db96d56Sopenharmony_ciclass Bz2DetectReadTest(Bz2Test, DetectReadTest): 8937db96d56Sopenharmony_ci def test_detect_stream_bz2(self): 8947db96d56Sopenharmony_ci # Originally, tarfile's stream detection looked for the string 8957db96d56Sopenharmony_ci # "BZh91" at the start of the file. This is incorrect because 8967db96d56Sopenharmony_ci # the '9' represents the blocksize (900,000 bytes). If the file was 8977db96d56Sopenharmony_ci # compressed using another blocksize autodetection fails. 8987db96d56Sopenharmony_ci with open(tarname, "rb") as fobj: 8997db96d56Sopenharmony_ci data = fobj.read() 9007db96d56Sopenharmony_ci 9017db96d56Sopenharmony_ci # Compress with blocksize 100,000 bytes, the file starts with "BZh11". 9027db96d56Sopenharmony_ci with bz2.BZ2File(tmpname, "wb", compresslevel=1) as fobj: 9037db96d56Sopenharmony_ci fobj.write(data) 9047db96d56Sopenharmony_ci 9057db96d56Sopenharmony_ci self._testfunc_file(tmpname, "r|*") 9067db96d56Sopenharmony_ci 9077db96d56Sopenharmony_ciclass LzmaDetectReadTest(LzmaTest, DetectReadTest): 9087db96d56Sopenharmony_ci pass 9097db96d56Sopenharmony_ci 9107db96d56Sopenharmony_ci 9117db96d56Sopenharmony_ciclass MemberReadTest(ReadTest, unittest.TestCase): 9127db96d56Sopenharmony_ci 9137db96d56Sopenharmony_ci def _test_member(self, tarinfo, chksum=None, **kwargs): 9147db96d56Sopenharmony_ci if chksum is not None: 9157db96d56Sopenharmony_ci with self.tar.extractfile(tarinfo) as f: 9167db96d56Sopenharmony_ci self.assertEqual(sha256sum(f.read()), chksum, 9177db96d56Sopenharmony_ci "wrong sha256sum for %s" % tarinfo.name) 9187db96d56Sopenharmony_ci 9197db96d56Sopenharmony_ci kwargs["mtime"] = 0o7606136617 9207db96d56Sopenharmony_ci kwargs["uid"] = 1000 9217db96d56Sopenharmony_ci kwargs["gid"] = 100 9227db96d56Sopenharmony_ci if "old-v7" not in tarinfo.name: 9237db96d56Sopenharmony_ci # V7 tar can't handle alphabetic owners. 9247db96d56Sopenharmony_ci kwargs["uname"] = "tarfile" 9257db96d56Sopenharmony_ci kwargs["gname"] = "tarfile" 9267db96d56Sopenharmony_ci for k, v in kwargs.items(): 9277db96d56Sopenharmony_ci self.assertEqual(getattr(tarinfo, k), v, 9287db96d56Sopenharmony_ci "wrong value in %s field of %s" % (k, tarinfo.name)) 9297db96d56Sopenharmony_ci 9307db96d56Sopenharmony_ci def test_find_regtype(self): 9317db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/regtype") 9327db96d56Sopenharmony_ci self._test_member(tarinfo, size=7011, chksum=sha256_regtype) 9337db96d56Sopenharmony_ci 9347db96d56Sopenharmony_ci def test_find_conttype(self): 9357db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/conttype") 9367db96d56Sopenharmony_ci self._test_member(tarinfo, size=7011, chksum=sha256_regtype) 9377db96d56Sopenharmony_ci 9387db96d56Sopenharmony_ci def test_find_dirtype(self): 9397db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/dirtype") 9407db96d56Sopenharmony_ci self._test_member(tarinfo, size=0) 9417db96d56Sopenharmony_ci 9427db96d56Sopenharmony_ci def test_find_dirtype_with_size(self): 9437db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/dirtype-with-size") 9447db96d56Sopenharmony_ci self._test_member(tarinfo, size=255) 9457db96d56Sopenharmony_ci 9467db96d56Sopenharmony_ci def test_find_lnktype(self): 9477db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/lnktype") 9487db96d56Sopenharmony_ci self._test_member(tarinfo, size=0, linkname="ustar/regtype") 9497db96d56Sopenharmony_ci 9507db96d56Sopenharmony_ci def test_find_symtype(self): 9517db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/symtype") 9527db96d56Sopenharmony_ci self._test_member(tarinfo, size=0, linkname="regtype") 9537db96d56Sopenharmony_ci 9547db96d56Sopenharmony_ci def test_find_blktype(self): 9557db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/blktype") 9567db96d56Sopenharmony_ci self._test_member(tarinfo, size=0, devmajor=3, devminor=0) 9577db96d56Sopenharmony_ci 9587db96d56Sopenharmony_ci def test_find_chrtype(self): 9597db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/chrtype") 9607db96d56Sopenharmony_ci self._test_member(tarinfo, size=0, devmajor=1, devminor=3) 9617db96d56Sopenharmony_ci 9627db96d56Sopenharmony_ci def test_find_fifotype(self): 9637db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/fifotype") 9647db96d56Sopenharmony_ci self._test_member(tarinfo, size=0) 9657db96d56Sopenharmony_ci 9667db96d56Sopenharmony_ci def test_find_sparse(self): 9677db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/sparse") 9687db96d56Sopenharmony_ci self._test_member(tarinfo, size=86016, chksum=sha256_sparse) 9697db96d56Sopenharmony_ci 9707db96d56Sopenharmony_ci def test_find_gnusparse(self): 9717db96d56Sopenharmony_ci tarinfo = self.tar.getmember("gnu/sparse") 9727db96d56Sopenharmony_ci self._test_member(tarinfo, size=86016, chksum=sha256_sparse) 9737db96d56Sopenharmony_ci 9747db96d56Sopenharmony_ci def test_find_gnusparse_00(self): 9757db96d56Sopenharmony_ci tarinfo = self.tar.getmember("gnu/sparse-0.0") 9767db96d56Sopenharmony_ci self._test_member(tarinfo, size=86016, chksum=sha256_sparse) 9777db96d56Sopenharmony_ci 9787db96d56Sopenharmony_ci def test_find_gnusparse_01(self): 9797db96d56Sopenharmony_ci tarinfo = self.tar.getmember("gnu/sparse-0.1") 9807db96d56Sopenharmony_ci self._test_member(tarinfo, size=86016, chksum=sha256_sparse) 9817db96d56Sopenharmony_ci 9827db96d56Sopenharmony_ci def test_find_gnusparse_10(self): 9837db96d56Sopenharmony_ci tarinfo = self.tar.getmember("gnu/sparse-1.0") 9847db96d56Sopenharmony_ci self._test_member(tarinfo, size=86016, chksum=sha256_sparse) 9857db96d56Sopenharmony_ci 9867db96d56Sopenharmony_ci def test_find_umlauts(self): 9877db96d56Sopenharmony_ci tarinfo = self.tar.getmember("ustar/umlauts-" 9887db96d56Sopenharmony_ci "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") 9897db96d56Sopenharmony_ci self._test_member(tarinfo, size=7011, chksum=sha256_regtype) 9907db96d56Sopenharmony_ci 9917db96d56Sopenharmony_ci def test_find_ustar_longname(self): 9927db96d56Sopenharmony_ci name = "ustar/" + "12345/" * 39 + "1234567/longname" 9937db96d56Sopenharmony_ci self.assertIn(name, self.tar.getnames()) 9947db96d56Sopenharmony_ci 9957db96d56Sopenharmony_ci def test_find_regtype_oldv7(self): 9967db96d56Sopenharmony_ci tarinfo = self.tar.getmember("misc/regtype-old-v7") 9977db96d56Sopenharmony_ci self._test_member(tarinfo, size=7011, chksum=sha256_regtype) 9987db96d56Sopenharmony_ci 9997db96d56Sopenharmony_ci def test_find_pax_umlauts(self): 10007db96d56Sopenharmony_ci self.tar.close() 10017db96d56Sopenharmony_ci self.tar = tarfile.open(self.tarname, mode=self.mode, 10027db96d56Sopenharmony_ci encoding="iso8859-1") 10037db96d56Sopenharmony_ci tarinfo = self.tar.getmember("pax/umlauts-" 10047db96d56Sopenharmony_ci "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") 10057db96d56Sopenharmony_ci self._test_member(tarinfo, size=7011, chksum=sha256_regtype) 10067db96d56Sopenharmony_ci 10077db96d56Sopenharmony_ci 10087db96d56Sopenharmony_ciclass LongnameTest: 10097db96d56Sopenharmony_ci 10107db96d56Sopenharmony_ci def test_read_longname(self): 10117db96d56Sopenharmony_ci # Test reading of longname (bug #1471427). 10127db96d56Sopenharmony_ci longname = self.subdir + "/" + "123/" * 125 + "longname" 10137db96d56Sopenharmony_ci try: 10147db96d56Sopenharmony_ci tarinfo = self.tar.getmember(longname) 10157db96d56Sopenharmony_ci except KeyError: 10167db96d56Sopenharmony_ci self.fail("longname not found") 10177db96d56Sopenharmony_ci self.assertNotEqual(tarinfo.type, tarfile.DIRTYPE, 10187db96d56Sopenharmony_ci "read longname as dirtype") 10197db96d56Sopenharmony_ci 10207db96d56Sopenharmony_ci def test_read_longlink(self): 10217db96d56Sopenharmony_ci longname = self.subdir + "/" + "123/" * 125 + "longname" 10227db96d56Sopenharmony_ci longlink = self.subdir + "/" + "123/" * 125 + "longlink" 10237db96d56Sopenharmony_ci try: 10247db96d56Sopenharmony_ci tarinfo = self.tar.getmember(longlink) 10257db96d56Sopenharmony_ci except KeyError: 10267db96d56Sopenharmony_ci self.fail("longlink not found") 10277db96d56Sopenharmony_ci self.assertEqual(tarinfo.linkname, longname, "linkname wrong") 10287db96d56Sopenharmony_ci 10297db96d56Sopenharmony_ci def test_truncated_longname(self): 10307db96d56Sopenharmony_ci longname = self.subdir + "/" + "123/" * 125 + "longname" 10317db96d56Sopenharmony_ci tarinfo = self.tar.getmember(longname) 10327db96d56Sopenharmony_ci offset = tarinfo.offset 10337db96d56Sopenharmony_ci self.tar.fileobj.seek(offset) 10347db96d56Sopenharmony_ci fobj = io.BytesIO(self.tar.fileobj.read(3 * 512)) 10357db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError): 10367db96d56Sopenharmony_ci tarfile.open(name="foo.tar", fileobj=fobj) 10377db96d56Sopenharmony_ci 10387db96d56Sopenharmony_ci def test_header_offset(self): 10397db96d56Sopenharmony_ci # Test if the start offset of the TarInfo object includes 10407db96d56Sopenharmony_ci # the preceding extended header. 10417db96d56Sopenharmony_ci longname = self.subdir + "/" + "123/" * 125 + "longname" 10427db96d56Sopenharmony_ci offset = self.tar.getmember(longname).offset 10437db96d56Sopenharmony_ci with open(tarname, "rb") as fobj: 10447db96d56Sopenharmony_ci fobj.seek(offset) 10457db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo.frombuf(fobj.read(512), 10467db96d56Sopenharmony_ci "iso8859-1", "strict") 10477db96d56Sopenharmony_ci self.assertEqual(tarinfo.type, self.longnametype) 10487db96d56Sopenharmony_ci 10497db96d56Sopenharmony_ci def test_longname_directory(self): 10507db96d56Sopenharmony_ci # Test reading a longlink directory. Issue #47231. 10517db96d56Sopenharmony_ci longdir = ('a' * 101) + '/' 10527db96d56Sopenharmony_ci with os_helper.temp_cwd(): 10537db96d56Sopenharmony_ci with tarfile.open(tmpname, 'w') as tar: 10547db96d56Sopenharmony_ci tar.format = self.format 10557db96d56Sopenharmony_ci try: 10567db96d56Sopenharmony_ci os.mkdir(longdir) 10577db96d56Sopenharmony_ci tar.add(longdir) 10587db96d56Sopenharmony_ci finally: 10597db96d56Sopenharmony_ci os.rmdir(longdir.rstrip("/")) 10607db96d56Sopenharmony_ci with tarfile.open(tmpname) as tar: 10617db96d56Sopenharmony_ci self.assertIsNotNone(tar.getmember(longdir)) 10627db96d56Sopenharmony_ci self.assertIsNotNone(tar.getmember(longdir.removesuffix('/'))) 10637db96d56Sopenharmony_ci 10647db96d56Sopenharmony_ciclass GNUReadTest(LongnameTest, ReadTest, unittest.TestCase): 10657db96d56Sopenharmony_ci 10667db96d56Sopenharmony_ci subdir = "gnu" 10677db96d56Sopenharmony_ci longnametype = tarfile.GNUTYPE_LONGNAME 10687db96d56Sopenharmony_ci format = tarfile.GNU_FORMAT 10697db96d56Sopenharmony_ci 10707db96d56Sopenharmony_ci # Since 3.2 tarfile is supposed to accurately restore sparse members and 10717db96d56Sopenharmony_ci # produce files with holes. This is what we actually want to test here. 10727db96d56Sopenharmony_ci # Unfortunately, not all platforms/filesystems support sparse files, and 10737db96d56Sopenharmony_ci # even on platforms that do it is non-trivial to make reliable assertions 10747db96d56Sopenharmony_ci # about holes in files. Therefore, we first do one basic test which works 10757db96d56Sopenharmony_ci # an all platforms, and after that a test that will work only on 10767db96d56Sopenharmony_ci # platforms/filesystems that prove to support sparse files. 10777db96d56Sopenharmony_ci def _test_sparse_file(self, name): 10787db96d56Sopenharmony_ci self.tar.extract(name, TEMPDIR, filter='data') 10797db96d56Sopenharmony_ci filename = os.path.join(TEMPDIR, name) 10807db96d56Sopenharmony_ci with open(filename, "rb") as fobj: 10817db96d56Sopenharmony_ci data = fobj.read() 10827db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_sparse, 10837db96d56Sopenharmony_ci "wrong sha256sum for %s" % name) 10847db96d56Sopenharmony_ci 10857db96d56Sopenharmony_ci if self._fs_supports_holes(): 10867db96d56Sopenharmony_ci s = os.stat(filename) 10877db96d56Sopenharmony_ci self.assertLess(s.st_blocks * 512, s.st_size) 10887db96d56Sopenharmony_ci 10897db96d56Sopenharmony_ci def test_sparse_file_old(self): 10907db96d56Sopenharmony_ci self._test_sparse_file("gnu/sparse") 10917db96d56Sopenharmony_ci 10927db96d56Sopenharmony_ci def test_sparse_file_00(self): 10937db96d56Sopenharmony_ci self._test_sparse_file("gnu/sparse-0.0") 10947db96d56Sopenharmony_ci 10957db96d56Sopenharmony_ci def test_sparse_file_01(self): 10967db96d56Sopenharmony_ci self._test_sparse_file("gnu/sparse-0.1") 10977db96d56Sopenharmony_ci 10987db96d56Sopenharmony_ci def test_sparse_file_10(self): 10997db96d56Sopenharmony_ci self._test_sparse_file("gnu/sparse-1.0") 11007db96d56Sopenharmony_ci 11017db96d56Sopenharmony_ci @staticmethod 11027db96d56Sopenharmony_ci def _fs_supports_holes(): 11037db96d56Sopenharmony_ci # Return True if the platform knows the st_blocks stat attribute and 11047db96d56Sopenharmony_ci # uses st_blocks units of 512 bytes, and if the filesystem is able to 11057db96d56Sopenharmony_ci # store holes of 4 KiB in files. 11067db96d56Sopenharmony_ci # 11077db96d56Sopenharmony_ci # The function returns False if page size is larger than 4 KiB. 11087db96d56Sopenharmony_ci # For example, ppc64 uses pages of 64 KiB. 11097db96d56Sopenharmony_ci if sys.platform.startswith("linux"): 11107db96d56Sopenharmony_ci # Linux evidentially has 512 byte st_blocks units. 11117db96d56Sopenharmony_ci name = os.path.join(TEMPDIR, "sparse-test") 11127db96d56Sopenharmony_ci with open(name, "wb") as fobj: 11137db96d56Sopenharmony_ci # Seek to "punch a hole" of 4 KiB 11147db96d56Sopenharmony_ci fobj.seek(4096) 11157db96d56Sopenharmony_ci fobj.write(b'x' * 4096) 11167db96d56Sopenharmony_ci fobj.truncate() 11177db96d56Sopenharmony_ci s = os.stat(name) 11187db96d56Sopenharmony_ci os_helper.unlink(name) 11197db96d56Sopenharmony_ci return (s.st_blocks * 512 < s.st_size) 11207db96d56Sopenharmony_ci else: 11217db96d56Sopenharmony_ci return False 11227db96d56Sopenharmony_ci 11237db96d56Sopenharmony_ci 11247db96d56Sopenharmony_ciclass PaxReadTest(LongnameTest, ReadTest, unittest.TestCase): 11257db96d56Sopenharmony_ci 11267db96d56Sopenharmony_ci subdir = "pax" 11277db96d56Sopenharmony_ci longnametype = tarfile.XHDTYPE 11287db96d56Sopenharmony_ci format = tarfile.PAX_FORMAT 11297db96d56Sopenharmony_ci 11307db96d56Sopenharmony_ci def test_pax_global_headers(self): 11317db96d56Sopenharmony_ci tar = tarfile.open(tarname, encoding="iso8859-1") 11327db96d56Sopenharmony_ci try: 11337db96d56Sopenharmony_ci tarinfo = tar.getmember("pax/regtype1") 11347db96d56Sopenharmony_ci self.assertEqual(tarinfo.uname, "foo") 11357db96d56Sopenharmony_ci self.assertEqual(tarinfo.gname, "bar") 11367db96d56Sopenharmony_ci self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), 11377db96d56Sopenharmony_ci "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") 11387db96d56Sopenharmony_ci 11397db96d56Sopenharmony_ci tarinfo = tar.getmember("pax/regtype2") 11407db96d56Sopenharmony_ci self.assertEqual(tarinfo.uname, "") 11417db96d56Sopenharmony_ci self.assertEqual(tarinfo.gname, "bar") 11427db96d56Sopenharmony_ci self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), 11437db96d56Sopenharmony_ci "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") 11447db96d56Sopenharmony_ci 11457db96d56Sopenharmony_ci tarinfo = tar.getmember("pax/regtype3") 11467db96d56Sopenharmony_ci self.assertEqual(tarinfo.uname, "tarfile") 11477db96d56Sopenharmony_ci self.assertEqual(tarinfo.gname, "tarfile") 11487db96d56Sopenharmony_ci self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), 11497db96d56Sopenharmony_ci "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") 11507db96d56Sopenharmony_ci finally: 11517db96d56Sopenharmony_ci tar.close() 11527db96d56Sopenharmony_ci 11537db96d56Sopenharmony_ci def test_pax_number_fields(self): 11547db96d56Sopenharmony_ci # All following number fields are read from the pax header. 11557db96d56Sopenharmony_ci tar = tarfile.open(tarname, encoding="iso8859-1") 11567db96d56Sopenharmony_ci try: 11577db96d56Sopenharmony_ci tarinfo = tar.getmember("pax/regtype4") 11587db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 7011) 11597db96d56Sopenharmony_ci self.assertEqual(tarinfo.uid, 123) 11607db96d56Sopenharmony_ci self.assertEqual(tarinfo.gid, 123) 11617db96d56Sopenharmony_ci self.assertEqual(tarinfo.mtime, 1041808783.0) 11627db96d56Sopenharmony_ci self.assertEqual(type(tarinfo.mtime), float) 11637db96d56Sopenharmony_ci self.assertEqual(float(tarinfo.pax_headers["atime"]), 1041808783.0) 11647db96d56Sopenharmony_ci self.assertEqual(float(tarinfo.pax_headers["ctime"]), 1041808783.0) 11657db96d56Sopenharmony_ci finally: 11667db96d56Sopenharmony_ci tar.close() 11677db96d56Sopenharmony_ci 11687db96d56Sopenharmony_ci def test_pax_header_bad_formats(self): 11697db96d56Sopenharmony_ci # The fields from the pax header have priority over the 11707db96d56Sopenharmony_ci # TarInfo. 11717db96d56Sopenharmony_ci pax_header_replacements = ( 11727db96d56Sopenharmony_ci b" foo=bar\n", 11737db96d56Sopenharmony_ci b"0 \n", 11747db96d56Sopenharmony_ci b"1 \n", 11757db96d56Sopenharmony_ci b"2 \n", 11767db96d56Sopenharmony_ci b"3 =\n", 11777db96d56Sopenharmony_ci b"4 =a\n", 11787db96d56Sopenharmony_ci b"1000000 foo=bar\n", 11797db96d56Sopenharmony_ci b"0 foo=bar\n", 11807db96d56Sopenharmony_ci b"-12 foo=bar\n", 11817db96d56Sopenharmony_ci b"000000000000000000000000036 foo=bar\n", 11827db96d56Sopenharmony_ci ) 11837db96d56Sopenharmony_ci pax_headers = {"foo": "bar"} 11847db96d56Sopenharmony_ci 11857db96d56Sopenharmony_ci for replacement in pax_header_replacements: 11867db96d56Sopenharmony_ci with self.subTest(header=replacement): 11877db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, 11887db96d56Sopenharmony_ci encoding="iso8859-1") 11897db96d56Sopenharmony_ci try: 11907db96d56Sopenharmony_ci t = tarfile.TarInfo() 11917db96d56Sopenharmony_ci t.name = "pax" # non-ASCII 11927db96d56Sopenharmony_ci t.uid = 1 11937db96d56Sopenharmony_ci t.pax_headers = pax_headers 11947db96d56Sopenharmony_ci tar.addfile(t) 11957db96d56Sopenharmony_ci finally: 11967db96d56Sopenharmony_ci tar.close() 11977db96d56Sopenharmony_ci 11987db96d56Sopenharmony_ci with open(tmpname, "rb") as f: 11997db96d56Sopenharmony_ci data = f.read() 12007db96d56Sopenharmony_ci self.assertIn(b"11 foo=bar\n", data) 12017db96d56Sopenharmony_ci data = data.replace(b"11 foo=bar\n", replacement) 12027db96d56Sopenharmony_ci 12037db96d56Sopenharmony_ci with open(tmpname, "wb") as f: 12047db96d56Sopenharmony_ci f.truncate() 12057db96d56Sopenharmony_ci f.write(data) 12067db96d56Sopenharmony_ci 12077db96d56Sopenharmony_ci with self.assertRaisesRegex(tarfile.ReadError, r"method tar: ReadError\('invalid header'\)"): 12087db96d56Sopenharmony_ci tarfile.open(tmpname, encoding="iso8859-1") 12097db96d56Sopenharmony_ci 12107db96d56Sopenharmony_ci 12117db96d56Sopenharmony_ciclass WriteTestBase(TarTest): 12127db96d56Sopenharmony_ci # Put all write tests in here that are supposed to be tested 12137db96d56Sopenharmony_ci # in all possible mode combinations. 12147db96d56Sopenharmony_ci 12157db96d56Sopenharmony_ci def test_fileobj_no_close(self): 12167db96d56Sopenharmony_ci fobj = io.BytesIO() 12177db96d56Sopenharmony_ci with tarfile.open(fileobj=fobj, mode=self.mode) as tar: 12187db96d56Sopenharmony_ci tar.addfile(tarfile.TarInfo("foo")) 12197db96d56Sopenharmony_ci self.assertFalse(fobj.closed, "external fileobjs must never closed") 12207db96d56Sopenharmony_ci # Issue #20238: Incomplete gzip output with mode="w:gz" 12217db96d56Sopenharmony_ci data = fobj.getvalue() 12227db96d56Sopenharmony_ci del tar 12237db96d56Sopenharmony_ci support.gc_collect() 12247db96d56Sopenharmony_ci self.assertFalse(fobj.closed) 12257db96d56Sopenharmony_ci self.assertEqual(data, fobj.getvalue()) 12267db96d56Sopenharmony_ci 12277db96d56Sopenharmony_ci def test_eof_marker(self): 12287db96d56Sopenharmony_ci # Make sure an end of archive marker is written (two zero blocks). 12297db96d56Sopenharmony_ci # tarfile insists on aligning archives to a 20 * 512 byte recordsize. 12307db96d56Sopenharmony_ci # So, we create an archive that has exactly 10240 bytes without the 12317db96d56Sopenharmony_ci # marker, and has 20480 bytes once the marker is written. 12327db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode) as tar: 12337db96d56Sopenharmony_ci t = tarfile.TarInfo("foo") 12347db96d56Sopenharmony_ci t.size = tarfile.RECORDSIZE - tarfile.BLOCKSIZE 12357db96d56Sopenharmony_ci tar.addfile(t, io.BytesIO(b"a" * t.size)) 12367db96d56Sopenharmony_ci 12377db96d56Sopenharmony_ci with self.open(tmpname, "rb") as fobj: 12387db96d56Sopenharmony_ci self.assertEqual(len(fobj.read()), tarfile.RECORDSIZE * 2) 12397db96d56Sopenharmony_ci 12407db96d56Sopenharmony_ci 12417db96d56Sopenharmony_ciclass WriteTest(WriteTestBase, unittest.TestCase): 12427db96d56Sopenharmony_ci 12437db96d56Sopenharmony_ci prefix = "w:" 12447db96d56Sopenharmony_ci 12457db96d56Sopenharmony_ci def test_100_char_name(self): 12467db96d56Sopenharmony_ci # The name field in a tar header stores strings of at most 100 chars. 12477db96d56Sopenharmony_ci # If a string is shorter than 100 chars it has to be padded with '\0', 12487db96d56Sopenharmony_ci # which implies that a string of exactly 100 chars is stored without 12497db96d56Sopenharmony_ci # a trailing '\0'. 12507db96d56Sopenharmony_ci name = "0123456789" * 10 12517db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 12527db96d56Sopenharmony_ci try: 12537db96d56Sopenharmony_ci t = tarfile.TarInfo(name) 12547db96d56Sopenharmony_ci tar.addfile(t) 12557db96d56Sopenharmony_ci finally: 12567db96d56Sopenharmony_ci tar.close() 12577db96d56Sopenharmony_ci 12587db96d56Sopenharmony_ci tar = tarfile.open(tmpname) 12597db96d56Sopenharmony_ci try: 12607db96d56Sopenharmony_ci self.assertEqual(tar.getnames()[0], name, 12617db96d56Sopenharmony_ci "failed to store 100 char filename") 12627db96d56Sopenharmony_ci finally: 12637db96d56Sopenharmony_ci tar.close() 12647db96d56Sopenharmony_ci 12657db96d56Sopenharmony_ci def test_tar_size(self): 12667db96d56Sopenharmony_ci # Test for bug #1013882. 12677db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 12687db96d56Sopenharmony_ci try: 12697db96d56Sopenharmony_ci path = os.path.join(TEMPDIR, "file") 12707db96d56Sopenharmony_ci with open(path, "wb") as fobj: 12717db96d56Sopenharmony_ci fobj.write(b"aaa") 12727db96d56Sopenharmony_ci tar.add(path) 12737db96d56Sopenharmony_ci finally: 12747db96d56Sopenharmony_ci tar.close() 12757db96d56Sopenharmony_ci self.assertGreater(os.path.getsize(tmpname), 0, 12767db96d56Sopenharmony_ci "tarfile is empty") 12777db96d56Sopenharmony_ci 12787db96d56Sopenharmony_ci # The test_*_size tests test for bug #1167128. 12797db96d56Sopenharmony_ci def test_file_size(self): 12807db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 12817db96d56Sopenharmony_ci try: 12827db96d56Sopenharmony_ci path = os.path.join(TEMPDIR, "file") 12837db96d56Sopenharmony_ci with open(path, "wb"): 12847db96d56Sopenharmony_ci pass 12857db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(path) 12867db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 0) 12877db96d56Sopenharmony_ci 12887db96d56Sopenharmony_ci with open(path, "wb") as fobj: 12897db96d56Sopenharmony_ci fobj.write(b"aaa") 12907db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(path) 12917db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 3) 12927db96d56Sopenharmony_ci finally: 12937db96d56Sopenharmony_ci tar.close() 12947db96d56Sopenharmony_ci 12957db96d56Sopenharmony_ci def test_directory_size(self): 12967db96d56Sopenharmony_ci path = os.path.join(TEMPDIR, "directory") 12977db96d56Sopenharmony_ci os.mkdir(path) 12987db96d56Sopenharmony_ci try: 12997db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 13007db96d56Sopenharmony_ci try: 13017db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(path) 13027db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 0) 13037db96d56Sopenharmony_ci finally: 13047db96d56Sopenharmony_ci tar.close() 13057db96d56Sopenharmony_ci finally: 13067db96d56Sopenharmony_ci os_helper.rmdir(path) 13077db96d56Sopenharmony_ci 13087db96d56Sopenharmony_ci # mock the following: 13097db96d56Sopenharmony_ci # os.listdir: so we know that files are in the wrong order 13107db96d56Sopenharmony_ci def test_ordered_recursion(self): 13117db96d56Sopenharmony_ci path = os.path.join(TEMPDIR, "directory") 13127db96d56Sopenharmony_ci os.mkdir(path) 13137db96d56Sopenharmony_ci open(os.path.join(path, "1"), "a").close() 13147db96d56Sopenharmony_ci open(os.path.join(path, "2"), "a").close() 13157db96d56Sopenharmony_ci try: 13167db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 13177db96d56Sopenharmony_ci try: 13187db96d56Sopenharmony_ci with unittest.mock.patch('os.listdir') as mock_listdir: 13197db96d56Sopenharmony_ci mock_listdir.return_value = ["2", "1"] 13207db96d56Sopenharmony_ci tar.add(path) 13217db96d56Sopenharmony_ci paths = [] 13227db96d56Sopenharmony_ci for m in tar.getmembers(): 13237db96d56Sopenharmony_ci paths.append(os.path.split(m.name)[-1]) 13247db96d56Sopenharmony_ci self.assertEqual(paths, ["directory", "1", "2"]); 13257db96d56Sopenharmony_ci finally: 13267db96d56Sopenharmony_ci tar.close() 13277db96d56Sopenharmony_ci finally: 13287db96d56Sopenharmony_ci os_helper.unlink(os.path.join(path, "1")) 13297db96d56Sopenharmony_ci os_helper.unlink(os.path.join(path, "2")) 13307db96d56Sopenharmony_ci os_helper.rmdir(path) 13317db96d56Sopenharmony_ci 13327db96d56Sopenharmony_ci def test_gettarinfo_pathlike_name(self): 13337db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode) as tar: 13347db96d56Sopenharmony_ci path = pathlib.Path(TEMPDIR) / "file" 13357db96d56Sopenharmony_ci with open(path, "wb") as fobj: 13367db96d56Sopenharmony_ci fobj.write(b"aaa") 13377db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(path) 13387db96d56Sopenharmony_ci tarinfo2 = tar.gettarinfo(os.fspath(path)) 13397db96d56Sopenharmony_ci self.assertIsInstance(tarinfo.name, str) 13407db96d56Sopenharmony_ci self.assertEqual(tarinfo.name, tarinfo2.name) 13417db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 3) 13427db96d56Sopenharmony_ci 13437db96d56Sopenharmony_ci @unittest.skipUnless(hasattr(os, "link"), 13447db96d56Sopenharmony_ci "Missing hardlink implementation") 13457db96d56Sopenharmony_ci def test_link_size(self): 13467db96d56Sopenharmony_ci link = os.path.join(TEMPDIR, "link") 13477db96d56Sopenharmony_ci target = os.path.join(TEMPDIR, "link_target") 13487db96d56Sopenharmony_ci with open(target, "wb") as fobj: 13497db96d56Sopenharmony_ci fobj.write(b"aaa") 13507db96d56Sopenharmony_ci try: 13517db96d56Sopenharmony_ci os.link(target, link) 13527db96d56Sopenharmony_ci except PermissionError as e: 13537db96d56Sopenharmony_ci self.skipTest('os.link(): %s' % e) 13547db96d56Sopenharmony_ci try: 13557db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 13567db96d56Sopenharmony_ci try: 13577db96d56Sopenharmony_ci # Record the link target in the inodes list. 13587db96d56Sopenharmony_ci tar.gettarinfo(target) 13597db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(link) 13607db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 0) 13617db96d56Sopenharmony_ci finally: 13627db96d56Sopenharmony_ci tar.close() 13637db96d56Sopenharmony_ci finally: 13647db96d56Sopenharmony_ci os_helper.unlink(target) 13657db96d56Sopenharmony_ci os_helper.unlink(link) 13667db96d56Sopenharmony_ci 13677db96d56Sopenharmony_ci @os_helper.skip_unless_symlink 13687db96d56Sopenharmony_ci def test_symlink_size(self): 13697db96d56Sopenharmony_ci path = os.path.join(TEMPDIR, "symlink") 13707db96d56Sopenharmony_ci os.symlink("link_target", path) 13717db96d56Sopenharmony_ci try: 13727db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 13737db96d56Sopenharmony_ci try: 13747db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(path) 13757db96d56Sopenharmony_ci self.assertEqual(tarinfo.size, 0) 13767db96d56Sopenharmony_ci finally: 13777db96d56Sopenharmony_ci tar.close() 13787db96d56Sopenharmony_ci finally: 13797db96d56Sopenharmony_ci os_helper.unlink(path) 13807db96d56Sopenharmony_ci 13817db96d56Sopenharmony_ci def test_add_self(self): 13827db96d56Sopenharmony_ci # Test for #1257255. 13837db96d56Sopenharmony_ci dstname = os.path.abspath(tmpname) 13847db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 13857db96d56Sopenharmony_ci try: 13867db96d56Sopenharmony_ci self.assertEqual(tar.name, dstname, 13877db96d56Sopenharmony_ci "archive name must be absolute") 13887db96d56Sopenharmony_ci tar.add(dstname) 13897db96d56Sopenharmony_ci self.assertEqual(tar.getnames(), [], 13907db96d56Sopenharmony_ci "added the archive to itself") 13917db96d56Sopenharmony_ci 13927db96d56Sopenharmony_ci with os_helper.change_cwd(TEMPDIR): 13937db96d56Sopenharmony_ci tar.add(dstname) 13947db96d56Sopenharmony_ci self.assertEqual(tar.getnames(), [], 13957db96d56Sopenharmony_ci "added the archive to itself") 13967db96d56Sopenharmony_ci finally: 13977db96d56Sopenharmony_ci tar.close() 13987db96d56Sopenharmony_ci 13997db96d56Sopenharmony_ci def test_filter(self): 14007db96d56Sopenharmony_ci tempdir = os.path.join(TEMPDIR, "filter") 14017db96d56Sopenharmony_ci os.mkdir(tempdir) 14027db96d56Sopenharmony_ci try: 14037db96d56Sopenharmony_ci for name in ("foo", "bar", "baz"): 14047db96d56Sopenharmony_ci name = os.path.join(tempdir, name) 14057db96d56Sopenharmony_ci os_helper.create_empty_file(name) 14067db96d56Sopenharmony_ci 14077db96d56Sopenharmony_ci def filter(tarinfo): 14087db96d56Sopenharmony_ci if os.path.basename(tarinfo.name) == "bar": 14097db96d56Sopenharmony_ci return 14107db96d56Sopenharmony_ci tarinfo.uid = 123 14117db96d56Sopenharmony_ci tarinfo.uname = "foo" 14127db96d56Sopenharmony_ci return tarinfo 14137db96d56Sopenharmony_ci 14147db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1") 14157db96d56Sopenharmony_ci try: 14167db96d56Sopenharmony_ci tar.add(tempdir, arcname="empty_dir", filter=filter) 14177db96d56Sopenharmony_ci finally: 14187db96d56Sopenharmony_ci tar.close() 14197db96d56Sopenharmony_ci 14207db96d56Sopenharmony_ci # Verify that filter is a keyword-only argument 14217db96d56Sopenharmony_ci with self.assertRaises(TypeError): 14227db96d56Sopenharmony_ci tar.add(tempdir, "empty_dir", True, None, filter) 14237db96d56Sopenharmony_ci 14247db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "r") 14257db96d56Sopenharmony_ci try: 14267db96d56Sopenharmony_ci for tarinfo in tar: 14277db96d56Sopenharmony_ci self.assertEqual(tarinfo.uid, 123) 14287db96d56Sopenharmony_ci self.assertEqual(tarinfo.uname, "foo") 14297db96d56Sopenharmony_ci self.assertEqual(len(tar.getmembers()), 3) 14307db96d56Sopenharmony_ci finally: 14317db96d56Sopenharmony_ci tar.close() 14327db96d56Sopenharmony_ci finally: 14337db96d56Sopenharmony_ci os_helper.rmtree(tempdir) 14347db96d56Sopenharmony_ci 14357db96d56Sopenharmony_ci # Guarantee that stored pathnames are not modified. Don't 14367db96d56Sopenharmony_ci # remove ./ or ../ or double slashes. Still make absolute 14377db96d56Sopenharmony_ci # pathnames relative. 14387db96d56Sopenharmony_ci # For details see bug #6054. 14397db96d56Sopenharmony_ci def _test_pathname(self, path, cmp_path=None, dir=False): 14407db96d56Sopenharmony_ci # Create a tarfile with an empty member named path 14417db96d56Sopenharmony_ci # and compare the stored name with the original. 14427db96d56Sopenharmony_ci foo = os.path.join(TEMPDIR, "foo") 14437db96d56Sopenharmony_ci if not dir: 14447db96d56Sopenharmony_ci os_helper.create_empty_file(foo) 14457db96d56Sopenharmony_ci else: 14467db96d56Sopenharmony_ci os.mkdir(foo) 14477db96d56Sopenharmony_ci 14487db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 14497db96d56Sopenharmony_ci try: 14507db96d56Sopenharmony_ci tar.add(foo, arcname=path) 14517db96d56Sopenharmony_ci finally: 14527db96d56Sopenharmony_ci tar.close() 14537db96d56Sopenharmony_ci 14547db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "r") 14557db96d56Sopenharmony_ci try: 14567db96d56Sopenharmony_ci t = tar.next() 14577db96d56Sopenharmony_ci finally: 14587db96d56Sopenharmony_ci tar.close() 14597db96d56Sopenharmony_ci 14607db96d56Sopenharmony_ci if not dir: 14617db96d56Sopenharmony_ci os_helper.unlink(foo) 14627db96d56Sopenharmony_ci else: 14637db96d56Sopenharmony_ci os_helper.rmdir(foo) 14647db96d56Sopenharmony_ci 14657db96d56Sopenharmony_ci self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) 14667db96d56Sopenharmony_ci 14677db96d56Sopenharmony_ci 14687db96d56Sopenharmony_ci @os_helper.skip_unless_symlink 14697db96d56Sopenharmony_ci def test_extractall_symlinks(self): 14707db96d56Sopenharmony_ci # Test if extractall works properly when tarfile contains symlinks 14717db96d56Sopenharmony_ci tempdir = os.path.join(TEMPDIR, "testsymlinks") 14727db96d56Sopenharmony_ci temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") 14737db96d56Sopenharmony_ci os.mkdir(tempdir) 14747db96d56Sopenharmony_ci try: 14757db96d56Sopenharmony_ci source_file = os.path.join(tempdir,'source') 14767db96d56Sopenharmony_ci target_file = os.path.join(tempdir,'symlink') 14777db96d56Sopenharmony_ci with open(source_file,'w') as f: 14787db96d56Sopenharmony_ci f.write('something\n') 14797db96d56Sopenharmony_ci os.symlink(source_file, target_file) 14807db96d56Sopenharmony_ci with tarfile.open(temparchive, 'w') as tar: 14817db96d56Sopenharmony_ci tar.add(source_file, arcname="source") 14827db96d56Sopenharmony_ci tar.add(target_file, arcname="symlink") 14837db96d56Sopenharmony_ci # Let's extract it to the location which contains the symlink 14847db96d56Sopenharmony_ci with tarfile.open(temparchive, errorlevel=2) as tar: 14857db96d56Sopenharmony_ci # this should not raise OSError: [Errno 17] File exists 14867db96d56Sopenharmony_ci try: 14877db96d56Sopenharmony_ci tar.extractall(path=tempdir, 14887db96d56Sopenharmony_ci filter='fully_trusted') 14897db96d56Sopenharmony_ci except OSError: 14907db96d56Sopenharmony_ci self.fail("extractall failed with symlinked files") 14917db96d56Sopenharmony_ci finally: 14927db96d56Sopenharmony_ci os_helper.unlink(temparchive) 14937db96d56Sopenharmony_ci os_helper.rmtree(tempdir) 14947db96d56Sopenharmony_ci 14957db96d56Sopenharmony_ci def test_pathnames(self): 14967db96d56Sopenharmony_ci self._test_pathname("foo") 14977db96d56Sopenharmony_ci self._test_pathname(os.path.join("foo", ".", "bar")) 14987db96d56Sopenharmony_ci self._test_pathname(os.path.join("foo", "..", "bar")) 14997db96d56Sopenharmony_ci self._test_pathname(os.path.join(".", "foo")) 15007db96d56Sopenharmony_ci self._test_pathname(os.path.join(".", "foo", ".")) 15017db96d56Sopenharmony_ci self._test_pathname(os.path.join(".", "foo", ".", "bar")) 15027db96d56Sopenharmony_ci self._test_pathname(os.path.join(".", "foo", "..", "bar")) 15037db96d56Sopenharmony_ci self._test_pathname(os.path.join(".", "foo", "..", "bar")) 15047db96d56Sopenharmony_ci self._test_pathname(os.path.join("..", "foo")) 15057db96d56Sopenharmony_ci self._test_pathname(os.path.join("..", "foo", "..")) 15067db96d56Sopenharmony_ci self._test_pathname(os.path.join("..", "foo", ".", "bar")) 15077db96d56Sopenharmony_ci self._test_pathname(os.path.join("..", "foo", "..", "bar")) 15087db96d56Sopenharmony_ci 15097db96d56Sopenharmony_ci self._test_pathname("foo" + os.sep + os.sep + "bar") 15107db96d56Sopenharmony_ci self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True) 15117db96d56Sopenharmony_ci 15127db96d56Sopenharmony_ci def test_abs_pathnames(self): 15137db96d56Sopenharmony_ci if sys.platform == "win32": 15147db96d56Sopenharmony_ci self._test_pathname("C:\\foo", "foo") 15157db96d56Sopenharmony_ci else: 15167db96d56Sopenharmony_ci self._test_pathname("/foo", "foo") 15177db96d56Sopenharmony_ci self._test_pathname("///foo", "foo") 15187db96d56Sopenharmony_ci 15197db96d56Sopenharmony_ci def test_cwd(self): 15207db96d56Sopenharmony_ci # Test adding the current working directory. 15217db96d56Sopenharmony_ci with os_helper.change_cwd(TEMPDIR): 15227db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 15237db96d56Sopenharmony_ci try: 15247db96d56Sopenharmony_ci tar.add(".") 15257db96d56Sopenharmony_ci finally: 15267db96d56Sopenharmony_ci tar.close() 15277db96d56Sopenharmony_ci 15287db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "r") 15297db96d56Sopenharmony_ci try: 15307db96d56Sopenharmony_ci for t in tar: 15317db96d56Sopenharmony_ci if t.name != ".": 15327db96d56Sopenharmony_ci self.assertTrue(t.name.startswith("./"), t.name) 15337db96d56Sopenharmony_ci finally: 15347db96d56Sopenharmony_ci tar.close() 15357db96d56Sopenharmony_ci 15367db96d56Sopenharmony_ci def test_open_nonwritable_fileobj(self): 15377db96d56Sopenharmony_ci for exctype in OSError, EOFError, RuntimeError: 15387db96d56Sopenharmony_ci class BadFile(io.BytesIO): 15397db96d56Sopenharmony_ci first = True 15407db96d56Sopenharmony_ci def write(self, data): 15417db96d56Sopenharmony_ci if self.first: 15427db96d56Sopenharmony_ci self.first = False 15437db96d56Sopenharmony_ci raise exctype 15447db96d56Sopenharmony_ci 15457db96d56Sopenharmony_ci f = BadFile() 15467db96d56Sopenharmony_ci with self.assertRaises(exctype): 15477db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode, fileobj=f, 15487db96d56Sopenharmony_ci format=tarfile.PAX_FORMAT, 15497db96d56Sopenharmony_ci pax_headers={'non': 'empty'}) 15507db96d56Sopenharmony_ci self.assertFalse(f.closed) 15517db96d56Sopenharmony_ci 15527db96d56Sopenharmony_ci 15537db96d56Sopenharmony_ciclass GzipWriteTest(GzipTest, WriteTest): 15547db96d56Sopenharmony_ci pass 15557db96d56Sopenharmony_ci 15567db96d56Sopenharmony_ci 15577db96d56Sopenharmony_ciclass Bz2WriteTest(Bz2Test, WriteTest): 15587db96d56Sopenharmony_ci pass 15597db96d56Sopenharmony_ci 15607db96d56Sopenharmony_ci 15617db96d56Sopenharmony_ciclass LzmaWriteTest(LzmaTest, WriteTest): 15627db96d56Sopenharmony_ci pass 15637db96d56Sopenharmony_ci 15647db96d56Sopenharmony_ci 15657db96d56Sopenharmony_ciclass StreamWriteTest(WriteTestBase, unittest.TestCase): 15667db96d56Sopenharmony_ci 15677db96d56Sopenharmony_ci prefix = "w|" 15687db96d56Sopenharmony_ci decompressor = None 15697db96d56Sopenharmony_ci 15707db96d56Sopenharmony_ci def test_stream_padding(self): 15717db96d56Sopenharmony_ci # Test for bug #1543303. 15727db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 15737db96d56Sopenharmony_ci tar.close() 15747db96d56Sopenharmony_ci if self.decompressor: 15757db96d56Sopenharmony_ci dec = self.decompressor() 15767db96d56Sopenharmony_ci with open(tmpname, "rb") as fobj: 15777db96d56Sopenharmony_ci data = fobj.read() 15787db96d56Sopenharmony_ci data = dec.decompress(data) 15797db96d56Sopenharmony_ci self.assertFalse(dec.unused_data, "found trailing data") 15807db96d56Sopenharmony_ci else: 15817db96d56Sopenharmony_ci with self.open(tmpname) as fobj: 15827db96d56Sopenharmony_ci data = fobj.read() 15837db96d56Sopenharmony_ci self.assertEqual(data.count(b"\0"), tarfile.RECORDSIZE, 15847db96d56Sopenharmony_ci "incorrect zero padding") 15857db96d56Sopenharmony_ci 15867db96d56Sopenharmony_ci @unittest.skipUnless(sys.platform != "win32" and hasattr(os, "umask"), 15877db96d56Sopenharmony_ci "Missing umask implementation") 15887db96d56Sopenharmony_ci @unittest.skipIf( 15897db96d56Sopenharmony_ci support.is_emscripten or support.is_wasi, 15907db96d56Sopenharmony_ci "Emscripten's/WASI's umask is a stub." 15917db96d56Sopenharmony_ci ) 15927db96d56Sopenharmony_ci def test_file_mode(self): 15937db96d56Sopenharmony_ci # Test for issue #8464: Create files with correct 15947db96d56Sopenharmony_ci # permissions. 15957db96d56Sopenharmony_ci if os.path.exists(tmpname): 15967db96d56Sopenharmony_ci os_helper.unlink(tmpname) 15977db96d56Sopenharmony_ci 15987db96d56Sopenharmony_ci original_umask = os.umask(0o022) 15997db96d56Sopenharmony_ci try: 16007db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 16017db96d56Sopenharmony_ci tar.close() 16027db96d56Sopenharmony_ci mode = os.stat(tmpname).st_mode & 0o777 16037db96d56Sopenharmony_ci self.assertEqual(mode, 0o644, "wrong file permissions") 16047db96d56Sopenharmony_ci finally: 16057db96d56Sopenharmony_ci os.umask(original_umask) 16067db96d56Sopenharmony_ci 16077db96d56Sopenharmony_ci 16087db96d56Sopenharmony_ciclass GzipStreamWriteTest(GzipTest, StreamWriteTest): 16097db96d56Sopenharmony_ci def test_source_directory_not_leaked(self): 16107db96d56Sopenharmony_ci """ 16117db96d56Sopenharmony_ci Ensure the source directory is not included in the tar header 16127db96d56Sopenharmony_ci per bpo-41316. 16137db96d56Sopenharmony_ci """ 16147db96d56Sopenharmony_ci tarfile.open(tmpname, self.mode).close() 16157db96d56Sopenharmony_ci payload = pathlib.Path(tmpname).read_text(encoding='latin-1') 16167db96d56Sopenharmony_ci assert os.path.dirname(tmpname) not in payload 16177db96d56Sopenharmony_ci 16187db96d56Sopenharmony_ci 16197db96d56Sopenharmony_ciclass Bz2StreamWriteTest(Bz2Test, StreamWriteTest): 16207db96d56Sopenharmony_ci decompressor = bz2.BZ2Decompressor if bz2 else None 16217db96d56Sopenharmony_ci 16227db96d56Sopenharmony_ciclass LzmaStreamWriteTest(LzmaTest, StreamWriteTest): 16237db96d56Sopenharmony_ci decompressor = lzma.LZMADecompressor if lzma else None 16247db96d56Sopenharmony_ci 16257db96d56Sopenharmony_ci 16267db96d56Sopenharmony_ciclass GNUWriteTest(unittest.TestCase): 16277db96d56Sopenharmony_ci # This testcase checks for correct creation of GNU Longname 16287db96d56Sopenharmony_ci # and Longlink extended headers (cp. bug #812325). 16297db96d56Sopenharmony_ci 16307db96d56Sopenharmony_ci def _length(self, s): 16317db96d56Sopenharmony_ci blocks = len(s) // 512 + 1 16327db96d56Sopenharmony_ci return blocks * 512 16337db96d56Sopenharmony_ci 16347db96d56Sopenharmony_ci def _calc_size(self, name, link=None): 16357db96d56Sopenharmony_ci # Initial tar header 16367db96d56Sopenharmony_ci count = 512 16377db96d56Sopenharmony_ci 16387db96d56Sopenharmony_ci if len(name) > tarfile.LENGTH_NAME: 16397db96d56Sopenharmony_ci # GNU longname extended header + longname 16407db96d56Sopenharmony_ci count += 512 16417db96d56Sopenharmony_ci count += self._length(name) 16427db96d56Sopenharmony_ci if link is not None and len(link) > tarfile.LENGTH_LINK: 16437db96d56Sopenharmony_ci # GNU longlink extended header + longlink 16447db96d56Sopenharmony_ci count += 512 16457db96d56Sopenharmony_ci count += self._length(link) 16467db96d56Sopenharmony_ci return count 16477db96d56Sopenharmony_ci 16487db96d56Sopenharmony_ci def _test(self, name, link=None): 16497db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo(name) 16507db96d56Sopenharmony_ci if link: 16517db96d56Sopenharmony_ci tarinfo.linkname = link 16527db96d56Sopenharmony_ci tarinfo.type = tarfile.LNKTYPE 16537db96d56Sopenharmony_ci 16547db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w") 16557db96d56Sopenharmony_ci try: 16567db96d56Sopenharmony_ci tar.format = tarfile.GNU_FORMAT 16577db96d56Sopenharmony_ci tar.addfile(tarinfo) 16587db96d56Sopenharmony_ci 16597db96d56Sopenharmony_ci v1 = self._calc_size(name, link) 16607db96d56Sopenharmony_ci v2 = tar.offset 16617db96d56Sopenharmony_ci self.assertEqual(v1, v2, "GNU longname/longlink creation failed") 16627db96d56Sopenharmony_ci finally: 16637db96d56Sopenharmony_ci tar.close() 16647db96d56Sopenharmony_ci 16657db96d56Sopenharmony_ci tar = tarfile.open(tmpname) 16667db96d56Sopenharmony_ci try: 16677db96d56Sopenharmony_ci member = tar.next() 16687db96d56Sopenharmony_ci self.assertIsNotNone(member, 16697db96d56Sopenharmony_ci "unable to read longname member") 16707db96d56Sopenharmony_ci self.assertEqual(tarinfo.name, member.name, 16717db96d56Sopenharmony_ci "unable to read longname member") 16727db96d56Sopenharmony_ci self.assertEqual(tarinfo.linkname, member.linkname, 16737db96d56Sopenharmony_ci "unable to read longname member") 16747db96d56Sopenharmony_ci finally: 16757db96d56Sopenharmony_ci tar.close() 16767db96d56Sopenharmony_ci 16777db96d56Sopenharmony_ci def test_longname_1023(self): 16787db96d56Sopenharmony_ci self._test(("longnam/" * 127) + "longnam") 16797db96d56Sopenharmony_ci 16807db96d56Sopenharmony_ci def test_longname_1024(self): 16817db96d56Sopenharmony_ci self._test(("longnam/" * 127) + "longname") 16827db96d56Sopenharmony_ci 16837db96d56Sopenharmony_ci def test_longname_1025(self): 16847db96d56Sopenharmony_ci self._test(("longnam/" * 127) + "longname_") 16857db96d56Sopenharmony_ci 16867db96d56Sopenharmony_ci def test_longlink_1023(self): 16877db96d56Sopenharmony_ci self._test("name", ("longlnk/" * 127) + "longlnk") 16887db96d56Sopenharmony_ci 16897db96d56Sopenharmony_ci def test_longlink_1024(self): 16907db96d56Sopenharmony_ci self._test("name", ("longlnk/" * 127) + "longlink") 16917db96d56Sopenharmony_ci 16927db96d56Sopenharmony_ci def test_longlink_1025(self): 16937db96d56Sopenharmony_ci self._test("name", ("longlnk/" * 127) + "longlink_") 16947db96d56Sopenharmony_ci 16957db96d56Sopenharmony_ci def test_longnamelink_1023(self): 16967db96d56Sopenharmony_ci self._test(("longnam/" * 127) + "longnam", 16977db96d56Sopenharmony_ci ("longlnk/" * 127) + "longlnk") 16987db96d56Sopenharmony_ci 16997db96d56Sopenharmony_ci def test_longnamelink_1024(self): 17007db96d56Sopenharmony_ci self._test(("longnam/" * 127) + "longname", 17017db96d56Sopenharmony_ci ("longlnk/" * 127) + "longlink") 17027db96d56Sopenharmony_ci 17037db96d56Sopenharmony_ci def test_longnamelink_1025(self): 17047db96d56Sopenharmony_ci self._test(("longnam/" * 127) + "longname_", 17057db96d56Sopenharmony_ci ("longlnk/" * 127) + "longlink_") 17067db96d56Sopenharmony_ci 17077db96d56Sopenharmony_ci 17087db96d56Sopenharmony_ciclass DeviceHeaderTest(WriteTestBase, unittest.TestCase): 17097db96d56Sopenharmony_ci 17107db96d56Sopenharmony_ci prefix = "w:" 17117db96d56Sopenharmony_ci 17127db96d56Sopenharmony_ci def test_headers_written_only_for_device_files(self): 17137db96d56Sopenharmony_ci # Regression test for bpo-18819. 17147db96d56Sopenharmony_ci tempdir = os.path.join(TEMPDIR, "device_header_test") 17157db96d56Sopenharmony_ci os.mkdir(tempdir) 17167db96d56Sopenharmony_ci try: 17177db96d56Sopenharmony_ci tar = tarfile.open(tmpname, self.mode) 17187db96d56Sopenharmony_ci try: 17197db96d56Sopenharmony_ci input_blk = tarfile.TarInfo(name="my_block_device") 17207db96d56Sopenharmony_ci input_reg = tarfile.TarInfo(name="my_regular_file") 17217db96d56Sopenharmony_ci input_blk.type = tarfile.BLKTYPE 17227db96d56Sopenharmony_ci input_reg.type = tarfile.REGTYPE 17237db96d56Sopenharmony_ci tar.addfile(input_blk) 17247db96d56Sopenharmony_ci tar.addfile(input_reg) 17257db96d56Sopenharmony_ci finally: 17267db96d56Sopenharmony_ci tar.close() 17277db96d56Sopenharmony_ci 17287db96d56Sopenharmony_ci # devmajor and devminor should be *interpreted* as 0 in both... 17297db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "r") 17307db96d56Sopenharmony_ci try: 17317db96d56Sopenharmony_ci output_blk = tar.getmember("my_block_device") 17327db96d56Sopenharmony_ci output_reg = tar.getmember("my_regular_file") 17337db96d56Sopenharmony_ci finally: 17347db96d56Sopenharmony_ci tar.close() 17357db96d56Sopenharmony_ci self.assertEqual(output_blk.devmajor, 0) 17367db96d56Sopenharmony_ci self.assertEqual(output_blk.devminor, 0) 17377db96d56Sopenharmony_ci self.assertEqual(output_reg.devmajor, 0) 17387db96d56Sopenharmony_ci self.assertEqual(output_reg.devminor, 0) 17397db96d56Sopenharmony_ci 17407db96d56Sopenharmony_ci # ...but the fields should not actually be set on regular files: 17417db96d56Sopenharmony_ci with open(tmpname, "rb") as infile: 17427db96d56Sopenharmony_ci buf = infile.read() 17437db96d56Sopenharmony_ci buf_blk = buf[output_blk.offset:output_blk.offset_data] 17447db96d56Sopenharmony_ci buf_reg = buf[output_reg.offset:output_reg.offset_data] 17457db96d56Sopenharmony_ci # See `struct posixheader` in GNU docs for byte offsets: 17467db96d56Sopenharmony_ci # <https://www.gnu.org/software/tar/manual/html_node/Standard.html> 17477db96d56Sopenharmony_ci device_headers = slice(329, 329 + 16) 17487db96d56Sopenharmony_ci self.assertEqual(buf_blk[device_headers], b"0000000\0" * 2) 17497db96d56Sopenharmony_ci self.assertEqual(buf_reg[device_headers], b"\0" * 16) 17507db96d56Sopenharmony_ci finally: 17517db96d56Sopenharmony_ci os_helper.rmtree(tempdir) 17527db96d56Sopenharmony_ci 17537db96d56Sopenharmony_ci 17547db96d56Sopenharmony_ciclass CreateTest(WriteTestBase, unittest.TestCase): 17557db96d56Sopenharmony_ci 17567db96d56Sopenharmony_ci prefix = "x:" 17577db96d56Sopenharmony_ci 17587db96d56Sopenharmony_ci file_path = os.path.join(TEMPDIR, "spameggs42") 17597db96d56Sopenharmony_ci 17607db96d56Sopenharmony_ci def setUp(self): 17617db96d56Sopenharmony_ci os_helper.unlink(tmpname) 17627db96d56Sopenharmony_ci 17637db96d56Sopenharmony_ci @classmethod 17647db96d56Sopenharmony_ci def setUpClass(cls): 17657db96d56Sopenharmony_ci with open(cls.file_path, "wb") as fobj: 17667db96d56Sopenharmony_ci fobj.write(b"aaa") 17677db96d56Sopenharmony_ci 17687db96d56Sopenharmony_ci @classmethod 17697db96d56Sopenharmony_ci def tearDownClass(cls): 17707db96d56Sopenharmony_ci os_helper.unlink(cls.file_path) 17717db96d56Sopenharmony_ci 17727db96d56Sopenharmony_ci def test_create(self): 17737db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode) as tobj: 17747db96d56Sopenharmony_ci tobj.add(self.file_path) 17757db96d56Sopenharmony_ci 17767db96d56Sopenharmony_ci with self.taropen(tmpname) as tobj: 17777db96d56Sopenharmony_ci names = tobj.getnames() 17787db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 17797db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 17807db96d56Sopenharmony_ci 17817db96d56Sopenharmony_ci def test_create_existing(self): 17827db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode) as tobj: 17837db96d56Sopenharmony_ci tobj.add(self.file_path) 17847db96d56Sopenharmony_ci 17857db96d56Sopenharmony_ci with self.assertRaises(FileExistsError): 17867db96d56Sopenharmony_ci tobj = tarfile.open(tmpname, self.mode) 17877db96d56Sopenharmony_ci 17887db96d56Sopenharmony_ci with self.taropen(tmpname) as tobj: 17897db96d56Sopenharmony_ci names = tobj.getnames() 17907db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 17917db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 17927db96d56Sopenharmony_ci 17937db96d56Sopenharmony_ci def test_create_taropen(self): 17947db96d56Sopenharmony_ci with self.taropen(tmpname, "x") as tobj: 17957db96d56Sopenharmony_ci tobj.add(self.file_path) 17967db96d56Sopenharmony_ci 17977db96d56Sopenharmony_ci with self.taropen(tmpname) as tobj: 17987db96d56Sopenharmony_ci names = tobj.getnames() 17997db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 18007db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 18017db96d56Sopenharmony_ci 18027db96d56Sopenharmony_ci def test_create_existing_taropen(self): 18037db96d56Sopenharmony_ci with self.taropen(tmpname, "x") as tobj: 18047db96d56Sopenharmony_ci tobj.add(self.file_path) 18057db96d56Sopenharmony_ci 18067db96d56Sopenharmony_ci with self.assertRaises(FileExistsError): 18077db96d56Sopenharmony_ci with self.taropen(tmpname, "x"): 18087db96d56Sopenharmony_ci pass 18097db96d56Sopenharmony_ci 18107db96d56Sopenharmony_ci with self.taropen(tmpname) as tobj: 18117db96d56Sopenharmony_ci names = tobj.getnames() 18127db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 18137db96d56Sopenharmony_ci self.assertIn("spameggs42", names[0]) 18147db96d56Sopenharmony_ci 18157db96d56Sopenharmony_ci def test_create_pathlike_name(self): 18167db96d56Sopenharmony_ci with tarfile.open(pathlib.Path(tmpname), self.mode) as tobj: 18177db96d56Sopenharmony_ci self.assertIsInstance(tobj.name, str) 18187db96d56Sopenharmony_ci self.assertEqual(tobj.name, os.path.abspath(tmpname)) 18197db96d56Sopenharmony_ci tobj.add(pathlib.Path(self.file_path)) 18207db96d56Sopenharmony_ci names = tobj.getnames() 18217db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 18227db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 18237db96d56Sopenharmony_ci 18247db96d56Sopenharmony_ci with self.taropen(tmpname) as tobj: 18257db96d56Sopenharmony_ci names = tobj.getnames() 18267db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 18277db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 18287db96d56Sopenharmony_ci 18297db96d56Sopenharmony_ci def test_create_taropen_pathlike_name(self): 18307db96d56Sopenharmony_ci with self.taropen(pathlib.Path(tmpname), "x") as tobj: 18317db96d56Sopenharmony_ci self.assertIsInstance(tobj.name, str) 18327db96d56Sopenharmony_ci self.assertEqual(tobj.name, os.path.abspath(tmpname)) 18337db96d56Sopenharmony_ci tobj.add(pathlib.Path(self.file_path)) 18347db96d56Sopenharmony_ci names = tobj.getnames() 18357db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 18367db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 18377db96d56Sopenharmony_ci 18387db96d56Sopenharmony_ci with self.taropen(tmpname) as tobj: 18397db96d56Sopenharmony_ci names = tobj.getnames() 18407db96d56Sopenharmony_ci self.assertEqual(len(names), 1) 18417db96d56Sopenharmony_ci self.assertIn('spameggs42', names[0]) 18427db96d56Sopenharmony_ci 18437db96d56Sopenharmony_ci 18447db96d56Sopenharmony_ciclass GzipCreateTest(GzipTest, CreateTest): 18457db96d56Sopenharmony_ci 18467db96d56Sopenharmony_ci def test_create_with_compresslevel(self): 18477db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode, compresslevel=1) as tobj: 18487db96d56Sopenharmony_ci tobj.add(self.file_path) 18497db96d56Sopenharmony_ci with tarfile.open(tmpname, 'r:gz', compresslevel=1) as tobj: 18507db96d56Sopenharmony_ci pass 18517db96d56Sopenharmony_ci 18527db96d56Sopenharmony_ci 18537db96d56Sopenharmony_ciclass Bz2CreateTest(Bz2Test, CreateTest): 18547db96d56Sopenharmony_ci 18557db96d56Sopenharmony_ci def test_create_with_compresslevel(self): 18567db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode, compresslevel=1) as tobj: 18577db96d56Sopenharmony_ci tobj.add(self.file_path) 18587db96d56Sopenharmony_ci with tarfile.open(tmpname, 'r:bz2', compresslevel=1) as tobj: 18597db96d56Sopenharmony_ci pass 18607db96d56Sopenharmony_ci 18617db96d56Sopenharmony_ci 18627db96d56Sopenharmony_ciclass LzmaCreateTest(LzmaTest, CreateTest): 18637db96d56Sopenharmony_ci 18647db96d56Sopenharmony_ci # Unlike gz and bz2, xz uses the preset keyword instead of compresslevel. 18657db96d56Sopenharmony_ci # It does not allow for preset to be specified when reading. 18667db96d56Sopenharmony_ci def test_create_with_preset(self): 18677db96d56Sopenharmony_ci with tarfile.open(tmpname, self.mode, preset=1) as tobj: 18687db96d56Sopenharmony_ci tobj.add(self.file_path) 18697db96d56Sopenharmony_ci 18707db96d56Sopenharmony_ci 18717db96d56Sopenharmony_ciclass CreateWithXModeTest(CreateTest): 18727db96d56Sopenharmony_ci 18737db96d56Sopenharmony_ci prefix = "x" 18747db96d56Sopenharmony_ci 18757db96d56Sopenharmony_ci test_create_taropen = None 18767db96d56Sopenharmony_ci test_create_existing_taropen = None 18777db96d56Sopenharmony_ci 18787db96d56Sopenharmony_ci 18797db96d56Sopenharmony_ci@unittest.skipUnless(hasattr(os, "link"), "Missing hardlink implementation") 18807db96d56Sopenharmony_ciclass HardlinkTest(unittest.TestCase): 18817db96d56Sopenharmony_ci # Test the creation of LNKTYPE (hardlink) members in an archive. 18827db96d56Sopenharmony_ci 18837db96d56Sopenharmony_ci def setUp(self): 18847db96d56Sopenharmony_ci self.foo = os.path.join(TEMPDIR, "foo") 18857db96d56Sopenharmony_ci self.bar = os.path.join(TEMPDIR, "bar") 18867db96d56Sopenharmony_ci 18877db96d56Sopenharmony_ci with open(self.foo, "wb") as fobj: 18887db96d56Sopenharmony_ci fobj.write(b"foo") 18897db96d56Sopenharmony_ci 18907db96d56Sopenharmony_ci try: 18917db96d56Sopenharmony_ci os.link(self.foo, self.bar) 18927db96d56Sopenharmony_ci except PermissionError as e: 18937db96d56Sopenharmony_ci self.skipTest('os.link(): %s' % e) 18947db96d56Sopenharmony_ci 18957db96d56Sopenharmony_ci self.tar = tarfile.open(tmpname, "w") 18967db96d56Sopenharmony_ci self.tar.add(self.foo) 18977db96d56Sopenharmony_ci 18987db96d56Sopenharmony_ci def tearDown(self): 18997db96d56Sopenharmony_ci self.tar.close() 19007db96d56Sopenharmony_ci os_helper.unlink(self.foo) 19017db96d56Sopenharmony_ci os_helper.unlink(self.bar) 19027db96d56Sopenharmony_ci 19037db96d56Sopenharmony_ci def test_add_twice(self): 19047db96d56Sopenharmony_ci # The same name will be added as a REGTYPE every 19057db96d56Sopenharmony_ci # time regardless of st_nlink. 19067db96d56Sopenharmony_ci tarinfo = self.tar.gettarinfo(self.foo) 19077db96d56Sopenharmony_ci self.assertEqual(tarinfo.type, tarfile.REGTYPE, 19087db96d56Sopenharmony_ci "add file as regular failed") 19097db96d56Sopenharmony_ci 19107db96d56Sopenharmony_ci def test_add_hardlink(self): 19117db96d56Sopenharmony_ci tarinfo = self.tar.gettarinfo(self.bar) 19127db96d56Sopenharmony_ci self.assertEqual(tarinfo.type, tarfile.LNKTYPE, 19137db96d56Sopenharmony_ci "add file as hardlink failed") 19147db96d56Sopenharmony_ci 19157db96d56Sopenharmony_ci def test_dereference_hardlink(self): 19167db96d56Sopenharmony_ci self.tar.dereference = True 19177db96d56Sopenharmony_ci tarinfo = self.tar.gettarinfo(self.bar) 19187db96d56Sopenharmony_ci self.assertEqual(tarinfo.type, tarfile.REGTYPE, 19197db96d56Sopenharmony_ci "dereferencing hardlink failed") 19207db96d56Sopenharmony_ci 19217db96d56Sopenharmony_ci 19227db96d56Sopenharmony_ciclass PaxWriteTest(GNUWriteTest): 19237db96d56Sopenharmony_ci 19247db96d56Sopenharmony_ci def _test(self, name, link=None): 19257db96d56Sopenharmony_ci # See GNUWriteTest. 19267db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo(name) 19277db96d56Sopenharmony_ci if link: 19287db96d56Sopenharmony_ci tarinfo.linkname = link 19297db96d56Sopenharmony_ci tarinfo.type = tarfile.LNKTYPE 19307db96d56Sopenharmony_ci 19317db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT) 19327db96d56Sopenharmony_ci try: 19337db96d56Sopenharmony_ci tar.addfile(tarinfo) 19347db96d56Sopenharmony_ci finally: 19357db96d56Sopenharmony_ci tar.close() 19367db96d56Sopenharmony_ci 19377db96d56Sopenharmony_ci tar = tarfile.open(tmpname) 19387db96d56Sopenharmony_ci try: 19397db96d56Sopenharmony_ci if link: 19407db96d56Sopenharmony_ci l = tar.getmembers()[0].linkname 19417db96d56Sopenharmony_ci self.assertEqual(link, l, "PAX longlink creation failed") 19427db96d56Sopenharmony_ci else: 19437db96d56Sopenharmony_ci n = tar.getmembers()[0].name 19447db96d56Sopenharmony_ci self.assertEqual(name, n, "PAX longname creation failed") 19457db96d56Sopenharmony_ci finally: 19467db96d56Sopenharmony_ci tar.close() 19477db96d56Sopenharmony_ci 19487db96d56Sopenharmony_ci def test_pax_global_header(self): 19497db96d56Sopenharmony_ci pax_headers = { 19507db96d56Sopenharmony_ci "foo": "bar", 19517db96d56Sopenharmony_ci "uid": "0", 19527db96d56Sopenharmony_ci "mtime": "1.23", 19537db96d56Sopenharmony_ci "test": "\xe4\xf6\xfc", 19547db96d56Sopenharmony_ci "\xe4\xf6\xfc": "test"} 19557db96d56Sopenharmony_ci 19567db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, 19577db96d56Sopenharmony_ci pax_headers=pax_headers) 19587db96d56Sopenharmony_ci try: 19597db96d56Sopenharmony_ci tar.addfile(tarfile.TarInfo("test")) 19607db96d56Sopenharmony_ci finally: 19617db96d56Sopenharmony_ci tar.close() 19627db96d56Sopenharmony_ci 19637db96d56Sopenharmony_ci # Test if the global header was written correctly. 19647db96d56Sopenharmony_ci tar = tarfile.open(tmpname, encoding="iso8859-1") 19657db96d56Sopenharmony_ci try: 19667db96d56Sopenharmony_ci self.assertEqual(tar.pax_headers, pax_headers) 19677db96d56Sopenharmony_ci self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers) 19687db96d56Sopenharmony_ci # Test if all the fields are strings. 19697db96d56Sopenharmony_ci for key, val in tar.pax_headers.items(): 19707db96d56Sopenharmony_ci self.assertIsNot(type(key), bytes) 19717db96d56Sopenharmony_ci self.assertIsNot(type(val), bytes) 19727db96d56Sopenharmony_ci if key in tarfile.PAX_NUMBER_FIELDS: 19737db96d56Sopenharmony_ci try: 19747db96d56Sopenharmony_ci tarfile.PAX_NUMBER_FIELDS[key](val) 19757db96d56Sopenharmony_ci except (TypeError, ValueError): 19767db96d56Sopenharmony_ci self.fail("unable to convert pax header field") 19777db96d56Sopenharmony_ci finally: 19787db96d56Sopenharmony_ci tar.close() 19797db96d56Sopenharmony_ci 19807db96d56Sopenharmony_ci def test_pax_extended_header(self): 19817db96d56Sopenharmony_ci # The fields from the pax header have priority over the 19827db96d56Sopenharmony_ci # TarInfo. 19837db96d56Sopenharmony_ci pax_headers = {"path": "foo", "uid": "123"} 19847db96d56Sopenharmony_ci 19857db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, 19867db96d56Sopenharmony_ci encoding="iso8859-1") 19877db96d56Sopenharmony_ci try: 19887db96d56Sopenharmony_ci t = tarfile.TarInfo() 19897db96d56Sopenharmony_ci t.name = "\xe4\xf6\xfc" # non-ASCII 19907db96d56Sopenharmony_ci t.uid = 8**8 # too large 19917db96d56Sopenharmony_ci t.pax_headers = pax_headers 19927db96d56Sopenharmony_ci tar.addfile(t) 19937db96d56Sopenharmony_ci finally: 19947db96d56Sopenharmony_ci tar.close() 19957db96d56Sopenharmony_ci 19967db96d56Sopenharmony_ci tar = tarfile.open(tmpname, encoding="iso8859-1") 19977db96d56Sopenharmony_ci try: 19987db96d56Sopenharmony_ci t = tar.getmembers()[0] 19997db96d56Sopenharmony_ci self.assertEqual(t.pax_headers, pax_headers) 20007db96d56Sopenharmony_ci self.assertEqual(t.name, "foo") 20017db96d56Sopenharmony_ci self.assertEqual(t.uid, 123) 20027db96d56Sopenharmony_ci finally: 20037db96d56Sopenharmony_ci tar.close() 20047db96d56Sopenharmony_ci 20057db96d56Sopenharmony_ci def test_create_pax_header(self): 20067db96d56Sopenharmony_ci # The ustar header should contain values that can be 20077db96d56Sopenharmony_ci # represented reasonably, even if a better (e.g. higher 20087db96d56Sopenharmony_ci # precision) version is set in the pax header. 20097db96d56Sopenharmony_ci # Issue #45863 20107db96d56Sopenharmony_ci 20117db96d56Sopenharmony_ci # values that should be kept 20127db96d56Sopenharmony_ci t = tarfile.TarInfo() 20137db96d56Sopenharmony_ci t.name = "foo" 20147db96d56Sopenharmony_ci t.mtime = 1000.1 20157db96d56Sopenharmony_ci t.size = 100 20167db96d56Sopenharmony_ci t.uid = 123 20177db96d56Sopenharmony_ci t.gid = 124 20187db96d56Sopenharmony_ci info = t.get_info() 20197db96d56Sopenharmony_ci header = t.create_pax_header(info, encoding="iso8859-1") 20207db96d56Sopenharmony_ci self.assertEqual(info['name'], "foo") 20217db96d56Sopenharmony_ci # mtime should be rounded to nearest second 20227db96d56Sopenharmony_ci self.assertIsInstance(info['mtime'], int) 20237db96d56Sopenharmony_ci self.assertEqual(info['mtime'], 1000) 20247db96d56Sopenharmony_ci self.assertEqual(info['size'], 100) 20257db96d56Sopenharmony_ci self.assertEqual(info['uid'], 123) 20267db96d56Sopenharmony_ci self.assertEqual(info['gid'], 124) 20277db96d56Sopenharmony_ci self.assertEqual(header, 20287db96d56Sopenharmony_ci b'././@PaxHeader' + bytes(86) \ 20297db96d56Sopenharmony_ci + b'0000000\x000000000\x000000000\x0000000000020\x0000000000000\x00010205\x00 x' \ 20307db96d56Sopenharmony_ci + bytes(100) + b'ustar\x0000'+ bytes(247) \ 20317db96d56Sopenharmony_ci + b'16 mtime=1000.1\n' + bytes(496) + b'foo' + bytes(97) \ 20327db96d56Sopenharmony_ci + b'0000644\x000000173\x000000174\x0000000000144\x0000000001750\x00006516\x00 0' \ 20337db96d56Sopenharmony_ci + bytes(100) + b'ustar\x0000' + bytes(247)) 20347db96d56Sopenharmony_ci 20357db96d56Sopenharmony_ci # values that should be changed 20367db96d56Sopenharmony_ci t = tarfile.TarInfo() 20377db96d56Sopenharmony_ci t.name = "foo\u3374" # can't be represented in ascii 20387db96d56Sopenharmony_ci t.mtime = 10**10 # too big 20397db96d56Sopenharmony_ci t.size = 10**10 # too big 20407db96d56Sopenharmony_ci t.uid = 8**8 # too big 20417db96d56Sopenharmony_ci t.gid = 8**8+1 # too big 20427db96d56Sopenharmony_ci info = t.get_info() 20437db96d56Sopenharmony_ci header = t.create_pax_header(info, encoding="iso8859-1") 20447db96d56Sopenharmony_ci # name is kept as-is in info but should be added to pax header 20457db96d56Sopenharmony_ci self.assertEqual(info['name'], "foo\u3374") 20467db96d56Sopenharmony_ci self.assertEqual(info['mtime'], 0) 20477db96d56Sopenharmony_ci self.assertEqual(info['size'], 0) 20487db96d56Sopenharmony_ci self.assertEqual(info['uid'], 0) 20497db96d56Sopenharmony_ci self.assertEqual(info['gid'], 0) 20507db96d56Sopenharmony_ci self.assertEqual(header, 20517db96d56Sopenharmony_ci b'././@PaxHeader' + bytes(86) \ 20527db96d56Sopenharmony_ci + b'0000000\x000000000\x000000000\x0000000000130\x0000000000000\x00010207\x00 x' \ 20537db96d56Sopenharmony_ci + bytes(100) + b'ustar\x0000' + bytes(247) \ 20547db96d56Sopenharmony_ci + b'15 path=foo\xe3\x8d\xb4\n16 uid=16777216\n' \ 20557db96d56Sopenharmony_ci + b'16 gid=16777217\n20 size=10000000000\n' \ 20567db96d56Sopenharmony_ci + b'21 mtime=10000000000\n'+ bytes(424) + b'foo?' + bytes(96) \ 20577db96d56Sopenharmony_ci + b'0000644\x000000000\x000000000\x0000000000000\x0000000000000\x00006540\x00 0' \ 20587db96d56Sopenharmony_ci + bytes(100) + b'ustar\x0000' + bytes(247)) 20597db96d56Sopenharmony_ci 20607db96d56Sopenharmony_ci 20617db96d56Sopenharmony_ciclass UnicodeTest: 20627db96d56Sopenharmony_ci 20637db96d56Sopenharmony_ci def test_iso8859_1_filename(self): 20647db96d56Sopenharmony_ci self._test_unicode_filename("iso8859-1") 20657db96d56Sopenharmony_ci 20667db96d56Sopenharmony_ci def test_utf7_filename(self): 20677db96d56Sopenharmony_ci self._test_unicode_filename("utf7") 20687db96d56Sopenharmony_ci 20697db96d56Sopenharmony_ci def test_utf8_filename(self): 20707db96d56Sopenharmony_ci self._test_unicode_filename("utf-8") 20717db96d56Sopenharmony_ci 20727db96d56Sopenharmony_ci def _test_unicode_filename(self, encoding): 20737db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w", format=self.format, 20747db96d56Sopenharmony_ci encoding=encoding, errors="strict") 20757db96d56Sopenharmony_ci try: 20767db96d56Sopenharmony_ci name = "\xe4\xf6\xfc" 20777db96d56Sopenharmony_ci tar.addfile(tarfile.TarInfo(name)) 20787db96d56Sopenharmony_ci finally: 20797db96d56Sopenharmony_ci tar.close() 20807db96d56Sopenharmony_ci 20817db96d56Sopenharmony_ci tar = tarfile.open(tmpname, encoding=encoding) 20827db96d56Sopenharmony_ci try: 20837db96d56Sopenharmony_ci self.assertEqual(tar.getmembers()[0].name, name) 20847db96d56Sopenharmony_ci finally: 20857db96d56Sopenharmony_ci tar.close() 20867db96d56Sopenharmony_ci 20877db96d56Sopenharmony_ci def test_unicode_filename_error(self): 20887db96d56Sopenharmony_ci tar = tarfile.open(tmpname, "w", format=self.format, 20897db96d56Sopenharmony_ci encoding="ascii", errors="strict") 20907db96d56Sopenharmony_ci try: 20917db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo() 20927db96d56Sopenharmony_ci 20937db96d56Sopenharmony_ci tarinfo.name = "\xe4\xf6\xfc" 20947db96d56Sopenharmony_ci self.assertRaises(UnicodeError, tar.addfile, tarinfo) 20957db96d56Sopenharmony_ci 20967db96d56Sopenharmony_ci tarinfo.name = "foo" 20977db96d56Sopenharmony_ci tarinfo.uname = "\xe4\xf6\xfc" 20987db96d56Sopenharmony_ci self.assertRaises(UnicodeError, tar.addfile, tarinfo) 20997db96d56Sopenharmony_ci finally: 21007db96d56Sopenharmony_ci tar.close() 21017db96d56Sopenharmony_ci 21027db96d56Sopenharmony_ci def test_unicode_argument(self): 21037db96d56Sopenharmony_ci tar = tarfile.open(tarname, "r", 21047db96d56Sopenharmony_ci encoding="iso8859-1", errors="strict") 21057db96d56Sopenharmony_ci try: 21067db96d56Sopenharmony_ci for t in tar: 21077db96d56Sopenharmony_ci self.assertIs(type(t.name), str) 21087db96d56Sopenharmony_ci self.assertIs(type(t.linkname), str) 21097db96d56Sopenharmony_ci self.assertIs(type(t.uname), str) 21107db96d56Sopenharmony_ci self.assertIs(type(t.gname), str) 21117db96d56Sopenharmony_ci finally: 21127db96d56Sopenharmony_ci tar.close() 21137db96d56Sopenharmony_ci 21147db96d56Sopenharmony_ci def test_uname_unicode(self): 21157db96d56Sopenharmony_ci t = tarfile.TarInfo("foo") 21167db96d56Sopenharmony_ci t.uname = "\xe4\xf6\xfc" 21177db96d56Sopenharmony_ci t.gname = "\xe4\xf6\xfc" 21187db96d56Sopenharmony_ci 21197db96d56Sopenharmony_ci tar = tarfile.open(tmpname, mode="w", format=self.format, 21207db96d56Sopenharmony_ci encoding="iso8859-1") 21217db96d56Sopenharmony_ci try: 21227db96d56Sopenharmony_ci tar.addfile(t) 21237db96d56Sopenharmony_ci finally: 21247db96d56Sopenharmony_ci tar.close() 21257db96d56Sopenharmony_ci 21267db96d56Sopenharmony_ci tar = tarfile.open(tmpname, encoding="iso8859-1") 21277db96d56Sopenharmony_ci try: 21287db96d56Sopenharmony_ci t = tar.getmember("foo") 21297db96d56Sopenharmony_ci self.assertEqual(t.uname, "\xe4\xf6\xfc") 21307db96d56Sopenharmony_ci self.assertEqual(t.gname, "\xe4\xf6\xfc") 21317db96d56Sopenharmony_ci 21327db96d56Sopenharmony_ci if self.format != tarfile.PAX_FORMAT: 21337db96d56Sopenharmony_ci tar.close() 21347db96d56Sopenharmony_ci tar = tarfile.open(tmpname, encoding="ascii") 21357db96d56Sopenharmony_ci t = tar.getmember("foo") 21367db96d56Sopenharmony_ci self.assertEqual(t.uname, "\udce4\udcf6\udcfc") 21377db96d56Sopenharmony_ci self.assertEqual(t.gname, "\udce4\udcf6\udcfc") 21387db96d56Sopenharmony_ci finally: 21397db96d56Sopenharmony_ci tar.close() 21407db96d56Sopenharmony_ci 21417db96d56Sopenharmony_ci 21427db96d56Sopenharmony_ciclass UstarUnicodeTest(UnicodeTest, unittest.TestCase): 21437db96d56Sopenharmony_ci 21447db96d56Sopenharmony_ci format = tarfile.USTAR_FORMAT 21457db96d56Sopenharmony_ci 21467db96d56Sopenharmony_ci # Test whether the utf-8 encoded version of a filename exceeds the 100 21477db96d56Sopenharmony_ci # bytes name field limit (every occurrence of '\xff' will be expanded to 2 21487db96d56Sopenharmony_ci # bytes). 21497db96d56Sopenharmony_ci def test_unicode_name1(self): 21507db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 10) 21517db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 10 + "0", ValueError) 21527db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 9 + "01234567\xff") 21537db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 9 + "012345678\xff", ValueError) 21547db96d56Sopenharmony_ci 21557db96d56Sopenharmony_ci def test_unicode_name2(self): 21567db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 9 + "012345\xff\xff") 21577db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 9 + "0123456\xff\xff", ValueError) 21587db96d56Sopenharmony_ci 21597db96d56Sopenharmony_ci # Test whether the utf-8 encoded version of a filename exceeds the 155 21607db96d56Sopenharmony_ci # bytes prefix + '/' + 100 bytes name limit. 21617db96d56Sopenharmony_ci def test_unicode_longname1(self): 21627db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 10) 21637db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "0123/4" + "0123456789" * 10, ValueError) 21647db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "012\xff/" + "0123456789" * 10) 21657db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "0123\xff/" + "0123456789" * 10, ValueError) 21667db96d56Sopenharmony_ci 21677db96d56Sopenharmony_ci def test_unicode_longname2(self): 21687db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01\xff/2" + "0123456789" * 10, ValueError) 21697db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01\xff\xff/" + "0123456789" * 10, ValueError) 21707db96d56Sopenharmony_ci 21717db96d56Sopenharmony_ci def test_unicode_longname3(self): 21727db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01\xff\xff/2" + "0123456789" * 10, ValueError) 21737db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "01234567\xff") 21747db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345678\xff", ValueError) 21757db96d56Sopenharmony_ci 21767db96d56Sopenharmony_ci def test_unicode_longname4(self): 21777db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345\xff\xff") 21787db96d56Sopenharmony_ci self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "0123456\xff\xff", ValueError) 21797db96d56Sopenharmony_ci 21807db96d56Sopenharmony_ci def _test_ustar_name(self, name, exc=None): 21817db96d56Sopenharmony_ci with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar: 21827db96d56Sopenharmony_ci t = tarfile.TarInfo(name) 21837db96d56Sopenharmony_ci if exc is None: 21847db96d56Sopenharmony_ci tar.addfile(t) 21857db96d56Sopenharmony_ci else: 21867db96d56Sopenharmony_ci self.assertRaises(exc, tar.addfile, t) 21877db96d56Sopenharmony_ci 21887db96d56Sopenharmony_ci if exc is None: 21897db96d56Sopenharmony_ci with tarfile.open(tmpname, "r", encoding="utf-8") as tar: 21907db96d56Sopenharmony_ci for t in tar: 21917db96d56Sopenharmony_ci self.assertEqual(name, t.name) 21927db96d56Sopenharmony_ci break 21937db96d56Sopenharmony_ci 21947db96d56Sopenharmony_ci # Test the same as above for the 100 bytes link field. 21957db96d56Sopenharmony_ci def test_unicode_link1(self): 21967db96d56Sopenharmony_ci self._test_ustar_link("0123456789" * 10) 21977db96d56Sopenharmony_ci self._test_ustar_link("0123456789" * 10 + "0", ValueError) 21987db96d56Sopenharmony_ci self._test_ustar_link("0123456789" * 9 + "01234567\xff") 21997db96d56Sopenharmony_ci self._test_ustar_link("0123456789" * 9 + "012345678\xff", ValueError) 22007db96d56Sopenharmony_ci 22017db96d56Sopenharmony_ci def test_unicode_link2(self): 22027db96d56Sopenharmony_ci self._test_ustar_link("0123456789" * 9 + "012345\xff\xff") 22037db96d56Sopenharmony_ci self._test_ustar_link("0123456789" * 9 + "0123456\xff\xff", ValueError) 22047db96d56Sopenharmony_ci 22057db96d56Sopenharmony_ci def _test_ustar_link(self, name, exc=None): 22067db96d56Sopenharmony_ci with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar: 22077db96d56Sopenharmony_ci t = tarfile.TarInfo("foo") 22087db96d56Sopenharmony_ci t.linkname = name 22097db96d56Sopenharmony_ci if exc is None: 22107db96d56Sopenharmony_ci tar.addfile(t) 22117db96d56Sopenharmony_ci else: 22127db96d56Sopenharmony_ci self.assertRaises(exc, tar.addfile, t) 22137db96d56Sopenharmony_ci 22147db96d56Sopenharmony_ci if exc is None: 22157db96d56Sopenharmony_ci with tarfile.open(tmpname, "r", encoding="utf-8") as tar: 22167db96d56Sopenharmony_ci for t in tar: 22177db96d56Sopenharmony_ci self.assertEqual(name, t.linkname) 22187db96d56Sopenharmony_ci break 22197db96d56Sopenharmony_ci 22207db96d56Sopenharmony_ci 22217db96d56Sopenharmony_ciclass GNUUnicodeTest(UnicodeTest, unittest.TestCase): 22227db96d56Sopenharmony_ci 22237db96d56Sopenharmony_ci format = tarfile.GNU_FORMAT 22247db96d56Sopenharmony_ci 22257db96d56Sopenharmony_ci def test_bad_pax_header(self): 22267db96d56Sopenharmony_ci # Test for issue #8633. GNU tar <= 1.23 creates raw binary fields 22277db96d56Sopenharmony_ci # without a hdrcharset=BINARY header. 22287db96d56Sopenharmony_ci for encoding, name in ( 22297db96d56Sopenharmony_ci ("utf-8", "pax/bad-pax-\udce4\udcf6\udcfc"), 22307db96d56Sopenharmony_ci ("iso8859-1", "pax/bad-pax-\xe4\xf6\xfc"),): 22317db96d56Sopenharmony_ci with tarfile.open(tarname, encoding=encoding, 22327db96d56Sopenharmony_ci errors="surrogateescape") as tar: 22337db96d56Sopenharmony_ci try: 22347db96d56Sopenharmony_ci t = tar.getmember(name) 22357db96d56Sopenharmony_ci except KeyError: 22367db96d56Sopenharmony_ci self.fail("unable to read bad GNU tar pax header") 22377db96d56Sopenharmony_ci 22387db96d56Sopenharmony_ci 22397db96d56Sopenharmony_ciclass PAXUnicodeTest(UnicodeTest, unittest.TestCase): 22407db96d56Sopenharmony_ci 22417db96d56Sopenharmony_ci format = tarfile.PAX_FORMAT 22427db96d56Sopenharmony_ci 22437db96d56Sopenharmony_ci # PAX_FORMAT ignores encoding in write mode. 22447db96d56Sopenharmony_ci test_unicode_filename_error = None 22457db96d56Sopenharmony_ci 22467db96d56Sopenharmony_ci def test_binary_header(self): 22477db96d56Sopenharmony_ci # Test a POSIX.1-2008 compatible header with a hdrcharset=BINARY field. 22487db96d56Sopenharmony_ci for encoding, name in ( 22497db96d56Sopenharmony_ci ("utf-8", "pax/hdrcharset-\udce4\udcf6\udcfc"), 22507db96d56Sopenharmony_ci ("iso8859-1", "pax/hdrcharset-\xe4\xf6\xfc"),): 22517db96d56Sopenharmony_ci with tarfile.open(tarname, encoding=encoding, 22527db96d56Sopenharmony_ci errors="surrogateescape") as tar: 22537db96d56Sopenharmony_ci try: 22547db96d56Sopenharmony_ci t = tar.getmember(name) 22557db96d56Sopenharmony_ci except KeyError: 22567db96d56Sopenharmony_ci self.fail("unable to read POSIX.1-2008 binary header") 22577db96d56Sopenharmony_ci 22587db96d56Sopenharmony_ci 22597db96d56Sopenharmony_ciclass AppendTestBase: 22607db96d56Sopenharmony_ci # Test append mode (cp. patch #1652681). 22617db96d56Sopenharmony_ci 22627db96d56Sopenharmony_ci def setUp(self): 22637db96d56Sopenharmony_ci self.tarname = tmpname 22647db96d56Sopenharmony_ci if os.path.exists(self.tarname): 22657db96d56Sopenharmony_ci os_helper.unlink(self.tarname) 22667db96d56Sopenharmony_ci 22677db96d56Sopenharmony_ci def _create_testtar(self, mode="w:"): 22687db96d56Sopenharmony_ci with tarfile.open(tarname, encoding="iso8859-1") as src: 22697db96d56Sopenharmony_ci t = src.getmember("ustar/regtype") 22707db96d56Sopenharmony_ci t.name = "foo" 22717db96d56Sopenharmony_ci with src.extractfile(t) as f: 22727db96d56Sopenharmony_ci with tarfile.open(self.tarname, mode) as tar: 22737db96d56Sopenharmony_ci tar.addfile(t, f) 22747db96d56Sopenharmony_ci 22757db96d56Sopenharmony_ci def test_append_compressed(self): 22767db96d56Sopenharmony_ci self._create_testtar("w:" + self.suffix) 22777db96d56Sopenharmony_ci self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a") 22787db96d56Sopenharmony_ci 22797db96d56Sopenharmony_ciclass AppendTest(AppendTestBase, unittest.TestCase): 22807db96d56Sopenharmony_ci test_append_compressed = None 22817db96d56Sopenharmony_ci 22827db96d56Sopenharmony_ci def _add_testfile(self, fileobj=None): 22837db96d56Sopenharmony_ci with tarfile.open(self.tarname, "a", fileobj=fileobj) as tar: 22847db96d56Sopenharmony_ci tar.addfile(tarfile.TarInfo("bar")) 22857db96d56Sopenharmony_ci 22867db96d56Sopenharmony_ci def _test(self, names=["bar"], fileobj=None): 22877db96d56Sopenharmony_ci with tarfile.open(self.tarname, fileobj=fileobj) as tar: 22887db96d56Sopenharmony_ci self.assertEqual(tar.getnames(), names) 22897db96d56Sopenharmony_ci 22907db96d56Sopenharmony_ci def test_non_existing(self): 22917db96d56Sopenharmony_ci self._add_testfile() 22927db96d56Sopenharmony_ci self._test() 22937db96d56Sopenharmony_ci 22947db96d56Sopenharmony_ci def test_empty(self): 22957db96d56Sopenharmony_ci tarfile.open(self.tarname, "w:").close() 22967db96d56Sopenharmony_ci self._add_testfile() 22977db96d56Sopenharmony_ci self._test() 22987db96d56Sopenharmony_ci 22997db96d56Sopenharmony_ci def test_empty_fileobj(self): 23007db96d56Sopenharmony_ci fobj = io.BytesIO(b"\0" * 1024) 23017db96d56Sopenharmony_ci self._add_testfile(fobj) 23027db96d56Sopenharmony_ci fobj.seek(0) 23037db96d56Sopenharmony_ci self._test(fileobj=fobj) 23047db96d56Sopenharmony_ci 23057db96d56Sopenharmony_ci def test_fileobj(self): 23067db96d56Sopenharmony_ci self._create_testtar() 23077db96d56Sopenharmony_ci with open(self.tarname, "rb") as fobj: 23087db96d56Sopenharmony_ci data = fobj.read() 23097db96d56Sopenharmony_ci fobj = io.BytesIO(data) 23107db96d56Sopenharmony_ci self._add_testfile(fobj) 23117db96d56Sopenharmony_ci fobj.seek(0) 23127db96d56Sopenharmony_ci self._test(names=["foo", "bar"], fileobj=fobj) 23137db96d56Sopenharmony_ci 23147db96d56Sopenharmony_ci def test_existing(self): 23157db96d56Sopenharmony_ci self._create_testtar() 23167db96d56Sopenharmony_ci self._add_testfile() 23177db96d56Sopenharmony_ci self._test(names=["foo", "bar"]) 23187db96d56Sopenharmony_ci 23197db96d56Sopenharmony_ci # Append mode is supposed to fail if the tarfile to append to 23207db96d56Sopenharmony_ci # does not end with a zero block. 23217db96d56Sopenharmony_ci def _test_error(self, data): 23227db96d56Sopenharmony_ci with open(self.tarname, "wb") as fobj: 23237db96d56Sopenharmony_ci fobj.write(data) 23247db96d56Sopenharmony_ci self.assertRaises(tarfile.ReadError, self._add_testfile) 23257db96d56Sopenharmony_ci 23267db96d56Sopenharmony_ci def test_null(self): 23277db96d56Sopenharmony_ci self._test_error(b"") 23287db96d56Sopenharmony_ci 23297db96d56Sopenharmony_ci def test_incomplete(self): 23307db96d56Sopenharmony_ci self._test_error(b"\0" * 13) 23317db96d56Sopenharmony_ci 23327db96d56Sopenharmony_ci def test_premature_eof(self): 23337db96d56Sopenharmony_ci data = tarfile.TarInfo("foo").tobuf() 23347db96d56Sopenharmony_ci self._test_error(data) 23357db96d56Sopenharmony_ci 23367db96d56Sopenharmony_ci def test_trailing_garbage(self): 23377db96d56Sopenharmony_ci data = tarfile.TarInfo("foo").tobuf() 23387db96d56Sopenharmony_ci self._test_error(data + b"\0" * 13) 23397db96d56Sopenharmony_ci 23407db96d56Sopenharmony_ci def test_invalid(self): 23417db96d56Sopenharmony_ci self._test_error(b"a" * 512) 23427db96d56Sopenharmony_ci 23437db96d56Sopenharmony_ciclass GzipAppendTest(GzipTest, AppendTestBase, unittest.TestCase): 23447db96d56Sopenharmony_ci pass 23457db96d56Sopenharmony_ci 23467db96d56Sopenharmony_ciclass Bz2AppendTest(Bz2Test, AppendTestBase, unittest.TestCase): 23477db96d56Sopenharmony_ci pass 23487db96d56Sopenharmony_ci 23497db96d56Sopenharmony_ciclass LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase): 23507db96d56Sopenharmony_ci pass 23517db96d56Sopenharmony_ci 23527db96d56Sopenharmony_ci 23537db96d56Sopenharmony_ciclass LimitsTest(unittest.TestCase): 23547db96d56Sopenharmony_ci 23557db96d56Sopenharmony_ci def test_ustar_limits(self): 23567db96d56Sopenharmony_ci # 100 char name 23577db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("0123456789" * 10) 23587db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.USTAR_FORMAT) 23597db96d56Sopenharmony_ci 23607db96d56Sopenharmony_ci # 101 char name that cannot be stored 23617db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("0123456789" * 10 + "0") 23627db96d56Sopenharmony_ci self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) 23637db96d56Sopenharmony_ci 23647db96d56Sopenharmony_ci # 256 char name with a slash at pos 156 23657db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("123/" * 62 + "longname") 23667db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.USTAR_FORMAT) 23677db96d56Sopenharmony_ci 23687db96d56Sopenharmony_ci # 256 char name that cannot be stored 23697db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname") 23707db96d56Sopenharmony_ci self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) 23717db96d56Sopenharmony_ci 23727db96d56Sopenharmony_ci # 512 char name 23737db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("123/" * 126 + "longname") 23747db96d56Sopenharmony_ci self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) 23757db96d56Sopenharmony_ci 23767db96d56Sopenharmony_ci # 512 char linkname 23777db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("longlink") 23787db96d56Sopenharmony_ci tarinfo.linkname = "123/" * 126 + "longname" 23797db96d56Sopenharmony_ci self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) 23807db96d56Sopenharmony_ci 23817db96d56Sopenharmony_ci # uid > 8 digits 23827db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("name") 23837db96d56Sopenharmony_ci tarinfo.uid = 0o10000000 23847db96d56Sopenharmony_ci self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT) 23857db96d56Sopenharmony_ci 23867db96d56Sopenharmony_ci def test_gnu_limits(self): 23877db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("123/" * 126 + "longname") 23887db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.GNU_FORMAT) 23897db96d56Sopenharmony_ci 23907db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("longlink") 23917db96d56Sopenharmony_ci tarinfo.linkname = "123/" * 126 + "longname" 23927db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.GNU_FORMAT) 23937db96d56Sopenharmony_ci 23947db96d56Sopenharmony_ci # uid >= 256 ** 7 23957db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("name") 23967db96d56Sopenharmony_ci tarinfo.uid = 0o4000000000000000000 23977db96d56Sopenharmony_ci self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT) 23987db96d56Sopenharmony_ci 23997db96d56Sopenharmony_ci def test_pax_limits(self): 24007db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("123/" * 126 + "longname") 24017db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.PAX_FORMAT) 24027db96d56Sopenharmony_ci 24037db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("longlink") 24047db96d56Sopenharmony_ci tarinfo.linkname = "123/" * 126 + "longname" 24057db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.PAX_FORMAT) 24067db96d56Sopenharmony_ci 24077db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo("name") 24087db96d56Sopenharmony_ci tarinfo.uid = 0o4000000000000000000 24097db96d56Sopenharmony_ci tarinfo.tobuf(tarfile.PAX_FORMAT) 24107db96d56Sopenharmony_ci 24117db96d56Sopenharmony_ci 24127db96d56Sopenharmony_ciclass MiscTest(unittest.TestCase): 24137db96d56Sopenharmony_ci 24147db96d56Sopenharmony_ci def test_char_fields(self): 24157db96d56Sopenharmony_ci self.assertEqual(tarfile.stn("foo", 8, "ascii", "strict"), 24167db96d56Sopenharmony_ci b"foo\0\0\0\0\0") 24177db96d56Sopenharmony_ci self.assertEqual(tarfile.stn("foobar", 3, "ascii", "strict"), 24187db96d56Sopenharmony_ci b"foo") 24197db96d56Sopenharmony_ci self.assertEqual(tarfile.nts(b"foo\0\0\0\0\0", "ascii", "strict"), 24207db96d56Sopenharmony_ci "foo") 24217db96d56Sopenharmony_ci self.assertEqual(tarfile.nts(b"foo\0bar\0", "ascii", "strict"), 24227db96d56Sopenharmony_ci "foo") 24237db96d56Sopenharmony_ci 24247db96d56Sopenharmony_ci def test_read_number_fields(self): 24257db96d56Sopenharmony_ci # Issue 13158: Test if GNU tar specific base-256 number fields 24267db96d56Sopenharmony_ci # are decoded correctly. 24277db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"0000001\x00"), 1) 24287db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"7777777\x00"), 0o7777777) 24297db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\x00\x20\x00\x00"), 24307db96d56Sopenharmony_ci 0o10000000) 24317db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\xff\xff\xff\xff"), 24327db96d56Sopenharmony_ci 0xffffffff) 24337db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\xff"), 24347db96d56Sopenharmony_ci -1) 24357db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\x9c"), 24367db96d56Sopenharmony_ci -100) 24377db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"), 24387db96d56Sopenharmony_ci -0x100000000000000) 24397db96d56Sopenharmony_ci 24407db96d56Sopenharmony_ci # Issue 24514: Test if empty number fields are converted to zero. 24417db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b"\0"), 0) 24427db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(b" \0"), 0) 24437db96d56Sopenharmony_ci 24447db96d56Sopenharmony_ci def test_write_number_fields(self): 24457db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(1), b"0000001\x00") 24467db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00") 24477db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(0o10000000, format=tarfile.GNU_FORMAT), 24487db96d56Sopenharmony_ci b"\x80\x00\x00\x00\x00\x20\x00\x00") 24497db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(0xffffffff, format=tarfile.GNU_FORMAT), 24507db96d56Sopenharmony_ci b"\x80\x00\x00\x00\xff\xff\xff\xff") 24517db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(-1, format=tarfile.GNU_FORMAT), 24527db96d56Sopenharmony_ci b"\xff\xff\xff\xff\xff\xff\xff\xff") 24537db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(-100, format=tarfile.GNU_FORMAT), 24547db96d56Sopenharmony_ci b"\xff\xff\xff\xff\xff\xff\xff\x9c") 24557db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(-0x100000000000000, 24567db96d56Sopenharmony_ci format=tarfile.GNU_FORMAT), 24577db96d56Sopenharmony_ci b"\xff\x00\x00\x00\x00\x00\x00\x00") 24587db96d56Sopenharmony_ci 24597db96d56Sopenharmony_ci # Issue 32713: Test if itn() supports float values outside the 24607db96d56Sopenharmony_ci # non-GNU format range 24617db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(-100.0, format=tarfile.GNU_FORMAT), 24627db96d56Sopenharmony_ci b"\xff\xff\xff\xff\xff\xff\xff\x9c") 24637db96d56Sopenharmony_ci self.assertEqual(tarfile.itn(8 ** 12 + 0.0, format=tarfile.GNU_FORMAT), 24647db96d56Sopenharmony_ci b"\x80\x00\x00\x10\x00\x00\x00\x00") 24657db96d56Sopenharmony_ci self.assertEqual(tarfile.nti(tarfile.itn(-0.1, format=tarfile.GNU_FORMAT)), 0) 24667db96d56Sopenharmony_ci 24677db96d56Sopenharmony_ci def test_number_field_limits(self): 24687db96d56Sopenharmony_ci with self.assertRaises(ValueError): 24697db96d56Sopenharmony_ci tarfile.itn(-1, 8, tarfile.USTAR_FORMAT) 24707db96d56Sopenharmony_ci with self.assertRaises(ValueError): 24717db96d56Sopenharmony_ci tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT) 24727db96d56Sopenharmony_ci with self.assertRaises(ValueError): 24737db96d56Sopenharmony_ci tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT) 24747db96d56Sopenharmony_ci with self.assertRaises(ValueError): 24757db96d56Sopenharmony_ci tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT) 24767db96d56Sopenharmony_ci 24777db96d56Sopenharmony_ci def test__all__(self): 24787db96d56Sopenharmony_ci not_exported = { 24797db96d56Sopenharmony_ci 'version', 'grp', 'pwd', 'symlink_exception', 'NUL', 'BLOCKSIZE', 24807db96d56Sopenharmony_ci 'RECORDSIZE', 'GNU_MAGIC', 'POSIX_MAGIC', 'LENGTH_NAME', 24817db96d56Sopenharmony_ci 'LENGTH_LINK', 'LENGTH_PREFIX', 'REGTYPE', 'AREGTYPE', 'LNKTYPE', 24827db96d56Sopenharmony_ci 'SYMTYPE', 'CHRTYPE', 'BLKTYPE', 'DIRTYPE', 'FIFOTYPE', 'CONTTYPE', 24837db96d56Sopenharmony_ci 'GNUTYPE_LONGNAME', 'GNUTYPE_LONGLINK', 'GNUTYPE_SPARSE', 24847db96d56Sopenharmony_ci 'XHDTYPE', 'XGLTYPE', 'SOLARIS_XHDTYPE', 'SUPPORTED_TYPES', 24857db96d56Sopenharmony_ci 'REGULAR_TYPES', 'GNU_TYPES', 'PAX_FIELDS', 'PAX_NAME_FIELDS', 24867db96d56Sopenharmony_ci 'PAX_NUMBER_FIELDS', 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 24877db96d56Sopenharmony_ci 'copyfileobj', 'filemode', 'EmptyHeaderError', 24887db96d56Sopenharmony_ci 'TruncatedHeaderError', 'EOFHeaderError', 'InvalidHeaderError', 24897db96d56Sopenharmony_ci 'SubsequentHeaderError', 'ExFileObject', 'main', 24907db96d56Sopenharmony_ci "fully_trusted_filter", "data_filter", 24917db96d56Sopenharmony_ci "tar_filter", "FilterError", "AbsoluteLinkError", 24927db96d56Sopenharmony_ci "OutsideDestinationError", "SpecialFileError", "AbsolutePathError", 24937db96d56Sopenharmony_ci "LinkOutsideDestinationError", 24947db96d56Sopenharmony_ci } 24957db96d56Sopenharmony_ci support.check__all__(self, tarfile, not_exported=not_exported) 24967db96d56Sopenharmony_ci 24977db96d56Sopenharmony_ci def test_useful_error_message_when_modules_missing(self): 24987db96d56Sopenharmony_ci fname = os.path.join(os.path.dirname(__file__), 'testtar.tar.xz') 24997db96d56Sopenharmony_ci with self.assertRaises(tarfile.ReadError) as excinfo: 25007db96d56Sopenharmony_ci error = tarfile.CompressionError('lzma module is not available'), 25017db96d56Sopenharmony_ci with unittest.mock.patch.object(tarfile.TarFile, 'xzopen', side_effect=error): 25027db96d56Sopenharmony_ci tarfile.open(fname) 25037db96d56Sopenharmony_ci 25047db96d56Sopenharmony_ci self.assertIn( 25057db96d56Sopenharmony_ci "\n- method xz: CompressionError('lzma module is not available')\n", 25067db96d56Sopenharmony_ci str(excinfo.exception), 25077db96d56Sopenharmony_ci ) 25087db96d56Sopenharmony_ci 25097db96d56Sopenharmony_ci 25107db96d56Sopenharmony_ciclass CommandLineTest(unittest.TestCase): 25117db96d56Sopenharmony_ci 25127db96d56Sopenharmony_ci def tarfilecmd(self, *args, **kwargs): 25137db96d56Sopenharmony_ci rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args, 25147db96d56Sopenharmony_ci **kwargs) 25157db96d56Sopenharmony_ci return out.replace(os.linesep.encode(), b'\n') 25167db96d56Sopenharmony_ci 25177db96d56Sopenharmony_ci def tarfilecmd_failure(self, *args): 25187db96d56Sopenharmony_ci return script_helper.assert_python_failure('-m', 'tarfile', *args) 25197db96d56Sopenharmony_ci 25207db96d56Sopenharmony_ci def make_simple_tarfile(self, tar_name): 25217db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt'), 25227db96d56Sopenharmony_ci support.findfile('tokenize_tests-no-coding-cookie-' 25237db96d56Sopenharmony_ci 'and-utf8-bom-sig-only.txt')] 25247db96d56Sopenharmony_ci self.addCleanup(os_helper.unlink, tar_name) 25257db96d56Sopenharmony_ci with tarfile.open(tar_name, 'w') as tf: 25267db96d56Sopenharmony_ci for tardata in files: 25277db96d56Sopenharmony_ci tf.add(tardata, arcname=os.path.basename(tardata)) 25287db96d56Sopenharmony_ci 25297db96d56Sopenharmony_ci def make_evil_tarfile(self, tar_name): 25307db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt')] 25317db96d56Sopenharmony_ci self.addCleanup(os_helper.unlink, tar_name) 25327db96d56Sopenharmony_ci with tarfile.open(tar_name, 'w') as tf: 25337db96d56Sopenharmony_ci benign = tarfile.TarInfo('benign') 25347db96d56Sopenharmony_ci tf.addfile(benign, fileobj=io.BytesIO(b'')) 25357db96d56Sopenharmony_ci evil = tarfile.TarInfo('../evil') 25367db96d56Sopenharmony_ci tf.addfile(evil, fileobj=io.BytesIO(b'')) 25377db96d56Sopenharmony_ci 25387db96d56Sopenharmony_ci def test_bad_use(self): 25397db96d56Sopenharmony_ci rc, out, err = self.tarfilecmd_failure() 25407db96d56Sopenharmony_ci self.assertEqual(out, b'') 25417db96d56Sopenharmony_ci self.assertIn(b'usage', err.lower()) 25427db96d56Sopenharmony_ci self.assertIn(b'error', err.lower()) 25437db96d56Sopenharmony_ci self.assertIn(b'required', err.lower()) 25447db96d56Sopenharmony_ci rc, out, err = self.tarfilecmd_failure('-l', '') 25457db96d56Sopenharmony_ci self.assertEqual(out, b'') 25467db96d56Sopenharmony_ci self.assertNotEqual(err.strip(), b'') 25477db96d56Sopenharmony_ci 25487db96d56Sopenharmony_ci def test_test_command(self): 25497db96d56Sopenharmony_ci for tar_name in testtarnames: 25507db96d56Sopenharmony_ci for opt in '-t', '--test': 25517db96d56Sopenharmony_ci out = self.tarfilecmd(opt, tar_name) 25527db96d56Sopenharmony_ci self.assertEqual(out, b'') 25537db96d56Sopenharmony_ci 25547db96d56Sopenharmony_ci def test_test_command_verbose(self): 25557db96d56Sopenharmony_ci for tar_name in testtarnames: 25567db96d56Sopenharmony_ci for opt in '-v', '--verbose': 25577db96d56Sopenharmony_ci out = self.tarfilecmd(opt, '-t', tar_name, 25587db96d56Sopenharmony_ci PYTHONIOENCODING='utf-8') 25597db96d56Sopenharmony_ci self.assertIn(b'is a tar archive.\n', out) 25607db96d56Sopenharmony_ci 25617db96d56Sopenharmony_ci def test_test_command_invalid_file(self): 25627db96d56Sopenharmony_ci zipname = support.findfile('zipdir.zip') 25637db96d56Sopenharmony_ci rc, out, err = self.tarfilecmd_failure('-t', zipname) 25647db96d56Sopenharmony_ci self.assertIn(b' is not a tar archive.', err) 25657db96d56Sopenharmony_ci self.assertEqual(out, b'') 25667db96d56Sopenharmony_ci self.assertEqual(rc, 1) 25677db96d56Sopenharmony_ci 25687db96d56Sopenharmony_ci for tar_name in testtarnames: 25697db96d56Sopenharmony_ci with self.subTest(tar_name=tar_name): 25707db96d56Sopenharmony_ci with open(tar_name, 'rb') as f: 25717db96d56Sopenharmony_ci data = f.read() 25727db96d56Sopenharmony_ci try: 25737db96d56Sopenharmony_ci with open(tmpname, 'wb') as f: 25747db96d56Sopenharmony_ci f.write(data[:511]) 25757db96d56Sopenharmony_ci rc, out, err = self.tarfilecmd_failure('-t', tmpname) 25767db96d56Sopenharmony_ci self.assertEqual(out, b'') 25777db96d56Sopenharmony_ci self.assertEqual(rc, 1) 25787db96d56Sopenharmony_ci finally: 25797db96d56Sopenharmony_ci os_helper.unlink(tmpname) 25807db96d56Sopenharmony_ci 25817db96d56Sopenharmony_ci def test_list_command(self): 25827db96d56Sopenharmony_ci for tar_name in testtarnames: 25837db96d56Sopenharmony_ci with support.captured_stdout() as t: 25847db96d56Sopenharmony_ci with tarfile.open(tar_name, 'r') as tf: 25857db96d56Sopenharmony_ci tf.list(verbose=False) 25867db96d56Sopenharmony_ci expected = t.getvalue().encode('ascii', 'backslashreplace') 25877db96d56Sopenharmony_ci for opt in '-l', '--list': 25887db96d56Sopenharmony_ci out = self.tarfilecmd(opt, tar_name, 25897db96d56Sopenharmony_ci PYTHONIOENCODING='ascii') 25907db96d56Sopenharmony_ci self.assertEqual(out, expected) 25917db96d56Sopenharmony_ci 25927db96d56Sopenharmony_ci def test_list_command_verbose(self): 25937db96d56Sopenharmony_ci for tar_name in testtarnames: 25947db96d56Sopenharmony_ci with support.captured_stdout() as t: 25957db96d56Sopenharmony_ci with tarfile.open(tar_name, 'r') as tf: 25967db96d56Sopenharmony_ci tf.list(verbose=True) 25977db96d56Sopenharmony_ci expected = t.getvalue().encode('ascii', 'backslashreplace') 25987db96d56Sopenharmony_ci for opt in '-v', '--verbose': 25997db96d56Sopenharmony_ci out = self.tarfilecmd(opt, '-l', tar_name, 26007db96d56Sopenharmony_ci PYTHONIOENCODING='ascii') 26017db96d56Sopenharmony_ci self.assertEqual(out, expected) 26027db96d56Sopenharmony_ci 26037db96d56Sopenharmony_ci def test_list_command_invalid_file(self): 26047db96d56Sopenharmony_ci zipname = support.findfile('zipdir.zip') 26057db96d56Sopenharmony_ci rc, out, err = self.tarfilecmd_failure('-l', zipname) 26067db96d56Sopenharmony_ci self.assertIn(b' is not a tar archive.', err) 26077db96d56Sopenharmony_ci self.assertEqual(out, b'') 26087db96d56Sopenharmony_ci self.assertEqual(rc, 1) 26097db96d56Sopenharmony_ci 26107db96d56Sopenharmony_ci def test_create_command(self): 26117db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt'), 26127db96d56Sopenharmony_ci support.findfile('tokenize_tests-no-coding-cookie-' 26137db96d56Sopenharmony_ci 'and-utf8-bom-sig-only.txt')] 26147db96d56Sopenharmony_ci for opt in '-c', '--create': 26157db96d56Sopenharmony_ci try: 26167db96d56Sopenharmony_ci out = self.tarfilecmd(opt, tmpname, *files) 26177db96d56Sopenharmony_ci self.assertEqual(out, b'') 26187db96d56Sopenharmony_ci with tarfile.open(tmpname) as tar: 26197db96d56Sopenharmony_ci tar.getmembers() 26207db96d56Sopenharmony_ci finally: 26217db96d56Sopenharmony_ci os_helper.unlink(tmpname) 26227db96d56Sopenharmony_ci 26237db96d56Sopenharmony_ci def test_create_command_verbose(self): 26247db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt'), 26257db96d56Sopenharmony_ci support.findfile('tokenize_tests-no-coding-cookie-' 26267db96d56Sopenharmony_ci 'and-utf8-bom-sig-only.txt')] 26277db96d56Sopenharmony_ci for opt in '-v', '--verbose': 26287db96d56Sopenharmony_ci try: 26297db96d56Sopenharmony_ci out = self.tarfilecmd(opt, '-c', tmpname, *files, 26307db96d56Sopenharmony_ci PYTHONIOENCODING='utf-8') 26317db96d56Sopenharmony_ci self.assertIn(b' file created.', out) 26327db96d56Sopenharmony_ci with tarfile.open(tmpname) as tar: 26337db96d56Sopenharmony_ci tar.getmembers() 26347db96d56Sopenharmony_ci finally: 26357db96d56Sopenharmony_ci os_helper.unlink(tmpname) 26367db96d56Sopenharmony_ci 26377db96d56Sopenharmony_ci def test_create_command_dotless_filename(self): 26387db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt')] 26397db96d56Sopenharmony_ci try: 26407db96d56Sopenharmony_ci out = self.tarfilecmd('-c', dotlessname, *files) 26417db96d56Sopenharmony_ci self.assertEqual(out, b'') 26427db96d56Sopenharmony_ci with tarfile.open(dotlessname) as tar: 26437db96d56Sopenharmony_ci tar.getmembers() 26447db96d56Sopenharmony_ci finally: 26457db96d56Sopenharmony_ci os_helper.unlink(dotlessname) 26467db96d56Sopenharmony_ci 26477db96d56Sopenharmony_ci def test_create_command_dot_started_filename(self): 26487db96d56Sopenharmony_ci tar_name = os.path.join(TEMPDIR, ".testtar") 26497db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt')] 26507db96d56Sopenharmony_ci try: 26517db96d56Sopenharmony_ci out = self.tarfilecmd('-c', tar_name, *files) 26527db96d56Sopenharmony_ci self.assertEqual(out, b'') 26537db96d56Sopenharmony_ci with tarfile.open(tar_name) as tar: 26547db96d56Sopenharmony_ci tar.getmembers() 26557db96d56Sopenharmony_ci finally: 26567db96d56Sopenharmony_ci os_helper.unlink(tar_name) 26577db96d56Sopenharmony_ci 26587db96d56Sopenharmony_ci def test_create_command_compressed(self): 26597db96d56Sopenharmony_ci files = [support.findfile('tokenize_tests.txt'), 26607db96d56Sopenharmony_ci support.findfile('tokenize_tests-no-coding-cookie-' 26617db96d56Sopenharmony_ci 'and-utf8-bom-sig-only.txt')] 26627db96d56Sopenharmony_ci for filetype in (GzipTest, Bz2Test, LzmaTest): 26637db96d56Sopenharmony_ci if not filetype.open: 26647db96d56Sopenharmony_ci continue 26657db96d56Sopenharmony_ci try: 26667db96d56Sopenharmony_ci tar_name = tmpname + '.' + filetype.suffix 26677db96d56Sopenharmony_ci out = self.tarfilecmd('-c', tar_name, *files) 26687db96d56Sopenharmony_ci with filetype.taropen(tar_name) as tar: 26697db96d56Sopenharmony_ci tar.getmembers() 26707db96d56Sopenharmony_ci finally: 26717db96d56Sopenharmony_ci os_helper.unlink(tar_name) 26727db96d56Sopenharmony_ci 26737db96d56Sopenharmony_ci def test_extract_command(self): 26747db96d56Sopenharmony_ci self.make_simple_tarfile(tmpname) 26757db96d56Sopenharmony_ci for opt in '-e', '--extract': 26767db96d56Sopenharmony_ci try: 26777db96d56Sopenharmony_ci with os_helper.temp_cwd(tarextdir): 26787db96d56Sopenharmony_ci out = self.tarfilecmd(opt, tmpname) 26797db96d56Sopenharmony_ci self.assertEqual(out, b'') 26807db96d56Sopenharmony_ci finally: 26817db96d56Sopenharmony_ci os_helper.rmtree(tarextdir) 26827db96d56Sopenharmony_ci 26837db96d56Sopenharmony_ci def test_extract_command_verbose(self): 26847db96d56Sopenharmony_ci self.make_simple_tarfile(tmpname) 26857db96d56Sopenharmony_ci for opt in '-v', '--verbose': 26867db96d56Sopenharmony_ci try: 26877db96d56Sopenharmony_ci with os_helper.temp_cwd(tarextdir): 26887db96d56Sopenharmony_ci out = self.tarfilecmd(opt, '-e', tmpname, 26897db96d56Sopenharmony_ci PYTHONIOENCODING='utf-8') 26907db96d56Sopenharmony_ci self.assertIn(b' file is extracted.', out) 26917db96d56Sopenharmony_ci finally: 26927db96d56Sopenharmony_ci os_helper.rmtree(tarextdir) 26937db96d56Sopenharmony_ci 26947db96d56Sopenharmony_ci def test_extract_command_filter(self): 26957db96d56Sopenharmony_ci self.make_evil_tarfile(tmpname) 26967db96d56Sopenharmony_ci # Make an inner directory, so the member named '../evil' 26977db96d56Sopenharmony_ci # is still extracted into `tarextdir` 26987db96d56Sopenharmony_ci destdir = os.path.join(tarextdir, 'dest') 26997db96d56Sopenharmony_ci os.mkdir(tarextdir) 27007db96d56Sopenharmony_ci try: 27017db96d56Sopenharmony_ci with os_helper.temp_cwd(destdir): 27027db96d56Sopenharmony_ci self.tarfilecmd_failure('-e', tmpname, 27037db96d56Sopenharmony_ci '-v', 27047db96d56Sopenharmony_ci '--filter', 'data') 27057db96d56Sopenharmony_ci out = self.tarfilecmd('-e', tmpname, 27067db96d56Sopenharmony_ci '-v', 27077db96d56Sopenharmony_ci '--filter', 'fully_trusted', 27087db96d56Sopenharmony_ci PYTHONIOENCODING='utf-8') 27097db96d56Sopenharmony_ci self.assertIn(b' file is extracted.', out) 27107db96d56Sopenharmony_ci finally: 27117db96d56Sopenharmony_ci os_helper.rmtree(tarextdir) 27127db96d56Sopenharmony_ci 27137db96d56Sopenharmony_ci def test_extract_command_different_directory(self): 27147db96d56Sopenharmony_ci self.make_simple_tarfile(tmpname) 27157db96d56Sopenharmony_ci try: 27167db96d56Sopenharmony_ci with os_helper.temp_cwd(tarextdir): 27177db96d56Sopenharmony_ci out = self.tarfilecmd('-e', tmpname, 'spamdir') 27187db96d56Sopenharmony_ci self.assertEqual(out, b'') 27197db96d56Sopenharmony_ci finally: 27207db96d56Sopenharmony_ci os_helper.rmtree(tarextdir) 27217db96d56Sopenharmony_ci 27227db96d56Sopenharmony_ci def test_extract_command_invalid_file(self): 27237db96d56Sopenharmony_ci zipname = support.findfile('zipdir.zip') 27247db96d56Sopenharmony_ci with os_helper.temp_cwd(tarextdir): 27257db96d56Sopenharmony_ci rc, out, err = self.tarfilecmd_failure('-e', zipname) 27267db96d56Sopenharmony_ci self.assertIn(b' is not a tar archive.', err) 27277db96d56Sopenharmony_ci self.assertEqual(out, b'') 27287db96d56Sopenharmony_ci self.assertEqual(rc, 1) 27297db96d56Sopenharmony_ci 27307db96d56Sopenharmony_ci 27317db96d56Sopenharmony_ciclass ContextManagerTest(unittest.TestCase): 27327db96d56Sopenharmony_ci 27337db96d56Sopenharmony_ci def test_basic(self): 27347db96d56Sopenharmony_ci with tarfile.open(tarname) as tar: 27357db96d56Sopenharmony_ci self.assertFalse(tar.closed, "closed inside runtime context") 27367db96d56Sopenharmony_ci self.assertTrue(tar.closed, "context manager failed") 27377db96d56Sopenharmony_ci 27387db96d56Sopenharmony_ci def test_closed(self): 27397db96d56Sopenharmony_ci # The __enter__() method is supposed to raise OSError 27407db96d56Sopenharmony_ci # if the TarFile object is already closed. 27417db96d56Sopenharmony_ci tar = tarfile.open(tarname) 27427db96d56Sopenharmony_ci tar.close() 27437db96d56Sopenharmony_ci with self.assertRaises(OSError): 27447db96d56Sopenharmony_ci with tar: 27457db96d56Sopenharmony_ci pass 27467db96d56Sopenharmony_ci 27477db96d56Sopenharmony_ci def test_exception(self): 27487db96d56Sopenharmony_ci # Test if the OSError exception is passed through properly. 27497db96d56Sopenharmony_ci with self.assertRaises(Exception) as exc: 27507db96d56Sopenharmony_ci with tarfile.open(tarname) as tar: 27517db96d56Sopenharmony_ci raise OSError 27527db96d56Sopenharmony_ci self.assertIsInstance(exc.exception, OSError, 27537db96d56Sopenharmony_ci "wrong exception raised in context manager") 27547db96d56Sopenharmony_ci self.assertTrue(tar.closed, "context manager failed") 27557db96d56Sopenharmony_ci 27567db96d56Sopenharmony_ci def test_no_eof(self): 27577db96d56Sopenharmony_ci # __exit__() must not write end-of-archive blocks if an 27587db96d56Sopenharmony_ci # exception was raised. 27597db96d56Sopenharmony_ci try: 27607db96d56Sopenharmony_ci with tarfile.open(tmpname, "w") as tar: 27617db96d56Sopenharmony_ci raise Exception 27627db96d56Sopenharmony_ci except: 27637db96d56Sopenharmony_ci pass 27647db96d56Sopenharmony_ci self.assertEqual(os.path.getsize(tmpname), 0, 27657db96d56Sopenharmony_ci "context manager wrote an end-of-archive block") 27667db96d56Sopenharmony_ci self.assertTrue(tar.closed, "context manager failed") 27677db96d56Sopenharmony_ci 27687db96d56Sopenharmony_ci def test_eof(self): 27697db96d56Sopenharmony_ci # __exit__() must write end-of-archive blocks, i.e. call 27707db96d56Sopenharmony_ci # TarFile.close() if there was no error. 27717db96d56Sopenharmony_ci with tarfile.open(tmpname, "w"): 27727db96d56Sopenharmony_ci pass 27737db96d56Sopenharmony_ci self.assertNotEqual(os.path.getsize(tmpname), 0, 27747db96d56Sopenharmony_ci "context manager wrote no end-of-archive block") 27757db96d56Sopenharmony_ci 27767db96d56Sopenharmony_ci def test_fileobj(self): 27777db96d56Sopenharmony_ci # Test that __exit__() did not close the external file 27787db96d56Sopenharmony_ci # object. 27797db96d56Sopenharmony_ci with open(tmpname, "wb") as fobj: 27807db96d56Sopenharmony_ci try: 27817db96d56Sopenharmony_ci with tarfile.open(fileobj=fobj, mode="w") as tar: 27827db96d56Sopenharmony_ci raise Exception 27837db96d56Sopenharmony_ci except: 27847db96d56Sopenharmony_ci pass 27857db96d56Sopenharmony_ci self.assertFalse(fobj.closed, "external file object was closed") 27867db96d56Sopenharmony_ci self.assertTrue(tar.closed, "context manager failed") 27877db96d56Sopenharmony_ci 27887db96d56Sopenharmony_ci 27897db96d56Sopenharmony_ci@unittest.skipIf(hasattr(os, "link"), "requires os.link to be missing") 27907db96d56Sopenharmony_ciclass LinkEmulationTest(ReadTest, unittest.TestCase): 27917db96d56Sopenharmony_ci 27927db96d56Sopenharmony_ci # Test for issue #8741 regression. On platforms that do not support 27937db96d56Sopenharmony_ci # symbolic or hard links tarfile tries to extract these types of members 27947db96d56Sopenharmony_ci # as the regular files they point to. 27957db96d56Sopenharmony_ci def _test_link_extraction(self, name): 27967db96d56Sopenharmony_ci self.tar.extract(name, TEMPDIR, filter='fully_trusted') 27977db96d56Sopenharmony_ci with open(os.path.join(TEMPDIR, name), "rb") as f: 27987db96d56Sopenharmony_ci data = f.read() 27997db96d56Sopenharmony_ci self.assertEqual(sha256sum(data), sha256_regtype) 28007db96d56Sopenharmony_ci 28017db96d56Sopenharmony_ci # See issues #1578269, #8879, and #17689 for some history on these skips 28027db96d56Sopenharmony_ci @unittest.skipIf(hasattr(os.path, "islink"), 28037db96d56Sopenharmony_ci "Skip emulation - has os.path.islink but not os.link") 28047db96d56Sopenharmony_ci def test_hardlink_extraction1(self): 28057db96d56Sopenharmony_ci self._test_link_extraction("ustar/lnktype") 28067db96d56Sopenharmony_ci 28077db96d56Sopenharmony_ci @unittest.skipIf(hasattr(os.path, "islink"), 28087db96d56Sopenharmony_ci "Skip emulation - has os.path.islink but not os.link") 28097db96d56Sopenharmony_ci def test_hardlink_extraction2(self): 28107db96d56Sopenharmony_ci self._test_link_extraction("./ustar/linktest2/lnktype") 28117db96d56Sopenharmony_ci 28127db96d56Sopenharmony_ci @unittest.skipIf(hasattr(os, "symlink"), 28137db96d56Sopenharmony_ci "Skip emulation if symlink exists") 28147db96d56Sopenharmony_ci def test_symlink_extraction1(self): 28157db96d56Sopenharmony_ci self._test_link_extraction("ustar/symtype") 28167db96d56Sopenharmony_ci 28177db96d56Sopenharmony_ci @unittest.skipIf(hasattr(os, "symlink"), 28187db96d56Sopenharmony_ci "Skip emulation if symlink exists") 28197db96d56Sopenharmony_ci def test_symlink_extraction2(self): 28207db96d56Sopenharmony_ci self._test_link_extraction("./ustar/linktest2/symtype") 28217db96d56Sopenharmony_ci 28227db96d56Sopenharmony_ci 28237db96d56Sopenharmony_ciclass Bz2PartialReadTest(Bz2Test, unittest.TestCase): 28247db96d56Sopenharmony_ci # Issue5068: The _BZ2Proxy.read() method loops forever 28257db96d56Sopenharmony_ci # on an empty or partial bzipped file. 28267db96d56Sopenharmony_ci 28277db96d56Sopenharmony_ci def _test_partial_input(self, mode): 28287db96d56Sopenharmony_ci class MyBytesIO(io.BytesIO): 28297db96d56Sopenharmony_ci hit_eof = False 28307db96d56Sopenharmony_ci def read(self, n): 28317db96d56Sopenharmony_ci if self.hit_eof: 28327db96d56Sopenharmony_ci raise AssertionError("infinite loop detected in " 28337db96d56Sopenharmony_ci "tarfile.open()") 28347db96d56Sopenharmony_ci self.hit_eof = self.tell() == len(self.getvalue()) 28357db96d56Sopenharmony_ci return super(MyBytesIO, self).read(n) 28367db96d56Sopenharmony_ci def seek(self, *args): 28377db96d56Sopenharmony_ci self.hit_eof = False 28387db96d56Sopenharmony_ci return super(MyBytesIO, self).seek(*args) 28397db96d56Sopenharmony_ci 28407db96d56Sopenharmony_ci data = bz2.compress(tarfile.TarInfo("foo").tobuf()) 28417db96d56Sopenharmony_ci for x in range(len(data) + 1): 28427db96d56Sopenharmony_ci try: 28437db96d56Sopenharmony_ci tarfile.open(fileobj=MyBytesIO(data[:x]), mode=mode) 28447db96d56Sopenharmony_ci except tarfile.ReadError: 28457db96d56Sopenharmony_ci pass # we have no interest in ReadErrors 28467db96d56Sopenharmony_ci 28477db96d56Sopenharmony_ci def test_partial_input(self): 28487db96d56Sopenharmony_ci self._test_partial_input("r") 28497db96d56Sopenharmony_ci 28507db96d56Sopenharmony_ci def test_partial_input_bz2(self): 28517db96d56Sopenharmony_ci self._test_partial_input("r:bz2") 28527db96d56Sopenharmony_ci 28537db96d56Sopenharmony_ci 28547db96d56Sopenharmony_cidef root_is_uid_gid_0(): 28557db96d56Sopenharmony_ci try: 28567db96d56Sopenharmony_ci import pwd, grp 28577db96d56Sopenharmony_ci except ImportError: 28587db96d56Sopenharmony_ci return False 28597db96d56Sopenharmony_ci if pwd.getpwuid(0)[0] != 'root': 28607db96d56Sopenharmony_ci return False 28617db96d56Sopenharmony_ci if grp.getgrgid(0)[0] != 'root': 28627db96d56Sopenharmony_ci return False 28637db96d56Sopenharmony_ci return True 28647db96d56Sopenharmony_ci 28657db96d56Sopenharmony_ci 28667db96d56Sopenharmony_ci@unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown") 28677db96d56Sopenharmony_ci@unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid") 28687db96d56Sopenharmony_ciclass NumericOwnerTest(unittest.TestCase): 28697db96d56Sopenharmony_ci # mock the following: 28707db96d56Sopenharmony_ci # os.chown: so we can test what's being called 28717db96d56Sopenharmony_ci # os.chmod: so the modes are not actually changed. if they are, we can't 28727db96d56Sopenharmony_ci # delete the files/directories 28737db96d56Sopenharmony_ci # os.geteuid: so we can lie and say we're root (uid = 0) 28747db96d56Sopenharmony_ci 28757db96d56Sopenharmony_ci @staticmethod 28767db96d56Sopenharmony_ci def _make_test_archive(filename_1, dirname_1, filename_2): 28777db96d56Sopenharmony_ci # the file contents to write 28787db96d56Sopenharmony_ci fobj = io.BytesIO(b"content") 28797db96d56Sopenharmony_ci 28807db96d56Sopenharmony_ci # create a tar file with a file, a directory, and a file within that 28817db96d56Sopenharmony_ci # directory. Assign various .uid/.gid values to them 28827db96d56Sopenharmony_ci items = [(filename_1, 99, 98, tarfile.REGTYPE, fobj), 28837db96d56Sopenharmony_ci (dirname_1, 77, 76, tarfile.DIRTYPE, None), 28847db96d56Sopenharmony_ci (filename_2, 88, 87, tarfile.REGTYPE, fobj), 28857db96d56Sopenharmony_ci ] 28867db96d56Sopenharmony_ci with tarfile.open(tmpname, 'w') as tarfl: 28877db96d56Sopenharmony_ci for name, uid, gid, typ, contents in items: 28887db96d56Sopenharmony_ci t = tarfile.TarInfo(name) 28897db96d56Sopenharmony_ci t.uid = uid 28907db96d56Sopenharmony_ci t.gid = gid 28917db96d56Sopenharmony_ci t.uname = 'root' 28927db96d56Sopenharmony_ci t.gname = 'root' 28937db96d56Sopenharmony_ci t.type = typ 28947db96d56Sopenharmony_ci tarfl.addfile(t, contents) 28957db96d56Sopenharmony_ci 28967db96d56Sopenharmony_ci # return the full pathname to the tar file 28977db96d56Sopenharmony_ci return tmpname 28987db96d56Sopenharmony_ci 28997db96d56Sopenharmony_ci @staticmethod 29007db96d56Sopenharmony_ci @contextmanager 29017db96d56Sopenharmony_ci def _setup_test(mock_geteuid): 29027db96d56Sopenharmony_ci mock_geteuid.return_value = 0 # lie and say we're root 29037db96d56Sopenharmony_ci fname = 'numeric-owner-testfile' 29047db96d56Sopenharmony_ci dirname = 'dir' 29057db96d56Sopenharmony_ci 29067db96d56Sopenharmony_ci # the names we want stored in the tarfile 29077db96d56Sopenharmony_ci filename_1 = fname 29087db96d56Sopenharmony_ci dirname_1 = dirname 29097db96d56Sopenharmony_ci filename_2 = os.path.join(dirname, fname) 29107db96d56Sopenharmony_ci 29117db96d56Sopenharmony_ci # create the tarfile with the contents we're after 29127db96d56Sopenharmony_ci tar_filename = NumericOwnerTest._make_test_archive(filename_1, 29137db96d56Sopenharmony_ci dirname_1, 29147db96d56Sopenharmony_ci filename_2) 29157db96d56Sopenharmony_ci 29167db96d56Sopenharmony_ci # open the tarfile for reading. yield it and the names of the items 29177db96d56Sopenharmony_ci # we stored into the file 29187db96d56Sopenharmony_ci with tarfile.open(tar_filename) as tarfl: 29197db96d56Sopenharmony_ci yield tarfl, filename_1, dirname_1, filename_2 29207db96d56Sopenharmony_ci 29217db96d56Sopenharmony_ci @unittest.mock.patch('os.chown') 29227db96d56Sopenharmony_ci @unittest.mock.patch('os.chmod') 29237db96d56Sopenharmony_ci @unittest.mock.patch('os.geteuid') 29247db96d56Sopenharmony_ci def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod, 29257db96d56Sopenharmony_ci mock_chown): 29267db96d56Sopenharmony_ci with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, 29277db96d56Sopenharmony_ci filename_2): 29287db96d56Sopenharmony_ci tarfl.extract(filename_1, TEMPDIR, numeric_owner=True, 29297db96d56Sopenharmony_ci filter='fully_trusted') 29307db96d56Sopenharmony_ci tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True, 29317db96d56Sopenharmony_ci filter='fully_trusted') 29327db96d56Sopenharmony_ci 29337db96d56Sopenharmony_ci # convert to filesystem paths 29347db96d56Sopenharmony_ci f_filename_1 = os.path.join(TEMPDIR, filename_1) 29357db96d56Sopenharmony_ci f_filename_2 = os.path.join(TEMPDIR, filename_2) 29367db96d56Sopenharmony_ci 29377db96d56Sopenharmony_ci mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98), 29387db96d56Sopenharmony_ci unittest.mock.call(f_filename_2, 88, 87), 29397db96d56Sopenharmony_ci ], 29407db96d56Sopenharmony_ci any_order=True) 29417db96d56Sopenharmony_ci 29427db96d56Sopenharmony_ci @unittest.mock.patch('os.chown') 29437db96d56Sopenharmony_ci @unittest.mock.patch('os.chmod') 29447db96d56Sopenharmony_ci @unittest.mock.patch('os.geteuid') 29457db96d56Sopenharmony_ci def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod, 29467db96d56Sopenharmony_ci mock_chown): 29477db96d56Sopenharmony_ci with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1, 29487db96d56Sopenharmony_ci filename_2): 29497db96d56Sopenharmony_ci tarfl.extractall(TEMPDIR, numeric_owner=True, 29507db96d56Sopenharmony_ci filter='fully_trusted') 29517db96d56Sopenharmony_ci 29527db96d56Sopenharmony_ci # convert to filesystem paths 29537db96d56Sopenharmony_ci f_filename_1 = os.path.join(TEMPDIR, filename_1) 29547db96d56Sopenharmony_ci f_dirname_1 = os.path.join(TEMPDIR, dirname_1) 29557db96d56Sopenharmony_ci f_filename_2 = os.path.join(TEMPDIR, filename_2) 29567db96d56Sopenharmony_ci 29577db96d56Sopenharmony_ci mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98), 29587db96d56Sopenharmony_ci unittest.mock.call(f_dirname_1, 77, 76), 29597db96d56Sopenharmony_ci unittest.mock.call(f_filename_2, 88, 87), 29607db96d56Sopenharmony_ci ], 29617db96d56Sopenharmony_ci any_order=True) 29627db96d56Sopenharmony_ci 29637db96d56Sopenharmony_ci # this test requires that uid=0 and gid=0 really be named 'root'. that's 29647db96d56Sopenharmony_ci # because the uname and gname in the test file are 'root', and extract() 29657db96d56Sopenharmony_ci # will look them up using pwd and grp to find their uid and gid, which we 29667db96d56Sopenharmony_ci # test here to be 0. 29677db96d56Sopenharmony_ci @unittest.skipUnless(root_is_uid_gid_0(), 29687db96d56Sopenharmony_ci 'uid=0,gid=0 must be named "root"') 29697db96d56Sopenharmony_ci @unittest.mock.patch('os.chown') 29707db96d56Sopenharmony_ci @unittest.mock.patch('os.chmod') 29717db96d56Sopenharmony_ci @unittest.mock.patch('os.geteuid') 29727db96d56Sopenharmony_ci def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod, 29737db96d56Sopenharmony_ci mock_chown): 29747db96d56Sopenharmony_ci with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _): 29757db96d56Sopenharmony_ci tarfl.extract(filename_1, TEMPDIR, numeric_owner=False, 29767db96d56Sopenharmony_ci filter='fully_trusted') 29777db96d56Sopenharmony_ci 29787db96d56Sopenharmony_ci # convert to filesystem paths 29797db96d56Sopenharmony_ci f_filename_1 = os.path.join(TEMPDIR, filename_1) 29807db96d56Sopenharmony_ci 29817db96d56Sopenharmony_ci mock_chown.assert_called_with(f_filename_1, 0, 0) 29827db96d56Sopenharmony_ci 29837db96d56Sopenharmony_ci @unittest.mock.patch('os.geteuid') 29847db96d56Sopenharmony_ci def test_keyword_only(self, mock_geteuid): 29857db96d56Sopenharmony_ci with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _): 29867db96d56Sopenharmony_ci self.assertRaises(TypeError, 29877db96d56Sopenharmony_ci tarfl.extract, filename_1, TEMPDIR, False, True) 29887db96d56Sopenharmony_ci 29897db96d56Sopenharmony_ci 29907db96d56Sopenharmony_ciclass ReplaceTests(ReadTest, unittest.TestCase): 29917db96d56Sopenharmony_ci def test_replace_name(self): 29927db96d56Sopenharmony_ci member = self.tar.getmember('ustar/regtype') 29937db96d56Sopenharmony_ci replaced = member.replace(name='misc/other') 29947db96d56Sopenharmony_ci self.assertEqual(replaced.name, 'misc/other') 29957db96d56Sopenharmony_ci self.assertEqual(member.name, 'ustar/regtype') 29967db96d56Sopenharmony_ci self.assertEqual(self.tar.getmember('ustar/regtype').name, 29977db96d56Sopenharmony_ci 'ustar/regtype') 29987db96d56Sopenharmony_ci 29997db96d56Sopenharmony_ci def test_replace_deep(self): 30007db96d56Sopenharmony_ci member = self.tar.getmember('pax/regtype1') 30017db96d56Sopenharmony_ci replaced = member.replace() 30027db96d56Sopenharmony_ci replaced.pax_headers['gname'] = 'not-bar' 30037db96d56Sopenharmony_ci self.assertEqual(member.pax_headers['gname'], 'bar') 30047db96d56Sopenharmony_ci self.assertEqual( 30057db96d56Sopenharmony_ci self.tar.getmember('pax/regtype1').pax_headers['gname'], 'bar') 30067db96d56Sopenharmony_ci 30077db96d56Sopenharmony_ci def test_replace_shallow(self): 30087db96d56Sopenharmony_ci member = self.tar.getmember('pax/regtype1') 30097db96d56Sopenharmony_ci replaced = member.replace(deep=False) 30107db96d56Sopenharmony_ci replaced.pax_headers['gname'] = 'not-bar' 30117db96d56Sopenharmony_ci self.assertEqual(member.pax_headers['gname'], 'not-bar') 30127db96d56Sopenharmony_ci self.assertEqual( 30137db96d56Sopenharmony_ci self.tar.getmember('pax/regtype1').pax_headers['gname'], 'not-bar') 30147db96d56Sopenharmony_ci 30157db96d56Sopenharmony_ci def test_replace_all(self): 30167db96d56Sopenharmony_ci member = self.tar.getmember('ustar/regtype') 30177db96d56Sopenharmony_ci for attr_name in ('name', 'mtime', 'mode', 'linkname', 30187db96d56Sopenharmony_ci 'uid', 'gid', 'uname', 'gname'): 30197db96d56Sopenharmony_ci with self.subTest(attr_name=attr_name): 30207db96d56Sopenharmony_ci replaced = member.replace(**{attr_name: None}) 30217db96d56Sopenharmony_ci self.assertEqual(getattr(replaced, attr_name), None) 30227db96d56Sopenharmony_ci self.assertNotEqual(getattr(member, attr_name), None) 30237db96d56Sopenharmony_ci 30247db96d56Sopenharmony_ci def test_replace_internal(self): 30257db96d56Sopenharmony_ci member = self.tar.getmember('ustar/regtype') 30267db96d56Sopenharmony_ci with self.assertRaises(TypeError): 30277db96d56Sopenharmony_ci member.replace(offset=123456789) 30287db96d56Sopenharmony_ci 30297db96d56Sopenharmony_ci 30307db96d56Sopenharmony_ciclass NoneInfoExtractTests(ReadTest): 30317db96d56Sopenharmony_ci # These mainly check that all kinds of members are extracted successfully 30327db96d56Sopenharmony_ci # if some metadata is None. 30337db96d56Sopenharmony_ci # Some of the methods do additional spot checks. 30347db96d56Sopenharmony_ci 30357db96d56Sopenharmony_ci # We also test that the default filters can deal with None. 30367db96d56Sopenharmony_ci 30377db96d56Sopenharmony_ci extraction_filter = None 30387db96d56Sopenharmony_ci 30397db96d56Sopenharmony_ci @classmethod 30407db96d56Sopenharmony_ci def setUpClass(cls): 30417db96d56Sopenharmony_ci tar = tarfile.open(tarname, mode='r', encoding="iso8859-1") 30427db96d56Sopenharmony_ci cls.control_dir = pathlib.Path(TEMPDIR) / "extractall_ctrl" 30437db96d56Sopenharmony_ci tar.errorlevel = 0 30447db96d56Sopenharmony_ci tar.extractall(cls.control_dir, filter=cls.extraction_filter) 30457db96d56Sopenharmony_ci tar.close() 30467db96d56Sopenharmony_ci cls.control_paths = set( 30477db96d56Sopenharmony_ci p.relative_to(cls.control_dir) 30487db96d56Sopenharmony_ci for p in pathlib.Path(cls.control_dir).glob('**/*')) 30497db96d56Sopenharmony_ci 30507db96d56Sopenharmony_ci @classmethod 30517db96d56Sopenharmony_ci def tearDownClass(cls): 30527db96d56Sopenharmony_ci shutil.rmtree(cls.control_dir) 30537db96d56Sopenharmony_ci 30547db96d56Sopenharmony_ci def check_files_present(self, directory): 30557db96d56Sopenharmony_ci got_paths = set( 30567db96d56Sopenharmony_ci p.relative_to(directory) 30577db96d56Sopenharmony_ci for p in pathlib.Path(directory).glob('**/*')) 30587db96d56Sopenharmony_ci self.assertEqual(self.control_paths, got_paths) 30597db96d56Sopenharmony_ci 30607db96d56Sopenharmony_ci @contextmanager 30617db96d56Sopenharmony_ci def extract_with_none(self, *attr_names): 30627db96d56Sopenharmony_ci DIR = pathlib.Path(TEMPDIR) / "extractall_none" 30637db96d56Sopenharmony_ci self.tar.errorlevel = 0 30647db96d56Sopenharmony_ci for member in self.tar.getmembers(): 30657db96d56Sopenharmony_ci for attr_name in attr_names: 30667db96d56Sopenharmony_ci setattr(member, attr_name, None) 30677db96d56Sopenharmony_ci with os_helper.temp_dir(DIR): 30687db96d56Sopenharmony_ci self.tar.extractall(DIR, filter='fully_trusted') 30697db96d56Sopenharmony_ci self.check_files_present(DIR) 30707db96d56Sopenharmony_ci yield DIR 30717db96d56Sopenharmony_ci 30727db96d56Sopenharmony_ci def test_extractall_none_mtime(self): 30737db96d56Sopenharmony_ci # mtimes of extracted files should be later than 'now' -- the mtime 30747db96d56Sopenharmony_ci # of a previously created directory. 30757db96d56Sopenharmony_ci now = pathlib.Path(TEMPDIR).stat().st_mtime 30767db96d56Sopenharmony_ci with self.extract_with_none('mtime') as DIR: 30777db96d56Sopenharmony_ci for path in pathlib.Path(DIR).glob('**/*'): 30787db96d56Sopenharmony_ci with self.subTest(path=path): 30797db96d56Sopenharmony_ci try: 30807db96d56Sopenharmony_ci mtime = path.stat().st_mtime 30817db96d56Sopenharmony_ci except OSError: 30827db96d56Sopenharmony_ci # Some systems can't stat symlinks, ignore those 30837db96d56Sopenharmony_ci if not path.is_symlink(): 30847db96d56Sopenharmony_ci raise 30857db96d56Sopenharmony_ci else: 30867db96d56Sopenharmony_ci self.assertGreaterEqual(path.stat().st_mtime, now) 30877db96d56Sopenharmony_ci 30887db96d56Sopenharmony_ci def test_extractall_none_mode(self): 30897db96d56Sopenharmony_ci # modes of directories and regular files should match the mode 30907db96d56Sopenharmony_ci # of a "normally" created directory or regular file 30917db96d56Sopenharmony_ci dir_mode = pathlib.Path(TEMPDIR).stat().st_mode 30927db96d56Sopenharmony_ci regular_file = pathlib.Path(TEMPDIR) / 'regular_file' 30937db96d56Sopenharmony_ci regular_file.write_text('') 30947db96d56Sopenharmony_ci regular_file_mode = regular_file.stat().st_mode 30957db96d56Sopenharmony_ci with self.extract_with_none('mode') as DIR: 30967db96d56Sopenharmony_ci for path in pathlib.Path(DIR).glob('**/*'): 30977db96d56Sopenharmony_ci with self.subTest(path=path): 30987db96d56Sopenharmony_ci if path.is_dir(): 30997db96d56Sopenharmony_ci self.assertEqual(path.stat().st_mode, dir_mode) 31007db96d56Sopenharmony_ci elif path.is_file(): 31017db96d56Sopenharmony_ci self.assertEqual(path.stat().st_mode, 31027db96d56Sopenharmony_ci regular_file_mode) 31037db96d56Sopenharmony_ci 31047db96d56Sopenharmony_ci def test_extractall_none_uid(self): 31057db96d56Sopenharmony_ci with self.extract_with_none('uid'): 31067db96d56Sopenharmony_ci pass 31077db96d56Sopenharmony_ci 31087db96d56Sopenharmony_ci def test_extractall_none_gid(self): 31097db96d56Sopenharmony_ci with self.extract_with_none('gid'): 31107db96d56Sopenharmony_ci pass 31117db96d56Sopenharmony_ci 31127db96d56Sopenharmony_ci def test_extractall_none_uname(self): 31137db96d56Sopenharmony_ci with self.extract_with_none('uname'): 31147db96d56Sopenharmony_ci pass 31157db96d56Sopenharmony_ci 31167db96d56Sopenharmony_ci def test_extractall_none_gname(self): 31177db96d56Sopenharmony_ci with self.extract_with_none('gname'): 31187db96d56Sopenharmony_ci pass 31197db96d56Sopenharmony_ci 31207db96d56Sopenharmony_ci def test_extractall_none_ownership(self): 31217db96d56Sopenharmony_ci with self.extract_with_none('uid', 'gid', 'uname', 'gname'): 31227db96d56Sopenharmony_ci pass 31237db96d56Sopenharmony_ci 31247db96d56Sopenharmony_ciclass NoneInfoExtractTests_Data(NoneInfoExtractTests, unittest.TestCase): 31257db96d56Sopenharmony_ci extraction_filter = 'data' 31267db96d56Sopenharmony_ci 31277db96d56Sopenharmony_ciclass NoneInfoExtractTests_FullyTrusted(NoneInfoExtractTests, 31287db96d56Sopenharmony_ci unittest.TestCase): 31297db96d56Sopenharmony_ci extraction_filter = 'fully_trusted' 31307db96d56Sopenharmony_ci 31317db96d56Sopenharmony_ciclass NoneInfoExtractTests_Tar(NoneInfoExtractTests, unittest.TestCase): 31327db96d56Sopenharmony_ci extraction_filter = 'tar' 31337db96d56Sopenharmony_ci 31347db96d56Sopenharmony_ciclass NoneInfoExtractTests_Default(NoneInfoExtractTests, 31357db96d56Sopenharmony_ci unittest.TestCase): 31367db96d56Sopenharmony_ci extraction_filter = None 31377db96d56Sopenharmony_ci 31387db96d56Sopenharmony_ciclass NoneInfoTests_Misc(unittest.TestCase): 31397db96d56Sopenharmony_ci def test_add(self): 31407db96d56Sopenharmony_ci # When addfile() encounters None metadata, it raises a ValueError 31417db96d56Sopenharmony_ci bio = io.BytesIO() 31427db96d56Sopenharmony_ci for tarformat in (tarfile.USTAR_FORMAT, tarfile.GNU_FORMAT, 31437db96d56Sopenharmony_ci tarfile.PAX_FORMAT): 31447db96d56Sopenharmony_ci with self.subTest(tarformat=tarformat): 31457db96d56Sopenharmony_ci tar = tarfile.open(fileobj=bio, mode='w', format=tarformat) 31467db96d56Sopenharmony_ci tarinfo = tar.gettarinfo(tarname) 31477db96d56Sopenharmony_ci try: 31487db96d56Sopenharmony_ci tar.addfile(tarinfo) 31497db96d56Sopenharmony_ci except Exception: 31507db96d56Sopenharmony_ci if tarformat == tarfile.USTAR_FORMAT: 31517db96d56Sopenharmony_ci # In the old, limited format, adding might fail for 31527db96d56Sopenharmony_ci # reasons like the UID being too large 31537db96d56Sopenharmony_ci pass 31547db96d56Sopenharmony_ci else: 31557db96d56Sopenharmony_ci raise 31567db96d56Sopenharmony_ci else: 31577db96d56Sopenharmony_ci for attr_name in ('mtime', 'mode', 'uid', 'gid', 31587db96d56Sopenharmony_ci 'uname', 'gname'): 31597db96d56Sopenharmony_ci with self.subTest(attr_name=attr_name): 31607db96d56Sopenharmony_ci replaced = tarinfo.replace(**{attr_name: None}) 31617db96d56Sopenharmony_ci with self.assertRaisesRegex(ValueError, 31627db96d56Sopenharmony_ci f"{attr_name}"): 31637db96d56Sopenharmony_ci tar.addfile(replaced) 31647db96d56Sopenharmony_ci 31657db96d56Sopenharmony_ci def test_list(self): 31667db96d56Sopenharmony_ci # Change some metadata to None, then compare list() output 31677db96d56Sopenharmony_ci # word-for-word. We want list() to not raise, and to only change 31687db96d56Sopenharmony_ci # printout for the affected piece of metadata. 31697db96d56Sopenharmony_ci # (n.b.: some contents of the test archive are hardcoded.) 31707db96d56Sopenharmony_ci for attr_names in ({'mtime'}, {'mode'}, {'uid'}, {'gid'}, 31717db96d56Sopenharmony_ci {'uname'}, {'gname'}, 31727db96d56Sopenharmony_ci {'uid', 'uname'}, {'gid', 'gname'}): 31737db96d56Sopenharmony_ci with (self.subTest(attr_names=attr_names), 31747db96d56Sopenharmony_ci tarfile.open(tarname, encoding="iso8859-1") as tar): 31757db96d56Sopenharmony_ci tio_prev = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') 31767db96d56Sopenharmony_ci with support.swap_attr(sys, 'stdout', tio_prev): 31777db96d56Sopenharmony_ci tar.list() 31787db96d56Sopenharmony_ci for member in tar.getmembers(): 31797db96d56Sopenharmony_ci for attr_name in attr_names: 31807db96d56Sopenharmony_ci setattr(member, attr_name, None) 31817db96d56Sopenharmony_ci tio_new = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') 31827db96d56Sopenharmony_ci with support.swap_attr(sys, 'stdout', tio_new): 31837db96d56Sopenharmony_ci tar.list() 31847db96d56Sopenharmony_ci for expected, got in zip(tio_prev.detach().getvalue().split(), 31857db96d56Sopenharmony_ci tio_new.detach().getvalue().split()): 31867db96d56Sopenharmony_ci if attr_names == {'mtime'} and re.match(rb'2003-01-\d\d', expected): 31877db96d56Sopenharmony_ci self.assertEqual(got, b'????-??-??') 31887db96d56Sopenharmony_ci elif attr_names == {'mtime'} and re.match(rb'\d\d:\d\d:\d\d', expected): 31897db96d56Sopenharmony_ci self.assertEqual(got, b'??:??:??') 31907db96d56Sopenharmony_ci elif attr_names == {'mode'} and re.match( 31917db96d56Sopenharmony_ci rb'.([r-][w-][x-]){3}', expected): 31927db96d56Sopenharmony_ci self.assertEqual(got, b'??????????') 31937db96d56Sopenharmony_ci elif attr_names == {'uname'} and expected.startswith( 31947db96d56Sopenharmony_ci (b'tarfile/', b'lars/', b'foo/')): 31957db96d56Sopenharmony_ci exp_user, exp_group = expected.split(b'/') 31967db96d56Sopenharmony_ci got_user, got_group = got.split(b'/') 31977db96d56Sopenharmony_ci self.assertEqual(got_group, exp_group) 31987db96d56Sopenharmony_ci self.assertRegex(got_user, b'[0-9]+') 31997db96d56Sopenharmony_ci elif attr_names == {'gname'} and expected.endswith( 32007db96d56Sopenharmony_ci (b'/tarfile', b'/users', b'/bar')): 32017db96d56Sopenharmony_ci exp_user, exp_group = expected.split(b'/') 32027db96d56Sopenharmony_ci got_user, got_group = got.split(b'/') 32037db96d56Sopenharmony_ci self.assertEqual(got_user, exp_user) 32047db96d56Sopenharmony_ci self.assertRegex(got_group, b'[0-9]+') 32057db96d56Sopenharmony_ci elif attr_names == {'uid'} and expected.startswith( 32067db96d56Sopenharmony_ci (b'1000/')): 32077db96d56Sopenharmony_ci exp_user, exp_group = expected.split(b'/') 32087db96d56Sopenharmony_ci got_user, got_group = got.split(b'/') 32097db96d56Sopenharmony_ci self.assertEqual(got_group, exp_group) 32107db96d56Sopenharmony_ci self.assertEqual(got_user, b'None') 32117db96d56Sopenharmony_ci elif attr_names == {'gid'} and expected.endswith((b'/100')): 32127db96d56Sopenharmony_ci exp_user, exp_group = expected.split(b'/') 32137db96d56Sopenharmony_ci got_user, got_group = got.split(b'/') 32147db96d56Sopenharmony_ci self.assertEqual(got_user, exp_user) 32157db96d56Sopenharmony_ci self.assertEqual(got_group, b'None') 32167db96d56Sopenharmony_ci elif attr_names == {'uid', 'uname'} and expected.startswith( 32177db96d56Sopenharmony_ci (b'tarfile/', b'lars/', b'foo/', b'1000/')): 32187db96d56Sopenharmony_ci exp_user, exp_group = expected.split(b'/') 32197db96d56Sopenharmony_ci got_user, got_group = got.split(b'/') 32207db96d56Sopenharmony_ci self.assertEqual(got_group, exp_group) 32217db96d56Sopenharmony_ci self.assertEqual(got_user, b'None') 32227db96d56Sopenharmony_ci elif attr_names == {'gname', 'gid'} and expected.endswith( 32237db96d56Sopenharmony_ci (b'/tarfile', b'/users', b'/bar', b'/100')): 32247db96d56Sopenharmony_ci exp_user, exp_group = expected.split(b'/') 32257db96d56Sopenharmony_ci got_user, got_group = got.split(b'/') 32267db96d56Sopenharmony_ci self.assertEqual(got_user, exp_user) 32277db96d56Sopenharmony_ci self.assertEqual(got_group, b'None') 32287db96d56Sopenharmony_ci else: 32297db96d56Sopenharmony_ci # In other cases the output should be the same 32307db96d56Sopenharmony_ci self.assertEqual(expected, got) 32317db96d56Sopenharmony_ci 32327db96d56Sopenharmony_cidef _filemode_to_int(mode): 32337db96d56Sopenharmony_ci """Inverse of `stat.filemode` (for permission bits) 32347db96d56Sopenharmony_ci 32357db96d56Sopenharmony_ci Using mode strings rather than numbers makes the later tests more readable. 32367db96d56Sopenharmony_ci """ 32377db96d56Sopenharmony_ci str_mode = mode[1:] 32387db96d56Sopenharmony_ci result = ( 32397db96d56Sopenharmony_ci {'r': stat.S_IRUSR, '-': 0}[str_mode[0]] 32407db96d56Sopenharmony_ci | {'w': stat.S_IWUSR, '-': 0}[str_mode[1]] 32417db96d56Sopenharmony_ci | {'x': stat.S_IXUSR, '-': 0, 32427db96d56Sopenharmony_ci 's': stat.S_IXUSR | stat.S_ISUID, 32437db96d56Sopenharmony_ci 'S': stat.S_ISUID}[str_mode[2]] 32447db96d56Sopenharmony_ci | {'r': stat.S_IRGRP, '-': 0}[str_mode[3]] 32457db96d56Sopenharmony_ci | {'w': stat.S_IWGRP, '-': 0}[str_mode[4]] 32467db96d56Sopenharmony_ci | {'x': stat.S_IXGRP, '-': 0, 32477db96d56Sopenharmony_ci 's': stat.S_IXGRP | stat.S_ISGID, 32487db96d56Sopenharmony_ci 'S': stat.S_ISGID}[str_mode[5]] 32497db96d56Sopenharmony_ci | {'r': stat.S_IROTH, '-': 0}[str_mode[6]] 32507db96d56Sopenharmony_ci | {'w': stat.S_IWOTH, '-': 0}[str_mode[7]] 32517db96d56Sopenharmony_ci | {'x': stat.S_IXOTH, '-': 0, 32527db96d56Sopenharmony_ci 't': stat.S_IXOTH | stat.S_ISVTX, 32537db96d56Sopenharmony_ci 'T': stat.S_ISVTX}[str_mode[8]] 32547db96d56Sopenharmony_ci ) 32557db96d56Sopenharmony_ci # check we did this right 32567db96d56Sopenharmony_ci assert stat.filemode(result)[1:] == mode[1:] 32577db96d56Sopenharmony_ci 32587db96d56Sopenharmony_ci return result 32597db96d56Sopenharmony_ci 32607db96d56Sopenharmony_ciclass ArchiveMaker: 32617db96d56Sopenharmony_ci """Helper to create a tar file with specific contents 32627db96d56Sopenharmony_ci 32637db96d56Sopenharmony_ci Usage: 32647db96d56Sopenharmony_ci 32657db96d56Sopenharmony_ci with ArchiveMaker() as t: 32667db96d56Sopenharmony_ci t.add('filename', ...) 32677db96d56Sopenharmony_ci 32687db96d56Sopenharmony_ci with t.open() as tar: 32697db96d56Sopenharmony_ci ... # `tar` is now a TarFile with 'filename' in it! 32707db96d56Sopenharmony_ci """ 32717db96d56Sopenharmony_ci def __init__(self): 32727db96d56Sopenharmony_ci self.bio = io.BytesIO() 32737db96d56Sopenharmony_ci 32747db96d56Sopenharmony_ci def __enter__(self): 32757db96d56Sopenharmony_ci self.tar_w = tarfile.TarFile(mode='w', fileobj=self.bio) 32767db96d56Sopenharmony_ci return self 32777db96d56Sopenharmony_ci 32787db96d56Sopenharmony_ci def __exit__(self, *exc): 32797db96d56Sopenharmony_ci self.tar_w.close() 32807db96d56Sopenharmony_ci self.contents = self.bio.getvalue() 32817db96d56Sopenharmony_ci self.bio = None 32827db96d56Sopenharmony_ci 32837db96d56Sopenharmony_ci def add(self, name, *, type=None, symlink_to=None, hardlink_to=None, 32847db96d56Sopenharmony_ci mode=None, **kwargs): 32857db96d56Sopenharmony_ci """Add a member to the test archive. Call within `with`.""" 32867db96d56Sopenharmony_ci name = str(name) 32877db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo(name).replace(**kwargs) 32887db96d56Sopenharmony_ci if mode: 32897db96d56Sopenharmony_ci tarinfo.mode = _filemode_to_int(mode) 32907db96d56Sopenharmony_ci if symlink_to is not None: 32917db96d56Sopenharmony_ci type = tarfile.SYMTYPE 32927db96d56Sopenharmony_ci tarinfo.linkname = str(symlink_to) 32937db96d56Sopenharmony_ci if hardlink_to is not None: 32947db96d56Sopenharmony_ci type = tarfile.LNKTYPE 32957db96d56Sopenharmony_ci tarinfo.linkname = str(hardlink_to) 32967db96d56Sopenharmony_ci if name.endswith('/') and type is None: 32977db96d56Sopenharmony_ci type = tarfile.DIRTYPE 32987db96d56Sopenharmony_ci if type is not None: 32997db96d56Sopenharmony_ci tarinfo.type = type 33007db96d56Sopenharmony_ci if tarinfo.isreg(): 33017db96d56Sopenharmony_ci fileobj = io.BytesIO(bytes(tarinfo.size)) 33027db96d56Sopenharmony_ci else: 33037db96d56Sopenharmony_ci fileobj = None 33047db96d56Sopenharmony_ci self.tar_w.addfile(tarinfo, fileobj) 33057db96d56Sopenharmony_ci 33067db96d56Sopenharmony_ci def open(self, **kwargs): 33077db96d56Sopenharmony_ci """Open the resulting archive as TarFile. Call after `with`.""" 33087db96d56Sopenharmony_ci bio = io.BytesIO(self.contents) 33097db96d56Sopenharmony_ci return tarfile.open(fileobj=bio, **kwargs) 33107db96d56Sopenharmony_ci 33117db96d56Sopenharmony_ci# Under WASI, `os_helper.can_symlink` is False to make 33127db96d56Sopenharmony_ci# `skip_unless_symlink` skip symlink tests. " 33137db96d56Sopenharmony_ci# But in the following tests we use can_symlink to *determine* which 33147db96d56Sopenharmony_ci# behavior is expected. 33157db96d56Sopenharmony_ci# Like other symlink tests, skip these on WASI for now. 33167db96d56Sopenharmony_ciif support.is_wasi: 33177db96d56Sopenharmony_ci def symlink_test(f): 33187db96d56Sopenharmony_ci return unittest.skip("WASI: Skip symlink test for now")(f) 33197db96d56Sopenharmony_cielse: 33207db96d56Sopenharmony_ci def symlink_test(f): 33217db96d56Sopenharmony_ci return f 33227db96d56Sopenharmony_ci 33237db96d56Sopenharmony_ci 33247db96d56Sopenharmony_ciclass TestExtractionFilters(unittest.TestCase): 33257db96d56Sopenharmony_ci 33267db96d56Sopenharmony_ci # A temporary directory for the extraction results. 33277db96d56Sopenharmony_ci # All files that "escape" the destination path should still end 33287db96d56Sopenharmony_ci # up in this directory. 33297db96d56Sopenharmony_ci outerdir = pathlib.Path(TEMPDIR) / 'outerdir' 33307db96d56Sopenharmony_ci 33317db96d56Sopenharmony_ci # The destination for the extraction, within `outerdir` 33327db96d56Sopenharmony_ci destdir = outerdir / 'dest' 33337db96d56Sopenharmony_ci 33347db96d56Sopenharmony_ci @contextmanager 33357db96d56Sopenharmony_ci def check_context(self, tar, filter): 33367db96d56Sopenharmony_ci """Extracts `tar` to `self.destdir` and allows checking the result 33377db96d56Sopenharmony_ci 33387db96d56Sopenharmony_ci If an error occurs, it must be checked using `expect_exception` 33397db96d56Sopenharmony_ci 33407db96d56Sopenharmony_ci Otherwise, all resulting files must be checked using `expect_file`, 33417db96d56Sopenharmony_ci except the destination directory itself and parent directories of 33427db96d56Sopenharmony_ci other files. 33437db96d56Sopenharmony_ci When checking directories, do so before their contents. 33447db96d56Sopenharmony_ci """ 33457db96d56Sopenharmony_ci with os_helper.temp_dir(self.outerdir): 33467db96d56Sopenharmony_ci try: 33477db96d56Sopenharmony_ci tar.extractall(self.destdir, filter=filter) 33487db96d56Sopenharmony_ci except Exception as exc: 33497db96d56Sopenharmony_ci self.raised_exception = exc 33507db96d56Sopenharmony_ci self.expected_paths = set() 33517db96d56Sopenharmony_ci else: 33527db96d56Sopenharmony_ci self.raised_exception = None 33537db96d56Sopenharmony_ci self.expected_paths = set(self.outerdir.glob('**/*')) 33547db96d56Sopenharmony_ci self.expected_paths.discard(self.destdir) 33557db96d56Sopenharmony_ci try: 33567db96d56Sopenharmony_ci yield 33577db96d56Sopenharmony_ci finally: 33587db96d56Sopenharmony_ci tar.close() 33597db96d56Sopenharmony_ci if self.raised_exception: 33607db96d56Sopenharmony_ci raise self.raised_exception 33617db96d56Sopenharmony_ci self.assertEqual(self.expected_paths, set()) 33627db96d56Sopenharmony_ci 33637db96d56Sopenharmony_ci def expect_file(self, name, type=None, symlink_to=None, mode=None): 33647db96d56Sopenharmony_ci """Check a single file. See check_context.""" 33657db96d56Sopenharmony_ci if self.raised_exception: 33667db96d56Sopenharmony_ci raise self.raised_exception 33677db96d56Sopenharmony_ci # use normpath() rather than resolve() so we don't follow symlinks 33687db96d56Sopenharmony_ci path = pathlib.Path(os.path.normpath(self.destdir / name)) 33697db96d56Sopenharmony_ci self.assertIn(path, self.expected_paths) 33707db96d56Sopenharmony_ci self.expected_paths.remove(path) 33717db96d56Sopenharmony_ci if mode is not None and os_helper.can_chmod(): 33727db96d56Sopenharmony_ci got = stat.filemode(stat.S_IMODE(path.stat().st_mode)) 33737db96d56Sopenharmony_ci self.assertEqual(got, mode) 33747db96d56Sopenharmony_ci if type is None and isinstance(name, str) and name.endswith('/'): 33757db96d56Sopenharmony_ci type = tarfile.DIRTYPE 33767db96d56Sopenharmony_ci if symlink_to is not None: 33777db96d56Sopenharmony_ci got = (self.destdir / name).readlink() 33787db96d56Sopenharmony_ci expected = pathlib.Path(symlink_to) 33797db96d56Sopenharmony_ci # The symlink might be the same (textually) as what we expect, 33807db96d56Sopenharmony_ci # but some systems change the link to an equivalent path, so 33817db96d56Sopenharmony_ci # we fall back to samefile(). 33827db96d56Sopenharmony_ci if expected != got: 33837db96d56Sopenharmony_ci self.assertTrue(got.samefile(expected)) 33847db96d56Sopenharmony_ci elif type == tarfile.REGTYPE or type is None: 33857db96d56Sopenharmony_ci self.assertTrue(path.is_file()) 33867db96d56Sopenharmony_ci elif type == tarfile.DIRTYPE: 33877db96d56Sopenharmony_ci self.assertTrue(path.is_dir()) 33887db96d56Sopenharmony_ci elif type == tarfile.FIFOTYPE: 33897db96d56Sopenharmony_ci self.assertTrue(path.is_fifo()) 33907db96d56Sopenharmony_ci else: 33917db96d56Sopenharmony_ci raise NotImplementedError(type) 33927db96d56Sopenharmony_ci for parent in path.parents: 33937db96d56Sopenharmony_ci self.expected_paths.discard(parent) 33947db96d56Sopenharmony_ci 33957db96d56Sopenharmony_ci def expect_exception(self, exc_type, message_re='.'): 33967db96d56Sopenharmony_ci with self.assertRaisesRegex(exc_type, message_re): 33977db96d56Sopenharmony_ci if self.raised_exception is not None: 33987db96d56Sopenharmony_ci raise self.raised_exception 33997db96d56Sopenharmony_ci self.raised_exception = None 34007db96d56Sopenharmony_ci 34017db96d56Sopenharmony_ci def test_benign_file(self): 34027db96d56Sopenharmony_ci with ArchiveMaker() as arc: 34037db96d56Sopenharmony_ci arc.add('benign.txt') 34047db96d56Sopenharmony_ci for filter in 'fully_trusted', 'tar', 'data': 34057db96d56Sopenharmony_ci with self.check_context(arc.open(), filter): 34067db96d56Sopenharmony_ci self.expect_file('benign.txt') 34077db96d56Sopenharmony_ci 34087db96d56Sopenharmony_ci def test_absolute(self): 34097db96d56Sopenharmony_ci # Test handling a member with an absolute path 34107db96d56Sopenharmony_ci # Inspired by 'absolute1' in https://github.com/jwilk/traversal-archives 34117db96d56Sopenharmony_ci with ArchiveMaker() as arc: 34127db96d56Sopenharmony_ci arc.add(self.outerdir / 'escaped.evil') 34137db96d56Sopenharmony_ci 34147db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 34157db96d56Sopenharmony_ci self.expect_file('../escaped.evil') 34167db96d56Sopenharmony_ci 34177db96d56Sopenharmony_ci for filter in 'tar', 'data': 34187db96d56Sopenharmony_ci with self.check_context(arc.open(), filter): 34197db96d56Sopenharmony_ci if str(self.outerdir).startswith('/'): 34207db96d56Sopenharmony_ci # We strip leading slashes, as e.g. GNU tar does 34217db96d56Sopenharmony_ci # (without --absolute-filenames). 34227db96d56Sopenharmony_ci outerdir_stripped = str(self.outerdir).lstrip('/') 34237db96d56Sopenharmony_ci self.expect_file(f'{outerdir_stripped}/escaped.evil') 34247db96d56Sopenharmony_ci else: 34257db96d56Sopenharmony_ci # On this system, absolute paths don't have leading 34267db96d56Sopenharmony_ci # slashes. 34277db96d56Sopenharmony_ci # So, there's nothing to strip. We refuse to unpack 34287db96d56Sopenharmony_ci # to an absolute path, nonetheless. 34297db96d56Sopenharmony_ci self.expect_exception( 34307db96d56Sopenharmony_ci tarfile.AbsolutePathError, 34317db96d56Sopenharmony_ci """['"].*escaped.evil['"] has an absolute path""") 34327db96d56Sopenharmony_ci 34337db96d56Sopenharmony_ci @symlink_test 34347db96d56Sopenharmony_ci def test_parent_symlink(self): 34357db96d56Sopenharmony_ci # Test interplaying symlinks 34367db96d56Sopenharmony_ci # Inspired by 'dirsymlink2a' in jwilk/traversal-archives 34377db96d56Sopenharmony_ci with ArchiveMaker() as arc: 34387db96d56Sopenharmony_ci arc.add('current', symlink_to='.') 34397db96d56Sopenharmony_ci arc.add('parent', symlink_to='current/..') 34407db96d56Sopenharmony_ci arc.add('parent/evil') 34417db96d56Sopenharmony_ci 34427db96d56Sopenharmony_ci if os_helper.can_symlink(): 34437db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 34447db96d56Sopenharmony_ci if self.raised_exception is not None: 34457db96d56Sopenharmony_ci # Windows will refuse to create a file that's a symlink to itself 34467db96d56Sopenharmony_ci # (and tarfile doesn't swallow that exception) 34477db96d56Sopenharmony_ci self.expect_exception(FileExistsError) 34487db96d56Sopenharmony_ci # The other cases will fail with this error too. 34497db96d56Sopenharmony_ci # Skip the rest of this test. 34507db96d56Sopenharmony_ci return 34517db96d56Sopenharmony_ci else: 34527db96d56Sopenharmony_ci self.expect_file('current', symlink_to='.') 34537db96d56Sopenharmony_ci self.expect_file('parent', symlink_to='current/..') 34547db96d56Sopenharmony_ci self.expect_file('../evil') 34557db96d56Sopenharmony_ci 34567db96d56Sopenharmony_ci with self.check_context(arc.open(), 'tar'): 34577db96d56Sopenharmony_ci self.expect_exception( 34587db96d56Sopenharmony_ci tarfile.OutsideDestinationError, 34597db96d56Sopenharmony_ci """'parent/evil' would be extracted to ['"].*evil['"], """ 34607db96d56Sopenharmony_ci + "which is outside the destination") 34617db96d56Sopenharmony_ci 34627db96d56Sopenharmony_ci with self.check_context(arc.open(), 'data'): 34637db96d56Sopenharmony_ci self.expect_exception( 34647db96d56Sopenharmony_ci tarfile.LinkOutsideDestinationError, 34657db96d56Sopenharmony_ci """'parent' would link to ['"].*outerdir['"], """ 34667db96d56Sopenharmony_ci + "which is outside the destination") 34677db96d56Sopenharmony_ci 34687db96d56Sopenharmony_ci else: 34697db96d56Sopenharmony_ci # No symlink support. The symlinks are ignored. 34707db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 34717db96d56Sopenharmony_ci self.expect_file('parent/evil') 34727db96d56Sopenharmony_ci with self.check_context(arc.open(), 'tar'): 34737db96d56Sopenharmony_ci self.expect_file('parent/evil') 34747db96d56Sopenharmony_ci with self.check_context(arc.open(), 'data'): 34757db96d56Sopenharmony_ci self.expect_file('parent/evil') 34767db96d56Sopenharmony_ci 34777db96d56Sopenharmony_ci @symlink_test 34787db96d56Sopenharmony_ci def test_parent_symlink2(self): 34797db96d56Sopenharmony_ci # Test interplaying symlinks 34807db96d56Sopenharmony_ci # Inspired by 'dirsymlink2b' in jwilk/traversal-archives 34817db96d56Sopenharmony_ci with ArchiveMaker() as arc: 34827db96d56Sopenharmony_ci arc.add('current', symlink_to='.') 34837db96d56Sopenharmony_ci arc.add('current/parent', symlink_to='..') 34847db96d56Sopenharmony_ci arc.add('parent/evil') 34857db96d56Sopenharmony_ci 34867db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 34877db96d56Sopenharmony_ci if os_helper.can_symlink(): 34887db96d56Sopenharmony_ci self.expect_file('current', symlink_to='.') 34897db96d56Sopenharmony_ci self.expect_file('parent', symlink_to='..') 34907db96d56Sopenharmony_ci self.expect_file('../evil') 34917db96d56Sopenharmony_ci else: 34927db96d56Sopenharmony_ci self.expect_file('current/') 34937db96d56Sopenharmony_ci self.expect_file('parent/evil') 34947db96d56Sopenharmony_ci 34957db96d56Sopenharmony_ci with self.check_context(arc.open(), 'tar'): 34967db96d56Sopenharmony_ci if os_helper.can_symlink(): 34977db96d56Sopenharmony_ci self.expect_exception( 34987db96d56Sopenharmony_ci tarfile.OutsideDestinationError, 34997db96d56Sopenharmony_ci "'parent/evil' would be extracted to " 35007db96d56Sopenharmony_ci + """['"].*evil['"], which is outside """ 35017db96d56Sopenharmony_ci + "the destination") 35027db96d56Sopenharmony_ci else: 35037db96d56Sopenharmony_ci self.expect_file('current/') 35047db96d56Sopenharmony_ci self.expect_file('parent/evil') 35057db96d56Sopenharmony_ci 35067db96d56Sopenharmony_ci with self.check_context(arc.open(), 'data'): 35077db96d56Sopenharmony_ci self.expect_exception( 35087db96d56Sopenharmony_ci tarfile.LinkOutsideDestinationError, 35097db96d56Sopenharmony_ci """'current/parent' would link to ['"].*['"], """ 35107db96d56Sopenharmony_ci + "which is outside the destination") 35117db96d56Sopenharmony_ci 35127db96d56Sopenharmony_ci @symlink_test 35137db96d56Sopenharmony_ci def test_absolute_symlink(self): 35147db96d56Sopenharmony_ci # Test symlink to an absolute path 35157db96d56Sopenharmony_ci # Inspired by 'dirsymlink' in jwilk/traversal-archives 35167db96d56Sopenharmony_ci with ArchiveMaker() as arc: 35177db96d56Sopenharmony_ci arc.add('parent', symlink_to=self.outerdir) 35187db96d56Sopenharmony_ci arc.add('parent/evil') 35197db96d56Sopenharmony_ci 35207db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 35217db96d56Sopenharmony_ci if os_helper.can_symlink(): 35227db96d56Sopenharmony_ci self.expect_file('parent', symlink_to=self.outerdir) 35237db96d56Sopenharmony_ci self.expect_file('../evil') 35247db96d56Sopenharmony_ci else: 35257db96d56Sopenharmony_ci self.expect_file('parent/evil') 35267db96d56Sopenharmony_ci 35277db96d56Sopenharmony_ci with self.check_context(arc.open(), 'tar'): 35287db96d56Sopenharmony_ci if os_helper.can_symlink(): 35297db96d56Sopenharmony_ci self.expect_exception( 35307db96d56Sopenharmony_ci tarfile.OutsideDestinationError, 35317db96d56Sopenharmony_ci "'parent/evil' would be extracted to " 35327db96d56Sopenharmony_ci + """['"].*evil['"], which is outside """ 35337db96d56Sopenharmony_ci + "the destination") 35347db96d56Sopenharmony_ci else: 35357db96d56Sopenharmony_ci self.expect_file('parent/evil') 35367db96d56Sopenharmony_ci 35377db96d56Sopenharmony_ci with self.check_context(arc.open(), 'data'): 35387db96d56Sopenharmony_ci self.expect_exception( 35397db96d56Sopenharmony_ci tarfile.AbsoluteLinkError, 35407db96d56Sopenharmony_ci "'parent' is a symlink to an absolute path") 35417db96d56Sopenharmony_ci 35427db96d56Sopenharmony_ci @symlink_test 35437db96d56Sopenharmony_ci def test_sly_relative0(self): 35447db96d56Sopenharmony_ci # Inspired by 'relative0' in jwilk/traversal-archives 35457db96d56Sopenharmony_ci with ArchiveMaker() as arc: 35467db96d56Sopenharmony_ci arc.add('../moo', symlink_to='..//tmp/moo') 35477db96d56Sopenharmony_ci 35487db96d56Sopenharmony_ci try: 35497db96d56Sopenharmony_ci with self.check_context(arc.open(), filter='fully_trusted'): 35507db96d56Sopenharmony_ci if os_helper.can_symlink(): 35517db96d56Sopenharmony_ci if isinstance(self.raised_exception, FileExistsError): 35527db96d56Sopenharmony_ci # XXX TarFile happens to fail creating a parent 35537db96d56Sopenharmony_ci # directory. 35547db96d56Sopenharmony_ci # This might be a bug, but fixing it would hurt 35557db96d56Sopenharmony_ci # security. 35567db96d56Sopenharmony_ci # Note that e.g. GNU `tar` rejects '..' components, 35577db96d56Sopenharmony_ci # so you could argue this is an invalid archive and we 35587db96d56Sopenharmony_ci # just raise an bad type of exception. 35597db96d56Sopenharmony_ci self.expect_exception(FileExistsError) 35607db96d56Sopenharmony_ci else: 35617db96d56Sopenharmony_ci self.expect_file('../moo', symlink_to='..//tmp/moo') 35627db96d56Sopenharmony_ci else: 35637db96d56Sopenharmony_ci # The symlink can't be extracted and is ignored 35647db96d56Sopenharmony_ci pass 35657db96d56Sopenharmony_ci except FileExistsError: 35667db96d56Sopenharmony_ci pass 35677db96d56Sopenharmony_ci 35687db96d56Sopenharmony_ci for filter in 'tar', 'data': 35697db96d56Sopenharmony_ci with self.check_context(arc.open(), filter): 35707db96d56Sopenharmony_ci self.expect_exception( 35717db96d56Sopenharmony_ci tarfile.OutsideDestinationError, 35727db96d56Sopenharmony_ci "'../moo' would be extracted to " 35737db96d56Sopenharmony_ci + "'.*moo', which is outside " 35747db96d56Sopenharmony_ci + "the destination") 35757db96d56Sopenharmony_ci 35767db96d56Sopenharmony_ci @symlink_test 35777db96d56Sopenharmony_ci def test_sly_relative2(self): 35787db96d56Sopenharmony_ci # Inspired by 'relative2' in jwilk/traversal-archives 35797db96d56Sopenharmony_ci with ArchiveMaker() as arc: 35807db96d56Sopenharmony_ci arc.add('tmp/') 35817db96d56Sopenharmony_ci arc.add('tmp/../../moo', symlink_to='tmp/../..//tmp/moo') 35827db96d56Sopenharmony_ci 35837db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 35847db96d56Sopenharmony_ci self.expect_file('tmp', type=tarfile.DIRTYPE) 35857db96d56Sopenharmony_ci if os_helper.can_symlink(): 35867db96d56Sopenharmony_ci self.expect_file('../moo', symlink_to='tmp/../../tmp/moo') 35877db96d56Sopenharmony_ci 35887db96d56Sopenharmony_ci for filter in 'tar', 'data': 35897db96d56Sopenharmony_ci with self.check_context(arc.open(), filter): 35907db96d56Sopenharmony_ci self.expect_exception( 35917db96d56Sopenharmony_ci tarfile.OutsideDestinationError, 35927db96d56Sopenharmony_ci "'tmp/../../moo' would be extracted to " 35937db96d56Sopenharmony_ci + """['"].*moo['"], which is outside the """ 35947db96d56Sopenharmony_ci + "destination") 35957db96d56Sopenharmony_ci 35967db96d56Sopenharmony_ci def test_modes(self): 35977db96d56Sopenharmony_ci # Test how file modes are extracted 35987db96d56Sopenharmony_ci # (Note that the modes are ignored on platforms without working chmod) 35997db96d56Sopenharmony_ci with ArchiveMaker() as arc: 36007db96d56Sopenharmony_ci arc.add('all_bits', mode='?rwsrwsrwt') 36017db96d56Sopenharmony_ci arc.add('perm_bits', mode='?rwxrwxrwx') 36027db96d56Sopenharmony_ci arc.add('exec_group_other', mode='?rw-rwxrwx') 36037db96d56Sopenharmony_ci arc.add('read_group_only', mode='?---r-----') 36047db96d56Sopenharmony_ci arc.add('no_bits', mode='?---------') 36057db96d56Sopenharmony_ci arc.add('dir/', mode='?---rwsrwt') 36067db96d56Sopenharmony_ci 36077db96d56Sopenharmony_ci # On some systems, setting the sticky bit is a no-op. 36087db96d56Sopenharmony_ci # Check if that's the case. 36097db96d56Sopenharmony_ci tmp_filename = os.path.join(TEMPDIR, "tmp.file") 36107db96d56Sopenharmony_ci with open(tmp_filename, 'w'): 36117db96d56Sopenharmony_ci pass 36127db96d56Sopenharmony_ci os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) 36137db96d56Sopenharmony_ci have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) 36147db96d56Sopenharmony_ci os.unlink(tmp_filename) 36157db96d56Sopenharmony_ci 36167db96d56Sopenharmony_ci os.mkdir(tmp_filename) 36177db96d56Sopenharmony_ci os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) 36187db96d56Sopenharmony_ci have_sticky_dirs = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) 36197db96d56Sopenharmony_ci os.rmdir(tmp_filename) 36207db96d56Sopenharmony_ci 36217db96d56Sopenharmony_ci with self.check_context(arc.open(), 'fully_trusted'): 36227db96d56Sopenharmony_ci if have_sticky_files: 36237db96d56Sopenharmony_ci self.expect_file('all_bits', mode='?rwsrwsrwt') 36247db96d56Sopenharmony_ci else: 36257db96d56Sopenharmony_ci self.expect_file('all_bits', mode='?rwsrwsrwx') 36267db96d56Sopenharmony_ci self.expect_file('perm_bits', mode='?rwxrwxrwx') 36277db96d56Sopenharmony_ci self.expect_file('exec_group_other', mode='?rw-rwxrwx') 36287db96d56Sopenharmony_ci self.expect_file('read_group_only', mode='?---r-----') 36297db96d56Sopenharmony_ci self.expect_file('no_bits', mode='?---------') 36307db96d56Sopenharmony_ci if have_sticky_dirs: 36317db96d56Sopenharmony_ci self.expect_file('dir/', mode='?---rwsrwt') 36327db96d56Sopenharmony_ci else: 36337db96d56Sopenharmony_ci self.expect_file('dir/', mode='?---rwsrwx') 36347db96d56Sopenharmony_ci 36357db96d56Sopenharmony_ci with self.check_context(arc.open(), 'tar'): 36367db96d56Sopenharmony_ci self.expect_file('all_bits', mode='?rwxr-xr-x') 36377db96d56Sopenharmony_ci self.expect_file('perm_bits', mode='?rwxr-xr-x') 36387db96d56Sopenharmony_ci self.expect_file('exec_group_other', mode='?rw-r-xr-x') 36397db96d56Sopenharmony_ci self.expect_file('read_group_only', mode='?---r-----') 36407db96d56Sopenharmony_ci self.expect_file('no_bits', mode='?---------') 36417db96d56Sopenharmony_ci self.expect_file('dir/', mode='?---r-xr-x') 36427db96d56Sopenharmony_ci 36437db96d56Sopenharmony_ci with self.check_context(arc.open(), 'data'): 36447db96d56Sopenharmony_ci normal_dir_mode = stat.filemode(stat.S_IMODE( 36457db96d56Sopenharmony_ci self.outerdir.stat().st_mode)) 36467db96d56Sopenharmony_ci self.expect_file('all_bits', mode='?rwxr-xr-x') 36477db96d56Sopenharmony_ci self.expect_file('perm_bits', mode='?rwxr-xr-x') 36487db96d56Sopenharmony_ci self.expect_file('exec_group_other', mode='?rw-r--r--') 36497db96d56Sopenharmony_ci self.expect_file('read_group_only', mode='?rw-r-----') 36507db96d56Sopenharmony_ci self.expect_file('no_bits', mode='?rw-------') 36517db96d56Sopenharmony_ci self.expect_file('dir/', mode=normal_dir_mode) 36527db96d56Sopenharmony_ci 36537db96d56Sopenharmony_ci def test_pipe(self): 36547db96d56Sopenharmony_ci # Test handling of a special file 36557db96d56Sopenharmony_ci with ArchiveMaker() as arc: 36567db96d56Sopenharmony_ci arc.add('foo', type=tarfile.FIFOTYPE) 36577db96d56Sopenharmony_ci 36587db96d56Sopenharmony_ci for filter in 'fully_trusted', 'tar': 36597db96d56Sopenharmony_ci with self.check_context(arc.open(), filter): 36607db96d56Sopenharmony_ci if hasattr(os, 'mkfifo'): 36617db96d56Sopenharmony_ci self.expect_file('foo', type=tarfile.FIFOTYPE) 36627db96d56Sopenharmony_ci else: 36637db96d56Sopenharmony_ci # The pipe can't be extracted and is skipped. 36647db96d56Sopenharmony_ci pass 36657db96d56Sopenharmony_ci 36667db96d56Sopenharmony_ci with self.check_context(arc.open(), 'data'): 36677db96d56Sopenharmony_ci self.expect_exception( 36687db96d56Sopenharmony_ci tarfile.SpecialFileError, 36697db96d56Sopenharmony_ci "'foo' is a special file") 36707db96d56Sopenharmony_ci 36717db96d56Sopenharmony_ci def test_special_files(self): 36727db96d56Sopenharmony_ci # Creating device files is tricky. Instead of attempting that let's 36737db96d56Sopenharmony_ci # only check the filter result. 36747db96d56Sopenharmony_ci for special_type in tarfile.FIFOTYPE, tarfile.CHRTYPE, tarfile.BLKTYPE: 36757db96d56Sopenharmony_ci tarinfo = tarfile.TarInfo('foo') 36767db96d56Sopenharmony_ci tarinfo.type = special_type 36777db96d56Sopenharmony_ci trusted = tarfile.fully_trusted_filter(tarinfo, '') 36787db96d56Sopenharmony_ci self.assertIs(trusted, tarinfo) 36797db96d56Sopenharmony_ci tar = tarfile.tar_filter(tarinfo, '') 36807db96d56Sopenharmony_ci self.assertEqual(tar.type, special_type) 36817db96d56Sopenharmony_ci with self.assertRaises(tarfile.SpecialFileError) as cm: 36827db96d56Sopenharmony_ci tarfile.data_filter(tarinfo, '') 36837db96d56Sopenharmony_ci self.assertIsInstance(cm.exception.tarinfo, tarfile.TarInfo) 36847db96d56Sopenharmony_ci self.assertEqual(cm.exception.tarinfo.name, 'foo') 36857db96d56Sopenharmony_ci 36867db96d56Sopenharmony_ci def test_fully_trusted_filter(self): 36877db96d56Sopenharmony_ci # The 'fully_trusted' filter returns the original TarInfo objects. 36887db96d56Sopenharmony_ci with tarfile.TarFile.open(tarname) as tar: 36897db96d56Sopenharmony_ci for tarinfo in tar.getmembers(): 36907db96d56Sopenharmony_ci filtered = tarfile.fully_trusted_filter(tarinfo, '') 36917db96d56Sopenharmony_ci self.assertIs(filtered, tarinfo) 36927db96d56Sopenharmony_ci 36937db96d56Sopenharmony_ci def test_tar_filter(self): 36947db96d56Sopenharmony_ci # The 'tar' filter returns TarInfo objects with the same name/type. 36957db96d56Sopenharmony_ci # (It can also fail for particularly "evil" input, but we don't have 36967db96d56Sopenharmony_ci # that in the test archive.) 36977db96d56Sopenharmony_ci with tarfile.TarFile.open(tarname) as tar: 36987db96d56Sopenharmony_ci for tarinfo in tar.getmembers(): 36997db96d56Sopenharmony_ci filtered = tarfile.tar_filter(tarinfo, '') 37007db96d56Sopenharmony_ci self.assertIs(filtered.name, tarinfo.name) 37017db96d56Sopenharmony_ci self.assertIs(filtered.type, tarinfo.type) 37027db96d56Sopenharmony_ci 37037db96d56Sopenharmony_ci def test_data_filter(self): 37047db96d56Sopenharmony_ci # The 'data' filter either raises, or returns TarInfo with the same 37057db96d56Sopenharmony_ci # name/type. 37067db96d56Sopenharmony_ci with tarfile.TarFile.open(tarname) as tar: 37077db96d56Sopenharmony_ci for tarinfo in tar.getmembers(): 37087db96d56Sopenharmony_ci try: 37097db96d56Sopenharmony_ci filtered = tarfile.data_filter(tarinfo, '') 37107db96d56Sopenharmony_ci except tarfile.FilterError: 37117db96d56Sopenharmony_ci continue 37127db96d56Sopenharmony_ci self.assertIs(filtered.name, tarinfo.name) 37137db96d56Sopenharmony_ci self.assertIs(filtered.type, tarinfo.type) 37147db96d56Sopenharmony_ci 37157db96d56Sopenharmony_ci def test_default_filter_warns_not(self): 37167db96d56Sopenharmony_ci """Ensure the default filter does not warn (like in 3.12)""" 37177db96d56Sopenharmony_ci with ArchiveMaker() as arc: 37187db96d56Sopenharmony_ci arc.add('foo') 37197db96d56Sopenharmony_ci with warnings_helper.check_no_warnings(self): 37207db96d56Sopenharmony_ci with self.check_context(arc.open(), None): 37217db96d56Sopenharmony_ci self.expect_file('foo') 37227db96d56Sopenharmony_ci 37237db96d56Sopenharmony_ci def test_change_default_filter_on_instance(self): 37247db96d56Sopenharmony_ci tar = tarfile.TarFile(tarname, 'r') 37257db96d56Sopenharmony_ci def strict_filter(tarinfo, path): 37267db96d56Sopenharmony_ci if tarinfo.name == 'ustar/regtype': 37277db96d56Sopenharmony_ci return tarinfo 37287db96d56Sopenharmony_ci else: 37297db96d56Sopenharmony_ci return None 37307db96d56Sopenharmony_ci tar.extraction_filter = strict_filter 37317db96d56Sopenharmony_ci with self.check_context(tar, None): 37327db96d56Sopenharmony_ci self.expect_file('ustar/regtype') 37337db96d56Sopenharmony_ci 37347db96d56Sopenharmony_ci def test_change_default_filter_on_class(self): 37357db96d56Sopenharmony_ci def strict_filter(tarinfo, path): 37367db96d56Sopenharmony_ci if tarinfo.name == 'ustar/regtype': 37377db96d56Sopenharmony_ci return tarinfo 37387db96d56Sopenharmony_ci else: 37397db96d56Sopenharmony_ci return None 37407db96d56Sopenharmony_ci tar = tarfile.TarFile(tarname, 'r') 37417db96d56Sopenharmony_ci with support.swap_attr(tarfile.TarFile, 'extraction_filter', 37427db96d56Sopenharmony_ci staticmethod(strict_filter)): 37437db96d56Sopenharmony_ci with self.check_context(tar, None): 37447db96d56Sopenharmony_ci self.expect_file('ustar/regtype') 37457db96d56Sopenharmony_ci 37467db96d56Sopenharmony_ci def test_change_default_filter_on_subclass(self): 37477db96d56Sopenharmony_ci class TarSubclass(tarfile.TarFile): 37487db96d56Sopenharmony_ci def extraction_filter(self, tarinfo, path): 37497db96d56Sopenharmony_ci if tarinfo.name == 'ustar/regtype': 37507db96d56Sopenharmony_ci return tarinfo 37517db96d56Sopenharmony_ci else: 37527db96d56Sopenharmony_ci return None 37537db96d56Sopenharmony_ci 37547db96d56Sopenharmony_ci tar = TarSubclass(tarname, 'r') 37557db96d56Sopenharmony_ci with self.check_context(tar, None): 37567db96d56Sopenharmony_ci self.expect_file('ustar/regtype') 37577db96d56Sopenharmony_ci 37587db96d56Sopenharmony_ci def test_change_default_filter_to_string(self): 37597db96d56Sopenharmony_ci tar = tarfile.TarFile(tarname, 'r') 37607db96d56Sopenharmony_ci tar.extraction_filter = 'data' 37617db96d56Sopenharmony_ci with self.check_context(tar, None): 37627db96d56Sopenharmony_ci self.expect_exception(TypeError) 37637db96d56Sopenharmony_ci 37647db96d56Sopenharmony_ci def test_custom_filter(self): 37657db96d56Sopenharmony_ci def custom_filter(tarinfo, path): 37667db96d56Sopenharmony_ci self.assertIs(path, self.destdir) 37677db96d56Sopenharmony_ci if tarinfo.name == 'move_this': 37687db96d56Sopenharmony_ci return tarinfo.replace(name='moved') 37697db96d56Sopenharmony_ci if tarinfo.name == 'ignore_this': 37707db96d56Sopenharmony_ci return None 37717db96d56Sopenharmony_ci return tarinfo 37727db96d56Sopenharmony_ci 37737db96d56Sopenharmony_ci with ArchiveMaker() as arc: 37747db96d56Sopenharmony_ci arc.add('move_this') 37757db96d56Sopenharmony_ci arc.add('ignore_this') 37767db96d56Sopenharmony_ci arc.add('keep') 37777db96d56Sopenharmony_ci with self.check_context(arc.open(), custom_filter): 37787db96d56Sopenharmony_ci self.expect_file('moved') 37797db96d56Sopenharmony_ci self.expect_file('keep') 37807db96d56Sopenharmony_ci 37817db96d56Sopenharmony_ci def test_bad_filter_name(self): 37827db96d56Sopenharmony_ci with ArchiveMaker() as arc: 37837db96d56Sopenharmony_ci arc.add('foo') 37847db96d56Sopenharmony_ci with self.check_context(arc.open(), 'bad filter name'): 37857db96d56Sopenharmony_ci self.expect_exception(ValueError) 37867db96d56Sopenharmony_ci 37877db96d56Sopenharmony_ci def test_stateful_filter(self): 37887db96d56Sopenharmony_ci # Stateful filters should be possible. 37897db96d56Sopenharmony_ci # (This doesn't really test tarfile. Rather, it demonstrates 37907db96d56Sopenharmony_ci # that third parties can implement a stateful filter.) 37917db96d56Sopenharmony_ci class StatefulFilter: 37927db96d56Sopenharmony_ci def __enter__(self): 37937db96d56Sopenharmony_ci self.num_files_processed = 0 37947db96d56Sopenharmony_ci return self 37957db96d56Sopenharmony_ci 37967db96d56Sopenharmony_ci def __call__(self, tarinfo, path): 37977db96d56Sopenharmony_ci try: 37987db96d56Sopenharmony_ci tarinfo = tarfile.data_filter(tarinfo, path) 37997db96d56Sopenharmony_ci except tarfile.FilterError: 38007db96d56Sopenharmony_ci return None 38017db96d56Sopenharmony_ci self.num_files_processed += 1 38027db96d56Sopenharmony_ci return tarinfo 38037db96d56Sopenharmony_ci 38047db96d56Sopenharmony_ci def __exit__(self, *exc_info): 38057db96d56Sopenharmony_ci self.done = True 38067db96d56Sopenharmony_ci 38077db96d56Sopenharmony_ci with ArchiveMaker() as arc: 38087db96d56Sopenharmony_ci arc.add('good') 38097db96d56Sopenharmony_ci arc.add('bad', symlink_to='/') 38107db96d56Sopenharmony_ci arc.add('good') 38117db96d56Sopenharmony_ci with StatefulFilter() as custom_filter: 38127db96d56Sopenharmony_ci with self.check_context(arc.open(), custom_filter): 38137db96d56Sopenharmony_ci self.expect_file('good') 38147db96d56Sopenharmony_ci self.assertEqual(custom_filter.num_files_processed, 2) 38157db96d56Sopenharmony_ci self.assertEqual(custom_filter.done, True) 38167db96d56Sopenharmony_ci 38177db96d56Sopenharmony_ci def test_errorlevel(self): 38187db96d56Sopenharmony_ci def extracterror_filter(tarinfo, path): 38197db96d56Sopenharmony_ci raise tarfile.ExtractError('failed with ExtractError') 38207db96d56Sopenharmony_ci def filtererror_filter(tarinfo, path): 38217db96d56Sopenharmony_ci raise tarfile.FilterError('failed with FilterError') 38227db96d56Sopenharmony_ci def oserror_filter(tarinfo, path): 38237db96d56Sopenharmony_ci raise OSError('failed with OSError') 38247db96d56Sopenharmony_ci def tarerror_filter(tarinfo, path): 38257db96d56Sopenharmony_ci raise tarfile.TarError('failed with base TarError') 38267db96d56Sopenharmony_ci def valueerror_filter(tarinfo, path): 38277db96d56Sopenharmony_ci raise ValueError('failed with ValueError') 38287db96d56Sopenharmony_ci 38297db96d56Sopenharmony_ci with ArchiveMaker() as arc: 38307db96d56Sopenharmony_ci arc.add('file') 38317db96d56Sopenharmony_ci 38327db96d56Sopenharmony_ci # If errorlevel is 0, errors affected by errorlevel are ignored 38337db96d56Sopenharmony_ci 38347db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=0), extracterror_filter): 38357db96d56Sopenharmony_ci self.expect_file('file') 38367db96d56Sopenharmony_ci 38377db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=0), filtererror_filter): 38387db96d56Sopenharmony_ci self.expect_file('file') 38397db96d56Sopenharmony_ci 38407db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=0), oserror_filter): 38417db96d56Sopenharmony_ci self.expect_file('file') 38427db96d56Sopenharmony_ci 38437db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=0), tarerror_filter): 38447db96d56Sopenharmony_ci self.expect_exception(tarfile.TarError) 38457db96d56Sopenharmony_ci 38467db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=0), valueerror_filter): 38477db96d56Sopenharmony_ci self.expect_exception(ValueError) 38487db96d56Sopenharmony_ci 38497db96d56Sopenharmony_ci # If 1, all fatal errors are raised 38507db96d56Sopenharmony_ci 38517db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=1), extracterror_filter): 38527db96d56Sopenharmony_ci self.expect_file('file') 38537db96d56Sopenharmony_ci 38547db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=1), filtererror_filter): 38557db96d56Sopenharmony_ci self.expect_exception(tarfile.FilterError) 38567db96d56Sopenharmony_ci 38577db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=1), oserror_filter): 38587db96d56Sopenharmony_ci self.expect_exception(OSError) 38597db96d56Sopenharmony_ci 38607db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=1), tarerror_filter): 38617db96d56Sopenharmony_ci self.expect_exception(tarfile.TarError) 38627db96d56Sopenharmony_ci 38637db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=1), valueerror_filter): 38647db96d56Sopenharmony_ci self.expect_exception(ValueError) 38657db96d56Sopenharmony_ci 38667db96d56Sopenharmony_ci # If 2, all non-fatal errors are raised as well. 38677db96d56Sopenharmony_ci 38687db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=2), extracterror_filter): 38697db96d56Sopenharmony_ci self.expect_exception(tarfile.ExtractError) 38707db96d56Sopenharmony_ci 38717db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=2), filtererror_filter): 38727db96d56Sopenharmony_ci self.expect_exception(tarfile.FilterError) 38737db96d56Sopenharmony_ci 38747db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=2), oserror_filter): 38757db96d56Sopenharmony_ci self.expect_exception(OSError) 38767db96d56Sopenharmony_ci 38777db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=2), tarerror_filter): 38787db96d56Sopenharmony_ci self.expect_exception(tarfile.TarError) 38797db96d56Sopenharmony_ci 38807db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel=2), valueerror_filter): 38817db96d56Sopenharmony_ci self.expect_exception(ValueError) 38827db96d56Sopenharmony_ci 38837db96d56Sopenharmony_ci # We only handle ExtractionError, FilterError & OSError specially. 38847db96d56Sopenharmony_ci 38857db96d56Sopenharmony_ci with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter): 38867db96d56Sopenharmony_ci self.expect_exception(TypeError) # errorlevel is not int 38877db96d56Sopenharmony_ci 38887db96d56Sopenharmony_ci 38897db96d56Sopenharmony_cidef setUpModule(): 38907db96d56Sopenharmony_ci os_helper.unlink(TEMPDIR) 38917db96d56Sopenharmony_ci os.makedirs(TEMPDIR) 38927db96d56Sopenharmony_ci 38937db96d56Sopenharmony_ci global testtarnames 38947db96d56Sopenharmony_ci testtarnames = [tarname] 38957db96d56Sopenharmony_ci with open(tarname, "rb") as fobj: 38967db96d56Sopenharmony_ci data = fobj.read() 38977db96d56Sopenharmony_ci 38987db96d56Sopenharmony_ci # Create compressed tarfiles. 38997db96d56Sopenharmony_ci for c in GzipTest, Bz2Test, LzmaTest: 39007db96d56Sopenharmony_ci if c.open: 39017db96d56Sopenharmony_ci os_helper.unlink(c.tarname) 39027db96d56Sopenharmony_ci testtarnames.append(c.tarname) 39037db96d56Sopenharmony_ci with c.open(c.tarname, "wb") as tar: 39047db96d56Sopenharmony_ci tar.write(data) 39057db96d56Sopenharmony_ci 39067db96d56Sopenharmony_cidef tearDownModule(): 39077db96d56Sopenharmony_ci if os.path.exists(TEMPDIR): 39087db96d56Sopenharmony_ci os_helper.rmtree(TEMPDIR) 39097db96d56Sopenharmony_ci 39107db96d56Sopenharmony_ciif __name__ == "__main__": 39117db96d56Sopenharmony_ci unittest.main() 3912