xref: /third_party/python/Lib/test/test_tarfile.py (revision 7db96d56)
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