blob: 6a901089611cd8b799624b6c2875f8ac25a3b045 [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
Christian Heimesc64a1a62019-09-25 16:30:20 +020014from test.support import script_helper, requires_hashdigest
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
60@support.requires_gzip
61class 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
67@support.requires_bz2
68class 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
74@support.requires_lzma
75class 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
389 data = Random(0).getrandbits(512*8).to_bytes(512, 'big')
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
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300432class MiscReadTestBase(CommonReadTest):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300433 def requires_name_attribute(self):
434 pass
435
Thomas Woutersed03b412007-08-28 21:37:11 +0000436 def test_no_name_argument(self):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300437 self.requires_name_attribute()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000438 with open(self.tarname, "rb") as fobj:
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300439 self.assertIsInstance(fobj.name, str)
440 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
441 self.assertIsInstance(tar.name, str)
442 self.assertEqual(tar.name, os.path.abspath(fobj.name))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000443
Thomas Woutersed03b412007-08-28 21:37:11 +0000444 def test_no_name_attribute(self):
Antoine Pitrou95f55602010-09-23 18:36:46 +0000445 with open(self.tarname, "rb") as fobj:
446 data = fobj.read()
Thomas Woutersed03b412007-08-28 21:37:11 +0000447 fobj = io.BytesIO(data)
448 self.assertRaises(AttributeError, getattr, fobj, "name")
449 tar = tarfile.open(fileobj=fobj, mode=self.mode)
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300450 self.assertIsNone(tar.name)
Thomas Woutersed03b412007-08-28 21:37:11 +0000451
452 def test_empty_name_attribute(self):
Antoine Pitrou95f55602010-09-23 18:36:46 +0000453 with open(self.tarname, "rb") as fobj:
454 data = fobj.read()
Thomas Woutersed03b412007-08-28 21:37:11 +0000455 fobj = io.BytesIO(data)
456 fobj.name = ""
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000457 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300458 self.assertIsNone(tar.name)
459
460 def test_int_name_attribute(self):
461 # Issue 21044: tarfile.open() should handle fileobj with an integer
462 # 'name' attribute.
463 fd = os.open(self.tarname, os.O_RDONLY)
464 with open(fd, 'rb') as fobj:
465 self.assertIsInstance(fobj.name, int)
466 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
467 self.assertIsNone(tar.name)
468
469 def test_bytes_name_attribute(self):
470 self.requires_name_attribute()
471 tarname = os.fsencode(self.tarname)
472 with open(tarname, 'rb') as fobj:
473 self.assertIsInstance(fobj.name, bytes)
474 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
475 self.assertIsInstance(tar.name, bytes)
476 self.assertEqual(tar.name, os.path.abspath(fobj.name))
Thomas Woutersed03b412007-08-28 21:37:11 +0000477
Serhiy Storchakac45cd162017-03-08 10:32:44 +0200478 def test_pathlike_name(self):
479 tarname = pathlib.Path(self.tarname)
480 with tarfile.open(tarname, mode=self.mode) as tar:
481 self.assertIsInstance(tar.name, str)
482 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
483 with self.taropen(tarname) as tar:
484 self.assertIsInstance(tar.name, str)
485 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
486 with tarfile.TarFile.open(tarname, mode=self.mode) as tar:
487 self.assertIsInstance(tar.name, str)
488 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
489 if self.suffix == '':
490 with tarfile.TarFile(tarname, mode='r') as tar:
491 self.assertIsInstance(tar.name, str)
492 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
493
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +0200494 def test_illegal_mode_arg(self):
495 with open(tmpname, 'wb'):
496 pass
497 with self.assertRaisesRegex(ValueError, 'mode must be '):
498 tar = self.taropen(tmpname, 'q')
499 with self.assertRaisesRegex(ValueError, 'mode must be '):
500 tar = self.taropen(tmpname, 'rw')
501 with self.assertRaisesRegex(ValueError, 'mode must be '):
502 tar = self.taropen(tmpname, '')
503
Christian Heimesd8654cf2007-12-02 15:22:16 +0000504 def test_fileobj_with_offset(self):
505 # Skip the first member and store values from the second member
506 # of the testtar.
507 tar = tarfile.open(self.tarname, mode=self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000508 try:
509 tar.next()
510 t = tar.next()
511 name = t.name
512 offset = t.offset
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200513 with tar.extractfile(t) as f:
514 data = f.read()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000515 finally:
516 tar.close()
Christian Heimesd8654cf2007-12-02 15:22:16 +0000517
518 # Open the testtar and seek to the offset of the second member.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300519 with self.open(self.tarname) as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000520 fobj.seek(offset)
Christian Heimesd8654cf2007-12-02 15:22:16 +0000521
Antoine Pitrou95f55602010-09-23 18:36:46 +0000522 # Test if the tarfile starts with the second member.
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +0200523 with tar.open(self.tarname, mode="r:", fileobj=fobj) as tar:
524 t = tar.next()
525 self.assertEqual(t.name, name)
526 # Read to the end of fileobj and test if seeking back to the
527 # beginning works.
528 tar.getmembers()
529 self.assertEqual(tar.extractfile(t).read(), data,
530 "seek back did not work")
Christian Heimesd8654cf2007-12-02 15:22:16 +0000531
Guido van Rossumd8faa362007-04-27 19:54:29 +0000532 def test_fail_comp(self):
533 # For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000534 self.assertRaises(tarfile.ReadError, tarfile.open, tarname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000535 with open(tarname, "rb") as fobj:
536 self.assertRaises(tarfile.ReadError, tarfile.open,
537 fileobj=fobj, mode=self.mode)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000538
539 def test_v7_dirtype(self):
540 # Test old style dirtype member (bug #1336623):
541 # Old V7 tars create directory members using an AREGTYPE
542 # header with a "/" appended to the filename field.
543 tarinfo = self.tar.getmember("misc/dirtype-old-v7")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300544 self.assertEqual(tarinfo.type, tarfile.DIRTYPE,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000545 "v7 dirtype failed")
546
Christian Heimes126d29a2008-02-11 22:57:17 +0000547 def test_xstar_type(self):
548 # The xstar format stores extra atime and ctime fields inside the
549 # space reserved for the prefix field. The prefix field must be
550 # ignored in this case, otherwise it will mess up the name.
551 try:
552 self.tar.getmember("misc/regtype-xstar")
553 except KeyError:
554 self.fail("failed to find misc/regtype-xstar (mangled prefix?)")
555
Guido van Rossumd8faa362007-04-27 19:54:29 +0000556 def test_check_members(self):
557 for tarinfo in self.tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300558 self.assertEqual(int(tarinfo.mtime), 0o7606136617,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000559 "wrong mtime for %s" % tarinfo.name)
560 if not tarinfo.name.startswith("ustar/"):
561 continue
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300562 self.assertEqual(tarinfo.uname, "tarfile",
Guido van Rossumd8faa362007-04-27 19:54:29 +0000563 "wrong uname for %s" % tarinfo.name)
564
565 def test_find_members(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300566 self.assertEqual(self.tar.getmembers()[-1].name, "misc/eof",
Guido van Rossumd8faa362007-04-27 19:54:29 +0000567 "could not find all members")
568
Brian Curtin74e45612010-07-09 15:58:59 +0000569 @unittest.skipUnless(hasattr(os, "link"),
570 "Missing hardlink implementation")
Brian Curtin3b4499c2010-12-28 14:31:47 +0000571 @support.skip_unless_symlink
Guido van Rossumd8faa362007-04-27 19:54:29 +0000572 def test_extract_hardlink(self):
573 # Test hardlink extraction (e.g. bug #857297).
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200574 with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000575 tar.extract("ustar/regtype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100576 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/regtype"))
Neal Norwitzf3396542005-10-28 05:52:22 +0000577
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200578 tar.extract("ustar/lnktype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100579 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype"))
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000580 with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
581 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +0200582 self.assertEqual(sha256sum(data), sha256_regtype)
Neal Norwitzf3396542005-10-28 05:52:22 +0000583
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200584 tar.extract("ustar/symtype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100585 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype"))
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000586 with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
587 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +0200588 self.assertEqual(sha256sum(data), sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000589
Christian Heimesfaf2f632008-01-06 16:59:19 +0000590 def test_extractall(self):
591 # Test if extractall() correctly restores directory permissions
592 # and times (see issue1735).
Christian Heimesfaf2f632008-01-06 16:59:19 +0000593 tar = tarfile.open(tarname, encoding="iso8859-1")
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000594 DIR = os.path.join(TEMPDIR, "extractall")
595 os.mkdir(DIR)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000596 try:
597 directories = [t for t in tar if t.isdir()]
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000598 tar.extractall(DIR, directories)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000599 for tarinfo in directories:
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000600 path = os.path.join(DIR, tarinfo.name)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000601 if sys.platform != "win32":
602 # Win32 has no support for fine grained permissions.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300603 self.assertEqual(tarinfo.mode & 0o777,
604 os.stat(path).st_mode & 0o777)
Victor Stinner26bfb5a2010-10-29 10:59:08 +0000605 def format_mtime(mtime):
606 if isinstance(mtime, float):
607 return "{} ({})".format(mtime, mtime.hex())
608 else:
609 return "{!r} (int)".format(mtime)
Victor Stinner14d8fe72010-10-29 11:02:06 +0000610 file_mtime = os.path.getmtime(path)
Victor Stinner26bfb5a2010-10-29 10:59:08 +0000611 errmsg = "tar mtime {0} != file time {1} of path {2!a}".format(
612 format_mtime(tarinfo.mtime),
613 format_mtime(file_mtime),
614 path)
615 self.assertEqual(tarinfo.mtime, file_mtime, errmsg)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000616 finally:
617 tar.close()
Tim Goldene0bd2c52014-05-06 13:24:26 +0100618 support.rmtree(DIR)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000619
Martin v. Löwis16f344d2010-11-01 21:39:13 +0000620 def test_extract_directory(self):
621 dirtype = "ustar/dirtype"
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000622 DIR = os.path.join(TEMPDIR, "extractdir")
623 os.mkdir(DIR)
624 try:
625 with tarfile.open(tarname, encoding="iso8859-1") as tar:
626 tarinfo = tar.getmember(dirtype)
627 tar.extract(tarinfo, path=DIR)
628 extracted = os.path.join(DIR, dirtype)
629 self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
630 if sys.platform != "win32":
631 self.assertEqual(os.stat(extracted).st_mode & 0o777, 0o755)
632 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +0100633 support.rmtree(DIR)
Martin v. Löwis16f344d2010-11-01 21:39:13 +0000634
Serhiy Storchakac45cd162017-03-08 10:32:44 +0200635 def test_extractall_pathlike_name(self):
636 DIR = pathlib.Path(TEMPDIR) / "extractall"
637 with support.temp_dir(DIR), \
638 tarfile.open(tarname, encoding="iso8859-1") as tar:
639 directories = [t for t in tar if t.isdir()]
640 tar.extractall(DIR, directories)
641 for tarinfo in directories:
642 path = DIR / tarinfo.name
643 self.assertEqual(os.path.getmtime(path), tarinfo.mtime)
644
645 def test_extract_pathlike_name(self):
646 dirtype = "ustar/dirtype"
647 DIR = pathlib.Path(TEMPDIR) / "extractall"
648 with support.temp_dir(DIR), \
649 tarfile.open(tarname, encoding="iso8859-1") as tar:
650 tarinfo = tar.getmember(dirtype)
651 tar.extract(tarinfo, path=DIR)
652 extracted = DIR / dirtype
653 self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
654
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000655 def test_init_close_fobj(self):
656 # Issue #7341: Close the internal file object in the TarFile
657 # constructor in case of an error. For the test we rely on
658 # the fact that opening an empty file raises a ReadError.
659 empty = os.path.join(TEMPDIR, "empty")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000660 with open(empty, "wb") as fobj:
661 fobj.write(b"")
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000662
663 try:
664 tar = object.__new__(tarfile.TarFile)
665 try:
666 tar.__init__(empty)
667 except tarfile.ReadError:
668 self.assertTrue(tar.fileobj.closed)
669 else:
670 self.fail("ReadError not raised")
671 finally:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000672 support.unlink(empty)
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000673
Serhiy Storchaka263fab92013-05-09 14:22:26 +0300674 def test_parallel_iteration(self):
675 # Issue #16601: Restarting iteration over tarfile continued
676 # from where it left off.
677 with tarfile.open(self.tarname) as tar:
678 for m1, m2 in zip(tar, tar):
679 self.assertEqual(m1.offset, m2.offset)
680 self.assertEqual(m1.get_info(), m2.get_info())
681
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300682class MiscReadTest(MiscReadTestBase, unittest.TestCase):
683 test_fail_comp = None
Guido van Rossumd8faa362007-04-27 19:54:29 +0000684
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300685class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase):
Serhiy Storchakaf22fe0f2014-01-13 19:08:00 +0200686 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000687
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300688class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300689 def requires_name_attribute(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300690 self.skipTest("BZ2File have no name attribute")
691
692class LzmaMiscReadTest(LzmaTest, MiscReadTestBase, unittest.TestCase):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300693 def requires_name_attribute(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300694 self.skipTest("LZMAFile have no name attribute")
695
696
697class StreamReadTest(CommonReadTest, unittest.TestCase):
698
699 prefix="r|"
Guido van Rossumd8faa362007-04-27 19:54:29 +0000700
Lars Gustäbeldd071042011-02-23 11:42:22 +0000701 def test_read_through(self):
702 # Issue #11224: A poorly designed _FileInFile.read() method
703 # caused seeking errors with stream tar files.
704 for tarinfo in self.tar:
705 if not tarinfo.isreg():
706 continue
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200707 with self.tar.extractfile(tarinfo) as fobj:
708 while True:
709 try:
710 buf = fobj.read(512)
711 except tarfile.StreamError:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300712 self.fail("simple read-through using "
713 "TarFile.extractfile() failed")
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200714 if not buf:
715 break
Lars Gustäbeldd071042011-02-23 11:42:22 +0000716
Guido van Rossumd8faa362007-04-27 19:54:29 +0000717 def test_fileobj_regular_file(self):
718 tarinfo = self.tar.next() # get "regtype" (can't use getmember)
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200719 with self.tar.extractfile(tarinfo) as fobj:
720 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300721 self.assertEqual(len(data), tarinfo.size,
722 "regular file extraction failed")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200723 self.assertEqual(sha256sum(data), sha256_regtype,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000724 "regular file extraction failed")
725
726 def test_provoke_stream_error(self):
727 tarinfos = self.tar.getmembers()
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200728 with self.tar.extractfile(tarinfos[0]) as f: # read the first member
729 self.assertRaises(tarfile.StreamError, f.read)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000730
Guido van Rossumd8faa362007-04-27 19:54:29 +0000731 def test_compare_members(self):
732 tar1 = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000733 try:
734 tar2 = self.tar
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000735
Antoine Pitrou95f55602010-09-23 18:36:46 +0000736 while True:
737 t1 = tar1.next()
738 t2 = tar2.next()
739 if t1 is None:
740 break
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300741 self.assertIsNotNone(t2, "stream.next() failed.")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000742
Antoine Pitrou95f55602010-09-23 18:36:46 +0000743 if t2.islnk() or t2.issym():
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300744 with self.assertRaises(tarfile.StreamError):
745 tar2.extractfile(t2)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000746 continue
Guido van Rossumd8faa362007-04-27 19:54:29 +0000747
Antoine Pitrou95f55602010-09-23 18:36:46 +0000748 v1 = tar1.extractfile(t1)
749 v2 = tar2.extractfile(t2)
750 if v1 is None:
751 continue
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300752 self.assertIsNotNone(v2, "stream.extractfile() failed")
753 self.assertEqual(v1.read(), v2.read(),
754 "stream extraction failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000755 finally:
756 tar1.close()
Thomas Wouters902d6eb2007-01-09 23:18:33 +0000757
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300758class GzipStreamReadTest(GzipTest, StreamReadTest):
759 pass
Thomas Wouters89f507f2006-12-13 04:49:30 +0000760
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300761class Bz2StreamReadTest(Bz2Test, StreamReadTest):
762 pass
Thomas Wouterscf297e42007-02-23 15:07:44 +0000763
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300764class LzmaStreamReadTest(LzmaTest, StreamReadTest):
765 pass
766
767
768class DetectReadTest(TarTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000769 def _testfunc_file(self, name, mode):
770 try:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000771 tar = tarfile.open(name, mode)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000772 except tarfile.ReadError as e:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000773 self.fail()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000774 else:
775 tar.close()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000776
Guido van Rossumd8faa362007-04-27 19:54:29 +0000777 def _testfunc_fileobj(self, name, mode):
778 try:
Antoine Pitrou605c2932010-09-23 20:15:14 +0000779 with open(name, "rb") as f:
780 tar = tarfile.open(name, mode, fileobj=f)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000781 except tarfile.ReadError as e:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000782 self.fail()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000783 else:
784 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000785
786 def _test_modes(self, testfunc):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300787 if self.suffix:
788 with self.assertRaises(tarfile.ReadError):
789 tarfile.open(tarname, mode="r:" + self.suffix)
790 with self.assertRaises(tarfile.ReadError):
791 tarfile.open(tarname, mode="r|" + self.suffix)
792 with self.assertRaises(tarfile.ReadError):
793 tarfile.open(self.tarname, mode="r:")
794 with self.assertRaises(tarfile.ReadError):
795 tarfile.open(self.tarname, mode="r|")
796 testfunc(self.tarname, "r")
797 testfunc(self.tarname, "r:" + self.suffix)
798 testfunc(self.tarname, "r:*")
799 testfunc(self.tarname, "r|" + self.suffix)
800 testfunc(self.tarname, "r|*")
Lars Gustäbel0a9dd2f2011-12-10 20:38:14 +0100801
Guido van Rossumd8faa362007-04-27 19:54:29 +0000802 def test_detect_file(self):
803 self._test_modes(self._testfunc_file)
804
805 def test_detect_fileobj(self):
806 self._test_modes(self._testfunc_fileobj)
807
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300808class GzipDetectReadTest(GzipTest, DetectReadTest):
809 pass
810
811class Bz2DetectReadTest(Bz2Test, DetectReadTest):
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100812 def test_detect_stream_bz2(self):
813 # Originally, tarfile's stream detection looked for the string
814 # "BZh91" at the start of the file. This is incorrect because
Victor Stinner8c663fd2017-11-08 14:44:44 -0800815 # the '9' represents the blocksize (900,000 bytes). If the file was
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100816 # compressed using another blocksize autodetection fails.
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100817 with open(tarname, "rb") as fobj:
818 data = fobj.read()
819
Victor Stinner8c663fd2017-11-08 14:44:44 -0800820 # Compress with blocksize 100,000 bytes, the file starts with "BZh11".
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100821 with bz2.BZ2File(tmpname, "wb", compresslevel=1) as fobj:
822 fobj.write(data)
823
824 self._testfunc_file(tmpname, "r|*")
825
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300826class LzmaDetectReadTest(LzmaTest, DetectReadTest):
827 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000828
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300829
830class MemberReadTest(ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000831
832 def _test_member(self, tarinfo, chksum=None, **kwargs):
833 if chksum is not None:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300834 with self.tar.extractfile(tarinfo) as f:
Christian Heimesc64a1a62019-09-25 16:30:20 +0200835 self.assertEqual(sha256sum(f.read()), chksum,
836 "wrong sha256sum for %s" % tarinfo.name)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000837
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000838 kwargs["mtime"] = 0o7606136617
Guido van Rossumd8faa362007-04-27 19:54:29 +0000839 kwargs["uid"] = 1000
840 kwargs["gid"] = 100
841 if "old-v7" not in tarinfo.name:
842 # V7 tar can't handle alphabetic owners.
843 kwargs["uname"] = "tarfile"
844 kwargs["gname"] = "tarfile"
845 for k, v in kwargs.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300846 self.assertEqual(getattr(tarinfo, k), v,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000847 "wrong value in %s field of %s" % (k, tarinfo.name))
848
849 def test_find_regtype(self):
850 tarinfo = self.tar.getmember("ustar/regtype")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200851 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000852
853 def test_find_conttype(self):
854 tarinfo = self.tar.getmember("ustar/conttype")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200855 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000856
857 def test_find_dirtype(self):
858 tarinfo = self.tar.getmember("ustar/dirtype")
859 self._test_member(tarinfo, size=0)
860
861 def test_find_dirtype_with_size(self):
862 tarinfo = self.tar.getmember("ustar/dirtype-with-size")
863 self._test_member(tarinfo, size=255)
864
865 def test_find_lnktype(self):
866 tarinfo = self.tar.getmember("ustar/lnktype")
867 self._test_member(tarinfo, size=0, linkname="ustar/regtype")
868
869 def test_find_symtype(self):
870 tarinfo = self.tar.getmember("ustar/symtype")
871 self._test_member(tarinfo, size=0, linkname="regtype")
872
873 def test_find_blktype(self):
874 tarinfo = self.tar.getmember("ustar/blktype")
875 self._test_member(tarinfo, size=0, devmajor=3, devminor=0)
876
877 def test_find_chrtype(self):
878 tarinfo = self.tar.getmember("ustar/chrtype")
879 self._test_member(tarinfo, size=0, devmajor=1, devminor=3)
880
881 def test_find_fifotype(self):
882 tarinfo = self.tar.getmember("ustar/fifotype")
883 self._test_member(tarinfo, size=0)
884
885 def test_find_sparse(self):
886 tarinfo = self.tar.getmember("ustar/sparse")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200887 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000888
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000889 def test_find_gnusparse(self):
890 tarinfo = self.tar.getmember("gnu/sparse")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200891 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000892
893 def test_find_gnusparse_00(self):
894 tarinfo = self.tar.getmember("gnu/sparse-0.0")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200895 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000896
897 def test_find_gnusparse_01(self):
898 tarinfo = self.tar.getmember("gnu/sparse-0.1")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200899 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000900
901 def test_find_gnusparse_10(self):
902 tarinfo = self.tar.getmember("gnu/sparse-1.0")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200903 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000904
Guido van Rossumd8faa362007-04-27 19:54:29 +0000905 def test_find_umlauts(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300906 tarinfo = self.tar.getmember("ustar/umlauts-"
907 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200908 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000909
910 def test_find_ustar_longname(self):
911 name = "ustar/" + "12345/" * 39 + "1234567/longname"
Benjamin Peterson577473f2010-01-19 00:09:57 +0000912 self.assertIn(name, self.tar.getnames())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000913
914 def test_find_regtype_oldv7(self):
915 tarinfo = self.tar.getmember("misc/regtype-old-v7")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200916 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000917
918 def test_find_pax_umlauts(self):
Antoine Pitrouab58b5f2010-09-23 19:39:35 +0000919 self.tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300920 self.tar = tarfile.open(self.tarname, mode=self.mode,
921 encoding="iso8859-1")
922 tarinfo = self.tar.getmember("pax/umlauts-"
923 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Christian Heimesc64a1a62019-09-25 16:30:20 +0200924 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000925
926
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300927class LongnameTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000928
929 def test_read_longname(self):
930 # Test reading of longname (bug #1471427).
Guido van Rossume7ba4952007-06-06 23:52:48 +0000931 longname = self.subdir + "/" + "123/" * 125 + "longname"
Guido van Rossumd8faa362007-04-27 19:54:29 +0000932 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000933 tarinfo = self.tar.getmember(longname)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000934 except KeyError:
935 self.fail("longname not found")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300936 self.assertNotEqual(tarinfo.type, tarfile.DIRTYPE,
937 "read longname as dirtype")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000938
939 def test_read_longlink(self):
940 longname = self.subdir + "/" + "123/" * 125 + "longname"
941 longlink = self.subdir + "/" + "123/" * 125 + "longlink"
942 try:
943 tarinfo = self.tar.getmember(longlink)
944 except KeyError:
945 self.fail("longlink not found")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300946 self.assertEqual(tarinfo.linkname, longname, "linkname wrong")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000947
948 def test_truncated_longname(self):
949 longname = self.subdir + "/" + "123/" * 125 + "longname"
950 tarinfo = self.tar.getmember(longname)
951 offset = tarinfo.offset
952 self.tar.fileobj.seek(offset)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000953 fobj = io.BytesIO(self.tar.fileobj.read(3 * 512))
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300954 with self.assertRaises(tarfile.ReadError):
955 tarfile.open(name="foo.tar", fileobj=fobj)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000956
Guido van Rossume7ba4952007-06-06 23:52:48 +0000957 def test_header_offset(self):
958 # Test if the start offset of the TarInfo object includes
959 # the preceding extended header.
960 longname = self.subdir + "/" + "123/" * 125 + "longname"
961 offset = self.tar.getmember(longname).offset
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000962 with open(tarname, "rb") as fobj:
963 fobj.seek(offset)
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300964 tarinfo = tarfile.TarInfo.frombuf(fobj.read(512),
965 "iso8859-1", "strict")
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000966 self.assertEqual(tarinfo.type, self.longnametype)
Guido van Rossume7ba4952007-06-06 23:52:48 +0000967
Guido van Rossumd8faa362007-04-27 19:54:29 +0000968
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300969class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000970
971 subdir = "gnu"
Guido van Rossume7ba4952007-06-06 23:52:48 +0000972 longnametype = tarfile.GNUTYPE_LONGNAME
Guido van Rossumd8faa362007-04-27 19:54:29 +0000973
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000974 # Since 3.2 tarfile is supposed to accurately restore sparse members and
975 # produce files with holes. This is what we actually want to test here.
976 # Unfortunately, not all platforms/filesystems support sparse files, and
977 # even on platforms that do it is non-trivial to make reliable assertions
978 # about holes in files. Therefore, we first do one basic test which works
979 # an all platforms, and after that a test that will work only on
980 # platforms/filesystems that prove to support sparse files.
981 def _test_sparse_file(self, name):
982 self.tar.extract(name, TEMPDIR)
983 filename = os.path.join(TEMPDIR, name)
984 with open(filename, "rb") as fobj:
985 data = fobj.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +0200986 self.assertEqual(sha256sum(data), sha256_sparse,
987 "wrong sha256sum for %s" % name)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000988
989 if self._fs_supports_holes():
990 s = os.stat(filename)
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300991 self.assertLess(s.st_blocks * 512, s.st_size)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000992
993 def test_sparse_file_old(self):
994 self._test_sparse_file("gnu/sparse")
995
996 def test_sparse_file_00(self):
997 self._test_sparse_file("gnu/sparse-0.0")
998
999 def test_sparse_file_01(self):
1000 self._test_sparse_file("gnu/sparse-0.1")
1001
1002 def test_sparse_file_10(self):
1003 self._test_sparse_file("gnu/sparse-1.0")
1004
1005 @staticmethod
1006 def _fs_supports_holes():
1007 # Return True if the platform knows the st_blocks stat attribute and
1008 # uses st_blocks units of 512 bytes, and if the filesystem is able to
Victor Stinnerb2385452019-01-21 10:24:12 +01001009 # store holes of 4 KiB in files.
1010 #
1011 # The function returns False if page size is larger than 4 KiB.
1012 # For example, ppc64 uses pages of 64 KiB.
Victor Stinner9c3de4a2011-08-17 20:49:41 +02001013 if sys.platform.startswith("linux"):
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001014 # Linux evidentially has 512 byte st_blocks units.
1015 name = os.path.join(TEMPDIR, "sparse-test")
1016 with open(name, "wb") as fobj:
Victor Stinnerb2385452019-01-21 10:24:12 +01001017 # Seek to "punch a hole" of 4 KiB
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001018 fobj.seek(4096)
Victor Stinnerb2385452019-01-21 10:24:12 +01001019 fobj.write(b'x' * 4096)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001020 fobj.truncate()
1021 s = os.stat(name)
Tim Goldene0bd2c52014-05-06 13:24:26 +01001022 support.unlink(name)
Victor Stinnerb2385452019-01-21 10:24:12 +01001023 return (s.st_blocks * 512 < s.st_size)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +00001024 else:
1025 return False
Guido van Rossumd8faa362007-04-27 19:54:29 +00001026
1027
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001028class PaxReadTest(LongnameTest, ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001029
1030 subdir = "pax"
Guido van Rossume7ba4952007-06-06 23:52:48 +00001031 longnametype = tarfile.XHDTYPE
Guido van Rossumd8faa362007-04-27 19:54:29 +00001032
Guido van Rossume7ba4952007-06-06 23:52:48 +00001033 def test_pax_global_headers(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001034 tar = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001035 try:
1036 tarinfo = tar.getmember("pax/regtype1")
1037 self.assertEqual(tarinfo.uname, "foo")
1038 self.assertEqual(tarinfo.gname, "bar")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001039 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1040 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Guido van Rossume7ba4952007-06-06 23:52:48 +00001041
Antoine Pitrou95f55602010-09-23 18:36:46 +00001042 tarinfo = tar.getmember("pax/regtype2")
1043 self.assertEqual(tarinfo.uname, "")
1044 self.assertEqual(tarinfo.gname, "bar")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001045 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1046 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001047
Antoine Pitrou95f55602010-09-23 18:36:46 +00001048 tarinfo = tar.getmember("pax/regtype3")
1049 self.assertEqual(tarinfo.uname, "tarfile")
1050 self.assertEqual(tarinfo.gname, "tarfile")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001051 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1052 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001053 finally:
1054 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001055
1056 def test_pax_number_fields(self):
1057 # All following number fields are read from the pax header.
1058 tar = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001059 try:
1060 tarinfo = tar.getmember("pax/regtype4")
1061 self.assertEqual(tarinfo.size, 7011)
1062 self.assertEqual(tarinfo.uid, 123)
1063 self.assertEqual(tarinfo.gid, 123)
1064 self.assertEqual(tarinfo.mtime, 1041808783.0)
1065 self.assertEqual(type(tarinfo.mtime), float)
1066 self.assertEqual(float(tarinfo.pax_headers["atime"]), 1041808783.0)
1067 self.assertEqual(float(tarinfo.pax_headers["ctime"]), 1041808783.0)
1068 finally:
1069 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001070
1071
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001072class WriteTestBase(TarTest):
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001073 # Put all write tests in here that are supposed to be tested
1074 # in all possible mode combinations.
1075
1076 def test_fileobj_no_close(self):
1077 fobj = io.BytesIO()
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001078 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
1079 tar.addfile(tarfile.TarInfo("foo"))
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001080 self.assertFalse(fobj.closed, "external fileobjs must never closed")
Serhiy Storchaka9fbec7a2014-01-18 15:53:05 +02001081 # Issue #20238: Incomplete gzip output with mode="w:gz"
1082 data = fobj.getvalue()
1083 del tar
1084 support.gc_collect()
1085 self.assertFalse(fobj.closed)
1086 self.assertEqual(data, fobj.getvalue())
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001087
Lars Gustäbel20703c62015-05-27 12:53:44 +02001088 def test_eof_marker(self):
1089 # Make sure an end of archive marker is written (two zero blocks).
1090 # tarfile insists on aligning archives to a 20 * 512 byte recordsize.
1091 # So, we create an archive that has exactly 10240 bytes without the
1092 # marker, and has 20480 bytes once the marker is written.
1093 with tarfile.open(tmpname, self.mode) as tar:
1094 t = tarfile.TarInfo("foo")
1095 t.size = tarfile.RECORDSIZE - tarfile.BLOCKSIZE
1096 tar.addfile(t, io.BytesIO(b"a" * t.size))
1097
1098 with self.open(tmpname, "rb") as fobj:
1099 self.assertEqual(len(fobj.read()), tarfile.RECORDSIZE * 2)
1100
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001101
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001102class WriteTest(WriteTestBase, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001103
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001104 prefix = "w:"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001105
1106 def test_100_char_name(self):
1107 # The name field in a tar header stores strings of at most 100 chars.
1108 # If a string is shorter than 100 chars it has to be padded with '\0',
1109 # which implies that a string of exactly 100 chars is stored without
1110 # a trailing '\0'.
1111 name = "0123456789" * 10
1112 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001113 try:
1114 t = tarfile.TarInfo(name)
1115 tar.addfile(t)
1116 finally:
1117 tar.close()
Thomas Wouterscf297e42007-02-23 15:07:44 +00001118
Guido van Rossumd8faa362007-04-27 19:54:29 +00001119 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001120 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001121 self.assertEqual(tar.getnames()[0], name,
Antoine Pitrou95f55602010-09-23 18:36:46 +00001122 "failed to store 100 char filename")
1123 finally:
1124 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001125
Guido van Rossumd8faa362007-04-27 19:54:29 +00001126 def test_tar_size(self):
1127 # Test for bug #1013882.
1128 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001129 try:
1130 path = os.path.join(TEMPDIR, "file")
1131 with open(path, "wb") as fobj:
1132 fobj.write(b"aaa")
1133 tar.add(path)
1134 finally:
1135 tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001136 self.assertGreater(os.path.getsize(tmpname), 0,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001137 "tarfile is empty")
Thomas Wouters89f507f2006-12-13 04:49:30 +00001138
Guido van Rossumd8faa362007-04-27 19:54:29 +00001139 # The test_*_size tests test for bug #1167128.
1140 def test_file_size(self):
1141 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001142 try:
1143 path = os.path.join(TEMPDIR, "file")
1144 with open(path, "wb"):
1145 pass
1146 tarinfo = tar.gettarinfo(path)
1147 self.assertEqual(tarinfo.size, 0)
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001148
Antoine Pitrou95f55602010-09-23 18:36:46 +00001149 with open(path, "wb") as fobj:
1150 fobj.write(b"aaa")
1151 tarinfo = tar.gettarinfo(path)
1152 self.assertEqual(tarinfo.size, 3)
1153 finally:
1154 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001155
1156 def test_directory_size(self):
1157 path = os.path.join(TEMPDIR, "directory")
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001158 os.mkdir(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001159 try:
1160 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001161 try:
1162 tarinfo = tar.gettarinfo(path)
1163 self.assertEqual(tarinfo.size, 0)
1164 finally:
1165 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001166 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001167 support.rmdir(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001168
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001169 # mock the following:
1170 # os.listdir: so we know that files are in the wrong order
Bernhard M. Wiedemann4ad703b2018-02-06 19:08:53 +01001171 def test_ordered_recursion(self):
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001172 path = os.path.join(TEMPDIR, "directory")
1173 os.mkdir(path)
1174 open(os.path.join(path, "1"), "a").close()
1175 open(os.path.join(path, "2"), "a").close()
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001176 try:
1177 tar = tarfile.open(tmpname, self.mode)
1178 try:
Bernhard M. Wiedemann4ad703b2018-02-06 19:08:53 +01001179 with unittest.mock.patch('os.listdir') as mock_listdir:
1180 mock_listdir.return_value = ["2", "1"]
1181 tar.add(path)
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001182 paths = []
1183 for m in tar.getmembers():
1184 paths.append(os.path.split(m.name)[-1])
1185 self.assertEqual(paths, ["directory", "1", "2"]);
1186 finally:
1187 tar.close()
1188 finally:
1189 support.unlink(os.path.join(path, "1"))
1190 support.unlink(os.path.join(path, "2"))
1191 support.rmdir(path)
1192
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001193 def test_gettarinfo_pathlike_name(self):
1194 with tarfile.open(tmpname, self.mode) as tar:
1195 path = pathlib.Path(TEMPDIR) / "file"
1196 with open(path, "wb") as fobj:
1197 fobj.write(b"aaa")
1198 tarinfo = tar.gettarinfo(path)
1199 tarinfo2 = tar.gettarinfo(os.fspath(path))
1200 self.assertIsInstance(tarinfo.name, str)
1201 self.assertEqual(tarinfo.name, tarinfo2.name)
1202 self.assertEqual(tarinfo.size, 3)
1203
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001204 @unittest.skipUnless(hasattr(os, "link"),
1205 "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001206 def test_link_size(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001207 link = os.path.join(TEMPDIR, "link")
1208 target = os.path.join(TEMPDIR, "link_target")
1209 with open(target, "wb") as fobj:
1210 fobj.write(b"aaa")
xdegayed7d4fea2017-11-12 18:02:06 +01001211 try:
1212 os.link(target, link)
1213 except PermissionError as e:
1214 self.skipTest('os.link(): %s' % e)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001215 try:
1216 tar = tarfile.open(tmpname, self.mode)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001217 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001218 # Record the link target in the inodes list.
1219 tar.gettarinfo(target)
1220 tarinfo = tar.gettarinfo(link)
1221 self.assertEqual(tarinfo.size, 0)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001222 finally:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001223 tar.close()
1224 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001225 support.unlink(target)
1226 support.unlink(link)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001227
Brian Curtin3b4499c2010-12-28 14:31:47 +00001228 @support.skip_unless_symlink
Guido van Rossumd8faa362007-04-27 19:54:29 +00001229 def test_symlink_size(self):
Brian Curtind40e6f72010-07-08 21:39:08 +00001230 path = os.path.join(TEMPDIR, "symlink")
1231 os.symlink("link_target", path)
1232 try:
1233 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001234 try:
1235 tarinfo = tar.gettarinfo(path)
1236 self.assertEqual(tarinfo.size, 0)
1237 finally:
1238 tar.close()
Brian Curtind40e6f72010-07-08 21:39:08 +00001239 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001240 support.unlink(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001241
1242 def test_add_self(self):
1243 # Test for #1257255.
1244 dstname = os.path.abspath(tmpname)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001245 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001246 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001247 self.assertEqual(tar.name, dstname,
1248 "archive name must be absolute")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001249 tar.add(dstname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001250 self.assertEqual(tar.getnames(), [],
1251 "added the archive to itself")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001252
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001253 with support.change_cwd(TEMPDIR):
1254 tar.add(dstname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001255 self.assertEqual(tar.getnames(), [],
1256 "added the archive to itself")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001257 finally:
1258 tar.close()
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001259
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001260 def test_filter(self):
1261 tempdir = os.path.join(TEMPDIR, "filter")
1262 os.mkdir(tempdir)
1263 try:
1264 for name in ("foo", "bar", "baz"):
1265 name = os.path.join(tempdir, name)
Victor Stinnerbf816222011-06-30 23:25:47 +02001266 support.create_empty_file(name)
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001267
1268 def filter(tarinfo):
1269 if os.path.basename(tarinfo.name) == "bar":
1270 return
1271 tarinfo.uid = 123
1272 tarinfo.uname = "foo"
1273 return tarinfo
1274
1275 tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001276 try:
1277 tar.add(tempdir, arcname="empty_dir", filter=filter)
1278 finally:
1279 tar.close()
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001280
Raymond Hettingera63a3122011-01-26 20:34:14 +00001281 # Verify that filter is a keyword-only argument
1282 with self.assertRaises(TypeError):
1283 tar.add(tempdir, "empty_dir", True, None, filter)
1284
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001285 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001286 try:
1287 for tarinfo in tar:
1288 self.assertEqual(tarinfo.uid, 123)
1289 self.assertEqual(tarinfo.uname, "foo")
1290 self.assertEqual(len(tar.getmembers()), 3)
1291 finally:
1292 tar.close()
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001293 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001294 support.rmtree(tempdir)
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001295
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001296 # Guarantee that stored pathnames are not modified. Don't
1297 # remove ./ or ../ or double slashes. Still make absolute
1298 # pathnames relative.
1299 # For details see bug #6054.
1300 def _test_pathname(self, path, cmp_path=None, dir=False):
1301 # Create a tarfile with an empty member named path
1302 # and compare the stored name with the original.
1303 foo = os.path.join(TEMPDIR, "foo")
1304 if not dir:
Victor Stinnerbf816222011-06-30 23:25:47 +02001305 support.create_empty_file(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001306 else:
1307 os.mkdir(foo)
1308
1309 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001310 try:
1311 tar.add(foo, arcname=path)
1312 finally:
1313 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001314
1315 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001316 try:
1317 t = tar.next()
1318 finally:
1319 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001320
1321 if not dir:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001322 support.unlink(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001323 else:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001324 support.rmdir(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001325
1326 self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/"))
1327
Senthil Kumaranbe5dbeb2011-04-30 06:09:51 +08001328
1329 @support.skip_unless_symlink
Senthil Kumaran123932f2011-04-28 15:38:12 +08001330 def test_extractall_symlinks(self):
1331 # Test if extractall works properly when tarfile contains symlinks
1332 tempdir = os.path.join(TEMPDIR, "testsymlinks")
1333 temparchive = os.path.join(TEMPDIR, "testsymlinks.tar")
1334 os.mkdir(tempdir)
1335 try:
1336 source_file = os.path.join(tempdir,'source')
1337 target_file = os.path.join(tempdir,'symlink')
1338 with open(source_file,'w') as f:
1339 f.write('something\n')
1340 os.symlink(source_file, target_file)
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001341 with tarfile.open(temparchive, 'w') as tar:
1342 tar.add(source_file)
1343 tar.add(target_file)
Senthil Kumaran123932f2011-04-28 15:38:12 +08001344 # Let's extract it to the location which contains the symlink
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001345 with tarfile.open(temparchive) as tar:
1346 # this should not raise OSError: [Errno 17] File exists
1347 try:
1348 tar.extractall(path=tempdir)
1349 except OSError:
1350 self.fail("extractall failed with symlinked files")
Senthil Kumaran123932f2011-04-28 15:38:12 +08001351 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001352 support.unlink(temparchive)
1353 support.rmtree(tempdir)
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001354
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001355 def test_pathnames(self):
1356 self._test_pathname("foo")
1357 self._test_pathname(os.path.join("foo", ".", "bar"))
1358 self._test_pathname(os.path.join("foo", "..", "bar"))
1359 self._test_pathname(os.path.join(".", "foo"))
1360 self._test_pathname(os.path.join(".", "foo", "."))
1361 self._test_pathname(os.path.join(".", "foo", ".", "bar"))
1362 self._test_pathname(os.path.join(".", "foo", "..", "bar"))
1363 self._test_pathname(os.path.join(".", "foo", "..", "bar"))
1364 self._test_pathname(os.path.join("..", "foo"))
1365 self._test_pathname(os.path.join("..", "foo", ".."))
1366 self._test_pathname(os.path.join("..", "foo", ".", "bar"))
1367 self._test_pathname(os.path.join("..", "foo", "..", "bar"))
1368
1369 self._test_pathname("foo" + os.sep + os.sep + "bar")
1370 self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True)
1371
1372 def test_abs_pathnames(self):
1373 if sys.platform == "win32":
1374 self._test_pathname("C:\\foo", "foo")
1375 else:
1376 self._test_pathname("/foo", "foo")
1377 self._test_pathname("///foo", "foo")
1378
1379 def test_cwd(self):
1380 # Test adding the current working directory.
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001381 with support.change_cwd(TEMPDIR):
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001382 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001383 try:
1384 tar.add(".")
1385 finally:
1386 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001387
1388 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001389 try:
1390 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001391 if t.name != ".":
1392 self.assertTrue(t.name.startswith("./"), t.name)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001393 finally:
1394 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001395
Serhiy Storchakac2d01422014-01-18 16:14:10 +02001396 def test_open_nonwritable_fileobj(self):
1397 for exctype in OSError, EOFError, RuntimeError:
1398 class BadFile(io.BytesIO):
1399 first = True
1400 def write(self, data):
1401 if self.first:
1402 self.first = False
1403 raise exctype
1404
1405 f = BadFile()
1406 with self.assertRaises(exctype):
1407 tar = tarfile.open(tmpname, self.mode, fileobj=f,
1408 format=tarfile.PAX_FORMAT,
1409 pax_headers={'non': 'empty'})
1410 self.assertFalse(f.closed)
1411
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001412class GzipWriteTest(GzipTest, WriteTest):
1413 pass
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001414
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001415class Bz2WriteTest(Bz2Test, WriteTest):
1416 pass
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001417
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001418class LzmaWriteTest(LzmaTest, WriteTest):
1419 pass
1420
1421
1422class StreamWriteTest(WriteTestBase, unittest.TestCase):
1423
1424 prefix = "w|"
1425 decompressor = None
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001426
Guido van Rossumd8faa362007-04-27 19:54:29 +00001427 def test_stream_padding(self):
1428 # Test for bug #1543303.
1429 tar = tarfile.open(tmpname, self.mode)
1430 tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001431 if self.decompressor:
1432 dec = self.decompressor()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001433 with open(tmpname, "rb") as fobj:
1434 data = fobj.read()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001435 data = dec.decompress(data)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001436 self.assertFalse(dec.unused_data, "found trailing data")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001437 else:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001438 with self.open(tmpname) as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +00001439 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001440 self.assertEqual(data.count(b"\0"), tarfile.RECORDSIZE,
1441 "incorrect zero padding")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001442
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001443 @unittest.skipUnless(sys.platform != "win32" and hasattr(os, "umask"),
1444 "Missing umask implementation")
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001445 def test_file_mode(self):
1446 # Test for issue #8464: Create files with correct
1447 # permissions.
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001448 if os.path.exists(tmpname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01001449 support.unlink(tmpname)
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001450
1451 original_umask = os.umask(0o022)
1452 try:
1453 tar = tarfile.open(tmpname, self.mode)
1454 tar.close()
1455 mode = os.stat(tmpname).st_mode & 0o777
1456 self.assertEqual(mode, 0o644, "wrong file permissions")
1457 finally:
1458 os.umask(original_umask)
1459
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001460class GzipStreamWriteTest(GzipTest, StreamWriteTest):
1461 pass
1462
1463class Bz2StreamWriteTest(Bz2Test, StreamWriteTest):
1464 decompressor = bz2.BZ2Decompressor if bz2 else None
1465
1466class LzmaStreamWriteTest(LzmaTest, StreamWriteTest):
1467 decompressor = lzma.LZMADecompressor if lzma else None
1468
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001469
Guido van Rossumd8faa362007-04-27 19:54:29 +00001470class GNUWriteTest(unittest.TestCase):
1471 # This testcase checks for correct creation of GNU Longname
1472 # and Longlink extended headers (cp. bug #812325).
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001473
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001474 def _length(self, s):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001475 blocks = len(s) // 512 + 1
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001476 return blocks * 512
1477
1478 def _calc_size(self, name, link=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001479 # Initial tar header
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001480 count = 512
1481
1482 if len(name) > tarfile.LENGTH_NAME:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001483 # GNU longname extended header + longname
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001484 count += 512
1485 count += self._length(name)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001486 if link is not None and len(link) > tarfile.LENGTH_LINK:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001487 # GNU longlink extended header + longlink
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001488 count += 512
1489 count += self._length(link)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001490 return count
1491
1492 def _test(self, name, link=None):
1493 tarinfo = tarfile.TarInfo(name)
1494 if link:
1495 tarinfo.linkname = link
1496 tarinfo.type = tarfile.LNKTYPE
1497
Guido van Rossumd8faa362007-04-27 19:54:29 +00001498 tar = tarfile.open(tmpname, "w")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001499 try:
1500 tar.format = tarfile.GNU_FORMAT
1501 tar.addfile(tarinfo)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001502
Antoine Pitrou95f55602010-09-23 18:36:46 +00001503 v1 = self._calc_size(name, link)
1504 v2 = tar.offset
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001505 self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001506 finally:
1507 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001508
Guido van Rossumd8faa362007-04-27 19:54:29 +00001509 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001510 try:
1511 member = tar.next()
1512 self.assertIsNotNone(member,
1513 "unable to read longname member")
1514 self.assertEqual(tarinfo.name, member.name,
1515 "unable to read longname member")
1516 self.assertEqual(tarinfo.linkname, member.linkname,
1517 "unable to read longname member")
1518 finally:
1519 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001520
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001521 def test_longname_1023(self):
1522 self._test(("longnam/" * 127) + "longnam")
1523
1524 def test_longname_1024(self):
1525 self._test(("longnam/" * 127) + "longname")
1526
1527 def test_longname_1025(self):
1528 self._test(("longnam/" * 127) + "longname_")
1529
1530 def test_longlink_1023(self):
1531 self._test("name", ("longlnk/" * 127) + "longlnk")
1532
1533 def test_longlink_1024(self):
1534 self._test("name", ("longlnk/" * 127) + "longlink")
1535
1536 def test_longlink_1025(self):
1537 self._test("name", ("longlnk/" * 127) + "longlink_")
1538
1539 def test_longnamelink_1023(self):
1540 self._test(("longnam/" * 127) + "longnam",
1541 ("longlnk/" * 127) + "longlnk")
1542
1543 def test_longnamelink_1024(self):
1544 self._test(("longnam/" * 127) + "longname",
1545 ("longlnk/" * 127) + "longlink")
1546
1547 def test_longnamelink_1025(self):
1548 self._test(("longnam/" * 127) + "longname_",
1549 ("longlnk/" * 127) + "longlink_")
1550
Guido van Rossumd8faa362007-04-27 19:54:29 +00001551
Lars Gustäbel20703c62015-05-27 12:53:44 +02001552class CreateTest(WriteTestBase, unittest.TestCase):
Berker Peksag0fe63252015-02-13 21:02:12 +02001553
1554 prefix = "x:"
1555
1556 file_path = os.path.join(TEMPDIR, "spameggs42")
1557
1558 def setUp(self):
1559 support.unlink(tmpname)
1560
1561 @classmethod
1562 def setUpClass(cls):
1563 with open(cls.file_path, "wb") as fobj:
1564 fobj.write(b"aaa")
1565
1566 @classmethod
1567 def tearDownClass(cls):
1568 support.unlink(cls.file_path)
1569
1570 def test_create(self):
1571 with tarfile.open(tmpname, self.mode) as tobj:
1572 tobj.add(self.file_path)
1573
1574 with self.taropen(tmpname) as tobj:
1575 names = tobj.getnames()
1576 self.assertEqual(len(names), 1)
1577 self.assertIn('spameggs42', names[0])
1578
1579 def test_create_existing(self):
1580 with tarfile.open(tmpname, self.mode) as tobj:
1581 tobj.add(self.file_path)
1582
1583 with self.assertRaises(FileExistsError):
1584 tobj = tarfile.open(tmpname, self.mode)
1585
1586 with self.taropen(tmpname) as tobj:
1587 names = tobj.getnames()
1588 self.assertEqual(len(names), 1)
1589 self.assertIn('spameggs42', names[0])
1590
1591 def test_create_taropen(self):
1592 with self.taropen(tmpname, "x") as tobj:
1593 tobj.add(self.file_path)
1594
1595 with self.taropen(tmpname) as tobj:
1596 names = tobj.getnames()
1597 self.assertEqual(len(names), 1)
1598 self.assertIn('spameggs42', names[0])
1599
1600 def test_create_existing_taropen(self):
1601 with self.taropen(tmpname, "x") as tobj:
1602 tobj.add(self.file_path)
1603
1604 with self.assertRaises(FileExistsError):
1605 with self.taropen(tmpname, "x"):
1606 pass
1607
1608 with self.taropen(tmpname) as tobj:
1609 names = tobj.getnames()
1610 self.assertEqual(len(names), 1)
1611 self.assertIn("spameggs42", names[0])
1612
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001613 def test_create_pathlike_name(self):
1614 with tarfile.open(pathlib.Path(tmpname), self.mode) as tobj:
1615 self.assertIsInstance(tobj.name, str)
1616 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1617 tobj.add(pathlib.Path(self.file_path))
1618 names = tobj.getnames()
1619 self.assertEqual(len(names), 1)
1620 self.assertIn('spameggs42', names[0])
1621
1622 with self.taropen(tmpname) as tobj:
1623 names = tobj.getnames()
1624 self.assertEqual(len(names), 1)
1625 self.assertIn('spameggs42', names[0])
1626
1627 def test_create_taropen_pathlike_name(self):
1628 with self.taropen(pathlib.Path(tmpname), "x") as tobj:
1629 self.assertIsInstance(tobj.name, str)
1630 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1631 tobj.add(pathlib.Path(self.file_path))
1632 names = tobj.getnames()
1633 self.assertEqual(len(names), 1)
1634 self.assertIn('spameggs42', names[0])
1635
1636 with self.taropen(tmpname) as tobj:
1637 names = tobj.getnames()
1638 self.assertEqual(len(names), 1)
1639 self.assertIn('spameggs42', names[0])
1640
Berker Peksag0fe63252015-02-13 21:02:12 +02001641
1642class GzipCreateTest(GzipTest, CreateTest):
1643 pass
1644
1645
1646class Bz2CreateTest(Bz2Test, CreateTest):
1647 pass
1648
1649
1650class LzmaCreateTest(LzmaTest, CreateTest):
1651 pass
1652
1653
1654class CreateWithXModeTest(CreateTest):
1655
1656 prefix = "x"
1657
1658 test_create_taropen = None
1659 test_create_existing_taropen = None
1660
1661
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001662@unittest.skipUnless(hasattr(os, "link"), "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001663class HardlinkTest(unittest.TestCase):
1664 # Test the creation of LNKTYPE (hardlink) members in an archive.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001665
1666 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001667 self.foo = os.path.join(TEMPDIR, "foo")
1668 self.bar = os.path.join(TEMPDIR, "bar")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001669
Antoine Pitrou95f55602010-09-23 18:36:46 +00001670 with open(self.foo, "wb") as fobj:
1671 fobj.write(b"foo")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001672
xdegayed7d4fea2017-11-12 18:02:06 +01001673 try:
1674 os.link(self.foo, self.bar)
1675 except PermissionError as e:
1676 self.skipTest('os.link(): %s' % e)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001677
Guido van Rossumd8faa362007-04-27 19:54:29 +00001678 self.tar = tarfile.open(tmpname, "w")
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001679 self.tar.add(self.foo)
1680
Guido van Rossumd8faa362007-04-27 19:54:29 +00001681 def tearDown(self):
Hirokazu Yamamotoaf079d42008-09-21 11:50:03 +00001682 self.tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001683 support.unlink(self.foo)
1684 support.unlink(self.bar)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001685
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001686 def test_add_twice(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001687 # The same name will be added as a REGTYPE every
1688 # time regardless of st_nlink.
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001689 tarinfo = self.tar.gettarinfo(self.foo)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001690 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001691 "add file as regular failed")
1692
1693 def test_add_hardlink(self):
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001694 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001695 self.assertEqual(tarinfo.type, tarfile.LNKTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001696 "add file as hardlink failed")
1697
1698 def test_dereference_hardlink(self):
1699 self.tar.dereference = True
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001700 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001701 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001702 "dereferencing hardlink failed")
1703
Neal Norwitza4f651a2004-07-20 22:07:44 +00001704
Guido van Rossumd8faa362007-04-27 19:54:29 +00001705class PaxWriteTest(GNUWriteTest):
Martin v. Löwis78be7df2005-03-05 12:47:42 +00001706
Guido van Rossumd8faa362007-04-27 19:54:29 +00001707 def _test(self, name, link=None):
1708 # See GNUWriteTest.
1709 tarinfo = tarfile.TarInfo(name)
1710 if link:
1711 tarinfo.linkname = link
1712 tarinfo.type = tarfile.LNKTYPE
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001713
Guido van Rossumd8faa362007-04-27 19:54:29 +00001714 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001715 try:
1716 tar.addfile(tarinfo)
1717 finally:
1718 tar.close()
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001719
Guido van Rossumd8faa362007-04-27 19:54:29 +00001720 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001721 try:
1722 if link:
1723 l = tar.getmembers()[0].linkname
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001724 self.assertEqual(link, l, "PAX longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001725 else:
1726 n = tar.getmembers()[0].name
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001727 self.assertEqual(name, n, "PAX longname creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001728 finally:
1729 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001730
Guido van Rossume7ba4952007-06-06 23:52:48 +00001731 def test_pax_global_header(self):
1732 pax_headers = {
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001733 "foo": "bar",
1734 "uid": "0",
1735 "mtime": "1.23",
Guido van Rossuma0557702007-08-07 23:19:53 +00001736 "test": "\xe4\xf6\xfc",
1737 "\xe4\xf6\xfc": "test"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001738
Benjamin Peterson886af962010-03-21 23:13:07 +00001739 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
Guido van Rossume7ba4952007-06-06 23:52:48 +00001740 pax_headers=pax_headers)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001741 try:
1742 tar.addfile(tarfile.TarInfo("test"))
1743 finally:
1744 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001745
1746 # Test if the global header was written correctly.
1747 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001748 try:
1749 self.assertEqual(tar.pax_headers, pax_headers)
1750 self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers)
1751 # Test if all the fields are strings.
1752 for key, val in tar.pax_headers.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001753 self.assertIsNot(type(key), bytes)
1754 self.assertIsNot(type(val), bytes)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001755 if key in tarfile.PAX_NUMBER_FIELDS:
1756 try:
1757 tarfile.PAX_NUMBER_FIELDS[key](val)
1758 except (TypeError, ValueError):
1759 self.fail("unable to convert pax header field")
1760 finally:
1761 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001762
1763 def test_pax_extended_header(self):
1764 # The fields from the pax header have priority over the
1765 # TarInfo.
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001766 pax_headers = {"path": "foo", "uid": "123"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001767
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001768 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
1769 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001770 try:
1771 t = tarfile.TarInfo()
1772 t.name = "\xe4\xf6\xfc" # non-ASCII
1773 t.uid = 8**8 # too large
1774 t.pax_headers = pax_headers
1775 tar.addfile(t)
1776 finally:
1777 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001778
1779 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001780 try:
1781 t = tar.getmembers()[0]
1782 self.assertEqual(t.pax_headers, pax_headers)
1783 self.assertEqual(t.name, "foo")
1784 self.assertEqual(t.uid, 123)
1785 finally:
1786 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001787
1788
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001789class UnicodeTest:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001790
1791 def test_iso8859_1_filename(self):
1792 self._test_unicode_filename("iso8859-1")
1793
1794 def test_utf7_filename(self):
1795 self._test_unicode_filename("utf7")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001796
1797 def test_utf8_filename(self):
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00001798 self._test_unicode_filename("utf-8")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001799
Guido van Rossumd8faa362007-04-27 19:54:29 +00001800 def _test_unicode_filename(self, encoding):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001801 tar = tarfile.open(tmpname, "w", format=self.format,
1802 encoding=encoding, errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001803 try:
1804 name = "\xe4\xf6\xfc"
1805 tar.addfile(tarfile.TarInfo(name))
1806 finally:
1807 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001808
1809 tar = tarfile.open(tmpname, encoding=encoding)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001810 try:
1811 self.assertEqual(tar.getmembers()[0].name, name)
1812 finally:
1813 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001814
1815 def test_unicode_filename_error(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001816 tar = tarfile.open(tmpname, "w", format=self.format,
1817 encoding="ascii", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001818 try:
1819 tarinfo = tarfile.TarInfo()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001820
Antoine Pitrou95f55602010-09-23 18:36:46 +00001821 tarinfo.name = "\xe4\xf6\xfc"
1822 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001823
Antoine Pitrou95f55602010-09-23 18:36:46 +00001824 tarinfo.name = "foo"
1825 tarinfo.uname = "\xe4\xf6\xfc"
1826 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
1827 finally:
1828 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001829
1830 def test_unicode_argument(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001831 tar = tarfile.open(tarname, "r",
1832 encoding="iso8859-1", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001833 try:
1834 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001835 self.assertIs(type(t.name), str)
1836 self.assertIs(type(t.linkname), str)
1837 self.assertIs(type(t.uname), str)
1838 self.assertIs(type(t.gname), str)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001839 finally:
1840 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001841
Guido van Rossume7ba4952007-06-06 23:52:48 +00001842 def test_uname_unicode(self):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001843 t = tarfile.TarInfo("foo")
1844 t.uname = "\xe4\xf6\xfc"
1845 t.gname = "\xe4\xf6\xfc"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001846
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001847 tar = tarfile.open(tmpname, mode="w", format=self.format,
1848 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001849 try:
1850 tar.addfile(t)
1851 finally:
1852 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001853
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001854 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001855 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001856 t = tar.getmember("foo")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001857 self.assertEqual(t.uname, "\xe4\xf6\xfc")
1858 self.assertEqual(t.gname, "\xe4\xf6\xfc")
1859
1860 if self.format != tarfile.PAX_FORMAT:
Antoine Pitrouab58b5f2010-09-23 19:39:35 +00001861 tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001862 tar = tarfile.open(tmpname, encoding="ascii")
1863 t = tar.getmember("foo")
1864 self.assertEqual(t.uname, "\udce4\udcf6\udcfc")
1865 self.assertEqual(t.gname, "\udce4\udcf6\udcfc")
1866 finally:
1867 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001868
Lars Gustäbelb506dc32007-08-07 18:36:16 +00001869
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001870class UstarUnicodeTest(UnicodeTest, unittest.TestCase):
1871
1872 format = tarfile.USTAR_FORMAT
1873
1874 # Test whether the utf-8 encoded version of a filename exceeds the 100
1875 # bytes name field limit (every occurrence of '\xff' will be expanded to 2
1876 # bytes).
1877 def test_unicode_name1(self):
1878 self._test_ustar_name("0123456789" * 10)
1879 self._test_ustar_name("0123456789" * 10 + "0", ValueError)
1880 self._test_ustar_name("0123456789" * 9 + "01234567\xff")
1881 self._test_ustar_name("0123456789" * 9 + "012345678\xff", ValueError)
1882
1883 def test_unicode_name2(self):
1884 self._test_ustar_name("0123456789" * 9 + "012345\xff\xff")
1885 self._test_ustar_name("0123456789" * 9 + "0123456\xff\xff", ValueError)
1886
1887 # Test whether the utf-8 encoded version of a filename exceeds the 155
1888 # bytes prefix + '/' + 100 bytes name limit.
1889 def test_unicode_longname1(self):
1890 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 10)
1891 self._test_ustar_name("0123456789" * 15 + "0123/4" + "0123456789" * 10, ValueError)
1892 self._test_ustar_name("0123456789" * 15 + "012\xff/" + "0123456789" * 10)
1893 self._test_ustar_name("0123456789" * 15 + "0123\xff/" + "0123456789" * 10, ValueError)
1894
1895 def test_unicode_longname2(self):
1896 self._test_ustar_name("0123456789" * 15 + "01\xff/2" + "0123456789" * 10, ValueError)
1897 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/" + "0123456789" * 10, ValueError)
1898
1899 def test_unicode_longname3(self):
1900 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/2" + "0123456789" * 10, ValueError)
1901 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "01234567\xff")
1902 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345678\xff", ValueError)
1903
1904 def test_unicode_longname4(self):
1905 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345\xff\xff")
1906 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "0123456\xff\xff", ValueError)
1907
1908 def _test_ustar_name(self, name, exc=None):
1909 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1910 t = tarfile.TarInfo(name)
1911 if exc is None:
1912 tar.addfile(t)
1913 else:
1914 self.assertRaises(exc, tar.addfile, t)
1915
1916 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001917 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001918 for t in tar:
1919 self.assertEqual(name, t.name)
1920 break
1921
1922 # Test the same as above for the 100 bytes link field.
1923 def test_unicode_link1(self):
1924 self._test_ustar_link("0123456789" * 10)
1925 self._test_ustar_link("0123456789" * 10 + "0", ValueError)
1926 self._test_ustar_link("0123456789" * 9 + "01234567\xff")
1927 self._test_ustar_link("0123456789" * 9 + "012345678\xff", ValueError)
1928
1929 def test_unicode_link2(self):
1930 self._test_ustar_link("0123456789" * 9 + "012345\xff\xff")
1931 self._test_ustar_link("0123456789" * 9 + "0123456\xff\xff", ValueError)
1932
1933 def _test_ustar_link(self, name, exc=None):
1934 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1935 t = tarfile.TarInfo("foo")
1936 t.linkname = name
1937 if exc is None:
1938 tar.addfile(t)
1939 else:
1940 self.assertRaises(exc, tar.addfile, t)
1941
1942 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001943 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001944 for t in tar:
1945 self.assertEqual(name, t.linkname)
1946 break
1947
1948
1949class GNUUnicodeTest(UnicodeTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001950
Guido van Rossume7ba4952007-06-06 23:52:48 +00001951 format = tarfile.GNU_FORMAT
Guido van Rossumd8faa362007-04-27 19:54:29 +00001952
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001953 def test_bad_pax_header(self):
1954 # Test for issue #8633. GNU tar <= 1.23 creates raw binary fields
1955 # without a hdrcharset=BINARY header.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001956 for encoding, name in (
1957 ("utf-8", "pax/bad-pax-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001958 ("iso8859-1", "pax/bad-pax-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001959 with tarfile.open(tarname, encoding=encoding,
1960 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001961 try:
1962 t = tar.getmember(name)
1963 except KeyError:
1964 self.fail("unable to read bad GNU tar pax header")
1965
Guido van Rossumd8faa362007-04-27 19:54:29 +00001966
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001967class PAXUnicodeTest(UnicodeTest, unittest.TestCase):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001968
1969 format = tarfile.PAX_FORMAT
1970
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001971 # PAX_FORMAT ignores encoding in write mode.
1972 test_unicode_filename_error = None
1973
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001974 def test_binary_header(self):
1975 # Test a POSIX.1-2008 compatible header with a hdrcharset=BINARY field.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001976 for encoding, name in (
1977 ("utf-8", "pax/hdrcharset-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001978 ("iso8859-1", "pax/hdrcharset-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001979 with tarfile.open(tarname, encoding=encoding,
1980 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001981 try:
1982 t = tar.getmember(name)
1983 except KeyError:
1984 self.fail("unable to read POSIX.1-2008 binary header")
1985
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001986
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001987class AppendTestBase:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001988 # Test append mode (cp. patch #1652681).
Thomas Wouters902d6eb2007-01-09 23:18:33 +00001989
Guido van Rossumd8faa362007-04-27 19:54:29 +00001990 def setUp(self):
1991 self.tarname = tmpname
1992 if os.path.exists(self.tarname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01001993 support.unlink(self.tarname)
Thomas Wouters902d6eb2007-01-09 23:18:33 +00001994
Guido van Rossumd8faa362007-04-27 19:54:29 +00001995 def _create_testtar(self, mode="w:"):
Antoine Pitrou95f55602010-09-23 18:36:46 +00001996 with tarfile.open(tarname, encoding="iso8859-1") as src:
1997 t = src.getmember("ustar/regtype")
1998 t.name = "foo"
Lars Gustäbel7a919e92012-05-05 18:15:03 +02001999 with src.extractfile(t) as f:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +00002000 with tarfile.open(self.tarname, mode) as tar:
2001 tar.addfile(t, f)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002002
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002003 def test_append_compressed(self):
2004 self._create_testtar("w:" + self.suffix)
2005 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a")
2006
2007class AppendTest(AppendTestBase, unittest.TestCase):
2008 test_append_compressed = None
2009
2010 def _add_testfile(self, fileobj=None):
2011 with tarfile.open(self.tarname, "a", fileobj=fileobj) as tar:
2012 tar.addfile(tarfile.TarInfo("bar"))
2013
Guido van Rossumd8faa362007-04-27 19:54:29 +00002014 def _test(self, names=["bar"], fileobj=None):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002015 with tarfile.open(self.tarname, fileobj=fileobj) as tar:
2016 self.assertEqual(tar.getnames(), names)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002017
2018 def test_non_existing(self):
2019 self._add_testfile()
2020 self._test()
2021
2022 def test_empty(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002023 tarfile.open(self.tarname, "w:").close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00002024 self._add_testfile()
2025 self._test()
2026
2027 def test_empty_fileobj(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002028 fobj = io.BytesIO(b"\0" * 1024)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002029 self._add_testfile(fobj)
2030 fobj.seek(0)
2031 self._test(fileobj=fobj)
2032
2033 def test_fileobj(self):
2034 self._create_testtar()
Antoine Pitrou95f55602010-09-23 18:36:46 +00002035 with open(self.tarname, "rb") as fobj:
2036 data = fobj.read()
Guido van Rossum34d19282007-08-09 01:03:29 +00002037 fobj = io.BytesIO(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002038 self._add_testfile(fobj)
2039 fobj.seek(0)
2040 self._test(names=["foo", "bar"], fileobj=fobj)
2041
2042 def test_existing(self):
2043 self._create_testtar()
2044 self._add_testfile()
2045 self._test(names=["foo", "bar"])
2046
Lars Gustäbel9520a432009-11-22 18:48:49 +00002047 # Append mode is supposed to fail if the tarfile to append to
2048 # does not end with a zero block.
2049 def _test_error(self, data):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002050 with open(self.tarname, "wb") as fobj:
2051 fobj.write(data)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002052 self.assertRaises(tarfile.ReadError, self._add_testfile)
2053
2054 def test_null(self):
2055 self._test_error(b"")
2056
2057 def test_incomplete(self):
2058 self._test_error(b"\0" * 13)
2059
2060 def test_premature_eof(self):
2061 data = tarfile.TarInfo("foo").tobuf()
2062 self._test_error(data)
2063
2064 def test_trailing_garbage(self):
2065 data = tarfile.TarInfo("foo").tobuf()
2066 self._test_error(data + b"\0" * 13)
2067
2068 def test_invalid(self):
2069 self._test_error(b"a" * 512)
2070
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002071class GzipAppendTest(GzipTest, AppendTestBase, unittest.TestCase):
2072 pass
2073
2074class Bz2AppendTest(Bz2Test, AppendTestBase, unittest.TestCase):
2075 pass
2076
2077class LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase):
2078 pass
2079
Guido van Rossumd8faa362007-04-27 19:54:29 +00002080
2081class LimitsTest(unittest.TestCase):
2082
2083 def test_ustar_limits(self):
2084 # 100 char name
2085 tarinfo = tarfile.TarInfo("0123456789" * 10)
Guido van Rossume7ba4952007-06-06 23:52:48 +00002086 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002087
2088 # 101 char name that cannot be stored
2089 tarinfo = tarfile.TarInfo("0123456789" * 10 + "0")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002090 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002091
2092 # 256 char name with a slash at pos 156
2093 tarinfo = tarfile.TarInfo("123/" * 62 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002094 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002095
2096 # 256 char name that cannot be stored
2097 tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002098 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002099
2100 # 512 char name
2101 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002102 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002103
2104 # 512 char linkname
2105 tarinfo = tarfile.TarInfo("longlink")
2106 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002107 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002108
2109 # uid > 8 digits
2110 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002111 tarinfo.uid = 0o10000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002112 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002113
2114 def test_gnu_limits(self):
2115 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002116 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002117
2118 tarinfo = tarfile.TarInfo("longlink")
2119 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002120 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002121
2122 # uid >= 256 ** 7
2123 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002124 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002125 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002126
2127 def test_pax_limits(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002128 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002129 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002130
2131 tarinfo = tarfile.TarInfo("longlink")
2132 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002133 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002134
2135 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002136 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002137 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002138
2139
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002140class MiscTest(unittest.TestCase):
2141
2142 def test_char_fields(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002143 self.assertEqual(tarfile.stn("foo", 8, "ascii", "strict"),
2144 b"foo\0\0\0\0\0")
2145 self.assertEqual(tarfile.stn("foobar", 3, "ascii", "strict"),
2146 b"foo")
2147 self.assertEqual(tarfile.nts(b"foo\0\0\0\0\0", "ascii", "strict"),
2148 "foo")
2149 self.assertEqual(tarfile.nts(b"foo\0bar\0", "ascii", "strict"),
2150 "foo")
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002151
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002152 def test_read_number_fields(self):
2153 # Issue 13158: Test if GNU tar specific base-256 number fields
2154 # are decoded correctly.
2155 self.assertEqual(tarfile.nti(b"0000001\x00"), 1)
2156 self.assertEqual(tarfile.nti(b"7777777\x00"), 0o7777777)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002157 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\x00\x20\x00\x00"),
2158 0o10000000)
2159 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\xff\xff\xff\xff"),
2160 0xffffffff)
2161 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\xff"),
2162 -1)
2163 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\x9c"),
2164 -100)
2165 self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"),
2166 -0x100000000000000)
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002167
Lars Gustäbelb7a688b2015-07-02 19:38:38 +02002168 # Issue 24514: Test if empty number fields are converted to zero.
2169 self.assertEqual(tarfile.nti(b"\0"), 0)
2170 self.assertEqual(tarfile.nti(b" \0"), 0)
2171
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002172 def test_write_number_fields(self):
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002173 self.assertEqual(tarfile.itn(1), b"0000001\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002174 self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002175 self.assertEqual(tarfile.itn(0o10000000, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002176 b"\x80\x00\x00\x00\x00\x20\x00\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002177 self.assertEqual(tarfile.itn(0xffffffff, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002178 b"\x80\x00\x00\x00\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002179 self.assertEqual(tarfile.itn(-1, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002180 b"\xff\xff\xff\xff\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002181 self.assertEqual(tarfile.itn(-100, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002182 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002183 self.assertEqual(tarfile.itn(-0x100000000000000,
2184 format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002185 b"\xff\x00\x00\x00\x00\x00\x00\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002186
Joffrey F72d9b2b2018-02-26 16:02:21 -08002187 # Issue 32713: Test if itn() supports float values outside the
2188 # non-GNU format range
2189 self.assertEqual(tarfile.itn(-100.0, format=tarfile.GNU_FORMAT),
2190 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
2191 self.assertEqual(tarfile.itn(8 ** 12 + 0.0, format=tarfile.GNU_FORMAT),
2192 b"\x80\x00\x00\x10\x00\x00\x00\x00")
2193 self.assertEqual(tarfile.nti(tarfile.itn(-0.1, format=tarfile.GNU_FORMAT)), 0)
2194
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002195 def test_number_field_limits(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002196 with self.assertRaises(ValueError):
2197 tarfile.itn(-1, 8, tarfile.USTAR_FORMAT)
2198 with self.assertRaises(ValueError):
2199 tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT)
2200 with self.assertRaises(ValueError):
2201 tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT)
2202 with self.assertRaises(ValueError):
2203 tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT)
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002204
Martin Panter104dcda2016-01-16 06:59:13 +00002205 def test__all__(self):
Martin Panter5318d102016-01-16 11:01:14 +00002206 blacklist = {'version', 'grp', 'pwd', 'symlink_exception',
Martin Panter104dcda2016-01-16 06:59:13 +00002207 'NUL', 'BLOCKSIZE', 'RECORDSIZE', 'GNU_MAGIC',
2208 'POSIX_MAGIC', 'LENGTH_NAME', 'LENGTH_LINK',
2209 'LENGTH_PREFIX', 'REGTYPE', 'AREGTYPE', 'LNKTYPE',
2210 'SYMTYPE', 'CHRTYPE', 'BLKTYPE', 'DIRTYPE', 'FIFOTYPE',
2211 'CONTTYPE', 'GNUTYPE_LONGNAME', 'GNUTYPE_LONGLINK',
2212 'GNUTYPE_SPARSE', 'XHDTYPE', 'XGLTYPE', 'SOLARIS_XHDTYPE',
2213 'SUPPORTED_TYPES', 'REGULAR_TYPES', 'GNU_TYPES',
2214 'PAX_FIELDS', 'PAX_NAME_FIELDS', 'PAX_NUMBER_FIELDS',
2215 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 'copyfileobj',
2216 'filemode',
2217 'EmptyHeaderError', 'TruncatedHeaderError',
2218 'EOFHeaderError', 'InvalidHeaderError',
Serhiy Storchaka2c1d3e32016-01-16 11:05:11 +02002219 'SubsequentHeaderError', 'ExFileObject',
Martin Panter104dcda2016-01-16 06:59:13 +00002220 'main'}
2221 support.check__all__(self, tarfile, blacklist=blacklist)
2222
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002223
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002224class CommandLineTest(unittest.TestCase):
2225
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002226 def tarfilecmd(self, *args, **kwargs):
2227 rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args,
2228 **kwargs)
Antoine Pitrou3b7b1e52013-11-24 01:55:05 +01002229 return out.replace(os.linesep.encode(), b'\n')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002230
2231 def tarfilecmd_failure(self, *args):
2232 return script_helper.assert_python_failure('-m', 'tarfile', *args)
2233
2234 def make_simple_tarfile(self, tar_name):
2235 files = [support.findfile('tokenize_tests.txt'),
2236 support.findfile('tokenize_tests-no-coding-cookie-'
2237 'and-utf8-bom-sig-only.txt')]
2238 self.addCleanup(support.unlink, tar_name)
2239 with tarfile.open(tar_name, 'w') as tf:
2240 for tardata in files:
2241 tf.add(tardata, arcname=os.path.basename(tardata))
2242
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002243 def test_bad_use(self):
2244 rc, out, err = self.tarfilecmd_failure()
2245 self.assertEqual(out, b'')
2246 self.assertIn(b'usage', err.lower())
2247 self.assertIn(b'error', err.lower())
2248 self.assertIn(b'required', err.lower())
2249 rc, out, err = self.tarfilecmd_failure('-l', '')
2250 self.assertEqual(out, b'')
2251 self.assertNotEqual(err.strip(), b'')
2252
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002253 def test_test_command(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002254 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002255 for opt in '-t', '--test':
2256 out = self.tarfilecmd(opt, tar_name)
2257 self.assertEqual(out, b'')
2258
2259 def test_test_command_verbose(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002260 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002261 for opt in '-v', '--verbose':
2262 out = self.tarfilecmd(opt, '-t', tar_name)
2263 self.assertIn(b'is a tar archive.\n', out)
2264
2265 def test_test_command_invalid_file(self):
2266 zipname = support.findfile('zipdir.zip')
2267 rc, out, err = self.tarfilecmd_failure('-t', zipname)
2268 self.assertIn(b' is not a tar archive.', err)
2269 self.assertEqual(out, b'')
2270 self.assertEqual(rc, 1)
2271
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002272 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002273 with self.subTest(tar_name=tar_name):
2274 with open(tar_name, 'rb') as f:
2275 data = f.read()
2276 try:
2277 with open(tmpname, 'wb') as f:
2278 f.write(data[:511])
2279 rc, out, err = self.tarfilecmd_failure('-t', tmpname)
2280 self.assertEqual(out, b'')
2281 self.assertEqual(rc, 1)
2282 finally:
2283 support.unlink(tmpname)
2284
2285 def test_list_command(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002286 for tar_name in testtarnames:
2287 with support.captured_stdout() as t:
2288 with tarfile.open(tar_name, 'r') as tf:
2289 tf.list(verbose=False)
2290 expected = t.getvalue().encode('ascii', 'backslashreplace')
2291 for opt in '-l', '--list':
2292 out = self.tarfilecmd(opt, tar_name,
2293 PYTHONIOENCODING='ascii')
2294 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002295
2296 def test_list_command_verbose(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002297 for tar_name in testtarnames:
2298 with support.captured_stdout() as t:
2299 with tarfile.open(tar_name, 'r') as tf:
2300 tf.list(verbose=True)
2301 expected = t.getvalue().encode('ascii', 'backslashreplace')
2302 for opt in '-v', '--verbose':
2303 out = self.tarfilecmd(opt, '-l', tar_name,
2304 PYTHONIOENCODING='ascii')
2305 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002306
2307 def test_list_command_invalid_file(self):
2308 zipname = support.findfile('zipdir.zip')
2309 rc, out, err = self.tarfilecmd_failure('-l', zipname)
2310 self.assertIn(b' is not a tar archive.', err)
2311 self.assertEqual(out, b'')
2312 self.assertEqual(rc, 1)
2313
2314 def test_create_command(self):
2315 files = [support.findfile('tokenize_tests.txt'),
2316 support.findfile('tokenize_tests-no-coding-cookie-'
2317 'and-utf8-bom-sig-only.txt')]
2318 for opt in '-c', '--create':
2319 try:
2320 out = self.tarfilecmd(opt, tmpname, *files)
2321 self.assertEqual(out, b'')
2322 with tarfile.open(tmpname) as tar:
2323 tar.getmembers()
2324 finally:
2325 support.unlink(tmpname)
2326
2327 def test_create_command_verbose(self):
2328 files = [support.findfile('tokenize_tests.txt'),
2329 support.findfile('tokenize_tests-no-coding-cookie-'
2330 'and-utf8-bom-sig-only.txt')]
2331 for opt in '-v', '--verbose':
2332 try:
2333 out = self.tarfilecmd(opt, '-c', tmpname, *files)
2334 self.assertIn(b' file created.', out)
2335 with tarfile.open(tmpname) as tar:
2336 tar.getmembers()
2337 finally:
2338 support.unlink(tmpname)
2339
2340 def test_create_command_dotless_filename(self):
2341 files = [support.findfile('tokenize_tests.txt')]
2342 try:
2343 out = self.tarfilecmd('-c', dotlessname, *files)
2344 self.assertEqual(out, b'')
2345 with tarfile.open(dotlessname) as tar:
2346 tar.getmembers()
2347 finally:
2348 support.unlink(dotlessname)
2349
2350 def test_create_command_dot_started_filename(self):
2351 tar_name = os.path.join(TEMPDIR, ".testtar")
2352 files = [support.findfile('tokenize_tests.txt')]
2353 try:
2354 out = self.tarfilecmd('-c', tar_name, *files)
2355 self.assertEqual(out, b'')
2356 with tarfile.open(tar_name) as tar:
2357 tar.getmembers()
2358 finally:
2359 support.unlink(tar_name)
2360
Serhiy Storchaka832dd5f2015-02-10 08:45:53 +02002361 def test_create_command_compressed(self):
2362 files = [support.findfile('tokenize_tests.txt'),
2363 support.findfile('tokenize_tests-no-coding-cookie-'
2364 'and-utf8-bom-sig-only.txt')]
2365 for filetype in (GzipTest, Bz2Test, LzmaTest):
2366 if not filetype.open:
2367 continue
2368 try:
2369 tar_name = tmpname + '.' + filetype.suffix
2370 out = self.tarfilecmd('-c', tar_name, *files)
2371 with filetype.taropen(tar_name) as tar:
2372 tar.getmembers()
2373 finally:
2374 support.unlink(tar_name)
2375
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002376 def test_extract_command(self):
2377 self.make_simple_tarfile(tmpname)
2378 for opt in '-e', '--extract':
2379 try:
2380 with support.temp_cwd(tarextdir):
2381 out = self.tarfilecmd(opt, tmpname)
2382 self.assertEqual(out, b'')
2383 finally:
2384 support.rmtree(tarextdir)
2385
2386 def test_extract_command_verbose(self):
2387 self.make_simple_tarfile(tmpname)
2388 for opt in '-v', '--verbose':
2389 try:
2390 with support.temp_cwd(tarextdir):
2391 out = self.tarfilecmd(opt, '-e', tmpname)
2392 self.assertIn(b' file is extracted.', out)
2393 finally:
2394 support.rmtree(tarextdir)
2395
2396 def test_extract_command_different_directory(self):
2397 self.make_simple_tarfile(tmpname)
2398 try:
2399 with support.temp_cwd(tarextdir):
2400 out = self.tarfilecmd('-e', tmpname, 'spamdir')
2401 self.assertEqual(out, b'')
2402 finally:
2403 support.rmtree(tarextdir)
2404
2405 def test_extract_command_invalid_file(self):
2406 zipname = support.findfile('zipdir.zip')
2407 with support.temp_cwd(tarextdir):
2408 rc, out, err = self.tarfilecmd_failure('-e', zipname)
2409 self.assertIn(b' is not a tar archive.', err)
2410 self.assertEqual(out, b'')
2411 self.assertEqual(rc, 1)
2412
2413
Lars Gustäbel01385812010-03-03 12:08:54 +00002414class ContextManagerTest(unittest.TestCase):
2415
2416 def test_basic(self):
2417 with tarfile.open(tarname) as tar:
2418 self.assertFalse(tar.closed, "closed inside runtime context")
2419 self.assertTrue(tar.closed, "context manager failed")
2420
2421 def test_closed(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002422 # The __enter__() method is supposed to raise OSError
Lars Gustäbel01385812010-03-03 12:08:54 +00002423 # if the TarFile object is already closed.
2424 tar = tarfile.open(tarname)
2425 tar.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002426 with self.assertRaises(OSError):
Lars Gustäbel01385812010-03-03 12:08:54 +00002427 with tar:
2428 pass
2429
2430 def test_exception(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002431 # Test if the OSError exception is passed through properly.
Lars Gustäbel01385812010-03-03 12:08:54 +00002432 with self.assertRaises(Exception) as exc:
2433 with tarfile.open(tarname) as tar:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002434 raise OSError
2435 self.assertIsInstance(exc.exception, OSError,
Lars Gustäbel01385812010-03-03 12:08:54 +00002436 "wrong exception raised in context manager")
2437 self.assertTrue(tar.closed, "context manager failed")
2438
2439 def test_no_eof(self):
2440 # __exit__() must not write end-of-archive blocks if an
2441 # exception was raised.
2442 try:
2443 with tarfile.open(tmpname, "w") as tar:
2444 raise Exception
2445 except:
2446 pass
2447 self.assertEqual(os.path.getsize(tmpname), 0,
2448 "context manager wrote an end-of-archive block")
2449 self.assertTrue(tar.closed, "context manager failed")
2450
2451 def test_eof(self):
2452 # __exit__() must write end-of-archive blocks, i.e. call
2453 # TarFile.close() if there was no error.
2454 with tarfile.open(tmpname, "w"):
2455 pass
2456 self.assertNotEqual(os.path.getsize(tmpname), 0,
2457 "context manager wrote no end-of-archive block")
2458
2459 def test_fileobj(self):
2460 # Test that __exit__() did not close the external file
2461 # object.
Antoine Pitrou95f55602010-09-23 18:36:46 +00002462 with open(tmpname, "wb") as fobj:
2463 try:
2464 with tarfile.open(fileobj=fobj, mode="w") as tar:
2465 raise Exception
2466 except:
2467 pass
2468 self.assertFalse(fobj.closed, "external file object was closed")
2469 self.assertTrue(tar.closed, "context manager failed")
Lars Gustäbel01385812010-03-03 12:08:54 +00002470
2471
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002472@unittest.skipIf(hasattr(os, "link"), "requires os.link to be missing")
2473class LinkEmulationTest(ReadTest, unittest.TestCase):
Lars Gustäbel1b512722010-06-03 12:45:16 +00002474
2475 # Test for issue #8741 regression. On platforms that do not support
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002476 # symbolic or hard links tarfile tries to extract these types of members
2477 # as the regular files they point to.
Lars Gustäbel1b512722010-06-03 12:45:16 +00002478 def _test_link_extraction(self, name):
2479 self.tar.extract(name, TEMPDIR)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002480 with open(os.path.join(TEMPDIR, name), "rb") as f:
2481 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +02002482 self.assertEqual(sha256sum(data), sha256_regtype)
Lars Gustäbel1b512722010-06-03 12:45:16 +00002483
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002484 # See issues #1578269, #8879, and #17689 for some history on these skips
Brian Curtind40e6f72010-07-08 21:39:08 +00002485 @unittest.skipIf(hasattr(os.path, "islink"),
2486 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002487 def test_hardlink_extraction1(self):
2488 self._test_link_extraction("ustar/lnktype")
2489
Brian Curtind40e6f72010-07-08 21:39:08 +00002490 @unittest.skipIf(hasattr(os.path, "islink"),
2491 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002492 def test_hardlink_extraction2(self):
2493 self._test_link_extraction("./ustar/linktest2/lnktype")
2494
Brian Curtin74e45612010-07-09 15:58:59 +00002495 @unittest.skipIf(hasattr(os, "symlink"),
2496 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002497 def test_symlink_extraction1(self):
2498 self._test_link_extraction("ustar/symtype")
2499
Brian Curtin74e45612010-07-09 15:58:59 +00002500 @unittest.skipIf(hasattr(os, "symlink"),
2501 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002502 def test_symlink_extraction2(self):
2503 self._test_link_extraction("./ustar/linktest2/symtype")
2504
2505
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002506class Bz2PartialReadTest(Bz2Test, unittest.TestCase):
Lars Gustäbel42e00912009-03-22 20:34:29 +00002507 # Issue5068: The _BZ2Proxy.read() method loops forever
2508 # on an empty or partial bzipped file.
2509
2510 def _test_partial_input(self, mode):
2511 class MyBytesIO(io.BytesIO):
2512 hit_eof = False
2513 def read(self, n):
2514 if self.hit_eof:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002515 raise AssertionError("infinite loop detected in "
2516 "tarfile.open()")
Lars Gustäbel42e00912009-03-22 20:34:29 +00002517 self.hit_eof = self.tell() == len(self.getvalue())
2518 return super(MyBytesIO, self).read(n)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002519 def seek(self, *args):
2520 self.hit_eof = False
2521 return super(MyBytesIO, self).seek(*args)
Lars Gustäbel42e00912009-03-22 20:34:29 +00002522
2523 data = bz2.compress(tarfile.TarInfo("foo").tobuf())
2524 for x in range(len(data) + 1):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002525 try:
2526 tarfile.open(fileobj=MyBytesIO(data[:x]), mode=mode)
2527 except tarfile.ReadError:
2528 pass # we have no interest in ReadErrors
Lars Gustäbel42e00912009-03-22 20:34:29 +00002529
2530 def test_partial_input(self):
2531 self._test_partial_input("r")
2532
2533 def test_partial_input_bz2(self):
2534 self._test_partial_input("r:bz2")
2535
2536
Eric V. Smith7a803892015-04-15 10:27:58 -04002537def root_is_uid_gid_0():
2538 try:
2539 import pwd, grp
2540 except ImportError:
2541 return False
2542 if pwd.getpwuid(0)[0] != 'root':
2543 return False
2544 if grp.getgrgid(0)[0] != 'root':
2545 return False
2546 return True
2547
2548
Zachary Waread3e27a2015-05-12 23:57:21 -05002549@unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown")
2550@unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid")
Eric V. Smith7a803892015-04-15 10:27:58 -04002551class NumericOwnerTest(unittest.TestCase):
2552 # mock the following:
2553 # os.chown: so we can test what's being called
2554 # os.chmod: so the modes are not actually changed. if they are, we can't
2555 # delete the files/directories
2556 # os.geteuid: so we can lie and say we're root (uid = 0)
2557
2558 @staticmethod
2559 def _make_test_archive(filename_1, dirname_1, filename_2):
2560 # the file contents to write
2561 fobj = io.BytesIO(b"content")
2562
2563 # create a tar file with a file, a directory, and a file within that
2564 # directory. Assign various .uid/.gid values to them
2565 items = [(filename_1, 99, 98, tarfile.REGTYPE, fobj),
2566 (dirname_1, 77, 76, tarfile.DIRTYPE, None),
2567 (filename_2, 88, 87, tarfile.REGTYPE, fobj),
2568 ]
2569 with tarfile.open(tmpname, 'w') as tarfl:
2570 for name, uid, gid, typ, contents in items:
2571 t = tarfile.TarInfo(name)
2572 t.uid = uid
2573 t.gid = gid
2574 t.uname = 'root'
2575 t.gname = 'root'
2576 t.type = typ
2577 tarfl.addfile(t, contents)
2578
2579 # return the full pathname to the tar file
2580 return tmpname
2581
2582 @staticmethod
2583 @contextmanager
2584 def _setup_test(mock_geteuid):
2585 mock_geteuid.return_value = 0 # lie and say we're root
2586 fname = 'numeric-owner-testfile'
2587 dirname = 'dir'
2588
2589 # the names we want stored in the tarfile
2590 filename_1 = fname
2591 dirname_1 = dirname
2592 filename_2 = os.path.join(dirname, fname)
2593
2594 # create the tarfile with the contents we're after
2595 tar_filename = NumericOwnerTest._make_test_archive(filename_1,
2596 dirname_1,
2597 filename_2)
2598
2599 # open the tarfile for reading. yield it and the names of the items
2600 # we stored into the file
2601 with tarfile.open(tar_filename) as tarfl:
2602 yield tarfl, filename_1, dirname_1, filename_2
2603
2604 @unittest.mock.patch('os.chown')
2605 @unittest.mock.patch('os.chmod')
2606 @unittest.mock.patch('os.geteuid')
2607 def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod,
2608 mock_chown):
2609 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _,
2610 filename_2):
2611 tarfl.extract(filename_1, TEMPDIR, numeric_owner=True)
2612 tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True)
2613
2614 # convert to filesystem paths
2615 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2616 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2617
2618 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2619 unittest.mock.call(f_filename_2, 88, 87),
2620 ],
2621 any_order=True)
2622
2623 @unittest.mock.patch('os.chown')
2624 @unittest.mock.patch('os.chmod')
2625 @unittest.mock.patch('os.geteuid')
2626 def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod,
2627 mock_chown):
2628 with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1,
2629 filename_2):
2630 tarfl.extractall(TEMPDIR, numeric_owner=True)
2631
2632 # convert to filesystem paths
2633 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2634 f_dirname_1 = os.path.join(TEMPDIR, dirname_1)
2635 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2636
2637 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2638 unittest.mock.call(f_dirname_1, 77, 76),
2639 unittest.mock.call(f_filename_2, 88, 87),
2640 ],
2641 any_order=True)
2642
2643 # this test requires that uid=0 and gid=0 really be named 'root'. that's
2644 # because the uname and gname in the test file are 'root', and extract()
2645 # will look them up using pwd and grp to find their uid and gid, which we
2646 # test here to be 0.
2647 @unittest.skipUnless(root_is_uid_gid_0(),
2648 'uid=0,gid=0 must be named "root"')
2649 @unittest.mock.patch('os.chown')
2650 @unittest.mock.patch('os.chmod')
2651 @unittest.mock.patch('os.geteuid')
2652 def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod,
2653 mock_chown):
2654 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2655 tarfl.extract(filename_1, TEMPDIR, numeric_owner=False)
2656
2657 # convert to filesystem paths
2658 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2659
2660 mock_chown.assert_called_with(f_filename_1, 0, 0)
2661
2662 @unittest.mock.patch('os.geteuid')
2663 def test_keyword_only(self, mock_geteuid):
2664 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2665 self.assertRaises(TypeError,
2666 tarfl.extract, filename_1, TEMPDIR, False, True)
2667
2668
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002669def setUpModule():
Antoine Pitrou95f55602010-09-23 18:36:46 +00002670 support.unlink(TEMPDIR)
Antoine Pitrou941ee882009-11-11 20:59:38 +00002671 os.makedirs(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002672
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002673 global testtarnames
2674 testtarnames = [tarname]
Antoine Pitrou95f55602010-09-23 18:36:46 +00002675 with open(tarname, "rb") as fobj:
2676 data = fobj.read()
Neal Norwitza4f651a2004-07-20 22:07:44 +00002677
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002678 # Create compressed tarfiles.
2679 for c in GzipTest, Bz2Test, LzmaTest:
2680 if c.open:
2681 support.unlink(c.tarname)
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002682 testtarnames.append(c.tarname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002683 with c.open(c.tarname, "wb") as tar:
2684 tar.write(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002685
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002686def tearDownModule():
2687 if os.path.exists(TEMPDIR):
Tim Goldene0bd2c52014-05-06 13:24:26 +01002688 support.rmtree(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002689
Neal Norwitz996acf12003-02-17 14:51:41 +00002690if __name__ == "__main__":
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002691 unittest.main()