blob: cae96802ded67e3c69b4bf1bad8849a1d009c07a [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
William Chargin674935b2020-02-12 11:56:02 -08001552class DeviceHeaderTest(WriteTestBase, unittest.TestCase):
1553
1554 prefix = "w:"
1555
1556 def test_headers_written_only_for_device_files(self):
1557 # Regression test for bpo-18819.
1558 tempdir = os.path.join(TEMPDIR, "device_header_test")
1559 os.mkdir(tempdir)
1560 try:
1561 tar = tarfile.open(tmpname, self.mode)
1562 try:
1563 input_blk = tarfile.TarInfo(name="my_block_device")
1564 input_reg = tarfile.TarInfo(name="my_regular_file")
1565 input_blk.type = tarfile.BLKTYPE
1566 input_reg.type = tarfile.REGTYPE
1567 tar.addfile(input_blk)
1568 tar.addfile(input_reg)
1569 finally:
1570 tar.close()
1571
1572 # devmajor and devminor should be *interpreted* as 0 in both...
1573 tar = tarfile.open(tmpname, "r")
1574 try:
1575 output_blk = tar.getmember("my_block_device")
1576 output_reg = tar.getmember("my_regular_file")
1577 finally:
1578 tar.close()
1579 self.assertEqual(output_blk.devmajor, 0)
1580 self.assertEqual(output_blk.devminor, 0)
1581 self.assertEqual(output_reg.devmajor, 0)
1582 self.assertEqual(output_reg.devminor, 0)
1583
1584 # ...but the fields should not actually be set on regular files:
1585 with open(tmpname, "rb") as infile:
1586 buf = infile.read()
1587 buf_blk = buf[output_blk.offset:output_blk.offset_data]
1588 buf_reg = buf[output_reg.offset:output_reg.offset_data]
1589 # See `struct posixheader` in GNU docs for byte offsets:
1590 # <https://www.gnu.org/software/tar/manual/html_node/Standard.html>
1591 device_headers = slice(329, 329 + 16)
1592 self.assertEqual(buf_blk[device_headers], b"0000000\0" * 2)
1593 self.assertEqual(buf_reg[device_headers], b"\0" * 16)
1594 finally:
1595 support.rmtree(tempdir)
1596
1597
Lars Gustäbel20703c62015-05-27 12:53:44 +02001598class CreateTest(WriteTestBase, unittest.TestCase):
Berker Peksag0fe63252015-02-13 21:02:12 +02001599
1600 prefix = "x:"
1601
1602 file_path = os.path.join(TEMPDIR, "spameggs42")
1603
1604 def setUp(self):
1605 support.unlink(tmpname)
1606
1607 @classmethod
1608 def setUpClass(cls):
1609 with open(cls.file_path, "wb") as fobj:
1610 fobj.write(b"aaa")
1611
1612 @classmethod
1613 def tearDownClass(cls):
1614 support.unlink(cls.file_path)
1615
1616 def test_create(self):
1617 with tarfile.open(tmpname, self.mode) as tobj:
1618 tobj.add(self.file_path)
1619
1620 with self.taropen(tmpname) as tobj:
1621 names = tobj.getnames()
1622 self.assertEqual(len(names), 1)
1623 self.assertIn('spameggs42', names[0])
1624
1625 def test_create_existing(self):
1626 with tarfile.open(tmpname, self.mode) as tobj:
1627 tobj.add(self.file_path)
1628
1629 with self.assertRaises(FileExistsError):
1630 tobj = tarfile.open(tmpname, self.mode)
1631
1632 with self.taropen(tmpname) as tobj:
1633 names = tobj.getnames()
1634 self.assertEqual(len(names), 1)
1635 self.assertIn('spameggs42', names[0])
1636
1637 def test_create_taropen(self):
1638 with self.taropen(tmpname, "x") as tobj:
1639 tobj.add(self.file_path)
1640
1641 with self.taropen(tmpname) as tobj:
1642 names = tobj.getnames()
1643 self.assertEqual(len(names), 1)
1644 self.assertIn('spameggs42', names[0])
1645
1646 def test_create_existing_taropen(self):
1647 with self.taropen(tmpname, "x") as tobj:
1648 tobj.add(self.file_path)
1649
1650 with self.assertRaises(FileExistsError):
1651 with self.taropen(tmpname, "x"):
1652 pass
1653
1654 with self.taropen(tmpname) as tobj:
1655 names = tobj.getnames()
1656 self.assertEqual(len(names), 1)
1657 self.assertIn("spameggs42", names[0])
1658
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001659 def test_create_pathlike_name(self):
1660 with tarfile.open(pathlib.Path(tmpname), self.mode) as tobj:
1661 self.assertIsInstance(tobj.name, str)
1662 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1663 tobj.add(pathlib.Path(self.file_path))
1664 names = tobj.getnames()
1665 self.assertEqual(len(names), 1)
1666 self.assertIn('spameggs42', names[0])
1667
1668 with self.taropen(tmpname) as tobj:
1669 names = tobj.getnames()
1670 self.assertEqual(len(names), 1)
1671 self.assertIn('spameggs42', names[0])
1672
1673 def test_create_taropen_pathlike_name(self):
1674 with self.taropen(pathlib.Path(tmpname), "x") as tobj:
1675 self.assertIsInstance(tobj.name, str)
1676 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1677 tobj.add(pathlib.Path(self.file_path))
1678 names = tobj.getnames()
1679 self.assertEqual(len(names), 1)
1680 self.assertIn('spameggs42', names[0])
1681
1682 with self.taropen(tmpname) as tobj:
1683 names = tobj.getnames()
1684 self.assertEqual(len(names), 1)
1685 self.assertIn('spameggs42', names[0])
1686
Berker Peksag0fe63252015-02-13 21:02:12 +02001687
1688class GzipCreateTest(GzipTest, CreateTest):
1689 pass
1690
1691
1692class Bz2CreateTest(Bz2Test, CreateTest):
1693 pass
1694
1695
1696class LzmaCreateTest(LzmaTest, CreateTest):
1697 pass
1698
1699
1700class CreateWithXModeTest(CreateTest):
1701
1702 prefix = "x"
1703
1704 test_create_taropen = None
1705 test_create_existing_taropen = None
1706
1707
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001708@unittest.skipUnless(hasattr(os, "link"), "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001709class HardlinkTest(unittest.TestCase):
1710 # Test the creation of LNKTYPE (hardlink) members in an archive.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001711
1712 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001713 self.foo = os.path.join(TEMPDIR, "foo")
1714 self.bar = os.path.join(TEMPDIR, "bar")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001715
Antoine Pitrou95f55602010-09-23 18:36:46 +00001716 with open(self.foo, "wb") as fobj:
1717 fobj.write(b"foo")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001718
xdegayed7d4fea2017-11-12 18:02:06 +01001719 try:
1720 os.link(self.foo, self.bar)
1721 except PermissionError as e:
1722 self.skipTest('os.link(): %s' % e)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001723
Guido van Rossumd8faa362007-04-27 19:54:29 +00001724 self.tar = tarfile.open(tmpname, "w")
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001725 self.tar.add(self.foo)
1726
Guido van Rossumd8faa362007-04-27 19:54:29 +00001727 def tearDown(self):
Hirokazu Yamamotoaf079d42008-09-21 11:50:03 +00001728 self.tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001729 support.unlink(self.foo)
1730 support.unlink(self.bar)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001731
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001732 def test_add_twice(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001733 # The same name will be added as a REGTYPE every
1734 # time regardless of st_nlink.
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001735 tarinfo = self.tar.gettarinfo(self.foo)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001736 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001737 "add file as regular failed")
1738
1739 def test_add_hardlink(self):
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001740 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001741 self.assertEqual(tarinfo.type, tarfile.LNKTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001742 "add file as hardlink failed")
1743
1744 def test_dereference_hardlink(self):
1745 self.tar.dereference = True
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001746 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001747 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001748 "dereferencing hardlink failed")
1749
Neal Norwitza4f651a2004-07-20 22:07:44 +00001750
Guido van Rossumd8faa362007-04-27 19:54:29 +00001751class PaxWriteTest(GNUWriteTest):
Martin v. Löwis78be7df2005-03-05 12:47:42 +00001752
Guido van Rossumd8faa362007-04-27 19:54:29 +00001753 def _test(self, name, link=None):
1754 # See GNUWriteTest.
1755 tarinfo = tarfile.TarInfo(name)
1756 if link:
1757 tarinfo.linkname = link
1758 tarinfo.type = tarfile.LNKTYPE
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001759
Guido van Rossumd8faa362007-04-27 19:54:29 +00001760 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001761 try:
1762 tar.addfile(tarinfo)
1763 finally:
1764 tar.close()
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001765
Guido van Rossumd8faa362007-04-27 19:54:29 +00001766 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001767 try:
1768 if link:
1769 l = tar.getmembers()[0].linkname
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001770 self.assertEqual(link, l, "PAX longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001771 else:
1772 n = tar.getmembers()[0].name
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001773 self.assertEqual(name, n, "PAX longname creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001774 finally:
1775 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001776
Guido van Rossume7ba4952007-06-06 23:52:48 +00001777 def test_pax_global_header(self):
1778 pax_headers = {
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001779 "foo": "bar",
1780 "uid": "0",
1781 "mtime": "1.23",
Guido van Rossuma0557702007-08-07 23:19:53 +00001782 "test": "\xe4\xf6\xfc",
1783 "\xe4\xf6\xfc": "test"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001784
Benjamin Peterson886af962010-03-21 23:13:07 +00001785 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
Guido van Rossume7ba4952007-06-06 23:52:48 +00001786 pax_headers=pax_headers)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001787 try:
1788 tar.addfile(tarfile.TarInfo("test"))
1789 finally:
1790 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001791
1792 # Test if the global header was written correctly.
1793 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001794 try:
1795 self.assertEqual(tar.pax_headers, pax_headers)
1796 self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers)
1797 # Test if all the fields are strings.
1798 for key, val in tar.pax_headers.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001799 self.assertIsNot(type(key), bytes)
1800 self.assertIsNot(type(val), bytes)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001801 if key in tarfile.PAX_NUMBER_FIELDS:
1802 try:
1803 tarfile.PAX_NUMBER_FIELDS[key](val)
1804 except (TypeError, ValueError):
1805 self.fail("unable to convert pax header field")
1806 finally:
1807 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001808
1809 def test_pax_extended_header(self):
1810 # The fields from the pax header have priority over the
1811 # TarInfo.
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001812 pax_headers = {"path": "foo", "uid": "123"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001813
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001814 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
1815 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001816 try:
1817 t = tarfile.TarInfo()
1818 t.name = "\xe4\xf6\xfc" # non-ASCII
1819 t.uid = 8**8 # too large
1820 t.pax_headers = pax_headers
1821 tar.addfile(t)
1822 finally:
1823 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001824
1825 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001826 try:
1827 t = tar.getmembers()[0]
1828 self.assertEqual(t.pax_headers, pax_headers)
1829 self.assertEqual(t.name, "foo")
1830 self.assertEqual(t.uid, 123)
1831 finally:
1832 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001833
1834
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001835class UnicodeTest:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001836
1837 def test_iso8859_1_filename(self):
1838 self._test_unicode_filename("iso8859-1")
1839
1840 def test_utf7_filename(self):
1841 self._test_unicode_filename("utf7")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001842
1843 def test_utf8_filename(self):
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00001844 self._test_unicode_filename("utf-8")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001845
Guido van Rossumd8faa362007-04-27 19:54:29 +00001846 def _test_unicode_filename(self, encoding):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001847 tar = tarfile.open(tmpname, "w", format=self.format,
1848 encoding=encoding, errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001849 try:
1850 name = "\xe4\xf6\xfc"
1851 tar.addfile(tarfile.TarInfo(name))
1852 finally:
1853 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001854
1855 tar = tarfile.open(tmpname, encoding=encoding)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001856 try:
1857 self.assertEqual(tar.getmembers()[0].name, name)
1858 finally:
1859 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001860
1861 def test_unicode_filename_error(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001862 tar = tarfile.open(tmpname, "w", format=self.format,
1863 encoding="ascii", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001864 try:
1865 tarinfo = tarfile.TarInfo()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001866
Antoine Pitrou95f55602010-09-23 18:36:46 +00001867 tarinfo.name = "\xe4\xf6\xfc"
1868 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001869
Antoine Pitrou95f55602010-09-23 18:36:46 +00001870 tarinfo.name = "foo"
1871 tarinfo.uname = "\xe4\xf6\xfc"
1872 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
1873 finally:
1874 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001875
1876 def test_unicode_argument(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001877 tar = tarfile.open(tarname, "r",
1878 encoding="iso8859-1", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001879 try:
1880 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001881 self.assertIs(type(t.name), str)
1882 self.assertIs(type(t.linkname), str)
1883 self.assertIs(type(t.uname), str)
1884 self.assertIs(type(t.gname), str)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001885 finally:
1886 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001887
Guido van Rossume7ba4952007-06-06 23:52:48 +00001888 def test_uname_unicode(self):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001889 t = tarfile.TarInfo("foo")
1890 t.uname = "\xe4\xf6\xfc"
1891 t.gname = "\xe4\xf6\xfc"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001892
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001893 tar = tarfile.open(tmpname, mode="w", format=self.format,
1894 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001895 try:
1896 tar.addfile(t)
1897 finally:
1898 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001899
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001900 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001901 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001902 t = tar.getmember("foo")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001903 self.assertEqual(t.uname, "\xe4\xf6\xfc")
1904 self.assertEqual(t.gname, "\xe4\xf6\xfc")
1905
1906 if self.format != tarfile.PAX_FORMAT:
Antoine Pitrouab58b5f2010-09-23 19:39:35 +00001907 tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001908 tar = tarfile.open(tmpname, encoding="ascii")
1909 t = tar.getmember("foo")
1910 self.assertEqual(t.uname, "\udce4\udcf6\udcfc")
1911 self.assertEqual(t.gname, "\udce4\udcf6\udcfc")
1912 finally:
1913 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001914
Lars Gustäbelb506dc32007-08-07 18:36:16 +00001915
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001916class UstarUnicodeTest(UnicodeTest, unittest.TestCase):
1917
1918 format = tarfile.USTAR_FORMAT
1919
1920 # Test whether the utf-8 encoded version of a filename exceeds the 100
1921 # bytes name field limit (every occurrence of '\xff' will be expanded to 2
1922 # bytes).
1923 def test_unicode_name1(self):
1924 self._test_ustar_name("0123456789" * 10)
1925 self._test_ustar_name("0123456789" * 10 + "0", ValueError)
1926 self._test_ustar_name("0123456789" * 9 + "01234567\xff")
1927 self._test_ustar_name("0123456789" * 9 + "012345678\xff", ValueError)
1928
1929 def test_unicode_name2(self):
1930 self._test_ustar_name("0123456789" * 9 + "012345\xff\xff")
1931 self._test_ustar_name("0123456789" * 9 + "0123456\xff\xff", ValueError)
1932
1933 # Test whether the utf-8 encoded version of a filename exceeds the 155
1934 # bytes prefix + '/' + 100 bytes name limit.
1935 def test_unicode_longname1(self):
1936 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 10)
1937 self._test_ustar_name("0123456789" * 15 + "0123/4" + "0123456789" * 10, ValueError)
1938 self._test_ustar_name("0123456789" * 15 + "012\xff/" + "0123456789" * 10)
1939 self._test_ustar_name("0123456789" * 15 + "0123\xff/" + "0123456789" * 10, ValueError)
1940
1941 def test_unicode_longname2(self):
1942 self._test_ustar_name("0123456789" * 15 + "01\xff/2" + "0123456789" * 10, ValueError)
1943 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/" + "0123456789" * 10, ValueError)
1944
1945 def test_unicode_longname3(self):
1946 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/2" + "0123456789" * 10, ValueError)
1947 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "01234567\xff")
1948 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345678\xff", ValueError)
1949
1950 def test_unicode_longname4(self):
1951 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345\xff\xff")
1952 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "0123456\xff\xff", ValueError)
1953
1954 def _test_ustar_name(self, name, exc=None):
1955 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1956 t = tarfile.TarInfo(name)
1957 if exc is None:
1958 tar.addfile(t)
1959 else:
1960 self.assertRaises(exc, tar.addfile, t)
1961
1962 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001963 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001964 for t in tar:
1965 self.assertEqual(name, t.name)
1966 break
1967
1968 # Test the same as above for the 100 bytes link field.
1969 def test_unicode_link1(self):
1970 self._test_ustar_link("0123456789" * 10)
1971 self._test_ustar_link("0123456789" * 10 + "0", ValueError)
1972 self._test_ustar_link("0123456789" * 9 + "01234567\xff")
1973 self._test_ustar_link("0123456789" * 9 + "012345678\xff", ValueError)
1974
1975 def test_unicode_link2(self):
1976 self._test_ustar_link("0123456789" * 9 + "012345\xff\xff")
1977 self._test_ustar_link("0123456789" * 9 + "0123456\xff\xff", ValueError)
1978
1979 def _test_ustar_link(self, name, exc=None):
1980 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1981 t = tarfile.TarInfo("foo")
1982 t.linkname = name
1983 if exc is None:
1984 tar.addfile(t)
1985 else:
1986 self.assertRaises(exc, tar.addfile, t)
1987
1988 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001989 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001990 for t in tar:
1991 self.assertEqual(name, t.linkname)
1992 break
1993
1994
1995class GNUUnicodeTest(UnicodeTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001996
Guido van Rossume7ba4952007-06-06 23:52:48 +00001997 format = tarfile.GNU_FORMAT
Guido van Rossumd8faa362007-04-27 19:54:29 +00001998
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001999 def test_bad_pax_header(self):
2000 # Test for issue #8633. GNU tar <= 1.23 creates raw binary fields
2001 # without a hdrcharset=BINARY header.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002002 for encoding, name in (
2003 ("utf-8", "pax/bad-pax-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002004 ("iso8859-1", "pax/bad-pax-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002005 with tarfile.open(tarname, encoding=encoding,
2006 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002007 try:
2008 t = tar.getmember(name)
2009 except KeyError:
2010 self.fail("unable to read bad GNU tar pax header")
2011
Guido van Rossumd8faa362007-04-27 19:54:29 +00002012
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02002013class PAXUnicodeTest(UnicodeTest, unittest.TestCase):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00002014
2015 format = tarfile.PAX_FORMAT
2016
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002017 # PAX_FORMAT ignores encoding in write mode.
2018 test_unicode_filename_error = None
2019
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002020 def test_binary_header(self):
2021 # Test a POSIX.1-2008 compatible header with a hdrcharset=BINARY field.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002022 for encoding, name in (
2023 ("utf-8", "pax/hdrcharset-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002024 ("iso8859-1", "pax/hdrcharset-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002025 with tarfile.open(tarname, encoding=encoding,
2026 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00002027 try:
2028 t = tar.getmember(name)
2029 except KeyError:
2030 self.fail("unable to read POSIX.1-2008 binary header")
2031
Lars Gustäbel3741eff2007-08-21 12:17:05 +00002032
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002033class AppendTestBase:
Guido van Rossumd8faa362007-04-27 19:54:29 +00002034 # Test append mode (cp. patch #1652681).
Thomas Wouters902d6eb2007-01-09 23:18:33 +00002035
Guido van Rossumd8faa362007-04-27 19:54:29 +00002036 def setUp(self):
2037 self.tarname = tmpname
2038 if os.path.exists(self.tarname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01002039 support.unlink(self.tarname)
Thomas Wouters902d6eb2007-01-09 23:18:33 +00002040
Guido van Rossumd8faa362007-04-27 19:54:29 +00002041 def _create_testtar(self, mode="w:"):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002042 with tarfile.open(tarname, encoding="iso8859-1") as src:
2043 t = src.getmember("ustar/regtype")
2044 t.name = "foo"
Lars Gustäbel7a919e92012-05-05 18:15:03 +02002045 with src.extractfile(t) as f:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +00002046 with tarfile.open(self.tarname, mode) as tar:
2047 tar.addfile(t, f)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002048
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002049 def test_append_compressed(self):
2050 self._create_testtar("w:" + self.suffix)
2051 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a")
2052
2053class AppendTest(AppendTestBase, unittest.TestCase):
2054 test_append_compressed = None
2055
2056 def _add_testfile(self, fileobj=None):
2057 with tarfile.open(self.tarname, "a", fileobj=fileobj) as tar:
2058 tar.addfile(tarfile.TarInfo("bar"))
2059
Guido van Rossumd8faa362007-04-27 19:54:29 +00002060 def _test(self, names=["bar"], fileobj=None):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002061 with tarfile.open(self.tarname, fileobj=fileobj) as tar:
2062 self.assertEqual(tar.getnames(), names)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002063
2064 def test_non_existing(self):
2065 self._add_testfile()
2066 self._test()
2067
2068 def test_empty(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002069 tarfile.open(self.tarname, "w:").close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00002070 self._add_testfile()
2071 self._test()
2072
2073 def test_empty_fileobj(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002074 fobj = io.BytesIO(b"\0" * 1024)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002075 self._add_testfile(fobj)
2076 fobj.seek(0)
2077 self._test(fileobj=fobj)
2078
2079 def test_fileobj(self):
2080 self._create_testtar()
Antoine Pitrou95f55602010-09-23 18:36:46 +00002081 with open(self.tarname, "rb") as fobj:
2082 data = fobj.read()
Guido van Rossum34d19282007-08-09 01:03:29 +00002083 fobj = io.BytesIO(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002084 self._add_testfile(fobj)
2085 fobj.seek(0)
2086 self._test(names=["foo", "bar"], fileobj=fobj)
2087
2088 def test_existing(self):
2089 self._create_testtar()
2090 self._add_testfile()
2091 self._test(names=["foo", "bar"])
2092
Lars Gustäbel9520a432009-11-22 18:48:49 +00002093 # Append mode is supposed to fail if the tarfile to append to
2094 # does not end with a zero block.
2095 def _test_error(self, data):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002096 with open(self.tarname, "wb") as fobj:
2097 fobj.write(data)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002098 self.assertRaises(tarfile.ReadError, self._add_testfile)
2099
2100 def test_null(self):
2101 self._test_error(b"")
2102
2103 def test_incomplete(self):
2104 self._test_error(b"\0" * 13)
2105
2106 def test_premature_eof(self):
2107 data = tarfile.TarInfo("foo").tobuf()
2108 self._test_error(data)
2109
2110 def test_trailing_garbage(self):
2111 data = tarfile.TarInfo("foo").tobuf()
2112 self._test_error(data + b"\0" * 13)
2113
2114 def test_invalid(self):
2115 self._test_error(b"a" * 512)
2116
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002117class GzipAppendTest(GzipTest, AppendTestBase, unittest.TestCase):
2118 pass
2119
2120class Bz2AppendTest(Bz2Test, AppendTestBase, unittest.TestCase):
2121 pass
2122
2123class LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase):
2124 pass
2125
Guido van Rossumd8faa362007-04-27 19:54:29 +00002126
2127class LimitsTest(unittest.TestCase):
2128
2129 def test_ustar_limits(self):
2130 # 100 char name
2131 tarinfo = tarfile.TarInfo("0123456789" * 10)
Guido van Rossume7ba4952007-06-06 23:52:48 +00002132 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002133
2134 # 101 char name that cannot be stored
2135 tarinfo = tarfile.TarInfo("0123456789" * 10 + "0")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002136 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002137
2138 # 256 char name with a slash at pos 156
2139 tarinfo = tarfile.TarInfo("123/" * 62 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002140 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002141
2142 # 256 char name that cannot be stored
2143 tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002144 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002145
2146 # 512 char name
2147 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002148 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002149
2150 # 512 char linkname
2151 tarinfo = tarfile.TarInfo("longlink")
2152 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002153 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002154
2155 # uid > 8 digits
2156 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002157 tarinfo.uid = 0o10000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002158 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002159
2160 def test_gnu_limits(self):
2161 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002162 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002163
2164 tarinfo = tarfile.TarInfo("longlink")
2165 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002166 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002167
2168 # uid >= 256 ** 7
2169 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002170 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002171 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002172
2173 def test_pax_limits(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002174 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002175 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002176
2177 tarinfo = tarfile.TarInfo("longlink")
2178 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002179 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002180
2181 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002182 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002183 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002184
2185
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002186class MiscTest(unittest.TestCase):
2187
2188 def test_char_fields(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002189 self.assertEqual(tarfile.stn("foo", 8, "ascii", "strict"),
2190 b"foo\0\0\0\0\0")
2191 self.assertEqual(tarfile.stn("foobar", 3, "ascii", "strict"),
2192 b"foo")
2193 self.assertEqual(tarfile.nts(b"foo\0\0\0\0\0", "ascii", "strict"),
2194 "foo")
2195 self.assertEqual(tarfile.nts(b"foo\0bar\0", "ascii", "strict"),
2196 "foo")
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002197
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002198 def test_read_number_fields(self):
2199 # Issue 13158: Test if GNU tar specific base-256 number fields
2200 # are decoded correctly.
2201 self.assertEqual(tarfile.nti(b"0000001\x00"), 1)
2202 self.assertEqual(tarfile.nti(b"7777777\x00"), 0o7777777)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002203 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\x00\x20\x00\x00"),
2204 0o10000000)
2205 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\xff\xff\xff\xff"),
2206 0xffffffff)
2207 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\xff"),
2208 -1)
2209 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\x9c"),
2210 -100)
2211 self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"),
2212 -0x100000000000000)
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002213
Lars Gustäbelb7a688b2015-07-02 19:38:38 +02002214 # Issue 24514: Test if empty number fields are converted to zero.
2215 self.assertEqual(tarfile.nti(b"\0"), 0)
2216 self.assertEqual(tarfile.nti(b" \0"), 0)
2217
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002218 def test_write_number_fields(self):
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002219 self.assertEqual(tarfile.itn(1), b"0000001\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002220 self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002221 self.assertEqual(tarfile.itn(0o10000000, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002222 b"\x80\x00\x00\x00\x00\x20\x00\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002223 self.assertEqual(tarfile.itn(0xffffffff, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002224 b"\x80\x00\x00\x00\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002225 self.assertEqual(tarfile.itn(-1, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002226 b"\xff\xff\xff\xff\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002227 self.assertEqual(tarfile.itn(-100, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002228 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002229 self.assertEqual(tarfile.itn(-0x100000000000000,
2230 format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002231 b"\xff\x00\x00\x00\x00\x00\x00\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002232
Joffrey F72d9b2b2018-02-26 16:02:21 -08002233 # Issue 32713: Test if itn() supports float values outside the
2234 # non-GNU format range
2235 self.assertEqual(tarfile.itn(-100.0, format=tarfile.GNU_FORMAT),
2236 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
2237 self.assertEqual(tarfile.itn(8 ** 12 + 0.0, format=tarfile.GNU_FORMAT),
2238 b"\x80\x00\x00\x10\x00\x00\x00\x00")
2239 self.assertEqual(tarfile.nti(tarfile.itn(-0.1, format=tarfile.GNU_FORMAT)), 0)
2240
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002241 def test_number_field_limits(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002242 with self.assertRaises(ValueError):
2243 tarfile.itn(-1, 8, tarfile.USTAR_FORMAT)
2244 with self.assertRaises(ValueError):
2245 tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT)
2246 with self.assertRaises(ValueError):
2247 tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT)
2248 with self.assertRaises(ValueError):
2249 tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT)
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002250
Martin Panter104dcda2016-01-16 06:59:13 +00002251 def test__all__(self):
Martin Panter5318d102016-01-16 11:01:14 +00002252 blacklist = {'version', 'grp', 'pwd', 'symlink_exception',
Martin Panter104dcda2016-01-16 06:59:13 +00002253 'NUL', 'BLOCKSIZE', 'RECORDSIZE', 'GNU_MAGIC',
2254 'POSIX_MAGIC', 'LENGTH_NAME', 'LENGTH_LINK',
2255 'LENGTH_PREFIX', 'REGTYPE', 'AREGTYPE', 'LNKTYPE',
2256 'SYMTYPE', 'CHRTYPE', 'BLKTYPE', 'DIRTYPE', 'FIFOTYPE',
2257 'CONTTYPE', 'GNUTYPE_LONGNAME', 'GNUTYPE_LONGLINK',
2258 'GNUTYPE_SPARSE', 'XHDTYPE', 'XGLTYPE', 'SOLARIS_XHDTYPE',
2259 'SUPPORTED_TYPES', 'REGULAR_TYPES', 'GNU_TYPES',
2260 'PAX_FIELDS', 'PAX_NAME_FIELDS', 'PAX_NUMBER_FIELDS',
2261 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 'copyfileobj',
2262 'filemode',
2263 'EmptyHeaderError', 'TruncatedHeaderError',
2264 'EOFHeaderError', 'InvalidHeaderError',
Serhiy Storchaka2c1d3e32016-01-16 11:05:11 +02002265 'SubsequentHeaderError', 'ExFileObject',
Martin Panter104dcda2016-01-16 06:59:13 +00002266 'main'}
2267 support.check__all__(self, tarfile, blacklist=blacklist)
2268
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002269
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002270class CommandLineTest(unittest.TestCase):
2271
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002272 def tarfilecmd(self, *args, **kwargs):
2273 rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args,
2274 **kwargs)
Antoine Pitrou3b7b1e52013-11-24 01:55:05 +01002275 return out.replace(os.linesep.encode(), b'\n')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002276
2277 def tarfilecmd_failure(self, *args):
2278 return script_helper.assert_python_failure('-m', 'tarfile', *args)
2279
2280 def make_simple_tarfile(self, tar_name):
2281 files = [support.findfile('tokenize_tests.txt'),
2282 support.findfile('tokenize_tests-no-coding-cookie-'
2283 'and-utf8-bom-sig-only.txt')]
2284 self.addCleanup(support.unlink, tar_name)
2285 with tarfile.open(tar_name, 'w') as tf:
2286 for tardata in files:
2287 tf.add(tardata, arcname=os.path.basename(tardata))
2288
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002289 def test_bad_use(self):
2290 rc, out, err = self.tarfilecmd_failure()
2291 self.assertEqual(out, b'')
2292 self.assertIn(b'usage', err.lower())
2293 self.assertIn(b'error', err.lower())
2294 self.assertIn(b'required', err.lower())
2295 rc, out, err = self.tarfilecmd_failure('-l', '')
2296 self.assertEqual(out, b'')
2297 self.assertNotEqual(err.strip(), b'')
2298
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002299 def test_test_command(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002300 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002301 for opt in '-t', '--test':
2302 out = self.tarfilecmd(opt, tar_name)
2303 self.assertEqual(out, b'')
2304
2305 def test_test_command_verbose(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002306 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002307 for opt in '-v', '--verbose':
2308 out = self.tarfilecmd(opt, '-t', tar_name)
2309 self.assertIn(b'is a tar archive.\n', out)
2310
2311 def test_test_command_invalid_file(self):
2312 zipname = support.findfile('zipdir.zip')
2313 rc, out, err = self.tarfilecmd_failure('-t', zipname)
2314 self.assertIn(b' is not a tar archive.', err)
2315 self.assertEqual(out, b'')
2316 self.assertEqual(rc, 1)
2317
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002318 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002319 with self.subTest(tar_name=tar_name):
2320 with open(tar_name, 'rb') as f:
2321 data = f.read()
2322 try:
2323 with open(tmpname, 'wb') as f:
2324 f.write(data[:511])
2325 rc, out, err = self.tarfilecmd_failure('-t', tmpname)
2326 self.assertEqual(out, b'')
2327 self.assertEqual(rc, 1)
2328 finally:
2329 support.unlink(tmpname)
2330
2331 def test_list_command(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002332 for tar_name in testtarnames:
2333 with support.captured_stdout() as t:
2334 with tarfile.open(tar_name, 'r') as tf:
2335 tf.list(verbose=False)
2336 expected = t.getvalue().encode('ascii', 'backslashreplace')
2337 for opt in '-l', '--list':
2338 out = self.tarfilecmd(opt, tar_name,
2339 PYTHONIOENCODING='ascii')
2340 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002341
2342 def test_list_command_verbose(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002343 for tar_name in testtarnames:
2344 with support.captured_stdout() as t:
2345 with tarfile.open(tar_name, 'r') as tf:
2346 tf.list(verbose=True)
2347 expected = t.getvalue().encode('ascii', 'backslashreplace')
2348 for opt in '-v', '--verbose':
2349 out = self.tarfilecmd(opt, '-l', tar_name,
2350 PYTHONIOENCODING='ascii')
2351 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002352
2353 def test_list_command_invalid_file(self):
2354 zipname = support.findfile('zipdir.zip')
2355 rc, out, err = self.tarfilecmd_failure('-l', zipname)
2356 self.assertIn(b' is not a tar archive.', err)
2357 self.assertEqual(out, b'')
2358 self.assertEqual(rc, 1)
2359
2360 def test_create_command(self):
2361 files = [support.findfile('tokenize_tests.txt'),
2362 support.findfile('tokenize_tests-no-coding-cookie-'
2363 'and-utf8-bom-sig-only.txt')]
2364 for opt in '-c', '--create':
2365 try:
2366 out = self.tarfilecmd(opt, tmpname, *files)
2367 self.assertEqual(out, b'')
2368 with tarfile.open(tmpname) as tar:
2369 tar.getmembers()
2370 finally:
2371 support.unlink(tmpname)
2372
2373 def test_create_command_verbose(self):
2374 files = [support.findfile('tokenize_tests.txt'),
2375 support.findfile('tokenize_tests-no-coding-cookie-'
2376 'and-utf8-bom-sig-only.txt')]
2377 for opt in '-v', '--verbose':
2378 try:
2379 out = self.tarfilecmd(opt, '-c', tmpname, *files)
2380 self.assertIn(b' file created.', out)
2381 with tarfile.open(tmpname) as tar:
2382 tar.getmembers()
2383 finally:
2384 support.unlink(tmpname)
2385
2386 def test_create_command_dotless_filename(self):
2387 files = [support.findfile('tokenize_tests.txt')]
2388 try:
2389 out = self.tarfilecmd('-c', dotlessname, *files)
2390 self.assertEqual(out, b'')
2391 with tarfile.open(dotlessname) as tar:
2392 tar.getmembers()
2393 finally:
2394 support.unlink(dotlessname)
2395
2396 def test_create_command_dot_started_filename(self):
2397 tar_name = os.path.join(TEMPDIR, ".testtar")
2398 files = [support.findfile('tokenize_tests.txt')]
2399 try:
2400 out = self.tarfilecmd('-c', tar_name, *files)
2401 self.assertEqual(out, b'')
2402 with tarfile.open(tar_name) as tar:
2403 tar.getmembers()
2404 finally:
2405 support.unlink(tar_name)
2406
Serhiy Storchaka832dd5f2015-02-10 08:45:53 +02002407 def test_create_command_compressed(self):
2408 files = [support.findfile('tokenize_tests.txt'),
2409 support.findfile('tokenize_tests-no-coding-cookie-'
2410 'and-utf8-bom-sig-only.txt')]
2411 for filetype in (GzipTest, Bz2Test, LzmaTest):
2412 if not filetype.open:
2413 continue
2414 try:
2415 tar_name = tmpname + '.' + filetype.suffix
2416 out = self.tarfilecmd('-c', tar_name, *files)
2417 with filetype.taropen(tar_name) as tar:
2418 tar.getmembers()
2419 finally:
2420 support.unlink(tar_name)
2421
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002422 def test_extract_command(self):
2423 self.make_simple_tarfile(tmpname)
2424 for opt in '-e', '--extract':
2425 try:
2426 with support.temp_cwd(tarextdir):
2427 out = self.tarfilecmd(opt, tmpname)
2428 self.assertEqual(out, b'')
2429 finally:
2430 support.rmtree(tarextdir)
2431
2432 def test_extract_command_verbose(self):
2433 self.make_simple_tarfile(tmpname)
2434 for opt in '-v', '--verbose':
2435 try:
2436 with support.temp_cwd(tarextdir):
2437 out = self.tarfilecmd(opt, '-e', tmpname)
2438 self.assertIn(b' file is extracted.', out)
2439 finally:
2440 support.rmtree(tarextdir)
2441
2442 def test_extract_command_different_directory(self):
2443 self.make_simple_tarfile(tmpname)
2444 try:
2445 with support.temp_cwd(tarextdir):
2446 out = self.tarfilecmd('-e', tmpname, 'spamdir')
2447 self.assertEqual(out, b'')
2448 finally:
2449 support.rmtree(tarextdir)
2450
2451 def test_extract_command_invalid_file(self):
2452 zipname = support.findfile('zipdir.zip')
2453 with support.temp_cwd(tarextdir):
2454 rc, out, err = self.tarfilecmd_failure('-e', zipname)
2455 self.assertIn(b' is not a tar archive.', err)
2456 self.assertEqual(out, b'')
2457 self.assertEqual(rc, 1)
2458
2459
Lars Gustäbel01385812010-03-03 12:08:54 +00002460class ContextManagerTest(unittest.TestCase):
2461
2462 def test_basic(self):
2463 with tarfile.open(tarname) as tar:
2464 self.assertFalse(tar.closed, "closed inside runtime context")
2465 self.assertTrue(tar.closed, "context manager failed")
2466
2467 def test_closed(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002468 # The __enter__() method is supposed to raise OSError
Lars Gustäbel01385812010-03-03 12:08:54 +00002469 # if the TarFile object is already closed.
2470 tar = tarfile.open(tarname)
2471 tar.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002472 with self.assertRaises(OSError):
Lars Gustäbel01385812010-03-03 12:08:54 +00002473 with tar:
2474 pass
2475
2476 def test_exception(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002477 # Test if the OSError exception is passed through properly.
Lars Gustäbel01385812010-03-03 12:08:54 +00002478 with self.assertRaises(Exception) as exc:
2479 with tarfile.open(tarname) as tar:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002480 raise OSError
2481 self.assertIsInstance(exc.exception, OSError,
Lars Gustäbel01385812010-03-03 12:08:54 +00002482 "wrong exception raised in context manager")
2483 self.assertTrue(tar.closed, "context manager failed")
2484
2485 def test_no_eof(self):
2486 # __exit__() must not write end-of-archive blocks if an
2487 # exception was raised.
2488 try:
2489 with tarfile.open(tmpname, "w") as tar:
2490 raise Exception
2491 except:
2492 pass
2493 self.assertEqual(os.path.getsize(tmpname), 0,
2494 "context manager wrote an end-of-archive block")
2495 self.assertTrue(tar.closed, "context manager failed")
2496
2497 def test_eof(self):
2498 # __exit__() must write end-of-archive blocks, i.e. call
2499 # TarFile.close() if there was no error.
2500 with tarfile.open(tmpname, "w"):
2501 pass
2502 self.assertNotEqual(os.path.getsize(tmpname), 0,
2503 "context manager wrote no end-of-archive block")
2504
2505 def test_fileobj(self):
2506 # Test that __exit__() did not close the external file
2507 # object.
Antoine Pitrou95f55602010-09-23 18:36:46 +00002508 with open(tmpname, "wb") as fobj:
2509 try:
2510 with tarfile.open(fileobj=fobj, mode="w") as tar:
2511 raise Exception
2512 except:
2513 pass
2514 self.assertFalse(fobj.closed, "external file object was closed")
2515 self.assertTrue(tar.closed, "context manager failed")
Lars Gustäbel01385812010-03-03 12:08:54 +00002516
2517
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002518@unittest.skipIf(hasattr(os, "link"), "requires os.link to be missing")
2519class LinkEmulationTest(ReadTest, unittest.TestCase):
Lars Gustäbel1b512722010-06-03 12:45:16 +00002520
2521 # Test for issue #8741 regression. On platforms that do not support
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002522 # symbolic or hard links tarfile tries to extract these types of members
2523 # as the regular files they point to.
Lars Gustäbel1b512722010-06-03 12:45:16 +00002524 def _test_link_extraction(self, name):
2525 self.tar.extract(name, TEMPDIR)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002526 with open(os.path.join(TEMPDIR, name), "rb") as f:
2527 data = f.read()
Christian Heimesc64a1a62019-09-25 16:30:20 +02002528 self.assertEqual(sha256sum(data), sha256_regtype)
Lars Gustäbel1b512722010-06-03 12:45:16 +00002529
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002530 # See issues #1578269, #8879, and #17689 for some history on these skips
Brian Curtind40e6f72010-07-08 21:39:08 +00002531 @unittest.skipIf(hasattr(os.path, "islink"),
2532 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002533 def test_hardlink_extraction1(self):
2534 self._test_link_extraction("ustar/lnktype")
2535
Brian Curtind40e6f72010-07-08 21:39:08 +00002536 @unittest.skipIf(hasattr(os.path, "islink"),
2537 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002538 def test_hardlink_extraction2(self):
2539 self._test_link_extraction("./ustar/linktest2/lnktype")
2540
Brian Curtin74e45612010-07-09 15:58:59 +00002541 @unittest.skipIf(hasattr(os, "symlink"),
2542 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002543 def test_symlink_extraction1(self):
2544 self._test_link_extraction("ustar/symtype")
2545
Brian Curtin74e45612010-07-09 15:58:59 +00002546 @unittest.skipIf(hasattr(os, "symlink"),
2547 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002548 def test_symlink_extraction2(self):
2549 self._test_link_extraction("./ustar/linktest2/symtype")
2550
2551
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002552class Bz2PartialReadTest(Bz2Test, unittest.TestCase):
Lars Gustäbel42e00912009-03-22 20:34:29 +00002553 # Issue5068: The _BZ2Proxy.read() method loops forever
2554 # on an empty or partial bzipped file.
2555
2556 def _test_partial_input(self, mode):
2557 class MyBytesIO(io.BytesIO):
2558 hit_eof = False
2559 def read(self, n):
2560 if self.hit_eof:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002561 raise AssertionError("infinite loop detected in "
2562 "tarfile.open()")
Lars Gustäbel42e00912009-03-22 20:34:29 +00002563 self.hit_eof = self.tell() == len(self.getvalue())
2564 return super(MyBytesIO, self).read(n)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002565 def seek(self, *args):
2566 self.hit_eof = False
2567 return super(MyBytesIO, self).seek(*args)
Lars Gustäbel42e00912009-03-22 20:34:29 +00002568
2569 data = bz2.compress(tarfile.TarInfo("foo").tobuf())
2570 for x in range(len(data) + 1):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002571 try:
2572 tarfile.open(fileobj=MyBytesIO(data[:x]), mode=mode)
2573 except tarfile.ReadError:
2574 pass # we have no interest in ReadErrors
Lars Gustäbel42e00912009-03-22 20:34:29 +00002575
2576 def test_partial_input(self):
2577 self._test_partial_input("r")
2578
2579 def test_partial_input_bz2(self):
2580 self._test_partial_input("r:bz2")
2581
2582
Eric V. Smith7a803892015-04-15 10:27:58 -04002583def root_is_uid_gid_0():
2584 try:
2585 import pwd, grp
2586 except ImportError:
2587 return False
2588 if pwd.getpwuid(0)[0] != 'root':
2589 return False
2590 if grp.getgrgid(0)[0] != 'root':
2591 return False
2592 return True
2593
2594
Zachary Waread3e27a2015-05-12 23:57:21 -05002595@unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown")
2596@unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid")
Eric V. Smith7a803892015-04-15 10:27:58 -04002597class NumericOwnerTest(unittest.TestCase):
2598 # mock the following:
2599 # os.chown: so we can test what's being called
2600 # os.chmod: so the modes are not actually changed. if they are, we can't
2601 # delete the files/directories
2602 # os.geteuid: so we can lie and say we're root (uid = 0)
2603
2604 @staticmethod
2605 def _make_test_archive(filename_1, dirname_1, filename_2):
2606 # the file contents to write
2607 fobj = io.BytesIO(b"content")
2608
2609 # create a tar file with a file, a directory, and a file within that
2610 # directory. Assign various .uid/.gid values to them
2611 items = [(filename_1, 99, 98, tarfile.REGTYPE, fobj),
2612 (dirname_1, 77, 76, tarfile.DIRTYPE, None),
2613 (filename_2, 88, 87, tarfile.REGTYPE, fobj),
2614 ]
2615 with tarfile.open(tmpname, 'w') as tarfl:
2616 for name, uid, gid, typ, contents in items:
2617 t = tarfile.TarInfo(name)
2618 t.uid = uid
2619 t.gid = gid
2620 t.uname = 'root'
2621 t.gname = 'root'
2622 t.type = typ
2623 tarfl.addfile(t, contents)
2624
2625 # return the full pathname to the tar file
2626 return tmpname
2627
2628 @staticmethod
2629 @contextmanager
2630 def _setup_test(mock_geteuid):
2631 mock_geteuid.return_value = 0 # lie and say we're root
2632 fname = 'numeric-owner-testfile'
2633 dirname = 'dir'
2634
2635 # the names we want stored in the tarfile
2636 filename_1 = fname
2637 dirname_1 = dirname
2638 filename_2 = os.path.join(dirname, fname)
2639
2640 # create the tarfile with the contents we're after
2641 tar_filename = NumericOwnerTest._make_test_archive(filename_1,
2642 dirname_1,
2643 filename_2)
2644
2645 # open the tarfile for reading. yield it and the names of the items
2646 # we stored into the file
2647 with tarfile.open(tar_filename) as tarfl:
2648 yield tarfl, filename_1, dirname_1, filename_2
2649
2650 @unittest.mock.patch('os.chown')
2651 @unittest.mock.patch('os.chmod')
2652 @unittest.mock.patch('os.geteuid')
2653 def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod,
2654 mock_chown):
2655 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _,
2656 filename_2):
2657 tarfl.extract(filename_1, TEMPDIR, numeric_owner=True)
2658 tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True)
2659
2660 # convert to filesystem paths
2661 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2662 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2663
2664 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2665 unittest.mock.call(f_filename_2, 88, 87),
2666 ],
2667 any_order=True)
2668
2669 @unittest.mock.patch('os.chown')
2670 @unittest.mock.patch('os.chmod')
2671 @unittest.mock.patch('os.geteuid')
2672 def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod,
2673 mock_chown):
2674 with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1,
2675 filename_2):
2676 tarfl.extractall(TEMPDIR, numeric_owner=True)
2677
2678 # convert to filesystem paths
2679 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2680 f_dirname_1 = os.path.join(TEMPDIR, dirname_1)
2681 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2682
2683 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2684 unittest.mock.call(f_dirname_1, 77, 76),
2685 unittest.mock.call(f_filename_2, 88, 87),
2686 ],
2687 any_order=True)
2688
2689 # this test requires that uid=0 and gid=0 really be named 'root'. that's
2690 # because the uname and gname in the test file are 'root', and extract()
2691 # will look them up using pwd and grp to find their uid and gid, which we
2692 # test here to be 0.
2693 @unittest.skipUnless(root_is_uid_gid_0(),
2694 'uid=0,gid=0 must be named "root"')
2695 @unittest.mock.patch('os.chown')
2696 @unittest.mock.patch('os.chmod')
2697 @unittest.mock.patch('os.geteuid')
2698 def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod,
2699 mock_chown):
2700 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2701 tarfl.extract(filename_1, TEMPDIR, numeric_owner=False)
2702
2703 # convert to filesystem paths
2704 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2705
2706 mock_chown.assert_called_with(f_filename_1, 0, 0)
2707
2708 @unittest.mock.patch('os.geteuid')
2709 def test_keyword_only(self, mock_geteuid):
2710 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2711 self.assertRaises(TypeError,
2712 tarfl.extract, filename_1, TEMPDIR, False, True)
2713
2714
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002715def setUpModule():
Antoine Pitrou95f55602010-09-23 18:36:46 +00002716 support.unlink(TEMPDIR)
Antoine Pitrou941ee882009-11-11 20:59:38 +00002717 os.makedirs(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002718
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002719 global testtarnames
2720 testtarnames = [tarname]
Antoine Pitrou95f55602010-09-23 18:36:46 +00002721 with open(tarname, "rb") as fobj:
2722 data = fobj.read()
Neal Norwitza4f651a2004-07-20 22:07:44 +00002723
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002724 # Create compressed tarfiles.
2725 for c in GzipTest, Bz2Test, LzmaTest:
2726 if c.open:
2727 support.unlink(c.tarname)
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002728 testtarnames.append(c.tarname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002729 with c.open(c.tarname, "wb") as tar:
2730 tar.write(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002731
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002732def tearDownModule():
2733 if os.path.exists(TEMPDIR):
Tim Goldene0bd2c52014-05-06 13:24:26 +01002734 support.rmtree(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002735
Neal Norwitz996acf12003-02-17 14:51:41 +00002736if __name__ == "__main__":
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002737 unittest.main()