blob: 3ddeb97f5268fe8ba1bd7c95b579e681d2243010 [file] [log] [blame]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001import sys
2import os
Lars Gustäbelb506dc32007-08-07 18:36:16 +00003import io
Christian Heimesc64a1a62019-09-25 16:30:20 +02004from hashlib import sha256
Eric V. Smith7a803892015-04-15 10:27:58 -04005from contextlib import contextmanager
Serhiy Storchakaa89d22a2016-10-30 20:52:29 +02006from random import Random
Serhiy Storchakac45cd162017-03-08 10:32:44 +02007import pathlib
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00008
9import unittest
Eric V. Smith7a803892015-04-15 10:27:58 -040010import unittest.mock
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000011import tarfile
12
Berker Peksagce643912015-05-06 06:33:17 +030013from test import support
Hai Shi66abe982020-04-29 09:11:29 +080014from test.support import script_helper
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000015
16# Check for our compression modules.
17try:
18 import gzip
Brett Cannon260fbe82013-07-04 18:16:15 -040019except ImportError:
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000020 gzip = None
21try:
22 import bz2
Brett Cannon260fbe82013-07-04 18:16:15 -040023except ImportError:
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000024 bz2 = None
Lars Gustäbel0a9dd2f2011-12-10 20:38:14 +010025try:
26 import lzma
Brett Cannon260fbe82013-07-04 18:16:15 -040027except ImportError:
Lars Gustäbel0a9dd2f2011-12-10 20:38:14 +010028 lzma = None
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000029
Christian Heimesc64a1a62019-09-25 16:30:20 +020030def sha256sum(data):
31 return sha256(data).hexdigest()
Guido van Rossumd8faa362007-04-27 19:54:29 +000032
Antoine Pitrouab58b5f2010-09-23 19:39:35 +000033TEMPDIR = os.path.abspath(support.TESTFN) + "-tardir"
Serhiy Storchakad27b4552013-11-24 01:53:29 +020034tarextdir = TEMPDIR + '-extract-test'
Antoine Pitrou941ee882009-11-11 20:59:38 +000035tarname = support.findfile("testtar.tar")
Guido van Rossumd8faa362007-04-27 19:54:29 +000036gzipname = os.path.join(TEMPDIR, "testtar.tar.gz")
37bz2name = os.path.join(TEMPDIR, "testtar.tar.bz2")
Lars Gustäbel0a9dd2f2011-12-10 20:38:14 +010038xzname = os.path.join(TEMPDIR, "testtar.tar.xz")
Guido van Rossumd8faa362007-04-27 19:54:29 +000039tmpname = os.path.join(TEMPDIR, "tmp.tar")
Serhiy Storchakad27b4552013-11-24 01:53:29 +020040dotlessname = os.path.join(TEMPDIR, "testtar")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000041
Christian Heimesc64a1a62019-09-25 16:30:20 +020042sha256_regtype = (
43 "e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce"
44)
45sha256_sparse = (
46 "4f05a776071146756345ceee937b33fc5644f5a96b9780d1c7d6a32cdf164d7b"
47)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000048
49
Serhiy Storchaka8b562922013-06-17 15:38:50 +030050class TarTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +000051 tarname = tarname
Serhiy Storchaka8b562922013-06-17 15:38:50 +030052 suffix = ''
53 open = io.FileIO
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +020054 taropen = tarfile.TarFile.taropen
Serhiy Storchaka8b562922013-06-17 15:38:50 +030055
56 @property
57 def mode(self):
58 return self.prefix + self.suffix
59
Hai Shia3ec3ad2020-05-19 06:02:57 +080060@support.requires_gzip()
Serhiy Storchaka8b562922013-06-17 15:38:50 +030061class GzipTest:
62 tarname = gzipname
63 suffix = 'gz'
64 open = gzip.GzipFile if gzip else None
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +020065 taropen = tarfile.TarFile.gzopen
Serhiy Storchaka8b562922013-06-17 15:38:50 +030066
Hai Shia3ec3ad2020-05-19 06:02:57 +080067@support.requires_bz2()
Serhiy Storchaka8b562922013-06-17 15:38:50 +030068class Bz2Test:
69 tarname = bz2name
70 suffix = 'bz2'
71 open = bz2.BZ2File if bz2 else None
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +020072 taropen = tarfile.TarFile.bz2open
Serhiy Storchaka8b562922013-06-17 15:38:50 +030073
Hai Shia3ec3ad2020-05-19 06:02:57 +080074@support.requires_lzma()
Serhiy Storchaka8b562922013-06-17 15:38:50 +030075class LzmaTest:
76 tarname = xzname
77 suffix = 'xz'
78 open = lzma.LZMAFile if lzma else None
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +020079 taropen = tarfile.TarFile.xzopen
Serhiy Storchaka8b562922013-06-17 15:38:50 +030080
81
82class ReadTest(TarTest):
83
84 prefix = "r:"
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000085
86 def setUp(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +030087 self.tar = tarfile.open(self.tarname, mode=self.mode,
88 encoding="iso8859-1")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000089
90 def tearDown(self):
91 self.tar.close()
92
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000093
Serhiy Storchaka8b562922013-06-17 15:38:50 +030094class UstarReadTest(ReadTest, unittest.TestCase):
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000095
Guido van Rossumd8faa362007-04-27 19:54:29 +000096 def test_fileobj_regular_file(self):
97 tarinfo = self.tar.getmember("ustar/regtype")
Lars Gustäbel7a919e92012-05-05 18:15:03 +020098 with self.tar.extractfile(tarinfo) as fobj:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +000099 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300100 self.assertEqual(len(data), tarinfo.size,
101 "regular file extraction failed")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200102 self.assertEqual(sha256sum(data), sha256_regtype,
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000103 "regular file extraction failed")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000104
Guido van Rossumd8faa362007-04-27 19:54:29 +0000105 def test_fileobj_readlines(self):
106 self.tar.extract("ustar/regtype", TEMPDIR)
107 tarinfo = self.tar.getmember("ustar/regtype")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000108 with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1:
109 lines1 = fobj1.readlines()
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000110
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200111 with self.tar.extractfile(tarinfo) as fobj:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000112 fobj2 = io.TextIOWrapper(fobj)
113 lines2 = fobj2.readlines()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300114 self.assertEqual(lines1, lines2,
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000115 "fileobj.readlines() failed")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300116 self.assertEqual(len(lines2), 114,
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000117 "fileobj.readlines() failed")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300118 self.assertEqual(lines2[83],
119 "I will gladly admit that Python is not the fastest "
120 "running scripting language.\n",
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000121 "fileobj.readlines() failed")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000122
Guido van Rossumd8faa362007-04-27 19:54:29 +0000123 def test_fileobj_iter(self):
124 self.tar.extract("ustar/regtype", TEMPDIR)
125 tarinfo = self.tar.getmember("ustar/regtype")
Victor Stinner4e86d5b2011-05-04 13:55:36 +0200126 with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000127 lines1 = fobj1.readlines()
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200128 with self.tar.extractfile(tarinfo) as fobj2:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000129 lines2 = list(io.TextIOWrapper(fobj2))
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300130 self.assertEqual(lines1, lines2,
131 "fileobj.__iter__() failed")
Martin v. Löwisdf241532005-03-03 08:17:42 +0000132
Guido van Rossumd8faa362007-04-27 19:54:29 +0000133 def test_fileobj_seek(self):
134 self.tar.extract("ustar/regtype", TEMPDIR)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000135 with open(os.path.join(TEMPDIR, "ustar/regtype"), "rb") as fobj:
136 data = fobj.read()
Neal Norwitzf3396542005-10-28 05:52:22 +0000137
Guido van Rossumd8faa362007-04-27 19:54:29 +0000138 tarinfo = self.tar.getmember("ustar/regtype")
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +0200139 with self.tar.extractfile(tarinfo) as fobj:
140 text = fobj.read()
141 fobj.seek(0)
142 self.assertEqual(0, fobj.tell(),
143 "seek() to file's start failed")
144 fobj.seek(2048, 0)
145 self.assertEqual(2048, fobj.tell(),
146 "seek() to absolute position failed")
147 fobj.seek(-1024, 1)
148 self.assertEqual(1024, fobj.tell(),
149 "seek() to negative relative position failed")
150 fobj.seek(1024, 1)
151 self.assertEqual(2048, fobj.tell(),
152 "seek() to positive relative position failed")
153 s = fobj.read(10)
154 self.assertEqual(s, data[2048:2058],
155 "read() after seek failed")
156 fobj.seek(0, 2)
157 self.assertEqual(tarinfo.size, fobj.tell(),
158 "seek() to file's end failed")
159 self.assertEqual(fobj.read(), b"",
160 "read() at file's end did not return empty string")
161 fobj.seek(-tarinfo.size, 2)
162 self.assertEqual(0, fobj.tell(),
163 "relative seek() to file's end failed")
164 fobj.seek(512)
165 s1 = fobj.readlines()
166 fobj.seek(512)
167 s2 = fobj.readlines()
168 self.assertEqual(s1, s2,
169 "readlines() after seek failed")
170 fobj.seek(0)
171 self.assertEqual(len(fobj.readline()), fobj.tell(),
172 "tell() after readline() failed")
173 fobj.seek(512)
174 self.assertEqual(len(fobj.readline()) + 512, fobj.tell(),
175 "tell() after seek() and readline() failed")
176 fobj.seek(0)
177 line = fobj.readline()
178 self.assertEqual(fobj.read(), data[len(line):],
179 "read() after readline() failed")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000180
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200181 def test_fileobj_text(self):
182 with self.tar.extractfile("ustar/regtype") as fobj:
183 fobj = io.TextIOWrapper(fobj)
184 data = fobj.read().encode("iso8859-1")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200185 self.assertEqual(sha256sum(data), sha256_regtype)
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200186 try:
187 fobj.seek(100)
188 except AttributeError:
189 # Issue #13815: seek() complained about a missing
190 # flush() method.
191 self.fail("seeking failed in text mode")
192
Lars Gustäbel1b512722010-06-03 12:45:16 +0000193 # Test if symbolic and hard links are resolved by extractfile(). The
194 # test link members each point to a regular member whose data is
195 # supposed to be exported.
196 def _test_fileobj_link(self, lnktype, regtype):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300197 with self.tar.extractfile(lnktype) as a, \
198 self.tar.extractfile(regtype) as b:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000199 self.assertEqual(a.name, b.name)
Lars Gustäbel1b512722010-06-03 12:45:16 +0000200
201 def test_fileobj_link1(self):
202 self._test_fileobj_link("ustar/lnktype", "ustar/regtype")
203
204 def test_fileobj_link2(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300205 self._test_fileobj_link("./ustar/linktest2/lnktype",
206 "ustar/linktest1/regtype")
Lars Gustäbel1b512722010-06-03 12:45:16 +0000207
208 def test_fileobj_symlink1(self):
209 self._test_fileobj_link("ustar/symtype", "ustar/regtype")
210
211 def test_fileobj_symlink2(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300212 self._test_fileobj_link("./ustar/linktest2/symtype",
213 "ustar/linktest1/regtype")
Lars Gustäbel1b512722010-06-03 12:45:16 +0000214
Lars Gustäbel1ef9eda2012-04-24 21:04:40 +0200215 def test_issue14160(self):
216 self._test_fileobj_link("symtype2", "ustar/regtype")
217
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300218class GzipUstarReadTest(GzipTest, UstarReadTest):
219 pass
220
221class Bz2UstarReadTest(Bz2Test, UstarReadTest):
222 pass
223
224class LzmaUstarReadTest(LzmaTest, UstarReadTest):
225 pass
226
Guido van Rossumd8faa362007-04-27 19:54:29 +0000227
Serhiy Storchaka3b4f1592014-02-05 20:53:36 +0200228class ListTest(ReadTest, unittest.TestCase):
229
230 # Override setUp to use default encoding (UTF-8)
231 def setUp(self):
232 self.tar = tarfile.open(self.tarname, mode=self.mode)
233
234 def test_list(self):
235 tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
236 with support.swap_attr(sys, 'stdout', tio):
237 self.tar.list(verbose=False)
238 out = tio.detach().getvalue()
239 self.assertIn(b'ustar/conttype', out)
240 self.assertIn(b'ustar/regtype', out)
241 self.assertIn(b'ustar/lnktype', out)
242 self.assertIn(b'ustar' + (b'/12345' * 40) + b'67/longname', out)
243 self.assertIn(b'./ustar/linktest2/symtype', out)
244 self.assertIn(b'./ustar/linktest2/lnktype', out)
245 # Make sure it puts trailing slash for directory
246 self.assertIn(b'ustar/dirtype/', out)
247 self.assertIn(b'ustar/dirtype-with-size/', out)
248 # Make sure it is able to print unencodable characters
Serhiy Storchaka162c4772014-02-19 18:44:12 +0200249 def conv(b):
250 s = b.decode(self.tar.encoding, 'surrogateescape')
251 return s.encode('ascii', 'backslashreplace')
252 self.assertIn(conv(b'ustar/umlauts-\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out)
253 self.assertIn(conv(b'misc/regtype-hpux-signed-chksum-'
254 b'\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out)
255 self.assertIn(conv(b'misc/regtype-old-v7-signed-chksum-'
256 b'\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out)
257 self.assertIn(conv(b'pax/bad-pax-\xe4\xf6\xfc'), out)
258 self.assertIn(conv(b'pax/hdrcharset-\xe4\xf6\xfc'), out)
Serhiy Storchaka3b4f1592014-02-05 20:53:36 +0200259 # Make sure it prints files separated by one newline without any
260 # 'ls -l'-like accessories if verbose flag is not being used
261 # ...
262 # ustar/conttype
263 # ustar/regtype
264 # ...
265 self.assertRegex(out, br'ustar/conttype ?\r?\n'
266 br'ustar/regtype ?\r?\n')
267 # Make sure it does not print the source of link without verbose flag
268 self.assertNotIn(b'link to', out)
269 self.assertNotIn(b'->', out)
270
271 def test_list_verbose(self):
272 tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
273 with support.swap_attr(sys, 'stdout', tio):
274 self.tar.list(verbose=True)
275 out = tio.detach().getvalue()
276 # Make sure it prints files separated by one newline with 'ls -l'-like
277 # accessories if verbose flag is being used
278 # ...
279 # ?rw-r--r-- tarfile/tarfile 7011 2003-01-06 07:19:43 ustar/conttype
280 # ?rw-r--r-- tarfile/tarfile 7011 2003-01-06 07:19:43 ustar/regtype
281 # ...
Serhiy Storchaka255493c2014-02-05 20:54:43 +0200282 self.assertRegex(out, (br'\?rw-r--r-- tarfile/tarfile\s+7011 '
Serhiy Storchaka3b4f1592014-02-05 20:53:36 +0200283 br'\d{4}-\d\d-\d\d\s+\d\d:\d\d:\d\d '
284 br'ustar/\w+type ?\r?\n') * 2)
285 # Make sure it prints the source of link with verbose flag
286 self.assertIn(b'ustar/symtype -> regtype', out)
287 self.assertIn(b'./ustar/linktest2/symtype -> ../linktest1/regtype', out)
288 self.assertIn(b'./ustar/linktest2/lnktype link to '
289 b'./ustar/linktest1/regtype', out)
290 self.assertIn(b'gnu' + (b'/123' * 125) + b'/longlink link to gnu' +
291 (b'/123' * 125) + b'/longname', out)
292 self.assertIn(b'pax' + (b'/123' * 125) + b'/longlink link to pax' +
293 (b'/123' * 125) + b'/longname', out)
294
Serhiy Storchakaa7eb7462014-08-21 10:01:16 +0300295 def test_list_members(self):
296 tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
297 def members(tar):
298 for tarinfo in tar.getmembers():
299 if 'reg' in tarinfo.name:
300 yield tarinfo
301 with support.swap_attr(sys, 'stdout', tio):
302 self.tar.list(verbose=False, members=members(self.tar))
303 out = tio.detach().getvalue()
304 self.assertIn(b'ustar/regtype', out)
305 self.assertNotIn(b'ustar/conttype', out)
306
Serhiy Storchaka3b4f1592014-02-05 20:53:36 +0200307
308class GzipListTest(GzipTest, ListTest):
309 pass
310
311
312class Bz2ListTest(Bz2Test, ListTest):
313 pass
314
315
316class LzmaListTest(LzmaTest, ListTest):
317 pass
318
319
Lars Gustäbel9520a432009-11-22 18:48:49 +0000320class CommonReadTest(ReadTest):
321
William Woodruffdd754ca2020-01-22 21:24:16 -0500322 def test_is_tarfile_erroneous(self):
323 with open(tmpname, "wb"):
324 pass
325
326 # is_tarfile works on filenames
327 self.assertFalse(tarfile.is_tarfile(tmpname))
328
329 # is_tarfile works on path-like objects
330 self.assertFalse(tarfile.is_tarfile(pathlib.Path(tmpname)))
331
332 # is_tarfile works on file objects
333 with open(tmpname, "rb") as fobj:
334 self.assertFalse(tarfile.is_tarfile(fobj))
335
336 # is_tarfile works on file-like objects
337 self.assertFalse(tarfile.is_tarfile(io.BytesIO(b"invalid")))
338
339 def test_is_tarfile_valid(self):
340 # is_tarfile works on filenames
341 self.assertTrue(tarfile.is_tarfile(self.tarname))
342
343 # is_tarfile works on path-like objects
344 self.assertTrue(tarfile.is_tarfile(pathlib.Path(self.tarname)))
345
346 # is_tarfile works on file objects
347 with open(self.tarname, "rb") as fobj:
348 self.assertTrue(tarfile.is_tarfile(fobj))
349
350 # is_tarfile works on file-like objects
351 with open(self.tarname, "rb") as fobj:
352 self.assertTrue(tarfile.is_tarfile(io.BytesIO(fobj.read())))
353
Lars Gustäbel9520a432009-11-22 18:48:49 +0000354 def test_empty_tarfile(self):
355 # Test for issue6123: Allow opening empty archives.
356 # This test checks if tarfile.open() is able to open an empty tar
357 # archive successfully. Note that an empty tar archive is not the
358 # same as an empty file!
Antoine Pitrou95f55602010-09-23 18:36:46 +0000359 with tarfile.open(tmpname, self.mode.replace("r", "w")):
360 pass
Lars Gustäbel9520a432009-11-22 18:48:49 +0000361 try:
362 tar = tarfile.open(tmpname, self.mode)
363 tar.getnames()
364 except tarfile.ReadError:
365 self.fail("tarfile.open() failed on empty archive")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000366 else:
367 self.assertListEqual(tar.getmembers(), [])
368 finally:
369 tar.close()
Lars Gustäbel9520a432009-11-22 18:48:49 +0000370
Serhiy Storchakaf22fe0f2014-01-13 19:08:00 +0200371 def test_non_existent_tarfile(self):
372 # Test for issue11513: prevent non-existent gzipped tarfiles raising
373 # multiple exceptions.
374 with self.assertRaisesRegex(FileNotFoundError, "xxx"):
375 tarfile.open("xxx", self.mode)
376
Lars Gustäbel9520a432009-11-22 18:48:49 +0000377 def test_null_tarfile(self):
378 # Test for issue6123: Allow opening empty archives.
379 # This test guarantees that tarfile.open() does not treat an empty
380 # file as an empty tar archive.
Antoine Pitrou95f55602010-09-23 18:36:46 +0000381 with open(tmpname, "wb"):
382 pass
Lars Gustäbel9520a432009-11-22 18:48:49 +0000383 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, self.mode)
384 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname)
385
386 def test_ignore_zeros(self):
387 # Test TarFile's ignore_zeros option.
Serhiy Storchakaa89d22a2016-10-30 20:52:29 +0200388 # generate 512 pseudorandom bytes
Victor Stinner87502dd2020-04-17 22:54:38 +0200389 data = Random(0).randbytes(512)
Lars Gustäbel9520a432009-11-22 18:48:49 +0000390 for char in (b'\0', b'a'):
391 # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a')
392 # are ignored correctly.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300393 with self.open(tmpname, "w") as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000394 fobj.write(char * 1024)
Serhiy Storchakaa89d22a2016-10-30 20:52:29 +0200395 tarinfo = tarfile.TarInfo("foo")
396 tarinfo.size = len(data)
397 fobj.write(tarinfo.tobuf())
398 fobj.write(data)
Lars Gustäbel9520a432009-11-22 18:48:49 +0000399
400 tar = tarfile.open(tmpname, mode="r", ignore_zeros=True)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000401 try:
402 self.assertListEqual(tar.getnames(), ["foo"],
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300403 "ignore_zeros=True should have skipped the %r-blocks" %
404 char)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000405 finally:
406 tar.close()
Lars Gustäbel9520a432009-11-22 18:48:49 +0000407
Lars Gustäbel03572682015-07-06 09:27:24 +0200408 def test_premature_end_of_archive(self):
409 for size in (512, 600, 1024, 1200):
410 with tarfile.open(tmpname, "w:") as tar:
411 t = tarfile.TarInfo("foo")
412 t.size = 1024
413 tar.addfile(t, io.BytesIO(b"a" * 1024))
414
415 with open(tmpname, "r+b") as fobj:
416 fobj.truncate(size)
417
418 with tarfile.open(tmpname) as tar:
419 with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
420 for t in tar:
421 pass
422
423 with tarfile.open(tmpname) as tar:
424 t = tar.next()
425
426 with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
427 tar.extract(t, TEMPDIR)
428
429 with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
430 tar.extractfile(t).read()
Lars Gustäbel9520a432009-11-22 18:48:49 +0000431
Rishi5a8d1212020-07-15 13:51:00 +0200432 def test_length_zero_header(self):
433 # bpo-39017 (CVE-2019-20907): reading a zero-length header should fail
434 # with an exception
435 with self.assertRaisesRegex(tarfile.ReadError, "file could not be opened successfully"):
436 with tarfile.open(support.findfile('recursion.tar')) as tar:
437 pass
438
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300439class MiscReadTestBase(CommonReadTest):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300440 def requires_name_attribute(self):
441 pass
442
Thomas Woutersed03b412007-08-28 21:37:11 +0000443 def test_no_name_argument(self):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300444 self.requires_name_attribute()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000445 with open(self.tarname, "rb") as fobj:
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300446 self.assertIsInstance(fobj.name, str)
447 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
448 self.assertIsInstance(tar.name, str)
449 self.assertEqual(tar.name, os.path.abspath(fobj.name))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000450
Thomas Woutersed03b412007-08-28 21:37:11 +0000451 def test_no_name_attribute(self):
Antoine Pitrou95f55602010-09-23 18:36:46 +0000452 with open(self.tarname, "rb") as fobj:
453 data = fobj.read()
Thomas Woutersed03b412007-08-28 21:37:11 +0000454 fobj = io.BytesIO(data)
455 self.assertRaises(AttributeError, getattr, fobj, "name")
456 tar = tarfile.open(fileobj=fobj, mode=self.mode)
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300457 self.assertIsNone(tar.name)
Thomas Woutersed03b412007-08-28 21:37:11 +0000458
459 def test_empty_name_attribute(self):
Antoine Pitrou95f55602010-09-23 18:36:46 +0000460 with open(self.tarname, "rb") as fobj:
461 data = fobj.read()
Thomas Woutersed03b412007-08-28 21:37:11 +0000462 fobj = io.BytesIO(data)
463 fobj.name = ""
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000464 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300465 self.assertIsNone(tar.name)
466
467 def test_int_name_attribute(self):
468 # Issue 21044: tarfile.open() should handle fileobj with an integer
469 # 'name' attribute.
470 fd = os.open(self.tarname, os.O_RDONLY)
471 with open(fd, 'rb') as fobj:
472 self.assertIsInstance(fobj.name, int)
473 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
474 self.assertIsNone(tar.name)
475
476 def test_bytes_name_attribute(self):
477 self.requires_name_attribute()
478 tarname = os.fsencode(self.tarname)
479 with open(tarname, 'rb') as fobj:
480 self.assertIsInstance(fobj.name, bytes)
481 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
482 self.assertIsInstance(tar.name, bytes)
483 self.assertEqual(tar.name, os.path.abspath(fobj.name))
Thomas Woutersed03b412007-08-28 21:37:11 +0000484
Serhiy Storchakac45cd162017-03-08 10:32:44 +0200485 def test_pathlike_name(self):
486 tarname = pathlib.Path(self.tarname)
487 with tarfile.open(tarname, mode=self.mode) as tar:
488 self.assertIsInstance(tar.name, str)
489 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
490 with self.taropen(tarname) as tar:
491 self.assertIsInstance(tar.name, str)
492 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
493 with tarfile.TarFile.open(tarname, mode=self.mode) as tar:
494 self.assertIsInstance(tar.name, str)
495 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
496 if self.suffix == '':
497 with tarfile.TarFile(tarname, mode='r') as tar:
498 self.assertIsInstance(tar.name, str)
499 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
500
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +0200501 def test_illegal_mode_arg(self):
502 with open(tmpname, 'wb'):
503 pass
504 with self.assertRaisesRegex(ValueError, 'mode must be '):
505 tar = self.taropen(tmpname, 'q')
506 with self.assertRaisesRegex(ValueError, 'mode must be '):
507 tar = self.taropen(tmpname, 'rw')
508 with self.assertRaisesRegex(ValueError, 'mode must be '):
509 tar = self.taropen(tmpname, '')
510
Christian Heimesd8654cf2007-12-02 15:22:16 +0000511 def test_fileobj_with_offset(self):
512 # Skip the first member and store values from the second member
513 # of the testtar.
514 tar = tarfile.open(self.tarname, mode=self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000515 try:
516 tar.next()
517 t = tar.next()
518 name = t.name
519 offset = t.offset
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200520 with tar.extractfile(t) as f:
521 data = f.read()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000522 finally:
523 tar.close()
Christian Heimesd8654cf2007-12-02 15:22:16 +0000524
525 # Open the testtar and seek to the offset of the second member.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300526 with self.open(self.tarname) as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000527 fobj.seek(offset)
Christian Heimesd8654cf2007-12-02 15:22:16 +0000528
Antoine Pitrou95f55602010-09-23 18:36:46 +0000529 # Test if the tarfile starts with the second member.
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +0200530 with tar.open(self.tarname, mode="r:", fileobj=fobj) as tar:
531 t = tar.next()
532 self.assertEqual(t.name, name)
533 # Read to the end of fileobj and test if seeking back to the
534 # beginning works.
535 tar.getmembers()
536 self.assertEqual(tar.extractfile(t).read(), data,
537 "seek back did not work")
Christian Heimesd8654cf2007-12-02 15:22:16 +0000538
Guido van Rossumd8faa362007-04-27 19:54:29 +0000539 def test_fail_comp(self):
540 # For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000541 self.assertRaises(tarfile.ReadError, tarfile.open, tarname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000542 with open(tarname, "rb") as fobj:
543 self.assertRaises(tarfile.ReadError, tarfile.open,
544 fileobj=fobj, mode=self.mode)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000545
546 def test_v7_dirtype(self):
547 # Test old style dirtype member (bug #1336623):
548 # Old V7 tars create directory members using an AREGTYPE
549 # header with a "/" appended to the filename field.
550 tarinfo = self.tar.getmember("misc/dirtype-old-v7")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300551 self.assertEqual(tarinfo.type, tarfile.DIRTYPE,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000552 "v7 dirtype failed")
553
Christian Heimes126d29a2008-02-11 22:57:17 +0000554 def test_xstar_type(self):
555 # The xstar format stores extra atime and ctime fields inside the
556 # space reserved for the prefix field. The prefix field must be
557 # ignored in this case, otherwise it will mess up the name.
558 try:
559 self.tar.getmember("misc/regtype-xstar")
560 except KeyError:
561 self.fail("failed to find misc/regtype-xstar (mangled prefix?)")
562
Guido van Rossumd8faa362007-04-27 19:54:29 +0000563 def test_check_members(self):
564 for tarinfo in self.tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300565 self.assertEqual(int(tarinfo.mtime), 0o7606136617,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000566 "wrong mtime for %s" % tarinfo.name)
567 if not tarinfo.name.startswith("ustar/"):
568 continue
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300569 self.assertEqual(tarinfo.uname, "tarfile",
Guido van Rossumd8faa362007-04-27 19:54:29 +0000570 "wrong uname for %s" % tarinfo.name)
571
572 def test_find_members(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300573 self.assertEqual(self.tar.getmembers()[-1].name, "misc/eof",
Guido van Rossumd8faa362007-04-27 19:54:29 +0000574 "could not find all members")
575
Brian Curtin74e45612010-07-09 15:58:59 +0000576 @unittest.skipUnless(hasattr(os, "link"),
577 "Missing hardlink implementation")
Brian Curtin3b4499c2010-12-28 14:31:47 +0000578 @support.skip_unless_symlink
Guido van Rossumd8faa362007-04-27 19:54:29 +0000579 def test_extract_hardlink(self):
580 # Test hardlink extraction (e.g. bug #857297).
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200581 with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000582 tar.extract("ustar/regtype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100583 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/regtype"))
Neal Norwitzf3396542005-10-28 05:52:22 +0000584
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200585 tar.extract("ustar/lnktype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100586 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype"))
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000587 with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
588 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +0200589 self.assertEqual(sha256sum(data), sha256_regtype)
Neal Norwitzf3396542005-10-28 05:52:22 +0000590
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200591 tar.extract("ustar/symtype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100592 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype"))
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000593 with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
594 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +0200595 self.assertEqual(sha256sum(data), sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000596
Christian Heimesfaf2f632008-01-06 16:59:19 +0000597 def test_extractall(self):
598 # Test if extractall() correctly restores directory permissions
599 # and times (see issue1735).
Christian Heimesfaf2f632008-01-06 16:59:19 +0000600 tar = tarfile.open(tarname, encoding="iso8859-1")
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000601 DIR = os.path.join(TEMPDIR, "extractall")
602 os.mkdir(DIR)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000603 try:
604 directories = [t for t in tar if t.isdir()]
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000605 tar.extractall(DIR, directories)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000606 for tarinfo in directories:
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000607 path = os.path.join(DIR, tarinfo.name)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000608 if sys.platform != "win32":
609 # Win32 has no support for fine grained permissions.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300610 self.assertEqual(tarinfo.mode & 0o777,
611 os.stat(path).st_mode & 0o777)
Victor Stinner26bfb5a2010-10-29 10:59:08 +0000612 def format_mtime(mtime):
613 if isinstance(mtime, float):
614 return "{} ({})".format(mtime, mtime.hex())
615 else:
616 return "{!r} (int)".format(mtime)
Victor Stinner14d8fe72010-10-29 11:02:06 +0000617 file_mtime = os.path.getmtime(path)
Victor Stinner26bfb5a2010-10-29 10:59:08 +0000618 errmsg = "tar mtime {0} != file time {1} of path {2!a}".format(
619 format_mtime(tarinfo.mtime),
620 format_mtime(file_mtime),
621 path)
622 self.assertEqual(tarinfo.mtime, file_mtime, errmsg)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000623 finally:
624 tar.close()
Tim Goldene0bd2c52014-05-06 13:24:26 +0100625 support.rmtree(DIR)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000626
Martin v. Löwis16f344d2010-11-01 21:39:13 +0000627 def test_extract_directory(self):
628 dirtype = "ustar/dirtype"
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000629 DIR = os.path.join(TEMPDIR, "extractdir")
630 os.mkdir(DIR)
631 try:
632 with tarfile.open(tarname, encoding="iso8859-1") as tar:
633 tarinfo = tar.getmember(dirtype)
634 tar.extract(tarinfo, path=DIR)
635 extracted = os.path.join(DIR, dirtype)
636 self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
637 if sys.platform != "win32":
638 self.assertEqual(os.stat(extracted).st_mode & 0o777, 0o755)
639 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +0100640 support.rmtree(DIR)
Martin v. Löwis16f344d2010-11-01 21:39:13 +0000641
Serhiy Storchakac45cd162017-03-08 10:32:44 +0200642 def test_extractall_pathlike_name(self):
643 DIR = pathlib.Path(TEMPDIR) / "extractall"
644 with support.temp_dir(DIR), \
645 tarfile.open(tarname, encoding="iso8859-1") as tar:
646 directories = [t for t in tar if t.isdir()]
647 tar.extractall(DIR, directories)
648 for tarinfo in directories:
649 path = DIR / tarinfo.name
650 self.assertEqual(os.path.getmtime(path), tarinfo.mtime)
651
652 def test_extract_pathlike_name(self):
653 dirtype = "ustar/dirtype"
654 DIR = pathlib.Path(TEMPDIR) / "extractall"
655 with support.temp_dir(DIR), \
656 tarfile.open(tarname, encoding="iso8859-1") as tar:
657 tarinfo = tar.getmember(dirtype)
658 tar.extract(tarinfo, path=DIR)
659 extracted = DIR / dirtype
660 self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
661
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000662 def test_init_close_fobj(self):
663 # Issue #7341: Close the internal file object in the TarFile
664 # constructor in case of an error. For the test we rely on
665 # the fact that opening an empty file raises a ReadError.
666 empty = os.path.join(TEMPDIR, "empty")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000667 with open(empty, "wb") as fobj:
668 fobj.write(b"")
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000669
670 try:
671 tar = object.__new__(tarfile.TarFile)
672 try:
673 tar.__init__(empty)
674 except tarfile.ReadError:
675 self.assertTrue(tar.fileobj.closed)
676 else:
677 self.fail("ReadError not raised")
678 finally:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000679 support.unlink(empty)
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000680
Serhiy Storchaka263fab92013-05-09 14:22:26 +0300681 def test_parallel_iteration(self):
682 # Issue #16601: Restarting iteration over tarfile continued
683 # from where it left off.
684 with tarfile.open(self.tarname) as tar:
685 for m1, m2 in zip(tar, tar):
686 self.assertEqual(m1.offset, m2.offset)
687 self.assertEqual(m1.get_info(), m2.get_info())
688
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300689class MiscReadTest(MiscReadTestBase, unittest.TestCase):
690 test_fail_comp = None
Guido van Rossumd8faa362007-04-27 19:54:29 +0000691
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300692class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase):
Serhiy Storchakaf22fe0f2014-01-13 19:08:00 +0200693 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000694
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300695class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300696 def requires_name_attribute(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300697 self.skipTest("BZ2File have no name attribute")
698
699class LzmaMiscReadTest(LzmaTest, MiscReadTestBase, unittest.TestCase):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300700 def requires_name_attribute(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300701 self.skipTest("LZMAFile have no name attribute")
702
703
704class StreamReadTest(CommonReadTest, unittest.TestCase):
705
706 prefix="r|"
Guido van Rossumd8faa362007-04-27 19:54:29 +0000707
Lars Gustäbeldd071042011-02-23 11:42:22 +0000708 def test_read_through(self):
709 # Issue #11224: A poorly designed _FileInFile.read() method
710 # caused seeking errors with stream tar files.
711 for tarinfo in self.tar:
712 if not tarinfo.isreg():
713 continue
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200714 with self.tar.extractfile(tarinfo) as fobj:
715 while True:
716 try:
717 buf = fobj.read(512)
718 except tarfile.StreamError:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300719 self.fail("simple read-through using "
720 "TarFile.extractfile() failed")
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200721 if not buf:
722 break
Lars Gustäbeldd071042011-02-23 11:42:22 +0000723
Guido van Rossumd8faa362007-04-27 19:54:29 +0000724 def test_fileobj_regular_file(self):
725 tarinfo = self.tar.next() # get "regtype" (can't use getmember)
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200726 with self.tar.extractfile(tarinfo) as fobj:
727 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300728 self.assertEqual(len(data), tarinfo.size,
729 "regular file extraction failed")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200730 self.assertEqual(sha256sum(data), sha256_regtype,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000731 "regular file extraction failed")
732
733 def test_provoke_stream_error(self):
734 tarinfos = self.tar.getmembers()
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200735 with self.tar.extractfile(tarinfos[0]) as f: # read the first member
736 self.assertRaises(tarfile.StreamError, f.read)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000737
Guido van Rossumd8faa362007-04-27 19:54:29 +0000738 def test_compare_members(self):
739 tar1 = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000740 try:
741 tar2 = self.tar
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000742
Antoine Pitrou95f55602010-09-23 18:36:46 +0000743 while True:
744 t1 = tar1.next()
745 t2 = tar2.next()
746 if t1 is None:
747 break
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300748 self.assertIsNotNone(t2, "stream.next() failed.")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000749
Antoine Pitrou95f55602010-09-23 18:36:46 +0000750 if t2.islnk() or t2.issym():
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300751 with self.assertRaises(tarfile.StreamError):
752 tar2.extractfile(t2)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000753 continue
Guido van Rossumd8faa362007-04-27 19:54:29 +0000754
Antoine Pitrou95f55602010-09-23 18:36:46 +0000755 v1 = tar1.extractfile(t1)
756 v2 = tar2.extractfile(t2)
757 if v1 is None:
758 continue
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300759 self.assertIsNotNone(v2, "stream.extractfile() failed")
760 self.assertEqual(v1.read(), v2.read(),
761 "stream extraction failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000762 finally:
763 tar1.close()
Thomas Wouters902d6eb2007-01-09 23:18:33 +0000764
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300765class GzipStreamReadTest(GzipTest, StreamReadTest):
766 pass
Thomas Wouters89f507f2006-12-13 04:49:30 +0000767
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300768class Bz2StreamReadTest(Bz2Test, StreamReadTest):
769 pass
Thomas Wouterscf297e42007-02-23 15:07:44 +0000770
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300771class LzmaStreamReadTest(LzmaTest, StreamReadTest):
772 pass
773
774
775class DetectReadTest(TarTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000776 def _testfunc_file(self, name, mode):
777 try:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000778 tar = tarfile.open(name, mode)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000779 except tarfile.ReadError as e:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000780 self.fail()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000781 else:
782 tar.close()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000783
Guido van Rossumd8faa362007-04-27 19:54:29 +0000784 def _testfunc_fileobj(self, name, mode):
785 try:
Antoine Pitrou605c2932010-09-23 20:15:14 +0000786 with open(name, "rb") as f:
787 tar = tarfile.open(name, mode, fileobj=f)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000788 except tarfile.ReadError as e:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000789 self.fail()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000790 else:
791 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000792
793 def _test_modes(self, testfunc):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300794 if self.suffix:
795 with self.assertRaises(tarfile.ReadError):
796 tarfile.open(tarname, mode="r:" + self.suffix)
797 with self.assertRaises(tarfile.ReadError):
798 tarfile.open(tarname, mode="r|" + self.suffix)
799 with self.assertRaises(tarfile.ReadError):
800 tarfile.open(self.tarname, mode="r:")
801 with self.assertRaises(tarfile.ReadError):
802 tarfile.open(self.tarname, mode="r|")
803 testfunc(self.tarname, "r")
804 testfunc(self.tarname, "r:" + self.suffix)
805 testfunc(self.tarname, "r:*")
806 testfunc(self.tarname, "r|" + self.suffix)
807 testfunc(self.tarname, "r|*")
Lars Gustäbel0a9dd2f2011-12-10 20:38:14 +0100808
Guido van Rossumd8faa362007-04-27 19:54:29 +0000809 def test_detect_file(self):
810 self._test_modes(self._testfunc_file)
811
812 def test_detect_fileobj(self):
813 self._test_modes(self._testfunc_fileobj)
814
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300815class GzipDetectReadTest(GzipTest, DetectReadTest):
816 pass
817
818class Bz2DetectReadTest(Bz2Test, DetectReadTest):
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100819 def test_detect_stream_bz2(self):
820 # Originally, tarfile's stream detection looked for the string
821 # "BZh91" at the start of the file. This is incorrect because
Victor Stinner8c663fd2017-11-08 14:44:44 -0800822 # the '9' represents the blocksize (900,000 bytes). If the file was
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100823 # compressed using another blocksize autodetection fails.
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100824 with open(tarname, "rb") as fobj:
825 data = fobj.read()
826
Victor Stinner8c663fd2017-11-08 14:44:44 -0800827 # Compress with blocksize 100,000 bytes, the file starts with "BZh11".
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100828 with bz2.BZ2File(tmpname, "wb", compresslevel=1) as fobj:
829 fobj.write(data)
830
831 self._testfunc_file(tmpname, "r|*")
832
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300833class LzmaDetectReadTest(LzmaTest, DetectReadTest):
834 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000835
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300836
837class MemberReadTest(ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000838
839 def _test_member(self, tarinfo, chksum=None, **kwargs):
840 if chksum is not None:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300841 with self.tar.extractfile(tarinfo) as f:
Christian Heimesc64a1a62019-09-25 16:30:20 +0200842 self.assertEqual(sha256sum(f.read()), chksum,
843 "wrong sha256sum for %s" % tarinfo.name)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000844
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000845 kwargs["mtime"] = 0o7606136617
Guido van Rossumd8faa362007-04-27 19:54:29 +0000846 kwargs["uid"] = 1000
847 kwargs["gid"] = 100
848 if "old-v7" not in tarinfo.name:
849 # V7 tar can't handle alphabetic owners.
850 kwargs["uname"] = "tarfile"
851 kwargs["gname"] = "tarfile"
852 for k, v in kwargs.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300853 self.assertEqual(getattr(tarinfo, k), v,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000854 "wrong value in %s field of %s" % (k, tarinfo.name))
855
856 def test_find_regtype(self):
857 tarinfo = self.tar.getmember("ustar/regtype")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200858 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000859
860 def test_find_conttype(self):
861 tarinfo = self.tar.getmember("ustar/conttype")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200862 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000863
864 def test_find_dirtype(self):
865 tarinfo = self.tar.getmember("ustar/dirtype")
866 self._test_member(tarinfo, size=0)
867
868 def test_find_dirtype_with_size(self):
869 tarinfo = self.tar.getmember("ustar/dirtype-with-size")
870 self._test_member(tarinfo, size=255)
871
872 def test_find_lnktype(self):
873 tarinfo = self.tar.getmember("ustar/lnktype")
874 self._test_member(tarinfo, size=0, linkname="ustar/regtype")
875
876 def test_find_symtype(self):
877 tarinfo = self.tar.getmember("ustar/symtype")
878 self._test_member(tarinfo, size=0, linkname="regtype")
879
880 def test_find_blktype(self):
881 tarinfo = self.tar.getmember("ustar/blktype")
882 self._test_member(tarinfo, size=0, devmajor=3, devminor=0)
883
884 def test_find_chrtype(self):
885 tarinfo = self.tar.getmember("ustar/chrtype")
886 self._test_member(tarinfo, size=0, devmajor=1, devminor=3)
887
888 def test_find_fifotype(self):
889 tarinfo = self.tar.getmember("ustar/fifotype")
890 self._test_member(tarinfo, size=0)
891
892 def test_find_sparse(self):
893 tarinfo = self.tar.getmember("ustar/sparse")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200894 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000895
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000896 def test_find_gnusparse(self):
897 tarinfo = self.tar.getmember("gnu/sparse")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200898 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000899
900 def test_find_gnusparse_00(self):
901 tarinfo = self.tar.getmember("gnu/sparse-0.0")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200902 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000903
904 def test_find_gnusparse_01(self):
905 tarinfo = self.tar.getmember("gnu/sparse-0.1")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200906 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000907
908 def test_find_gnusparse_10(self):
909 tarinfo = self.tar.getmember("gnu/sparse-1.0")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200910 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000911
Guido van Rossumd8faa362007-04-27 19:54:29 +0000912 def test_find_umlauts(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300913 tarinfo = self.tar.getmember("ustar/umlauts-"
914 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200915 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000916
917 def test_find_ustar_longname(self):
918 name = "ustar/" + "12345/" * 39 + "1234567/longname"
Benjamin Peterson577473f2010-01-19 00:09:57 +0000919 self.assertIn(name, self.tar.getnames())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000920
921 def test_find_regtype_oldv7(self):
922 tarinfo = self.tar.getmember("misc/regtype-old-v7")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200923 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000924
925 def test_find_pax_umlauts(self):
Antoine Pitrouab58b5f2010-09-23 19:39:35 +0000926 self.tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300927 self.tar = tarfile.open(self.tarname, mode=self.mode,
928 encoding="iso8859-1")
929 tarinfo = self.tar.getmember("pax/umlauts-"
930 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200931 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000932
933
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300934class LongnameTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000935
936 def test_read_longname(self):
937 # Test reading of longname (bug #1471427).
Guido van Rossume7ba4952007-06-06 23:52:48 +0000938 longname = self.subdir + "/" + "123/" * 125 + "longname"
Guido van Rossumd8faa362007-04-27 19:54:29 +0000939 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000940 tarinfo = self.tar.getmember(longname)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941 except KeyError:
942 self.fail("longname not found")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300943 self.assertNotEqual(tarinfo.type, tarfile.DIRTYPE,
944 "read longname as dirtype")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000945
946 def test_read_longlink(self):
947 longname = self.subdir + "/" + "123/" * 125 + "longname"
948 longlink = self.subdir + "/" + "123/" * 125 + "longlink"
949 try:
950 tarinfo = self.tar.getmember(longlink)
951 except KeyError:
952 self.fail("longlink not found")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300953 self.assertEqual(tarinfo.linkname, longname, "linkname wrong")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000954
955 def test_truncated_longname(self):
956 longname = self.subdir + "/" + "123/" * 125 + "longname"
957 tarinfo = self.tar.getmember(longname)
958 offset = tarinfo.offset
959 self.tar.fileobj.seek(offset)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000960 fobj = io.BytesIO(self.tar.fileobj.read(3 * 512))
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300961 with self.assertRaises(tarfile.ReadError):
962 tarfile.open(name="foo.tar", fileobj=fobj)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000963
Guido van Rossume7ba4952007-06-06 23:52:48 +0000964 def test_header_offset(self):
965 # Test if the start offset of the TarInfo object includes
966 # the preceding extended header.
967 longname = self.subdir + "/" + "123/" * 125 + "longname"
968 offset = self.tar.getmember(longname).offset
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000969 with open(tarname, "rb") as fobj:
970 fobj.seek(offset)
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300971 tarinfo = tarfile.TarInfo.frombuf(fobj.read(512),
972 "iso8859-1", "strict")
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000973 self.assertEqual(tarinfo.type, self.longnametype)
Guido van Rossume7ba4952007-06-06 23:52:48 +0000974
Guido van Rossumd8faa362007-04-27 19:54:29 +0000975
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300976class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000977
978 subdir = "gnu"
Guido van Rossume7ba4952007-06-06 23:52:48 +0000979 longnametype = tarfile.GNUTYPE_LONGNAME
Guido van Rossumd8faa362007-04-27 19:54:29 +0000980
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000981 # Since 3.2 tarfile is supposed to accurately restore sparse members and
982 # produce files with holes. This is what we actually want to test here.
983 # Unfortunately, not all platforms/filesystems support sparse files, and
984 # even on platforms that do it is non-trivial to make reliable assertions
985 # about holes in files. Therefore, we first do one basic test which works
986 # an all platforms, and after that a test that will work only on
987 # platforms/filesystems that prove to support sparse files.
988 def _test_sparse_file(self, name):
989 self.tar.extract(name, TEMPDIR)
990 filename = os.path.join(TEMPDIR, name)
991 with open(filename, "rb") as fobj:
992 data = fobj.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +0200993 self.assertEqual(sha256sum(data), sha256_sparse,
994 "wrong sha256sum for %s" % name)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000995
996 if self._fs_supports_holes():
997 s = os.stat(filename)
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300998 self.assertLess(s.st_blocks * 512, s.st_size)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000999
1000 def test_sparse_file_old(self):
1001 self._test_sparse_file("gnu/sparse")
1002
1003 def test_sparse_file_00(self):
1004 self._test_sparse_file("gnu/sparse-0.0")
1005
1006 def test_sparse_file_01(self):
1007 self._test_sparse_file("gnu/sparse-0.1")
1008
1009 def test_sparse_file_10(self):
1010 self._test_sparse_file("gnu/sparse-1.0")
1011
1012 @staticmethod
1013 def _fs_supports_holes():
1014 # Return True if the platform knows the st_blocks stat attribute and
1015 # uses st_blocks units of 512 bytes, and if the filesystem is able to
Victor Stinnerb2385452019-01-21 10:24:12 +01001016 # store holes of 4 KiB in files.
1017 #
1018 # The function returns False if page size is larger than 4 KiB.
1019 # For example, ppc64 uses pages of 64 KiB.
Victor Stinner9c3de4a2011-08-17 20:49:41 +02001020 if sys.platform.startswith("linux"):
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001021 # Linux evidentially has 512 byte st_blocks units.
1022 name = os.path.join(TEMPDIR, "sparse-test")
1023 with open(name, "wb") as fobj:
Victor Stinnerb2385452019-01-21 10:24:12 +01001024 # Seek to "punch a hole" of 4 KiB
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001025 fobj.seek(4096)
Victor Stinnerb2385452019-01-21 10:24:12 +01001026 fobj.write(b'x' * 4096)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001027 fobj.truncate()
1028 s = os.stat(name)
Tim Goldene0bd2c52014-05-06 13:24:26 +01001029 support.unlink(name)
Victor Stinnerb2385452019-01-21 10:24:12 +01001030 return (s.st_blocks * 512 < s.st_size)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001031 else:
1032 return False
Guido van Rossumd8faa362007-04-27 19:54:29 +00001033
1034
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001035class PaxReadTest(LongnameTest, ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001036
1037 subdir = "pax"
Guido van Rossume7ba4952007-06-06 23:52:48 +00001038 longnametype = tarfile.XHDTYPE
Guido van Rossumd8faa362007-04-27 19:54:29 +00001039
Guido van Rossume7ba4952007-06-06 23:52:48 +00001040 def test_pax_global_headers(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001041 tar = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001042 try:
1043 tarinfo = tar.getmember("pax/regtype1")
1044 self.assertEqual(tarinfo.uname, "foo")
1045 self.assertEqual(tarinfo.gname, "bar")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001046 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1047 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Guido van Rossume7ba4952007-06-06 23:52:48 +00001048
Antoine Pitrou95f55602010-09-23 18:36:46 +00001049 tarinfo = tar.getmember("pax/regtype2")
1050 self.assertEqual(tarinfo.uname, "")
1051 self.assertEqual(tarinfo.gname, "bar")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001052 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1053 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001054
Antoine Pitrou95f55602010-09-23 18:36:46 +00001055 tarinfo = tar.getmember("pax/regtype3")
1056 self.assertEqual(tarinfo.uname, "tarfile")
1057 self.assertEqual(tarinfo.gname, "tarfile")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001058 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1059 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001060 finally:
1061 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001062
1063 def test_pax_number_fields(self):
1064 # All following number fields are read from the pax header.
1065 tar = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001066 try:
1067 tarinfo = tar.getmember("pax/regtype4")
1068 self.assertEqual(tarinfo.size, 7011)
1069 self.assertEqual(tarinfo.uid, 123)
1070 self.assertEqual(tarinfo.gid, 123)
1071 self.assertEqual(tarinfo.mtime, 1041808783.0)
1072 self.assertEqual(type(tarinfo.mtime), float)
1073 self.assertEqual(float(tarinfo.pax_headers["atime"]), 1041808783.0)
1074 self.assertEqual(float(tarinfo.pax_headers["ctime"]), 1041808783.0)
1075 finally:
1076 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001077
1078
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001079class WriteTestBase(TarTest):
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001080 # Put all write tests in here that are supposed to be tested
1081 # in all possible mode combinations.
1082
1083 def test_fileobj_no_close(self):
1084 fobj = io.BytesIO()
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001085 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
1086 tar.addfile(tarfile.TarInfo("foo"))
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001087 self.assertFalse(fobj.closed, "external fileobjs must never closed")
Serhiy Storchaka9fbec7a2014-01-18 15:53:05 +02001088 # Issue #20238: Incomplete gzip output with mode="w:gz"
1089 data = fobj.getvalue()
1090 del tar
1091 support.gc_collect()
1092 self.assertFalse(fobj.closed)
1093 self.assertEqual(data, fobj.getvalue())
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001094
Lars Gustäbel20703c62015-05-27 12:53:44 +02001095 def test_eof_marker(self):
1096 # Make sure an end of archive marker is written (two zero blocks).
1097 # tarfile insists on aligning archives to a 20 * 512 byte recordsize.
1098 # So, we create an archive that has exactly 10240 bytes without the
1099 # marker, and has 20480 bytes once the marker is written.
1100 with tarfile.open(tmpname, self.mode) as tar:
1101 t = tarfile.TarInfo("foo")
1102 t.size = tarfile.RECORDSIZE - tarfile.BLOCKSIZE
1103 tar.addfile(t, io.BytesIO(b"a" * t.size))
1104
1105 with self.open(tmpname, "rb") as fobj:
1106 self.assertEqual(len(fobj.read()), tarfile.RECORDSIZE * 2)
1107
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001108
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001109class WriteTest(WriteTestBase, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001110
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001111 prefix = "w:"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001112
1113 def test_100_char_name(self):
1114 # The name field in a tar header stores strings of at most 100 chars.
1115 # If a string is shorter than 100 chars it has to be padded with '\0',
1116 # which implies that a string of exactly 100 chars is stored without
1117 # a trailing '\0'.
1118 name = "0123456789" * 10
1119 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001120 try:
1121 t = tarfile.TarInfo(name)
1122 tar.addfile(t)
1123 finally:
1124 tar.close()
Thomas Wouterscf297e42007-02-23 15:07:44 +00001125
Guido van Rossumd8faa362007-04-27 19:54:29 +00001126 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001127 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001128 self.assertEqual(tar.getnames()[0], name,
Antoine Pitrou95f55602010-09-23 18:36:46 +00001129 "failed to store 100 char filename")
1130 finally:
1131 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001132
Guido van Rossumd8faa362007-04-27 19:54:29 +00001133 def test_tar_size(self):
1134 # Test for bug #1013882.
1135 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001136 try:
1137 path = os.path.join(TEMPDIR, "file")
1138 with open(path, "wb") as fobj:
1139 fobj.write(b"aaa")
1140 tar.add(path)
1141 finally:
1142 tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001143 self.assertGreater(os.path.getsize(tmpname), 0,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001144 "tarfile is empty")
Thomas Wouters89f507f2006-12-13 04:49:30 +00001145
Guido van Rossumd8faa362007-04-27 19:54:29 +00001146 # The test_*_size tests test for bug #1167128.
1147 def test_file_size(self):
1148 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001149 try:
1150 path = os.path.join(TEMPDIR, "file")
1151 with open(path, "wb"):
1152 pass
1153 tarinfo = tar.gettarinfo(path)
1154 self.assertEqual(tarinfo.size, 0)
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001155
Antoine Pitrou95f55602010-09-23 18:36:46 +00001156 with open(path, "wb") as fobj:
1157 fobj.write(b"aaa")
1158 tarinfo = tar.gettarinfo(path)
1159 self.assertEqual(tarinfo.size, 3)
1160 finally:
1161 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001162
1163 def test_directory_size(self):
1164 path = os.path.join(TEMPDIR, "directory")
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001165 os.mkdir(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001166 try:
1167 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001168 try:
1169 tarinfo = tar.gettarinfo(path)
1170 self.assertEqual(tarinfo.size, 0)
1171 finally:
1172 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001173 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001174 support.rmdir(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001175
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001176 # mock the following:
1177 # os.listdir: so we know that files are in the wrong order
Bernhard M. Wiedemann4ad703b2018-02-06 19:08:53 +01001178 def test_ordered_recursion(self):
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001179 path = os.path.join(TEMPDIR, "directory")
1180 os.mkdir(path)
1181 open(os.path.join(path, "1"), "a").close()
1182 open(os.path.join(path, "2"), "a").close()
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001183 try:
1184 tar = tarfile.open(tmpname, self.mode)
1185 try:
Bernhard M. Wiedemann4ad703b2018-02-06 19:08:53 +01001186 with unittest.mock.patch('os.listdir') as mock_listdir:
1187 mock_listdir.return_value = ["2", "1"]
1188 tar.add(path)
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001189 paths = []
1190 for m in tar.getmembers():
1191 paths.append(os.path.split(m.name)[-1])
1192 self.assertEqual(paths, ["directory", "1", "2"]);
1193 finally:
1194 tar.close()
1195 finally:
1196 support.unlink(os.path.join(path, "1"))
1197 support.unlink(os.path.join(path, "2"))
1198 support.rmdir(path)
1199
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001200 def test_gettarinfo_pathlike_name(self):
1201 with tarfile.open(tmpname, self.mode) as tar:
1202 path = pathlib.Path(TEMPDIR) / "file"
1203 with open(path, "wb") as fobj:
1204 fobj.write(b"aaa")
1205 tarinfo = tar.gettarinfo(path)
1206 tarinfo2 = tar.gettarinfo(os.fspath(path))
1207 self.assertIsInstance(tarinfo.name, str)
1208 self.assertEqual(tarinfo.name, tarinfo2.name)
1209 self.assertEqual(tarinfo.size, 3)
1210
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001211 @unittest.skipUnless(hasattr(os, "link"),
1212 "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001213 def test_link_size(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001214 link = os.path.join(TEMPDIR, "link")
1215 target = os.path.join(TEMPDIR, "link_target")
1216 with open(target, "wb") as fobj:
1217 fobj.write(b"aaa")
xdegayed7d4fea2017-11-12 18:02:06 +01001218 try:
1219 os.link(target, link)
1220 except PermissionError as e:
1221 self.skipTest('os.link(): %s' % e)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001222 try:
1223 tar = tarfile.open(tmpname, self.mode)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001224 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001225 # Record the link target in the inodes list.
1226 tar.gettarinfo(target)
1227 tarinfo = tar.gettarinfo(link)
1228 self.assertEqual(tarinfo.size, 0)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001229 finally:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001230 tar.close()
1231 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001232 support.unlink(target)
1233 support.unlink(link)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001234
Brian Curtin3b4499c2010-12-28 14:31:47 +00001235 @support.skip_unless_symlink
Guido van Rossumd8faa362007-04-27 19:54:29 +00001236 def test_symlink_size(self):
Brian Curtind40e6f72010-07-08 21:39:08 +00001237 path = os.path.join(TEMPDIR, "symlink")
1238 os.symlink("link_target", path)
1239 try:
1240 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001241 try:
1242 tarinfo = tar.gettarinfo(path)
1243 self.assertEqual(tarinfo.size, 0)
1244 finally:
1245 tar.close()
Brian Curtind40e6f72010-07-08 21:39:08 +00001246 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001247 support.unlink(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001248
1249 def test_add_self(self):
1250 # Test for #1257255.
1251 dstname = os.path.abspath(tmpname)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001252 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001253 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001254 self.assertEqual(tar.name, dstname,
1255 "archive name must be absolute")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001256 tar.add(dstname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001257 self.assertEqual(tar.getnames(), [],
1258 "added the archive to itself")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001259
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001260 with support.change_cwd(TEMPDIR):
1261 tar.add(dstname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001262 self.assertEqual(tar.getnames(), [],
1263 "added the archive to itself")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001264 finally:
1265 tar.close()
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001266
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001267 def test_filter(self):
1268 tempdir = os.path.join(TEMPDIR, "filter")
1269 os.mkdir(tempdir)
1270 try:
1271 for name in ("foo", "bar", "baz"):
1272 name = os.path.join(tempdir, name)
Victor Stinnerbf816222011-06-30 23:25:47 +02001273 support.create_empty_file(name)
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001274
1275 def filter(tarinfo):
1276 if os.path.basename(tarinfo.name) == "bar":
1277 return
1278 tarinfo.uid = 123
1279 tarinfo.uname = "foo"
1280 return tarinfo
1281
1282 tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001283 try:
1284 tar.add(tempdir, arcname="empty_dir", filter=filter)
1285 finally:
1286 tar.close()
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001287
Raymond Hettingera63a3122011-01-26 20:34:14 +00001288 # Verify that filter is a keyword-only argument
1289 with self.assertRaises(TypeError):
1290 tar.add(tempdir, "empty_dir", True, None, filter)
1291
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001292 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001293 try:
1294 for tarinfo in tar:
1295 self.assertEqual(tarinfo.uid, 123)
1296 self.assertEqual(tarinfo.uname, "foo")
1297 self.assertEqual(len(tar.getmembers()), 3)
1298 finally:
1299 tar.close()
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001300 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001301 support.rmtree(tempdir)
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001302
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001303 # Guarantee that stored pathnames are not modified. Don't
1304 # remove ./ or ../ or double slashes. Still make absolute
1305 # pathnames relative.
1306 # For details see bug #6054.
1307 def _test_pathname(self, path, cmp_path=None, dir=False):
1308 # Create a tarfile with an empty member named path
1309 # and compare the stored name with the original.
1310 foo = os.path.join(TEMPDIR, "foo")
1311 if not dir:
Victor Stinnerbf816222011-06-30 23:25:47 +02001312 support.create_empty_file(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001313 else:
1314 os.mkdir(foo)
1315
1316 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001317 try:
1318 tar.add(foo, arcname=path)
1319 finally:
1320 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001321
1322 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001323 try:
1324 t = tar.next()
1325 finally:
1326 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001327
1328 if not dir:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001329 support.unlink(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001330 else:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001331 support.rmdir(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001332
1333 self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/"))
1334
Senthil Kumaranbe5dbeb2011-04-30 06:09:51 +08001335
1336 @support.skip_unless_symlink
Senthil Kumaran123932f2011-04-28 15:38:12 +08001337 def test_extractall_symlinks(self):
1338 # Test if extractall works properly when tarfile contains symlinks
1339 tempdir = os.path.join(TEMPDIR, "testsymlinks")
1340 temparchive = os.path.join(TEMPDIR, "testsymlinks.tar")
1341 os.mkdir(tempdir)
1342 try:
1343 source_file = os.path.join(tempdir,'source')
1344 target_file = os.path.join(tempdir,'symlink')
1345 with open(source_file,'w') as f:
1346 f.write('something\n')
1347 os.symlink(source_file, target_file)
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001348 with tarfile.open(temparchive, 'w') as tar:
1349 tar.add(source_file)
1350 tar.add(target_file)
Senthil Kumaran123932f2011-04-28 15:38:12 +08001351 # Let's extract it to the location which contains the symlink
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001352 with tarfile.open(temparchive) as tar:
1353 # this should not raise OSError: [Errno 17] File exists
1354 try:
1355 tar.extractall(path=tempdir)
1356 except OSError:
1357 self.fail("extractall failed with symlinked files")
Senthil Kumaran123932f2011-04-28 15:38:12 +08001358 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001359 support.unlink(temparchive)
1360 support.rmtree(tempdir)
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001361
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001362 def test_pathnames(self):
1363 self._test_pathname("foo")
1364 self._test_pathname(os.path.join("foo", ".", "bar"))
1365 self._test_pathname(os.path.join("foo", "..", "bar"))
1366 self._test_pathname(os.path.join(".", "foo"))
1367 self._test_pathname(os.path.join(".", "foo", "."))
1368 self._test_pathname(os.path.join(".", "foo", ".", "bar"))
1369 self._test_pathname(os.path.join(".", "foo", "..", "bar"))
1370 self._test_pathname(os.path.join(".", "foo", "..", "bar"))
1371 self._test_pathname(os.path.join("..", "foo"))
1372 self._test_pathname(os.path.join("..", "foo", ".."))
1373 self._test_pathname(os.path.join("..", "foo", ".", "bar"))
1374 self._test_pathname(os.path.join("..", "foo", "..", "bar"))
1375
1376 self._test_pathname("foo" + os.sep + os.sep + "bar")
1377 self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True)
1378
1379 def test_abs_pathnames(self):
1380 if sys.platform == "win32":
1381 self._test_pathname("C:\\foo", "foo")
1382 else:
1383 self._test_pathname("/foo", "foo")
1384 self._test_pathname("///foo", "foo")
1385
1386 def test_cwd(self):
1387 # Test adding the current working directory.
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001388 with support.change_cwd(TEMPDIR):
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001389 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001390 try:
1391 tar.add(".")
1392 finally:
1393 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001394
1395 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001396 try:
1397 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001398 if t.name != ".":
1399 self.assertTrue(t.name.startswith("./"), t.name)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001400 finally:
1401 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001402
Serhiy Storchakac2d01422014-01-18 16:14:10 +02001403 def test_open_nonwritable_fileobj(self):
1404 for exctype in OSError, EOFError, RuntimeError:
1405 class BadFile(io.BytesIO):
1406 first = True
1407 def write(self, data):
1408 if self.first:
1409 self.first = False
1410 raise exctype
1411
1412 f = BadFile()
1413 with self.assertRaises(exctype):
1414 tar = tarfile.open(tmpname, self.mode, fileobj=f,
1415 format=tarfile.PAX_FORMAT,
1416 pax_headers={'non': 'empty'})
1417 self.assertFalse(f.closed)
1418
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001419class GzipWriteTest(GzipTest, WriteTest):
1420 pass
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001421
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001422class Bz2WriteTest(Bz2Test, WriteTest):
1423 pass
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001424
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001425class LzmaWriteTest(LzmaTest, WriteTest):
1426 pass
1427
1428
1429class StreamWriteTest(WriteTestBase, unittest.TestCase):
1430
1431 prefix = "w|"
1432 decompressor = None
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001433
Guido van Rossumd8faa362007-04-27 19:54:29 +00001434 def test_stream_padding(self):
1435 # Test for bug #1543303.
1436 tar = tarfile.open(tmpname, self.mode)
1437 tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001438 if self.decompressor:
1439 dec = self.decompressor()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001440 with open(tmpname, "rb") as fobj:
1441 data = fobj.read()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001442 data = dec.decompress(data)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001443 self.assertFalse(dec.unused_data, "found trailing data")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001444 else:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001445 with self.open(tmpname) as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +00001446 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001447 self.assertEqual(data.count(b"\0"), tarfile.RECORDSIZE,
1448 "incorrect zero padding")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001449
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001450 @unittest.skipUnless(sys.platform != "win32" and hasattr(os, "umask"),
1451 "Missing umask implementation")
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001452 def test_file_mode(self):
1453 # Test for issue #8464: Create files with correct
1454 # permissions.
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001455 if os.path.exists(tmpname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01001456 support.unlink(tmpname)
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001457
1458 original_umask = os.umask(0o022)
1459 try:
1460 tar = tarfile.open(tmpname, self.mode)
1461 tar.close()
1462 mode = os.stat(tmpname).st_mode & 0o777
1463 self.assertEqual(mode, 0o644, "wrong file permissions")
1464 finally:
1465 os.umask(original_umask)
1466
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001467class GzipStreamWriteTest(GzipTest, StreamWriteTest):
1468 pass
1469
1470class Bz2StreamWriteTest(Bz2Test, StreamWriteTest):
1471 decompressor = bz2.BZ2Decompressor if bz2 else None
1472
1473class LzmaStreamWriteTest(LzmaTest, StreamWriteTest):
1474 decompressor = lzma.LZMADecompressor if lzma else None
1475
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001476
Guido van Rossumd8faa362007-04-27 19:54:29 +00001477class GNUWriteTest(unittest.TestCase):
1478 # This testcase checks for correct creation of GNU Longname
1479 # and Longlink extended headers (cp. bug #812325).
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001480
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001481 def _length(self, s):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001482 blocks = len(s) // 512 + 1
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001483 return blocks * 512
1484
1485 def _calc_size(self, name, link=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001486 # Initial tar header
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001487 count = 512
1488
1489 if len(name) > tarfile.LENGTH_NAME:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001490 # GNU longname extended header + longname
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001491 count += 512
1492 count += self._length(name)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001493 if link is not None and len(link) > tarfile.LENGTH_LINK:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001494 # GNU longlink extended header + longlink
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001495 count += 512
1496 count += self._length(link)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001497 return count
1498
1499 def _test(self, name, link=None):
1500 tarinfo = tarfile.TarInfo(name)
1501 if link:
1502 tarinfo.linkname = link
1503 tarinfo.type = tarfile.LNKTYPE
1504
Guido van Rossumd8faa362007-04-27 19:54:29 +00001505 tar = tarfile.open(tmpname, "w")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001506 try:
1507 tar.format = tarfile.GNU_FORMAT
1508 tar.addfile(tarinfo)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001509
Antoine Pitrou95f55602010-09-23 18:36:46 +00001510 v1 = self._calc_size(name, link)
1511 v2 = tar.offset
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001512 self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001513 finally:
1514 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001515
Guido van Rossumd8faa362007-04-27 19:54:29 +00001516 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001517 try:
1518 member = tar.next()
1519 self.assertIsNotNone(member,
1520 "unable to read longname member")
1521 self.assertEqual(tarinfo.name, member.name,
1522 "unable to read longname member")
1523 self.assertEqual(tarinfo.linkname, member.linkname,
1524 "unable to read longname member")
1525 finally:
1526 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001527
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001528 def test_longname_1023(self):
1529 self._test(("longnam/" * 127) + "longnam")
1530
1531 def test_longname_1024(self):
1532 self._test(("longnam/" * 127) + "longname")
1533
1534 def test_longname_1025(self):
1535 self._test(("longnam/" * 127) + "longname_")
1536
1537 def test_longlink_1023(self):
1538 self._test("name", ("longlnk/" * 127) + "longlnk")
1539
1540 def test_longlink_1024(self):
1541 self._test("name", ("longlnk/" * 127) + "longlink")
1542
1543 def test_longlink_1025(self):
1544 self._test("name", ("longlnk/" * 127) + "longlink_")
1545
1546 def test_longnamelink_1023(self):
1547 self._test(("longnam/" * 127) + "longnam",
1548 ("longlnk/" * 127) + "longlnk")
1549
1550 def test_longnamelink_1024(self):
1551 self._test(("longnam/" * 127) + "longname",
1552 ("longlnk/" * 127) + "longlink")
1553
1554 def test_longnamelink_1025(self):
1555 self._test(("longnam/" * 127) + "longname_",
1556 ("longlnk/" * 127) + "longlink_")
1557
Guido van Rossumd8faa362007-04-27 19:54:29 +00001558
William Chargin674935b2020-02-12 11:56:02 -08001559class DeviceHeaderTest(WriteTestBase, unittest.TestCase):
1560
1561 prefix = "w:"
1562
1563 def test_headers_written_only_for_device_files(self):
1564 # Regression test for bpo-18819.
1565 tempdir = os.path.join(TEMPDIR, "device_header_test")
1566 os.mkdir(tempdir)
1567 try:
1568 tar = tarfile.open(tmpname, self.mode)
1569 try:
1570 input_blk = tarfile.TarInfo(name="my_block_device")
1571 input_reg = tarfile.TarInfo(name="my_regular_file")
1572 input_blk.type = tarfile.BLKTYPE
1573 input_reg.type = tarfile.REGTYPE
1574 tar.addfile(input_blk)
1575 tar.addfile(input_reg)
1576 finally:
1577 tar.close()
1578
1579 # devmajor and devminor should be *interpreted* as 0 in both...
1580 tar = tarfile.open(tmpname, "r")
1581 try:
1582 output_blk = tar.getmember("my_block_device")
1583 output_reg = tar.getmember("my_regular_file")
1584 finally:
1585 tar.close()
1586 self.assertEqual(output_blk.devmajor, 0)
1587 self.assertEqual(output_blk.devminor, 0)
1588 self.assertEqual(output_reg.devmajor, 0)
1589 self.assertEqual(output_reg.devminor, 0)
1590
1591 # ...but the fields should not actually be set on regular files:
1592 with open(tmpname, "rb") as infile:
1593 buf = infile.read()
1594 buf_blk = buf[output_blk.offset:output_blk.offset_data]
1595 buf_reg = buf[output_reg.offset:output_reg.offset_data]
1596 # See `struct posixheader` in GNU docs for byte offsets:
1597 # <https://www.gnu.org/software/tar/manual/html_node/Standard.html>
1598 device_headers = slice(329, 329 + 16)
1599 self.assertEqual(buf_blk[device_headers], b"0000000\0" * 2)
1600 self.assertEqual(buf_reg[device_headers], b"\0" * 16)
1601 finally:
1602 support.rmtree(tempdir)
1603
1604
Lars Gustäbel20703c62015-05-27 12:53:44 +02001605class CreateTest(WriteTestBase, unittest.TestCase):
Berker Peksag0fe63252015-02-13 21:02:12 +02001606
1607 prefix = "x:"
1608
1609 file_path = os.path.join(TEMPDIR, "spameggs42")
1610
1611 def setUp(self):
1612 support.unlink(tmpname)
1613
1614 @classmethod
1615 def setUpClass(cls):
1616 with open(cls.file_path, "wb") as fobj:
1617 fobj.write(b"aaa")
1618
1619 @classmethod
1620 def tearDownClass(cls):
1621 support.unlink(cls.file_path)
1622
1623 def test_create(self):
1624 with tarfile.open(tmpname, self.mode) as tobj:
1625 tobj.add(self.file_path)
1626
1627 with self.taropen(tmpname) as tobj:
1628 names = tobj.getnames()
1629 self.assertEqual(len(names), 1)
1630 self.assertIn('spameggs42', names[0])
1631
1632 def test_create_existing(self):
1633 with tarfile.open(tmpname, self.mode) as tobj:
1634 tobj.add(self.file_path)
1635
1636 with self.assertRaises(FileExistsError):
1637 tobj = tarfile.open(tmpname, self.mode)
1638
1639 with self.taropen(tmpname) as tobj:
1640 names = tobj.getnames()
1641 self.assertEqual(len(names), 1)
1642 self.assertIn('spameggs42', names[0])
1643
1644 def test_create_taropen(self):
1645 with self.taropen(tmpname, "x") as tobj:
1646 tobj.add(self.file_path)
1647
1648 with self.taropen(tmpname) as tobj:
1649 names = tobj.getnames()
1650 self.assertEqual(len(names), 1)
1651 self.assertIn('spameggs42', names[0])
1652
1653 def test_create_existing_taropen(self):
1654 with self.taropen(tmpname, "x") as tobj:
1655 tobj.add(self.file_path)
1656
1657 with self.assertRaises(FileExistsError):
1658 with self.taropen(tmpname, "x"):
1659 pass
1660
1661 with self.taropen(tmpname) as tobj:
1662 names = tobj.getnames()
1663 self.assertEqual(len(names), 1)
1664 self.assertIn("spameggs42", names[0])
1665
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001666 def test_create_pathlike_name(self):
1667 with tarfile.open(pathlib.Path(tmpname), self.mode) as tobj:
1668 self.assertIsInstance(tobj.name, str)
1669 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1670 tobj.add(pathlib.Path(self.file_path))
1671 names = tobj.getnames()
1672 self.assertEqual(len(names), 1)
1673 self.assertIn('spameggs42', names[0])
1674
1675 with self.taropen(tmpname) as tobj:
1676 names = tobj.getnames()
1677 self.assertEqual(len(names), 1)
1678 self.assertIn('spameggs42', names[0])
1679
1680 def test_create_taropen_pathlike_name(self):
1681 with self.taropen(pathlib.Path(tmpname), "x") as tobj:
1682 self.assertIsInstance(tobj.name, str)
1683 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1684 tobj.add(pathlib.Path(self.file_path))
1685 names = tobj.getnames()
1686 self.assertEqual(len(names), 1)
1687 self.assertIn('spameggs42', names[0])
1688
1689 with self.taropen(tmpname) as tobj:
1690 names = tobj.getnames()
1691 self.assertEqual(len(names), 1)
1692 self.assertIn('spameggs42', names[0])
1693
Berker Peksag0fe63252015-02-13 21:02:12 +02001694
1695class GzipCreateTest(GzipTest, CreateTest):
1696 pass
1697
1698
1699class Bz2CreateTest(Bz2Test, CreateTest):
1700 pass
1701
1702
1703class LzmaCreateTest(LzmaTest, CreateTest):
1704 pass
1705
1706
1707class CreateWithXModeTest(CreateTest):
1708
1709 prefix = "x"
1710
1711 test_create_taropen = None
1712 test_create_existing_taropen = None
1713
1714
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001715@unittest.skipUnless(hasattr(os, "link"), "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001716class HardlinkTest(unittest.TestCase):
1717 # Test the creation of LNKTYPE (hardlink) members in an archive.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001718
1719 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001720 self.foo = os.path.join(TEMPDIR, "foo")
1721 self.bar = os.path.join(TEMPDIR, "bar")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001722
Antoine Pitrou95f55602010-09-23 18:36:46 +00001723 with open(self.foo, "wb") as fobj:
1724 fobj.write(b"foo")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001725
xdegayed7d4fea2017-11-12 18:02:06 +01001726 try:
1727 os.link(self.foo, self.bar)
1728 except PermissionError as e:
1729 self.skipTest('os.link(): %s' % e)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001730
Guido van Rossumd8faa362007-04-27 19:54:29 +00001731 self.tar = tarfile.open(tmpname, "w")
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001732 self.tar.add(self.foo)
1733
Guido van Rossumd8faa362007-04-27 19:54:29 +00001734 def tearDown(self):
Hirokazu Yamamotoaf079d42008-09-21 11:50:03 +00001735 self.tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001736 support.unlink(self.foo)
1737 support.unlink(self.bar)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001738
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001739 def test_add_twice(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001740 # The same name will be added as a REGTYPE every
1741 # time regardless of st_nlink.
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001742 tarinfo = self.tar.gettarinfo(self.foo)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001743 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001744 "add file as regular failed")
1745
1746 def test_add_hardlink(self):
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001747 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001748 self.assertEqual(tarinfo.type, tarfile.LNKTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001749 "add file as hardlink failed")
1750
1751 def test_dereference_hardlink(self):
1752 self.tar.dereference = True
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001753 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001754 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001755 "dereferencing hardlink failed")
1756
Neal Norwitza4f651a2004-07-20 22:07:44 +00001757
Guido van Rossumd8faa362007-04-27 19:54:29 +00001758class PaxWriteTest(GNUWriteTest):
Martin v. Löwis78be7df2005-03-05 12:47:42 +00001759
Guido van Rossumd8faa362007-04-27 19:54:29 +00001760 def _test(self, name, link=None):
1761 # See GNUWriteTest.
1762 tarinfo = tarfile.TarInfo(name)
1763 if link:
1764 tarinfo.linkname = link
1765 tarinfo.type = tarfile.LNKTYPE
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001766
Guido van Rossumd8faa362007-04-27 19:54:29 +00001767 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001768 try:
1769 tar.addfile(tarinfo)
1770 finally:
1771 tar.close()
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001772
Guido van Rossumd8faa362007-04-27 19:54:29 +00001773 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001774 try:
1775 if link:
1776 l = tar.getmembers()[0].linkname
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001777 self.assertEqual(link, l, "PAX longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001778 else:
1779 n = tar.getmembers()[0].name
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001780 self.assertEqual(name, n, "PAX longname creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001781 finally:
1782 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001783
Guido van Rossume7ba4952007-06-06 23:52:48 +00001784 def test_pax_global_header(self):
1785 pax_headers = {
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001786 "foo": "bar",
1787 "uid": "0",
1788 "mtime": "1.23",
Guido van Rossuma0557702007-08-07 23:19:53 +00001789 "test": "\xe4\xf6\xfc",
1790 "\xe4\xf6\xfc": "test"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001791
Benjamin Peterson886af962010-03-21 23:13:07 +00001792 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
Guido van Rossume7ba4952007-06-06 23:52:48 +00001793 pax_headers=pax_headers)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001794 try:
1795 tar.addfile(tarfile.TarInfo("test"))
1796 finally:
1797 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001798
1799 # Test if the global header was written correctly.
1800 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001801 try:
1802 self.assertEqual(tar.pax_headers, pax_headers)
1803 self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers)
1804 # Test if all the fields are strings.
1805 for key, val in tar.pax_headers.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001806 self.assertIsNot(type(key), bytes)
1807 self.assertIsNot(type(val), bytes)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001808 if key in tarfile.PAX_NUMBER_FIELDS:
1809 try:
1810 tarfile.PAX_NUMBER_FIELDS[key](val)
1811 except (TypeError, ValueError):
1812 self.fail("unable to convert pax header field")
1813 finally:
1814 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001815
1816 def test_pax_extended_header(self):
1817 # The fields from the pax header have priority over the
1818 # TarInfo.
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001819 pax_headers = {"path": "foo", "uid": "123"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001820
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001821 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
1822 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001823 try:
1824 t = tarfile.TarInfo()
1825 t.name = "\xe4\xf6\xfc" # non-ASCII
1826 t.uid = 8**8 # too large
1827 t.pax_headers = pax_headers
1828 tar.addfile(t)
1829 finally:
1830 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001831
1832 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001833 try:
1834 t = tar.getmembers()[0]
1835 self.assertEqual(t.pax_headers, pax_headers)
1836 self.assertEqual(t.name, "foo")
1837 self.assertEqual(t.uid, 123)
1838 finally:
1839 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001840
1841
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001842class UnicodeTest:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001843
1844 def test_iso8859_1_filename(self):
1845 self._test_unicode_filename("iso8859-1")
1846
1847 def test_utf7_filename(self):
1848 self._test_unicode_filename("utf7")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001849
1850 def test_utf8_filename(self):
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00001851 self._test_unicode_filename("utf-8")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001852
Guido van Rossumd8faa362007-04-27 19:54:29 +00001853 def _test_unicode_filename(self, encoding):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001854 tar = tarfile.open(tmpname, "w", format=self.format,
1855 encoding=encoding, errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001856 try:
1857 name = "\xe4\xf6\xfc"
1858 tar.addfile(tarfile.TarInfo(name))
1859 finally:
1860 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001861
1862 tar = tarfile.open(tmpname, encoding=encoding)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001863 try:
1864 self.assertEqual(tar.getmembers()[0].name, name)
1865 finally:
1866 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001867
1868 def test_unicode_filename_error(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001869 tar = tarfile.open(tmpname, "w", format=self.format,
1870 encoding="ascii", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001871 try:
1872 tarinfo = tarfile.TarInfo()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001873
Antoine Pitrou95f55602010-09-23 18:36:46 +00001874 tarinfo.name = "\xe4\xf6\xfc"
1875 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001876
Antoine Pitrou95f55602010-09-23 18:36:46 +00001877 tarinfo.name = "foo"
1878 tarinfo.uname = "\xe4\xf6\xfc"
1879 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
1880 finally:
1881 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001882
1883 def test_unicode_argument(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001884 tar = tarfile.open(tarname, "r",
1885 encoding="iso8859-1", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001886 try:
1887 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001888 self.assertIs(type(t.name), str)
1889 self.assertIs(type(t.linkname), str)
1890 self.assertIs(type(t.uname), str)
1891 self.assertIs(type(t.gname), str)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001892 finally:
1893 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001894
Guido van Rossume7ba4952007-06-06 23:52:48 +00001895 def test_uname_unicode(self):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001896 t = tarfile.TarInfo("foo")
1897 t.uname = "\xe4\xf6\xfc"
1898 t.gname = "\xe4\xf6\xfc"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001899
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001900 tar = tarfile.open(tmpname, mode="w", format=self.format,
1901 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001902 try:
1903 tar.addfile(t)
1904 finally:
1905 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001906
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001907 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001908 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001909 t = tar.getmember("foo")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001910 self.assertEqual(t.uname, "\xe4\xf6\xfc")
1911 self.assertEqual(t.gname, "\xe4\xf6\xfc")
1912
1913 if self.format != tarfile.PAX_FORMAT:
Antoine Pitrouab58b5f2010-09-23 19:39:35 +00001914 tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001915 tar = tarfile.open(tmpname, encoding="ascii")
1916 t = tar.getmember("foo")
1917 self.assertEqual(t.uname, "\udce4\udcf6\udcfc")
1918 self.assertEqual(t.gname, "\udce4\udcf6\udcfc")
1919 finally:
1920 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001921
Lars Gustäbelb506dc32007-08-07 18:36:16 +00001922
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001923class UstarUnicodeTest(UnicodeTest, unittest.TestCase):
1924
1925 format = tarfile.USTAR_FORMAT
1926
1927 # Test whether the utf-8 encoded version of a filename exceeds the 100
1928 # bytes name field limit (every occurrence of '\xff' will be expanded to 2
1929 # bytes).
1930 def test_unicode_name1(self):
1931 self._test_ustar_name("0123456789" * 10)
1932 self._test_ustar_name("0123456789" * 10 + "0", ValueError)
1933 self._test_ustar_name("0123456789" * 9 + "01234567\xff")
1934 self._test_ustar_name("0123456789" * 9 + "012345678\xff", ValueError)
1935
1936 def test_unicode_name2(self):
1937 self._test_ustar_name("0123456789" * 9 + "012345\xff\xff")
1938 self._test_ustar_name("0123456789" * 9 + "0123456\xff\xff", ValueError)
1939
1940 # Test whether the utf-8 encoded version of a filename exceeds the 155
1941 # bytes prefix + '/' + 100 bytes name limit.
1942 def test_unicode_longname1(self):
1943 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 10)
1944 self._test_ustar_name("0123456789" * 15 + "0123/4" + "0123456789" * 10, ValueError)
1945 self._test_ustar_name("0123456789" * 15 + "012\xff/" + "0123456789" * 10)
1946 self._test_ustar_name("0123456789" * 15 + "0123\xff/" + "0123456789" * 10, ValueError)
1947
1948 def test_unicode_longname2(self):
1949 self._test_ustar_name("0123456789" * 15 + "01\xff/2" + "0123456789" * 10, ValueError)
1950 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/" + "0123456789" * 10, ValueError)
1951
1952 def test_unicode_longname3(self):
1953 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/2" + "0123456789" * 10, ValueError)
1954 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "01234567\xff")
1955 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345678\xff", ValueError)
1956
1957 def test_unicode_longname4(self):
1958 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345\xff\xff")
1959 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "0123456\xff\xff", ValueError)
1960
1961 def _test_ustar_name(self, name, exc=None):
1962 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1963 t = tarfile.TarInfo(name)
1964 if exc is None:
1965 tar.addfile(t)
1966 else:
1967 self.assertRaises(exc, tar.addfile, t)
1968
1969 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001970 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001971 for t in tar:
1972 self.assertEqual(name, t.name)
1973 break
1974
1975 # Test the same as above for the 100 bytes link field.
1976 def test_unicode_link1(self):
1977 self._test_ustar_link("0123456789" * 10)
1978 self._test_ustar_link("0123456789" * 10 + "0", ValueError)
1979 self._test_ustar_link("0123456789" * 9 + "01234567\xff")
1980 self._test_ustar_link("0123456789" * 9 + "012345678\xff", ValueError)
1981
1982 def test_unicode_link2(self):
1983 self._test_ustar_link("0123456789" * 9 + "012345\xff\xff")
1984 self._test_ustar_link("0123456789" * 9 + "0123456\xff\xff", ValueError)
1985
1986 def _test_ustar_link(self, name, exc=None):
1987 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1988 t = tarfile.TarInfo("foo")
1989 t.linkname = name
1990 if exc is None:
1991 tar.addfile(t)
1992 else:
1993 self.assertRaises(exc, tar.addfile, t)
1994
1995 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001996 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001997 for t in tar:
1998 self.assertEqual(name, t.linkname)
1999 break
2000
2001
2002class GNUUnicodeTest(UnicodeTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002003
Guido van Rossume7ba4952007-06-06 23:52:48 +00002004 format = tarfile.GNU_FORMAT
Guido van Rossumd8faa362007-04-27 19:54:29 +00002005
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002006 def test_bad_pax_header(self):
2007 # Test for issue #8633. GNU tar <= 1.23 creates raw binary fields
2008 # without a hdrcharset=BINARY header.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002009 for encoding, name in (
2010 ("utf-8", "pax/bad-pax-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002011 ("iso8859-1", "pax/bad-pax-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002012 with tarfile.open(tarname, encoding=encoding,
2013 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002014 try:
2015 t = tar.getmember(name)
2016 except KeyError:
2017 self.fail("unable to read bad GNU tar pax header")
2018
Guido van Rossumd8faa362007-04-27 19:54:29 +00002019
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02002020class PAXUnicodeTest(UnicodeTest, unittest.TestCase):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00002021
2022 format = tarfile.PAX_FORMAT
2023
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002024 # PAX_FORMAT ignores encoding in write mode.
2025 test_unicode_filename_error = None
2026
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002027 def test_binary_header(self):
2028 # Test a POSIX.1-2008 compatible header with a hdrcharset=BINARY field.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002029 for encoding, name in (
2030 ("utf-8", "pax/hdrcharset-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002031 ("iso8859-1", "pax/hdrcharset-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002032 with tarfile.open(tarname, encoding=encoding,
2033 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002034 try:
2035 t = tar.getmember(name)
2036 except KeyError:
2037 self.fail("unable to read POSIX.1-2008 binary header")
2038
Lars Gustäbel3741eff2007-08-21 12:17:05 +00002039
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002040class AppendTestBase:
Guido van Rossumd8faa362007-04-27 19:54:29 +00002041 # Test append mode (cp. patch #1652681).
Thomas Wouters902d6eb2007-01-09 23:18:33 +00002042
Guido van Rossumd8faa362007-04-27 19:54:29 +00002043 def setUp(self):
2044 self.tarname = tmpname
2045 if os.path.exists(self.tarname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01002046 support.unlink(self.tarname)
Thomas Wouters902d6eb2007-01-09 23:18:33 +00002047
Guido van Rossumd8faa362007-04-27 19:54:29 +00002048 def _create_testtar(self, mode="w:"):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002049 with tarfile.open(tarname, encoding="iso8859-1") as src:
2050 t = src.getmember("ustar/regtype")
2051 t.name = "foo"
Lars Gustäbel7a919e92012-05-05 18:15:03 +02002052 with src.extractfile(t) as f:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +00002053 with tarfile.open(self.tarname, mode) as tar:
2054 tar.addfile(t, f)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002055
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002056 def test_append_compressed(self):
2057 self._create_testtar("w:" + self.suffix)
2058 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a")
2059
2060class AppendTest(AppendTestBase, unittest.TestCase):
2061 test_append_compressed = None
2062
2063 def _add_testfile(self, fileobj=None):
2064 with tarfile.open(self.tarname, "a", fileobj=fileobj) as tar:
2065 tar.addfile(tarfile.TarInfo("bar"))
2066
Guido van Rossumd8faa362007-04-27 19:54:29 +00002067 def _test(self, names=["bar"], fileobj=None):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002068 with tarfile.open(self.tarname, fileobj=fileobj) as tar:
2069 self.assertEqual(tar.getnames(), names)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002070
2071 def test_non_existing(self):
2072 self._add_testfile()
2073 self._test()
2074
2075 def test_empty(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002076 tarfile.open(self.tarname, "w:").close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00002077 self._add_testfile()
2078 self._test()
2079
2080 def test_empty_fileobj(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002081 fobj = io.BytesIO(b"\0" * 1024)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002082 self._add_testfile(fobj)
2083 fobj.seek(0)
2084 self._test(fileobj=fobj)
2085
2086 def test_fileobj(self):
2087 self._create_testtar()
Antoine Pitrou95f55602010-09-23 18:36:46 +00002088 with open(self.tarname, "rb") as fobj:
2089 data = fobj.read()
Guido van Rossum34d19282007-08-09 01:03:29 +00002090 fobj = io.BytesIO(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002091 self._add_testfile(fobj)
2092 fobj.seek(0)
2093 self._test(names=["foo", "bar"], fileobj=fobj)
2094
2095 def test_existing(self):
2096 self._create_testtar()
2097 self._add_testfile()
2098 self._test(names=["foo", "bar"])
2099
Lars Gustäbel9520a432009-11-22 18:48:49 +00002100 # Append mode is supposed to fail if the tarfile to append to
2101 # does not end with a zero block.
2102 def _test_error(self, data):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002103 with open(self.tarname, "wb") as fobj:
2104 fobj.write(data)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002105 self.assertRaises(tarfile.ReadError, self._add_testfile)
2106
2107 def test_null(self):
2108 self._test_error(b"")
2109
2110 def test_incomplete(self):
2111 self._test_error(b"\0" * 13)
2112
2113 def test_premature_eof(self):
2114 data = tarfile.TarInfo("foo").tobuf()
2115 self._test_error(data)
2116
2117 def test_trailing_garbage(self):
2118 data = tarfile.TarInfo("foo").tobuf()
2119 self._test_error(data + b"\0" * 13)
2120
2121 def test_invalid(self):
2122 self._test_error(b"a" * 512)
2123
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002124class GzipAppendTest(GzipTest, AppendTestBase, unittest.TestCase):
2125 pass
2126
2127class Bz2AppendTest(Bz2Test, AppendTestBase, unittest.TestCase):
2128 pass
2129
2130class LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase):
2131 pass
2132
Guido van Rossumd8faa362007-04-27 19:54:29 +00002133
2134class LimitsTest(unittest.TestCase):
2135
2136 def test_ustar_limits(self):
2137 # 100 char name
2138 tarinfo = tarfile.TarInfo("0123456789" * 10)
Guido van Rossume7ba4952007-06-06 23:52:48 +00002139 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002140
2141 # 101 char name that cannot be stored
2142 tarinfo = tarfile.TarInfo("0123456789" * 10 + "0")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002143 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002144
2145 # 256 char name with a slash at pos 156
2146 tarinfo = tarfile.TarInfo("123/" * 62 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002147 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002148
2149 # 256 char name that cannot be stored
2150 tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002151 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002152
2153 # 512 char name
2154 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002155 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002156
2157 # 512 char linkname
2158 tarinfo = tarfile.TarInfo("longlink")
2159 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002160 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002161
2162 # uid > 8 digits
2163 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002164 tarinfo.uid = 0o10000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002165 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002166
2167 def test_gnu_limits(self):
2168 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002169 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002170
2171 tarinfo = tarfile.TarInfo("longlink")
2172 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002173 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002174
2175 # uid >= 256 ** 7
2176 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002177 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002178 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002179
2180 def test_pax_limits(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002181 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002182 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002183
2184 tarinfo = tarfile.TarInfo("longlink")
2185 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002186 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002187
2188 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002189 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002190 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002191
2192
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002193class MiscTest(unittest.TestCase):
2194
2195 def test_char_fields(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002196 self.assertEqual(tarfile.stn("foo", 8, "ascii", "strict"),
2197 b"foo\0\0\0\0\0")
2198 self.assertEqual(tarfile.stn("foobar", 3, "ascii", "strict"),
2199 b"foo")
2200 self.assertEqual(tarfile.nts(b"foo\0\0\0\0\0", "ascii", "strict"),
2201 "foo")
2202 self.assertEqual(tarfile.nts(b"foo\0bar\0", "ascii", "strict"),
2203 "foo")
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002204
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002205 def test_read_number_fields(self):
2206 # Issue 13158: Test if GNU tar specific base-256 number fields
2207 # are decoded correctly.
2208 self.assertEqual(tarfile.nti(b"0000001\x00"), 1)
2209 self.assertEqual(tarfile.nti(b"7777777\x00"), 0o7777777)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002210 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\x00\x20\x00\x00"),
2211 0o10000000)
2212 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\xff\xff\xff\xff"),
2213 0xffffffff)
2214 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\xff"),
2215 -1)
2216 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\x9c"),
2217 -100)
2218 self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"),
2219 -0x100000000000000)
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002220
Lars Gustäbelb7a688b2015-07-02 19:38:38 +02002221 # Issue 24514: Test if empty number fields are converted to zero.
2222 self.assertEqual(tarfile.nti(b"\0"), 0)
2223 self.assertEqual(tarfile.nti(b" \0"), 0)
2224
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002225 def test_write_number_fields(self):
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002226 self.assertEqual(tarfile.itn(1), b"0000001\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002227 self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002228 self.assertEqual(tarfile.itn(0o10000000, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002229 b"\x80\x00\x00\x00\x00\x20\x00\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002230 self.assertEqual(tarfile.itn(0xffffffff, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002231 b"\x80\x00\x00\x00\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002232 self.assertEqual(tarfile.itn(-1, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002233 b"\xff\xff\xff\xff\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002234 self.assertEqual(tarfile.itn(-100, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002235 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002236 self.assertEqual(tarfile.itn(-0x100000000000000,
2237 format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002238 b"\xff\x00\x00\x00\x00\x00\x00\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002239
Joffrey F72d9b2b2018-02-26 16:02:21 -08002240 # Issue 32713: Test if itn() supports float values outside the
2241 # non-GNU format range
2242 self.assertEqual(tarfile.itn(-100.0, format=tarfile.GNU_FORMAT),
2243 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
2244 self.assertEqual(tarfile.itn(8 ** 12 + 0.0, format=tarfile.GNU_FORMAT),
2245 b"\x80\x00\x00\x10\x00\x00\x00\x00")
2246 self.assertEqual(tarfile.nti(tarfile.itn(-0.1, format=tarfile.GNU_FORMAT)), 0)
2247
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002248 def test_number_field_limits(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002249 with self.assertRaises(ValueError):
2250 tarfile.itn(-1, 8, tarfile.USTAR_FORMAT)
2251 with self.assertRaises(ValueError):
2252 tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT)
2253 with self.assertRaises(ValueError):
2254 tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT)
2255 with self.assertRaises(ValueError):
2256 tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT)
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002257
Martin Panter104dcda2016-01-16 06:59:13 +00002258 def test__all__(self):
Martin Panter5318d102016-01-16 11:01:14 +00002259 blacklist = {'version', 'grp', 'pwd', 'symlink_exception',
Martin Panter104dcda2016-01-16 06:59:13 +00002260 'NUL', 'BLOCKSIZE', 'RECORDSIZE', 'GNU_MAGIC',
2261 'POSIX_MAGIC', 'LENGTH_NAME', 'LENGTH_LINK',
2262 'LENGTH_PREFIX', 'REGTYPE', 'AREGTYPE', 'LNKTYPE',
2263 'SYMTYPE', 'CHRTYPE', 'BLKTYPE', 'DIRTYPE', 'FIFOTYPE',
2264 'CONTTYPE', 'GNUTYPE_LONGNAME', 'GNUTYPE_LONGLINK',
2265 'GNUTYPE_SPARSE', 'XHDTYPE', 'XGLTYPE', 'SOLARIS_XHDTYPE',
2266 'SUPPORTED_TYPES', 'REGULAR_TYPES', 'GNU_TYPES',
2267 'PAX_FIELDS', 'PAX_NAME_FIELDS', 'PAX_NUMBER_FIELDS',
2268 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 'copyfileobj',
2269 'filemode',
2270 'EmptyHeaderError', 'TruncatedHeaderError',
2271 'EOFHeaderError', 'InvalidHeaderError',
Serhiy Storchaka2c1d3e32016-01-16 11:05:11 +02002272 'SubsequentHeaderError', 'ExFileObject',
Martin Panter104dcda2016-01-16 06:59:13 +00002273 'main'}
2274 support.check__all__(self, tarfile, blacklist=blacklist)
2275
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002276
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002277class CommandLineTest(unittest.TestCase):
2278
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002279 def tarfilecmd(self, *args, **kwargs):
2280 rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args,
2281 **kwargs)
Antoine Pitrou3b7b1e52013-11-24 01:55:05 +01002282 return out.replace(os.linesep.encode(), b'\n')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002283
2284 def tarfilecmd_failure(self, *args):
2285 return script_helper.assert_python_failure('-m', 'tarfile', *args)
2286
2287 def make_simple_tarfile(self, tar_name):
2288 files = [support.findfile('tokenize_tests.txt'),
2289 support.findfile('tokenize_tests-no-coding-cookie-'
2290 'and-utf8-bom-sig-only.txt')]
2291 self.addCleanup(support.unlink, tar_name)
2292 with tarfile.open(tar_name, 'w') as tf:
2293 for tardata in files:
2294 tf.add(tardata, arcname=os.path.basename(tardata))
2295
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002296 def test_bad_use(self):
2297 rc, out, err = self.tarfilecmd_failure()
2298 self.assertEqual(out, b'')
2299 self.assertIn(b'usage', err.lower())
2300 self.assertIn(b'error', err.lower())
2301 self.assertIn(b'required', err.lower())
2302 rc, out, err = self.tarfilecmd_failure('-l', '')
2303 self.assertEqual(out, b'')
2304 self.assertNotEqual(err.strip(), b'')
2305
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002306 def test_test_command(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002307 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002308 for opt in '-t', '--test':
2309 out = self.tarfilecmd(opt, tar_name)
2310 self.assertEqual(out, b'')
2311
2312 def test_test_command_verbose(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002313 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002314 for opt in '-v', '--verbose':
Serhiy Storchaka700cfa82020-06-25 17:56:31 +03002315 out = self.tarfilecmd(opt, '-t', tar_name,
2316 PYTHONIOENCODING='utf-8')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002317 self.assertIn(b'is a tar archive.\n', out)
2318
2319 def test_test_command_invalid_file(self):
2320 zipname = support.findfile('zipdir.zip')
2321 rc, out, err = self.tarfilecmd_failure('-t', zipname)
2322 self.assertIn(b' is not a tar archive.', err)
2323 self.assertEqual(out, b'')
2324 self.assertEqual(rc, 1)
2325
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002326 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002327 with self.subTest(tar_name=tar_name):
2328 with open(tar_name, 'rb') as f:
2329 data = f.read()
2330 try:
2331 with open(tmpname, 'wb') as f:
2332 f.write(data[:511])
2333 rc, out, err = self.tarfilecmd_failure('-t', tmpname)
2334 self.assertEqual(out, b'')
2335 self.assertEqual(rc, 1)
2336 finally:
2337 support.unlink(tmpname)
2338
2339 def test_list_command(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002340 for tar_name in testtarnames:
2341 with support.captured_stdout() as t:
2342 with tarfile.open(tar_name, 'r') as tf:
2343 tf.list(verbose=False)
2344 expected = t.getvalue().encode('ascii', 'backslashreplace')
2345 for opt in '-l', '--list':
2346 out = self.tarfilecmd(opt, tar_name,
2347 PYTHONIOENCODING='ascii')
2348 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002349
2350 def test_list_command_verbose(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002351 for tar_name in testtarnames:
2352 with support.captured_stdout() as t:
2353 with tarfile.open(tar_name, 'r') as tf:
2354 tf.list(verbose=True)
2355 expected = t.getvalue().encode('ascii', 'backslashreplace')
2356 for opt in '-v', '--verbose':
2357 out = self.tarfilecmd(opt, '-l', tar_name,
2358 PYTHONIOENCODING='ascii')
2359 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002360
2361 def test_list_command_invalid_file(self):
2362 zipname = support.findfile('zipdir.zip')
2363 rc, out, err = self.tarfilecmd_failure('-l', zipname)
2364 self.assertIn(b' is not a tar archive.', err)
2365 self.assertEqual(out, b'')
2366 self.assertEqual(rc, 1)
2367
2368 def test_create_command(self):
2369 files = [support.findfile('tokenize_tests.txt'),
2370 support.findfile('tokenize_tests-no-coding-cookie-'
2371 'and-utf8-bom-sig-only.txt')]
2372 for opt in '-c', '--create':
2373 try:
2374 out = self.tarfilecmd(opt, tmpname, *files)
2375 self.assertEqual(out, b'')
2376 with tarfile.open(tmpname) as tar:
2377 tar.getmembers()
2378 finally:
2379 support.unlink(tmpname)
2380
2381 def test_create_command_verbose(self):
2382 files = [support.findfile('tokenize_tests.txt'),
2383 support.findfile('tokenize_tests-no-coding-cookie-'
2384 'and-utf8-bom-sig-only.txt')]
2385 for opt in '-v', '--verbose':
2386 try:
Serhiy Storchaka700cfa82020-06-25 17:56:31 +03002387 out = self.tarfilecmd(opt, '-c', tmpname, *files,
2388 PYTHONIOENCODING='utf-8')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002389 self.assertIn(b' file created.', out)
2390 with tarfile.open(tmpname) as tar:
2391 tar.getmembers()
2392 finally:
2393 support.unlink(tmpname)
2394
2395 def test_create_command_dotless_filename(self):
2396 files = [support.findfile('tokenize_tests.txt')]
2397 try:
2398 out = self.tarfilecmd('-c', dotlessname, *files)
2399 self.assertEqual(out, b'')
2400 with tarfile.open(dotlessname) as tar:
2401 tar.getmembers()
2402 finally:
2403 support.unlink(dotlessname)
2404
2405 def test_create_command_dot_started_filename(self):
2406 tar_name = os.path.join(TEMPDIR, ".testtar")
2407 files = [support.findfile('tokenize_tests.txt')]
2408 try:
2409 out = self.tarfilecmd('-c', tar_name, *files)
2410 self.assertEqual(out, b'')
2411 with tarfile.open(tar_name) as tar:
2412 tar.getmembers()
2413 finally:
2414 support.unlink(tar_name)
2415
Serhiy Storchaka832dd5f2015-02-10 08:45:53 +02002416 def test_create_command_compressed(self):
2417 files = [support.findfile('tokenize_tests.txt'),
2418 support.findfile('tokenize_tests-no-coding-cookie-'
2419 'and-utf8-bom-sig-only.txt')]
2420 for filetype in (GzipTest, Bz2Test, LzmaTest):
2421 if not filetype.open:
2422 continue
2423 try:
2424 tar_name = tmpname + '.' + filetype.suffix
2425 out = self.tarfilecmd('-c', tar_name, *files)
2426 with filetype.taropen(tar_name) as tar:
2427 tar.getmembers()
2428 finally:
2429 support.unlink(tar_name)
2430
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002431 def test_extract_command(self):
2432 self.make_simple_tarfile(tmpname)
2433 for opt in '-e', '--extract':
2434 try:
2435 with support.temp_cwd(tarextdir):
2436 out = self.tarfilecmd(opt, tmpname)
2437 self.assertEqual(out, b'')
2438 finally:
2439 support.rmtree(tarextdir)
2440
2441 def test_extract_command_verbose(self):
2442 self.make_simple_tarfile(tmpname)
2443 for opt in '-v', '--verbose':
2444 try:
2445 with support.temp_cwd(tarextdir):
Serhiy Storchaka700cfa82020-06-25 17:56:31 +03002446 out = self.tarfilecmd(opt, '-e', tmpname,
2447 PYTHONIOENCODING='utf-8')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002448 self.assertIn(b' file is extracted.', out)
2449 finally:
2450 support.rmtree(tarextdir)
2451
2452 def test_extract_command_different_directory(self):
2453 self.make_simple_tarfile(tmpname)
2454 try:
2455 with support.temp_cwd(tarextdir):
2456 out = self.tarfilecmd('-e', tmpname, 'spamdir')
2457 self.assertEqual(out, b'')
2458 finally:
2459 support.rmtree(tarextdir)
2460
2461 def test_extract_command_invalid_file(self):
2462 zipname = support.findfile('zipdir.zip')
2463 with support.temp_cwd(tarextdir):
2464 rc, out, err = self.tarfilecmd_failure('-e', zipname)
2465 self.assertIn(b' is not a tar archive.', err)
2466 self.assertEqual(out, b'')
2467 self.assertEqual(rc, 1)
2468
2469
Lars Gustäbel01385812010-03-03 12:08:54 +00002470class ContextManagerTest(unittest.TestCase):
2471
2472 def test_basic(self):
2473 with tarfile.open(tarname) as tar:
2474 self.assertFalse(tar.closed, "closed inside runtime context")
2475 self.assertTrue(tar.closed, "context manager failed")
2476
2477 def test_closed(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002478 # The __enter__() method is supposed to raise OSError
Lars Gustäbel01385812010-03-03 12:08:54 +00002479 # if the TarFile object is already closed.
2480 tar = tarfile.open(tarname)
2481 tar.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002482 with self.assertRaises(OSError):
Lars Gustäbel01385812010-03-03 12:08:54 +00002483 with tar:
2484 pass
2485
2486 def test_exception(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002487 # Test if the OSError exception is passed through properly.
Lars Gustäbel01385812010-03-03 12:08:54 +00002488 with self.assertRaises(Exception) as exc:
2489 with tarfile.open(tarname) as tar:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002490 raise OSError
2491 self.assertIsInstance(exc.exception, OSError,
Lars Gustäbel01385812010-03-03 12:08:54 +00002492 "wrong exception raised in context manager")
2493 self.assertTrue(tar.closed, "context manager failed")
2494
2495 def test_no_eof(self):
2496 # __exit__() must not write end-of-archive blocks if an
2497 # exception was raised.
2498 try:
2499 with tarfile.open(tmpname, "w") as tar:
2500 raise Exception
2501 except:
2502 pass
2503 self.assertEqual(os.path.getsize(tmpname), 0,
2504 "context manager wrote an end-of-archive block")
2505 self.assertTrue(tar.closed, "context manager failed")
2506
2507 def test_eof(self):
2508 # __exit__() must write end-of-archive blocks, i.e. call
2509 # TarFile.close() if there was no error.
2510 with tarfile.open(tmpname, "w"):
2511 pass
2512 self.assertNotEqual(os.path.getsize(tmpname), 0,
2513 "context manager wrote no end-of-archive block")
2514
2515 def test_fileobj(self):
2516 # Test that __exit__() did not close the external file
2517 # object.
Antoine Pitrou95f55602010-09-23 18:36:46 +00002518 with open(tmpname, "wb") as fobj:
2519 try:
2520 with tarfile.open(fileobj=fobj, mode="w") as tar:
2521 raise Exception
2522 except:
2523 pass
2524 self.assertFalse(fobj.closed, "external file object was closed")
2525 self.assertTrue(tar.closed, "context manager failed")
Lars Gustäbel01385812010-03-03 12:08:54 +00002526
2527
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002528@unittest.skipIf(hasattr(os, "link"), "requires os.link to be missing")
2529class LinkEmulationTest(ReadTest, unittest.TestCase):
Lars Gustäbel1b512722010-06-03 12:45:16 +00002530
2531 # Test for issue #8741 regression. On platforms that do not support
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002532 # symbolic or hard links tarfile tries to extract these types of members
2533 # as the regular files they point to.
Lars Gustäbel1b512722010-06-03 12:45:16 +00002534 def _test_link_extraction(self, name):
2535 self.tar.extract(name, TEMPDIR)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002536 with open(os.path.join(TEMPDIR, name), "rb") as f:
2537 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +02002538 self.assertEqual(sha256sum(data), sha256_regtype)
Lars Gustäbel1b512722010-06-03 12:45:16 +00002539
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002540 # See issues #1578269, #8879, and #17689 for some history on these skips
Brian Curtind40e6f72010-07-08 21:39:08 +00002541 @unittest.skipIf(hasattr(os.path, "islink"),
2542 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002543 def test_hardlink_extraction1(self):
2544 self._test_link_extraction("ustar/lnktype")
2545
Brian Curtind40e6f72010-07-08 21:39:08 +00002546 @unittest.skipIf(hasattr(os.path, "islink"),
2547 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002548 def test_hardlink_extraction2(self):
2549 self._test_link_extraction("./ustar/linktest2/lnktype")
2550
Brian Curtin74e45612010-07-09 15:58:59 +00002551 @unittest.skipIf(hasattr(os, "symlink"),
2552 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002553 def test_symlink_extraction1(self):
2554 self._test_link_extraction("ustar/symtype")
2555
Brian Curtin74e45612010-07-09 15:58:59 +00002556 @unittest.skipIf(hasattr(os, "symlink"),
2557 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002558 def test_symlink_extraction2(self):
2559 self._test_link_extraction("./ustar/linktest2/symtype")
2560
2561
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002562class Bz2PartialReadTest(Bz2Test, unittest.TestCase):
Lars Gustäbel42e00912009-03-22 20:34:29 +00002563 # Issue5068: The _BZ2Proxy.read() method loops forever
2564 # on an empty or partial bzipped file.
2565
2566 def _test_partial_input(self, mode):
2567 class MyBytesIO(io.BytesIO):
2568 hit_eof = False
2569 def read(self, n):
2570 if self.hit_eof:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002571 raise AssertionError("infinite loop detected in "
2572 "tarfile.open()")
Lars Gustäbel42e00912009-03-22 20:34:29 +00002573 self.hit_eof = self.tell() == len(self.getvalue())
2574 return super(MyBytesIO, self).read(n)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002575 def seek(self, *args):
2576 self.hit_eof = False
2577 return super(MyBytesIO, self).seek(*args)
Lars Gustäbel42e00912009-03-22 20:34:29 +00002578
2579 data = bz2.compress(tarfile.TarInfo("foo").tobuf())
2580 for x in range(len(data) + 1):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002581 try:
2582 tarfile.open(fileobj=MyBytesIO(data[:x]), mode=mode)
2583 except tarfile.ReadError:
2584 pass # we have no interest in ReadErrors
Lars Gustäbel42e00912009-03-22 20:34:29 +00002585
2586 def test_partial_input(self):
2587 self._test_partial_input("r")
2588
2589 def test_partial_input_bz2(self):
2590 self._test_partial_input("r:bz2")
2591
2592
Eric V. Smith7a803892015-04-15 10:27:58 -04002593def root_is_uid_gid_0():
2594 try:
2595 import pwd, grp
2596 except ImportError:
2597 return False
2598 if pwd.getpwuid(0)[0] != 'root':
2599 return False
2600 if grp.getgrgid(0)[0] != 'root':
2601 return False
2602 return True
2603
2604
Zachary Waread3e27a2015-05-12 23:57:21 -05002605@unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown")
2606@unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid")
Eric V. Smith7a803892015-04-15 10:27:58 -04002607class NumericOwnerTest(unittest.TestCase):
2608 # mock the following:
2609 # os.chown: so we can test what's being called
2610 # os.chmod: so the modes are not actually changed. if they are, we can't
2611 # delete the files/directories
2612 # os.geteuid: so we can lie and say we're root (uid = 0)
2613
2614 @staticmethod
2615 def _make_test_archive(filename_1, dirname_1, filename_2):
2616 # the file contents to write
2617 fobj = io.BytesIO(b"content")
2618
2619 # create a tar file with a file, a directory, and a file within that
2620 # directory. Assign various .uid/.gid values to them
2621 items = [(filename_1, 99, 98, tarfile.REGTYPE, fobj),
2622 (dirname_1, 77, 76, tarfile.DIRTYPE, None),
2623 (filename_2, 88, 87, tarfile.REGTYPE, fobj),
2624 ]
2625 with tarfile.open(tmpname, 'w') as tarfl:
2626 for name, uid, gid, typ, contents in items:
2627 t = tarfile.TarInfo(name)
2628 t.uid = uid
2629 t.gid = gid
2630 t.uname = 'root'
2631 t.gname = 'root'
2632 t.type = typ
2633 tarfl.addfile(t, contents)
2634
2635 # return the full pathname to the tar file
2636 return tmpname
2637
2638 @staticmethod
2639 @contextmanager
2640 def _setup_test(mock_geteuid):
2641 mock_geteuid.return_value = 0 # lie and say we're root
2642 fname = 'numeric-owner-testfile'
2643 dirname = 'dir'
2644
2645 # the names we want stored in the tarfile
2646 filename_1 = fname
2647 dirname_1 = dirname
2648 filename_2 = os.path.join(dirname, fname)
2649
2650 # create the tarfile with the contents we're after
2651 tar_filename = NumericOwnerTest._make_test_archive(filename_1,
2652 dirname_1,
2653 filename_2)
2654
2655 # open the tarfile for reading. yield it and the names of the items
2656 # we stored into the file
2657 with tarfile.open(tar_filename) as tarfl:
2658 yield tarfl, filename_1, dirname_1, filename_2
2659
2660 @unittest.mock.patch('os.chown')
2661 @unittest.mock.patch('os.chmod')
2662 @unittest.mock.patch('os.geteuid')
2663 def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod,
2664 mock_chown):
2665 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _,
2666 filename_2):
2667 tarfl.extract(filename_1, TEMPDIR, numeric_owner=True)
2668 tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True)
2669
2670 # convert to filesystem paths
2671 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2672 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2673
2674 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2675 unittest.mock.call(f_filename_2, 88, 87),
2676 ],
2677 any_order=True)
2678
2679 @unittest.mock.patch('os.chown')
2680 @unittest.mock.patch('os.chmod')
2681 @unittest.mock.patch('os.geteuid')
2682 def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod,
2683 mock_chown):
2684 with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1,
2685 filename_2):
2686 tarfl.extractall(TEMPDIR, numeric_owner=True)
2687
2688 # convert to filesystem paths
2689 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2690 f_dirname_1 = os.path.join(TEMPDIR, dirname_1)
2691 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2692
2693 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2694 unittest.mock.call(f_dirname_1, 77, 76),
2695 unittest.mock.call(f_filename_2, 88, 87),
2696 ],
2697 any_order=True)
2698
2699 # this test requires that uid=0 and gid=0 really be named 'root'. that's
2700 # because the uname and gname in the test file are 'root', and extract()
2701 # will look them up using pwd and grp to find their uid and gid, which we
2702 # test here to be 0.
2703 @unittest.skipUnless(root_is_uid_gid_0(),
2704 'uid=0,gid=0 must be named "root"')
2705 @unittest.mock.patch('os.chown')
2706 @unittest.mock.patch('os.chmod')
2707 @unittest.mock.patch('os.geteuid')
2708 def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod,
2709 mock_chown):
2710 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2711 tarfl.extract(filename_1, TEMPDIR, numeric_owner=False)
2712
2713 # convert to filesystem paths
2714 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2715
2716 mock_chown.assert_called_with(f_filename_1, 0, 0)
2717
2718 @unittest.mock.patch('os.geteuid')
2719 def test_keyword_only(self, mock_geteuid):
2720 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2721 self.assertRaises(TypeError,
2722 tarfl.extract, filename_1, TEMPDIR, False, True)
2723
2724
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002725def setUpModule():
Antoine Pitrou95f55602010-09-23 18:36:46 +00002726 support.unlink(TEMPDIR)
Antoine Pitrou941ee882009-11-11 20:59:38 +00002727 os.makedirs(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002728
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002729 global testtarnames
2730 testtarnames = [tarname]
Antoine Pitrou95f55602010-09-23 18:36:46 +00002731 with open(tarname, "rb") as fobj:
2732 data = fobj.read()
Neal Norwitza4f651a2004-07-20 22:07:44 +00002733
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002734 # Create compressed tarfiles.
2735 for c in GzipTest, Bz2Test, LzmaTest:
2736 if c.open:
2737 support.unlink(c.tarname)
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002738 testtarnames.append(c.tarname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002739 with c.open(c.tarname, "wb") as tar:
2740 tar.write(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002741
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002742def tearDownModule():
2743 if os.path.exists(TEMPDIR):
Tim Goldene0bd2c52014-05-06 13:24:26 +01002744 support.rmtree(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002745
Neal Norwitz996acf12003-02-17 14:51:41 +00002746if __name__ == "__main__":
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002747 unittest.main()