blob: 15324a4e48819ef67b8c3dd2916bef455c62af0f [file] [log] [blame]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001import sys
2import os
Lars Gustäbelb506dc32007-08-07 18:36:16 +00003import io
Miss Islington (bot)66cd0412019-09-25 08:50:31 -07004from 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
Miss Islington (bot)66cd0412019-09-25 08:50:31 -070014from 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
Miss Islington (bot)66cd0412019-09-25 08:50:31 -070030def 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
Miss Islington (bot)66cd0412019-09-25 08:50:31 -070042sha256_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")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700102 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")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700185 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
322 def test_empty_tarfile(self):
323 # Test for issue6123: Allow opening empty archives.
324 # This test checks if tarfile.open() is able to open an empty tar
325 # archive successfully. Note that an empty tar archive is not the
326 # same as an empty file!
Antoine Pitrou95f55602010-09-23 18:36:46 +0000327 with tarfile.open(tmpname, self.mode.replace("r", "w")):
328 pass
Lars Gustäbel9520a432009-11-22 18:48:49 +0000329 try:
330 tar = tarfile.open(tmpname, self.mode)
331 tar.getnames()
332 except tarfile.ReadError:
333 self.fail("tarfile.open() failed on empty archive")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000334 else:
335 self.assertListEqual(tar.getmembers(), [])
336 finally:
337 tar.close()
Lars Gustäbel9520a432009-11-22 18:48:49 +0000338
Serhiy Storchakaf22fe0f2014-01-13 19:08:00 +0200339 def test_non_existent_tarfile(self):
340 # Test for issue11513: prevent non-existent gzipped tarfiles raising
341 # multiple exceptions.
342 with self.assertRaisesRegex(FileNotFoundError, "xxx"):
343 tarfile.open("xxx", self.mode)
344
Lars Gustäbel9520a432009-11-22 18:48:49 +0000345 def test_null_tarfile(self):
346 # Test for issue6123: Allow opening empty archives.
347 # This test guarantees that tarfile.open() does not treat an empty
348 # file as an empty tar archive.
Antoine Pitrou95f55602010-09-23 18:36:46 +0000349 with open(tmpname, "wb"):
350 pass
Lars Gustäbel9520a432009-11-22 18:48:49 +0000351 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, self.mode)
352 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname)
353
354 def test_ignore_zeros(self):
355 # Test TarFile's ignore_zeros option.
Serhiy Storchakaa89d22a2016-10-30 20:52:29 +0200356 # generate 512 pseudorandom bytes
357 data = Random(0).getrandbits(512*8).to_bytes(512, 'big')
Lars Gustäbel9520a432009-11-22 18:48:49 +0000358 for char in (b'\0', b'a'):
359 # Test if EOFHeaderError ('\0') and InvalidHeaderError ('a')
360 # are ignored correctly.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300361 with self.open(tmpname, "w") as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000362 fobj.write(char * 1024)
Serhiy Storchakaa89d22a2016-10-30 20:52:29 +0200363 tarinfo = tarfile.TarInfo("foo")
364 tarinfo.size = len(data)
365 fobj.write(tarinfo.tobuf())
366 fobj.write(data)
Lars Gustäbel9520a432009-11-22 18:48:49 +0000367
368 tar = tarfile.open(tmpname, mode="r", ignore_zeros=True)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000369 try:
370 self.assertListEqual(tar.getnames(), ["foo"],
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300371 "ignore_zeros=True should have skipped the %r-blocks" %
372 char)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000373 finally:
374 tar.close()
Lars Gustäbel9520a432009-11-22 18:48:49 +0000375
Lars Gustäbel03572682015-07-06 09:27:24 +0200376 def test_premature_end_of_archive(self):
377 for size in (512, 600, 1024, 1200):
378 with tarfile.open(tmpname, "w:") as tar:
379 t = tarfile.TarInfo("foo")
380 t.size = 1024
381 tar.addfile(t, io.BytesIO(b"a" * 1024))
382
383 with open(tmpname, "r+b") as fobj:
384 fobj.truncate(size)
385
386 with tarfile.open(tmpname) as tar:
387 with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
388 for t in tar:
389 pass
390
391 with tarfile.open(tmpname) as tar:
392 t = tar.next()
393
394 with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
395 tar.extract(t, TEMPDIR)
396
397 with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
398 tar.extractfile(t).read()
Lars Gustäbel9520a432009-11-22 18:48:49 +0000399
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300400class MiscReadTestBase(CommonReadTest):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300401 def requires_name_attribute(self):
402 pass
403
Thomas Woutersed03b412007-08-28 21:37:11 +0000404 def test_no_name_argument(self):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300405 self.requires_name_attribute()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000406 with open(self.tarname, "rb") as fobj:
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300407 self.assertIsInstance(fobj.name, str)
408 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
409 self.assertIsInstance(tar.name, str)
410 self.assertEqual(tar.name, os.path.abspath(fobj.name))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000411
Thomas Woutersed03b412007-08-28 21:37:11 +0000412 def test_no_name_attribute(self):
Antoine Pitrou95f55602010-09-23 18:36:46 +0000413 with open(self.tarname, "rb") as fobj:
414 data = fobj.read()
Thomas Woutersed03b412007-08-28 21:37:11 +0000415 fobj = io.BytesIO(data)
416 self.assertRaises(AttributeError, getattr, fobj, "name")
417 tar = tarfile.open(fileobj=fobj, mode=self.mode)
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300418 self.assertIsNone(tar.name)
Thomas Woutersed03b412007-08-28 21:37:11 +0000419
420 def test_empty_name_attribute(self):
Antoine Pitrou95f55602010-09-23 18:36:46 +0000421 with open(self.tarname, "rb") as fobj:
422 data = fobj.read()
Thomas Woutersed03b412007-08-28 21:37:11 +0000423 fobj = io.BytesIO(data)
424 fobj.name = ""
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000425 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300426 self.assertIsNone(tar.name)
427
428 def test_int_name_attribute(self):
429 # Issue 21044: tarfile.open() should handle fileobj with an integer
430 # 'name' attribute.
431 fd = os.open(self.tarname, os.O_RDONLY)
432 with open(fd, 'rb') as fobj:
433 self.assertIsInstance(fobj.name, int)
434 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
435 self.assertIsNone(tar.name)
436
437 def test_bytes_name_attribute(self):
438 self.requires_name_attribute()
439 tarname = os.fsencode(self.tarname)
440 with open(tarname, 'rb') as fobj:
441 self.assertIsInstance(fobj.name, bytes)
442 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
443 self.assertIsInstance(tar.name, bytes)
444 self.assertEqual(tar.name, os.path.abspath(fobj.name))
Thomas Woutersed03b412007-08-28 21:37:11 +0000445
Serhiy Storchakac45cd162017-03-08 10:32:44 +0200446 def test_pathlike_name(self):
447 tarname = pathlib.Path(self.tarname)
448 with tarfile.open(tarname, mode=self.mode) as tar:
449 self.assertIsInstance(tar.name, str)
450 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
451 with self.taropen(tarname) as tar:
452 self.assertIsInstance(tar.name, str)
453 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
454 with tarfile.TarFile.open(tarname, mode=self.mode) as tar:
455 self.assertIsInstance(tar.name, str)
456 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
457 if self.suffix == '':
458 with tarfile.TarFile(tarname, mode='r') as tar:
459 self.assertIsInstance(tar.name, str)
460 self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
461
Serhiy Storchaka53ad0cd2014-01-18 15:35:37 +0200462 def test_illegal_mode_arg(self):
463 with open(tmpname, 'wb'):
464 pass
465 with self.assertRaisesRegex(ValueError, 'mode must be '):
466 tar = self.taropen(tmpname, 'q')
467 with self.assertRaisesRegex(ValueError, 'mode must be '):
468 tar = self.taropen(tmpname, 'rw')
469 with self.assertRaisesRegex(ValueError, 'mode must be '):
470 tar = self.taropen(tmpname, '')
471
Christian Heimesd8654cf2007-12-02 15:22:16 +0000472 def test_fileobj_with_offset(self):
473 # Skip the first member and store values from the second member
474 # of the testtar.
475 tar = tarfile.open(self.tarname, mode=self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000476 try:
477 tar.next()
478 t = tar.next()
479 name = t.name
480 offset = t.offset
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200481 with tar.extractfile(t) as f:
482 data = f.read()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000483 finally:
484 tar.close()
Christian Heimesd8654cf2007-12-02 15:22:16 +0000485
486 # Open the testtar and seek to the offset of the second member.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300487 with self.open(self.tarname) as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000488 fobj.seek(offset)
Christian Heimesd8654cf2007-12-02 15:22:16 +0000489
Antoine Pitrou95f55602010-09-23 18:36:46 +0000490 # Test if the tarfile starts with the second member.
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +0200491 with tar.open(self.tarname, mode="r:", fileobj=fobj) as tar:
492 t = tar.next()
493 self.assertEqual(t.name, name)
494 # Read to the end of fileobj and test if seeking back to the
495 # beginning works.
496 tar.getmembers()
497 self.assertEqual(tar.extractfile(t).read(), data,
498 "seek back did not work")
Christian Heimesd8654cf2007-12-02 15:22:16 +0000499
Guido van Rossumd8faa362007-04-27 19:54:29 +0000500 def test_fail_comp(self):
501 # For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000502 self.assertRaises(tarfile.ReadError, tarfile.open, tarname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000503 with open(tarname, "rb") as fobj:
504 self.assertRaises(tarfile.ReadError, tarfile.open,
505 fileobj=fobj, mode=self.mode)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000506
507 def test_v7_dirtype(self):
508 # Test old style dirtype member (bug #1336623):
509 # Old V7 tars create directory members using an AREGTYPE
510 # header with a "/" appended to the filename field.
511 tarinfo = self.tar.getmember("misc/dirtype-old-v7")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300512 self.assertEqual(tarinfo.type, tarfile.DIRTYPE,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000513 "v7 dirtype failed")
514
Christian Heimes126d29a2008-02-11 22:57:17 +0000515 def test_xstar_type(self):
516 # The xstar format stores extra atime and ctime fields inside the
517 # space reserved for the prefix field. The prefix field must be
518 # ignored in this case, otherwise it will mess up the name.
519 try:
520 self.tar.getmember("misc/regtype-xstar")
521 except KeyError:
522 self.fail("failed to find misc/regtype-xstar (mangled prefix?)")
523
Guido van Rossumd8faa362007-04-27 19:54:29 +0000524 def test_check_members(self):
525 for tarinfo in self.tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300526 self.assertEqual(int(tarinfo.mtime), 0o7606136617,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000527 "wrong mtime for %s" % tarinfo.name)
528 if not tarinfo.name.startswith("ustar/"):
529 continue
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300530 self.assertEqual(tarinfo.uname, "tarfile",
Guido van Rossumd8faa362007-04-27 19:54:29 +0000531 "wrong uname for %s" % tarinfo.name)
532
533 def test_find_members(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300534 self.assertEqual(self.tar.getmembers()[-1].name, "misc/eof",
Guido van Rossumd8faa362007-04-27 19:54:29 +0000535 "could not find all members")
536
Brian Curtin74e45612010-07-09 15:58:59 +0000537 @unittest.skipUnless(hasattr(os, "link"),
538 "Missing hardlink implementation")
Brian Curtin3b4499c2010-12-28 14:31:47 +0000539 @support.skip_unless_symlink
Guido van Rossumd8faa362007-04-27 19:54:29 +0000540 def test_extract_hardlink(self):
541 # Test hardlink extraction (e.g. bug #857297).
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200542 with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000543 tar.extract("ustar/regtype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100544 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/regtype"))
Neal Norwitzf3396542005-10-28 05:52:22 +0000545
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200546 tar.extract("ustar/lnktype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100547 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype"))
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000548 with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
549 data = f.read()
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700550 self.assertEqual(sha256sum(data), sha256_regtype)
Neal Norwitzf3396542005-10-28 05:52:22 +0000551
Serhiy Storchaka88339c42012-12-30 20:16:30 +0200552 tar.extract("ustar/symtype", TEMPDIR)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100553 self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype"))
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000554 with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
555 data = f.read()
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700556 self.assertEqual(sha256sum(data), sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000557
Christian Heimesfaf2f632008-01-06 16:59:19 +0000558 def test_extractall(self):
559 # Test if extractall() correctly restores directory permissions
560 # and times (see issue1735).
Christian Heimesfaf2f632008-01-06 16:59:19 +0000561 tar = tarfile.open(tarname, encoding="iso8859-1")
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000562 DIR = os.path.join(TEMPDIR, "extractall")
563 os.mkdir(DIR)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000564 try:
565 directories = [t for t in tar if t.isdir()]
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000566 tar.extractall(DIR, directories)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000567 for tarinfo in directories:
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000568 path = os.path.join(DIR, tarinfo.name)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000569 if sys.platform != "win32":
570 # Win32 has no support for fine grained permissions.
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300571 self.assertEqual(tarinfo.mode & 0o777,
572 os.stat(path).st_mode & 0o777)
Victor Stinner26bfb5a2010-10-29 10:59:08 +0000573 def format_mtime(mtime):
574 if isinstance(mtime, float):
575 return "{} ({})".format(mtime, mtime.hex())
576 else:
577 return "{!r} (int)".format(mtime)
Victor Stinner14d8fe72010-10-29 11:02:06 +0000578 file_mtime = os.path.getmtime(path)
Victor Stinner26bfb5a2010-10-29 10:59:08 +0000579 errmsg = "tar mtime {0} != file time {1} of path {2!a}".format(
580 format_mtime(tarinfo.mtime),
581 format_mtime(file_mtime),
582 path)
583 self.assertEqual(tarinfo.mtime, file_mtime, errmsg)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000584 finally:
585 tar.close()
Tim Goldene0bd2c52014-05-06 13:24:26 +0100586 support.rmtree(DIR)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000587
Martin v. Löwis16f344d2010-11-01 21:39:13 +0000588 def test_extract_directory(self):
589 dirtype = "ustar/dirtype"
Martin v. Löwisbe647e22010-11-01 22:08:46 +0000590 DIR = os.path.join(TEMPDIR, "extractdir")
591 os.mkdir(DIR)
592 try:
593 with tarfile.open(tarname, encoding="iso8859-1") as tar:
594 tarinfo = tar.getmember(dirtype)
595 tar.extract(tarinfo, path=DIR)
596 extracted = os.path.join(DIR, dirtype)
597 self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
598 if sys.platform != "win32":
599 self.assertEqual(os.stat(extracted).st_mode & 0o777, 0o755)
600 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +0100601 support.rmtree(DIR)
Martin v. Löwis16f344d2010-11-01 21:39:13 +0000602
Serhiy Storchakac45cd162017-03-08 10:32:44 +0200603 def test_extractall_pathlike_name(self):
604 DIR = pathlib.Path(TEMPDIR) / "extractall"
605 with support.temp_dir(DIR), \
606 tarfile.open(tarname, encoding="iso8859-1") as tar:
607 directories = [t for t in tar if t.isdir()]
608 tar.extractall(DIR, directories)
609 for tarinfo in directories:
610 path = DIR / tarinfo.name
611 self.assertEqual(os.path.getmtime(path), tarinfo.mtime)
612
613 def test_extract_pathlike_name(self):
614 dirtype = "ustar/dirtype"
615 DIR = pathlib.Path(TEMPDIR) / "extractall"
616 with support.temp_dir(DIR), \
617 tarfile.open(tarname, encoding="iso8859-1") as tar:
618 tarinfo = tar.getmember(dirtype)
619 tar.extract(tarinfo, path=DIR)
620 extracted = DIR / dirtype
621 self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
622
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000623 def test_init_close_fobj(self):
624 # Issue #7341: Close the internal file object in the TarFile
625 # constructor in case of an error. For the test we rely on
626 # the fact that opening an empty file raises a ReadError.
627 empty = os.path.join(TEMPDIR, "empty")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000628 with open(empty, "wb") as fobj:
629 fobj.write(b"")
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000630
631 try:
632 tar = object.__new__(tarfile.TarFile)
633 try:
634 tar.__init__(empty)
635 except tarfile.ReadError:
636 self.assertTrue(tar.fileobj.closed)
637 else:
638 self.fail("ReadError not raised")
639 finally:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000640 support.unlink(empty)
Lars Gustäbelb7f09232009-11-23 15:48:33 +0000641
Serhiy Storchaka263fab92013-05-09 14:22:26 +0300642 def test_parallel_iteration(self):
643 # Issue #16601: Restarting iteration over tarfile continued
644 # from where it left off.
645 with tarfile.open(self.tarname) as tar:
646 for m1, m2 in zip(tar, tar):
647 self.assertEqual(m1.offset, m2.offset)
648 self.assertEqual(m1.get_info(), m2.get_info())
649
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300650class MiscReadTest(MiscReadTestBase, unittest.TestCase):
651 test_fail_comp = None
Guido van Rossumd8faa362007-04-27 19:54:29 +0000652
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300653class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase):
Serhiy Storchakaf22fe0f2014-01-13 19:08:00 +0200654 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000655
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300656class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300657 def requires_name_attribute(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300658 self.skipTest("BZ2File have no name attribute")
659
660class LzmaMiscReadTest(LzmaTest, MiscReadTestBase, unittest.TestCase):
Serhiy Storchaka2c6a3ae2014-07-16 23:58:58 +0300661 def requires_name_attribute(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300662 self.skipTest("LZMAFile have no name attribute")
663
664
665class StreamReadTest(CommonReadTest, unittest.TestCase):
666
667 prefix="r|"
Guido van Rossumd8faa362007-04-27 19:54:29 +0000668
Lars Gustäbeldd071042011-02-23 11:42:22 +0000669 def test_read_through(self):
670 # Issue #11224: A poorly designed _FileInFile.read() method
671 # caused seeking errors with stream tar files.
672 for tarinfo in self.tar:
673 if not tarinfo.isreg():
674 continue
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200675 with self.tar.extractfile(tarinfo) as fobj:
676 while True:
677 try:
678 buf = fobj.read(512)
679 except tarfile.StreamError:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300680 self.fail("simple read-through using "
681 "TarFile.extractfile() failed")
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200682 if not buf:
683 break
Lars Gustäbeldd071042011-02-23 11:42:22 +0000684
Guido van Rossumd8faa362007-04-27 19:54:29 +0000685 def test_fileobj_regular_file(self):
686 tarinfo = self.tar.next() # get "regtype" (can't use getmember)
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200687 with self.tar.extractfile(tarinfo) as fobj:
688 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300689 self.assertEqual(len(data), tarinfo.size,
690 "regular file extraction failed")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700691 self.assertEqual(sha256sum(data), sha256_regtype,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000692 "regular file extraction failed")
693
694 def test_provoke_stream_error(self):
695 tarinfos = self.tar.getmembers()
Lars Gustäbel7a919e92012-05-05 18:15:03 +0200696 with self.tar.extractfile(tarinfos[0]) as f: # read the first member
697 self.assertRaises(tarfile.StreamError, f.read)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000698
Guido van Rossumd8faa362007-04-27 19:54:29 +0000699 def test_compare_members(self):
700 tar1 = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000701 try:
702 tar2 = self.tar
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000703
Antoine Pitrou95f55602010-09-23 18:36:46 +0000704 while True:
705 t1 = tar1.next()
706 t2 = tar2.next()
707 if t1 is None:
708 break
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300709 self.assertIsNotNone(t2, "stream.next() failed.")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000710
Antoine Pitrou95f55602010-09-23 18:36:46 +0000711 if t2.islnk() or t2.issym():
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300712 with self.assertRaises(tarfile.StreamError):
713 tar2.extractfile(t2)
Antoine Pitrou95f55602010-09-23 18:36:46 +0000714 continue
Guido van Rossumd8faa362007-04-27 19:54:29 +0000715
Antoine Pitrou95f55602010-09-23 18:36:46 +0000716 v1 = tar1.extractfile(t1)
717 v2 = tar2.extractfile(t2)
718 if v1 is None:
719 continue
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300720 self.assertIsNotNone(v2, "stream.extractfile() failed")
721 self.assertEqual(v1.read(), v2.read(),
722 "stream extraction failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +0000723 finally:
724 tar1.close()
Thomas Wouters902d6eb2007-01-09 23:18:33 +0000725
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300726class GzipStreamReadTest(GzipTest, StreamReadTest):
727 pass
Thomas Wouters89f507f2006-12-13 04:49:30 +0000728
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300729class Bz2StreamReadTest(Bz2Test, StreamReadTest):
730 pass
Thomas Wouterscf297e42007-02-23 15:07:44 +0000731
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300732class LzmaStreamReadTest(LzmaTest, StreamReadTest):
733 pass
734
735
736class DetectReadTest(TarTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000737 def _testfunc_file(self, name, mode):
738 try:
Antoine Pitrou95f55602010-09-23 18:36:46 +0000739 tar = tarfile.open(name, mode)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000740 except tarfile.ReadError as e:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000741 self.fail()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000742 else:
743 tar.close()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000744
Guido van Rossumd8faa362007-04-27 19:54:29 +0000745 def _testfunc_fileobj(self, name, mode):
746 try:
Antoine Pitrou605c2932010-09-23 20:15:14 +0000747 with open(name, "rb") as f:
748 tar = tarfile.open(name, mode, fileobj=f)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000749 except tarfile.ReadError as e:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000750 self.fail()
Antoine Pitrou95f55602010-09-23 18:36:46 +0000751 else:
752 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000753
754 def _test_modes(self, testfunc):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300755 if self.suffix:
756 with self.assertRaises(tarfile.ReadError):
757 tarfile.open(tarname, mode="r:" + self.suffix)
758 with self.assertRaises(tarfile.ReadError):
759 tarfile.open(tarname, mode="r|" + self.suffix)
760 with self.assertRaises(tarfile.ReadError):
761 tarfile.open(self.tarname, mode="r:")
762 with self.assertRaises(tarfile.ReadError):
763 tarfile.open(self.tarname, mode="r|")
764 testfunc(self.tarname, "r")
765 testfunc(self.tarname, "r:" + self.suffix)
766 testfunc(self.tarname, "r:*")
767 testfunc(self.tarname, "r|" + self.suffix)
768 testfunc(self.tarname, "r|*")
Lars Gustäbel0a9dd2f2011-12-10 20:38:14 +0100769
Guido van Rossumd8faa362007-04-27 19:54:29 +0000770 def test_detect_file(self):
771 self._test_modes(self._testfunc_file)
772
773 def test_detect_fileobj(self):
774 self._test_modes(self._testfunc_fileobj)
775
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300776class GzipDetectReadTest(GzipTest, DetectReadTest):
777 pass
778
779class Bz2DetectReadTest(Bz2Test, DetectReadTest):
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100780 def test_detect_stream_bz2(self):
781 # Originally, tarfile's stream detection looked for the string
782 # "BZh91" at the start of the file. This is incorrect because
Victor Stinner8c663fd2017-11-08 14:44:44 -0800783 # the '9' represents the blocksize (900,000 bytes). If the file was
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100784 # compressed using another blocksize autodetection fails.
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100785 with open(tarname, "rb") as fobj:
786 data = fobj.read()
787
Victor Stinner8c663fd2017-11-08 14:44:44 -0800788 # Compress with blocksize 100,000 bytes, the file starts with "BZh11".
Lars Gustäbeled1ac582011-12-06 12:56:38 +0100789 with bz2.BZ2File(tmpname, "wb", compresslevel=1) as fobj:
790 fobj.write(data)
791
792 self._testfunc_file(tmpname, "r|*")
793
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300794class LzmaDetectReadTest(LzmaTest, DetectReadTest):
795 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000796
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300797
798class MemberReadTest(ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000799
800 def _test_member(self, tarinfo, chksum=None, **kwargs):
801 if chksum is not None:
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300802 with self.tar.extractfile(tarinfo) as f:
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700803 self.assertEqual(sha256sum(f.read()), chksum,
804 "wrong sha256sum for %s" % tarinfo.name)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000805
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000806 kwargs["mtime"] = 0o7606136617
Guido van Rossumd8faa362007-04-27 19:54:29 +0000807 kwargs["uid"] = 1000
808 kwargs["gid"] = 100
809 if "old-v7" not in tarinfo.name:
810 # V7 tar can't handle alphabetic owners.
811 kwargs["uname"] = "tarfile"
812 kwargs["gname"] = "tarfile"
813 for k, v in kwargs.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300814 self.assertEqual(getattr(tarinfo, k), v,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000815 "wrong value in %s field of %s" % (k, tarinfo.name))
816
817 def test_find_regtype(self):
818 tarinfo = self.tar.getmember("ustar/regtype")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700819 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000820
821 def test_find_conttype(self):
822 tarinfo = self.tar.getmember("ustar/conttype")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700823 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000824
825 def test_find_dirtype(self):
826 tarinfo = self.tar.getmember("ustar/dirtype")
827 self._test_member(tarinfo, size=0)
828
829 def test_find_dirtype_with_size(self):
830 tarinfo = self.tar.getmember("ustar/dirtype-with-size")
831 self._test_member(tarinfo, size=255)
832
833 def test_find_lnktype(self):
834 tarinfo = self.tar.getmember("ustar/lnktype")
835 self._test_member(tarinfo, size=0, linkname="ustar/regtype")
836
837 def test_find_symtype(self):
838 tarinfo = self.tar.getmember("ustar/symtype")
839 self._test_member(tarinfo, size=0, linkname="regtype")
840
841 def test_find_blktype(self):
842 tarinfo = self.tar.getmember("ustar/blktype")
843 self._test_member(tarinfo, size=0, devmajor=3, devminor=0)
844
845 def test_find_chrtype(self):
846 tarinfo = self.tar.getmember("ustar/chrtype")
847 self._test_member(tarinfo, size=0, devmajor=1, devminor=3)
848
849 def test_find_fifotype(self):
850 tarinfo = self.tar.getmember("ustar/fifotype")
851 self._test_member(tarinfo, size=0)
852
853 def test_find_sparse(self):
854 tarinfo = self.tar.getmember("ustar/sparse")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700855 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000856
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000857 def test_find_gnusparse(self):
858 tarinfo = self.tar.getmember("gnu/sparse")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700859 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000860
861 def test_find_gnusparse_00(self):
862 tarinfo = self.tar.getmember("gnu/sparse-0.0")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700863 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000864
865 def test_find_gnusparse_01(self):
866 tarinfo = self.tar.getmember("gnu/sparse-0.1")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700867 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000868
869 def test_find_gnusparse_10(self):
870 tarinfo = self.tar.getmember("gnu/sparse-1.0")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700871 self._test_member(tarinfo, size=86016, chksum=sha256_sparse)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000872
Guido van Rossumd8faa362007-04-27 19:54:29 +0000873 def test_find_umlauts(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300874 tarinfo = self.tar.getmember("ustar/umlauts-"
875 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700876 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000877
878 def test_find_ustar_longname(self):
879 name = "ustar/" + "12345/" * 39 + "1234567/longname"
Benjamin Peterson577473f2010-01-19 00:09:57 +0000880 self.assertIn(name, self.tar.getnames())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000881
882 def test_find_regtype_oldv7(self):
883 tarinfo = self.tar.getmember("misc/regtype-old-v7")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700884 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000885
886 def test_find_pax_umlauts(self):
Antoine Pitrouab58b5f2010-09-23 19:39:35 +0000887 self.tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300888 self.tar = tarfile.open(self.tarname, mode=self.mode,
889 encoding="iso8859-1")
890 tarinfo = self.tar.getmember("pax/umlauts-"
891 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700892 self._test_member(tarinfo, size=7011, chksum=sha256_regtype)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000893
894
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300895class LongnameTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000896
897 def test_read_longname(self):
898 # Test reading of longname (bug #1471427).
Guido van Rossume7ba4952007-06-06 23:52:48 +0000899 longname = self.subdir + "/" + "123/" * 125 + "longname"
Guido van Rossumd8faa362007-04-27 19:54:29 +0000900 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000901 tarinfo = self.tar.getmember(longname)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000902 except KeyError:
903 self.fail("longname not found")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300904 self.assertNotEqual(tarinfo.type, tarfile.DIRTYPE,
905 "read longname as dirtype")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000906
907 def test_read_longlink(self):
908 longname = self.subdir + "/" + "123/" * 125 + "longname"
909 longlink = self.subdir + "/" + "123/" * 125 + "longlink"
910 try:
911 tarinfo = self.tar.getmember(longlink)
912 except KeyError:
913 self.fail("longlink not found")
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300914 self.assertEqual(tarinfo.linkname, longname, "linkname wrong")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000915
916 def test_truncated_longname(self):
917 longname = self.subdir + "/" + "123/" * 125 + "longname"
918 tarinfo = self.tar.getmember(longname)
919 offset = tarinfo.offset
920 self.tar.fileobj.seek(offset)
Lars Gustäbelb506dc32007-08-07 18:36:16 +0000921 fobj = io.BytesIO(self.tar.fileobj.read(3 * 512))
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300922 with self.assertRaises(tarfile.ReadError):
923 tarfile.open(name="foo.tar", fileobj=fobj)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000924
Guido van Rossume7ba4952007-06-06 23:52:48 +0000925 def test_header_offset(self):
926 # Test if the start offset of the TarInfo object includes
927 # the preceding extended header.
928 longname = self.subdir + "/" + "123/" * 125 + "longname"
929 offset = self.tar.getmember(longname).offset
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000930 with open(tarname, "rb") as fobj:
931 fobj.seek(offset)
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300932 tarinfo = tarfile.TarInfo.frombuf(fobj.read(512),
933 "iso8859-1", "strict")
Antoine Pitroue1eca4e2010-10-29 23:49:49 +0000934 self.assertEqual(tarinfo.type, self.longnametype)
Guido van Rossume7ba4952007-06-06 23:52:48 +0000935
Guido van Rossumd8faa362007-04-27 19:54:29 +0000936
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300937class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000938
939 subdir = "gnu"
Guido van Rossume7ba4952007-06-06 23:52:48 +0000940 longnametype = tarfile.GNUTYPE_LONGNAME
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000942 # Since 3.2 tarfile is supposed to accurately restore sparse members and
943 # produce files with holes. This is what we actually want to test here.
944 # Unfortunately, not all platforms/filesystems support sparse files, and
945 # even on platforms that do it is non-trivial to make reliable assertions
946 # about holes in files. Therefore, we first do one basic test which works
947 # an all platforms, and after that a test that will work only on
948 # platforms/filesystems that prove to support sparse files.
949 def _test_sparse_file(self, name):
950 self.tar.extract(name, TEMPDIR)
951 filename = os.path.join(TEMPDIR, name)
952 with open(filename, "rb") as fobj:
953 data = fobj.read()
Miss Islington (bot)66cd0412019-09-25 08:50:31 -0700954 self.assertEqual(sha256sum(data), sha256_sparse,
955 "wrong sha256sum for %s" % name)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000956
957 if self._fs_supports_holes():
958 s = os.stat(filename)
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300959 self.assertLess(s.st_blocks * 512, s.st_size)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000960
961 def test_sparse_file_old(self):
962 self._test_sparse_file("gnu/sparse")
963
964 def test_sparse_file_00(self):
965 self._test_sparse_file("gnu/sparse-0.0")
966
967 def test_sparse_file_01(self):
968 self._test_sparse_file("gnu/sparse-0.1")
969
970 def test_sparse_file_10(self):
971 self._test_sparse_file("gnu/sparse-1.0")
972
973 @staticmethod
974 def _fs_supports_holes():
975 # Return True if the platform knows the st_blocks stat attribute and
976 # uses st_blocks units of 512 bytes, and if the filesystem is able to
Victor Stinnerb2385452019-01-21 10:24:12 +0100977 # store holes of 4 KiB in files.
978 #
979 # The function returns False if page size is larger than 4 KiB.
980 # For example, ppc64 uses pages of 64 KiB.
Victor Stinner9c3de4a2011-08-17 20:49:41 +0200981 if sys.platform.startswith("linux"):
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000982 # Linux evidentially has 512 byte st_blocks units.
983 name = os.path.join(TEMPDIR, "sparse-test")
984 with open(name, "wb") as fobj:
Victor Stinnerb2385452019-01-21 10:24:12 +0100985 # Seek to "punch a hole" of 4 KiB
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000986 fobj.seek(4096)
Victor Stinnerb2385452019-01-21 10:24:12 +0100987 fobj.write(b'x' * 4096)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000988 fobj.truncate()
989 s = os.stat(name)
Tim Goldene0bd2c52014-05-06 13:24:26 +0100990 support.unlink(name)
Victor Stinnerb2385452019-01-21 10:24:12 +0100991 return (s.st_blocks * 512 < s.st_size)
Lars Gustäbel9cbdd752010-10-29 09:08:19 +0000992 else:
993 return False
Guido van Rossumd8faa362007-04-27 19:54:29 +0000994
995
Serhiy Storchaka8b562922013-06-17 15:38:50 +0300996class PaxReadTest(LongnameTest, ReadTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000997
998 subdir = "pax"
Guido van Rossume7ba4952007-06-06 23:52:48 +0000999 longnametype = tarfile.XHDTYPE
Guido van Rossumd8faa362007-04-27 19:54:29 +00001000
Guido van Rossume7ba4952007-06-06 23:52:48 +00001001 def test_pax_global_headers(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001002 tar = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001003 try:
1004 tarinfo = tar.getmember("pax/regtype1")
1005 self.assertEqual(tarinfo.uname, "foo")
1006 self.assertEqual(tarinfo.gname, "bar")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001007 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1008 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Guido van Rossume7ba4952007-06-06 23:52:48 +00001009
Antoine Pitrou95f55602010-09-23 18:36:46 +00001010 tarinfo = tar.getmember("pax/regtype2")
1011 self.assertEqual(tarinfo.uname, "")
1012 self.assertEqual(tarinfo.gname, "bar")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001013 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1014 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001015
Antoine Pitrou95f55602010-09-23 18:36:46 +00001016 tarinfo = tar.getmember("pax/regtype3")
1017 self.assertEqual(tarinfo.uname, "tarfile")
1018 self.assertEqual(tarinfo.gname, "tarfile")
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001019 self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"),
1020 "\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001021 finally:
1022 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001023
1024 def test_pax_number_fields(self):
1025 # All following number fields are read from the pax header.
1026 tar = tarfile.open(tarname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001027 try:
1028 tarinfo = tar.getmember("pax/regtype4")
1029 self.assertEqual(tarinfo.size, 7011)
1030 self.assertEqual(tarinfo.uid, 123)
1031 self.assertEqual(tarinfo.gid, 123)
1032 self.assertEqual(tarinfo.mtime, 1041808783.0)
1033 self.assertEqual(type(tarinfo.mtime), float)
1034 self.assertEqual(float(tarinfo.pax_headers["atime"]), 1041808783.0)
1035 self.assertEqual(float(tarinfo.pax_headers["ctime"]), 1041808783.0)
1036 finally:
1037 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001038
1039
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001040class WriteTestBase(TarTest):
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001041 # Put all write tests in here that are supposed to be tested
1042 # in all possible mode combinations.
1043
1044 def test_fileobj_no_close(self):
1045 fobj = io.BytesIO()
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001046 with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
1047 tar.addfile(tarfile.TarInfo("foo"))
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001048 self.assertFalse(fobj.closed, "external fileobjs must never closed")
Serhiy Storchaka9fbec7a2014-01-18 15:53:05 +02001049 # Issue #20238: Incomplete gzip output with mode="w:gz"
1050 data = fobj.getvalue()
1051 del tar
1052 support.gc_collect()
1053 self.assertFalse(fobj.closed)
1054 self.assertEqual(data, fobj.getvalue())
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001055
Lars Gustäbel20703c62015-05-27 12:53:44 +02001056 def test_eof_marker(self):
1057 # Make sure an end of archive marker is written (two zero blocks).
1058 # tarfile insists on aligning archives to a 20 * 512 byte recordsize.
1059 # So, we create an archive that has exactly 10240 bytes without the
1060 # marker, and has 20480 bytes once the marker is written.
1061 with tarfile.open(tmpname, self.mode) as tar:
1062 t = tarfile.TarInfo("foo")
1063 t.size = tarfile.RECORDSIZE - tarfile.BLOCKSIZE
1064 tar.addfile(t, io.BytesIO(b"a" * t.size))
1065
1066 with self.open(tmpname, "rb") as fobj:
1067 self.assertEqual(len(fobj.read()), tarfile.RECORDSIZE * 2)
1068
Georg Brandlf08a9dd2008-06-10 16:57:31 +00001069
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001070class WriteTest(WriteTestBase, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001071
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001072 prefix = "w:"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001073
1074 def test_100_char_name(self):
1075 # The name field in a tar header stores strings of at most 100 chars.
1076 # If a string is shorter than 100 chars it has to be padded with '\0',
1077 # which implies that a string of exactly 100 chars is stored without
1078 # a trailing '\0'.
1079 name = "0123456789" * 10
1080 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001081 try:
1082 t = tarfile.TarInfo(name)
1083 tar.addfile(t)
1084 finally:
1085 tar.close()
Thomas Wouterscf297e42007-02-23 15:07:44 +00001086
Guido van Rossumd8faa362007-04-27 19:54:29 +00001087 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001088 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001089 self.assertEqual(tar.getnames()[0], name,
Antoine Pitrou95f55602010-09-23 18:36:46 +00001090 "failed to store 100 char filename")
1091 finally:
1092 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001093
Guido van Rossumd8faa362007-04-27 19:54:29 +00001094 def test_tar_size(self):
1095 # Test for bug #1013882.
1096 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001097 try:
1098 path = os.path.join(TEMPDIR, "file")
1099 with open(path, "wb") as fobj:
1100 fobj.write(b"aaa")
1101 tar.add(path)
1102 finally:
1103 tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001104 self.assertGreater(os.path.getsize(tmpname), 0,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001105 "tarfile is empty")
Thomas Wouters89f507f2006-12-13 04:49:30 +00001106
Guido van Rossumd8faa362007-04-27 19:54:29 +00001107 # The test_*_size tests test for bug #1167128.
1108 def test_file_size(self):
1109 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001110 try:
1111 path = os.path.join(TEMPDIR, "file")
1112 with open(path, "wb"):
1113 pass
1114 tarinfo = tar.gettarinfo(path)
1115 self.assertEqual(tarinfo.size, 0)
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001116
Antoine Pitrou95f55602010-09-23 18:36:46 +00001117 with open(path, "wb") as fobj:
1118 fobj.write(b"aaa")
1119 tarinfo = tar.gettarinfo(path)
1120 self.assertEqual(tarinfo.size, 3)
1121 finally:
1122 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001123
1124 def test_directory_size(self):
1125 path = os.path.join(TEMPDIR, "directory")
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001126 os.mkdir(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001127 try:
1128 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001129 try:
1130 tarinfo = tar.gettarinfo(path)
1131 self.assertEqual(tarinfo.size, 0)
1132 finally:
1133 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001134 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001135 support.rmdir(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001136
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001137 # mock the following:
1138 # os.listdir: so we know that files are in the wrong order
Bernhard M. Wiedemann4ad703b2018-02-06 19:08:53 +01001139 def test_ordered_recursion(self):
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001140 path = os.path.join(TEMPDIR, "directory")
1141 os.mkdir(path)
1142 open(os.path.join(path, "1"), "a").close()
1143 open(os.path.join(path, "2"), "a").close()
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001144 try:
1145 tar = tarfile.open(tmpname, self.mode)
1146 try:
Bernhard M. Wiedemann4ad703b2018-02-06 19:08:53 +01001147 with unittest.mock.patch('os.listdir') as mock_listdir:
1148 mock_listdir.return_value = ["2", "1"]
1149 tar.add(path)
Bernhard M. Wiedemann84521042018-01-31 11:17:10 +01001150 paths = []
1151 for m in tar.getmembers():
1152 paths.append(os.path.split(m.name)[-1])
1153 self.assertEqual(paths, ["directory", "1", "2"]);
1154 finally:
1155 tar.close()
1156 finally:
1157 support.unlink(os.path.join(path, "1"))
1158 support.unlink(os.path.join(path, "2"))
1159 support.rmdir(path)
1160
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001161 def test_gettarinfo_pathlike_name(self):
1162 with tarfile.open(tmpname, self.mode) as tar:
1163 path = pathlib.Path(TEMPDIR) / "file"
1164 with open(path, "wb") as fobj:
1165 fobj.write(b"aaa")
1166 tarinfo = tar.gettarinfo(path)
1167 tarinfo2 = tar.gettarinfo(os.fspath(path))
1168 self.assertIsInstance(tarinfo.name, str)
1169 self.assertEqual(tarinfo.name, tarinfo2.name)
1170 self.assertEqual(tarinfo.size, 3)
1171
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001172 @unittest.skipUnless(hasattr(os, "link"),
1173 "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001174 def test_link_size(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001175 link = os.path.join(TEMPDIR, "link")
1176 target = os.path.join(TEMPDIR, "link_target")
1177 with open(target, "wb") as fobj:
1178 fobj.write(b"aaa")
xdegayed7d4fea2017-11-12 18:02:06 +01001179 try:
1180 os.link(target, link)
1181 except PermissionError as e:
1182 self.skipTest('os.link(): %s' % e)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001183 try:
1184 tar = tarfile.open(tmpname, self.mode)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001185 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001186 # Record the link target in the inodes list.
1187 tar.gettarinfo(target)
1188 tarinfo = tar.gettarinfo(link)
1189 self.assertEqual(tarinfo.size, 0)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001190 finally:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001191 tar.close()
1192 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001193 support.unlink(target)
1194 support.unlink(link)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001195
Brian Curtin3b4499c2010-12-28 14:31:47 +00001196 @support.skip_unless_symlink
Guido van Rossumd8faa362007-04-27 19:54:29 +00001197 def test_symlink_size(self):
Brian Curtind40e6f72010-07-08 21:39:08 +00001198 path = os.path.join(TEMPDIR, "symlink")
1199 os.symlink("link_target", path)
1200 try:
1201 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001202 try:
1203 tarinfo = tar.gettarinfo(path)
1204 self.assertEqual(tarinfo.size, 0)
1205 finally:
1206 tar.close()
Brian Curtind40e6f72010-07-08 21:39:08 +00001207 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001208 support.unlink(path)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001209
1210 def test_add_self(self):
1211 # Test for #1257255.
1212 dstname = os.path.abspath(tmpname)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001213 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001214 try:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001215 self.assertEqual(tar.name, dstname,
1216 "archive name must be absolute")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001217 tar.add(dstname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001218 self.assertEqual(tar.getnames(), [],
1219 "added the archive to itself")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001220
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001221 with support.change_cwd(TEMPDIR):
1222 tar.add(dstname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001223 self.assertEqual(tar.getnames(), [],
1224 "added the archive to itself")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001225 finally:
1226 tar.close()
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001227
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001228 def test_filter(self):
1229 tempdir = os.path.join(TEMPDIR, "filter")
1230 os.mkdir(tempdir)
1231 try:
1232 for name in ("foo", "bar", "baz"):
1233 name = os.path.join(tempdir, name)
Victor Stinnerbf816222011-06-30 23:25:47 +02001234 support.create_empty_file(name)
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001235
1236 def filter(tarinfo):
1237 if os.path.basename(tarinfo.name) == "bar":
1238 return
1239 tarinfo.uid = 123
1240 tarinfo.uname = "foo"
1241 return tarinfo
1242
1243 tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001244 try:
1245 tar.add(tempdir, arcname="empty_dir", filter=filter)
1246 finally:
1247 tar.close()
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001248
Raymond Hettingera63a3122011-01-26 20:34:14 +00001249 # Verify that filter is a keyword-only argument
1250 with self.assertRaises(TypeError):
1251 tar.add(tempdir, "empty_dir", True, None, filter)
1252
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001253 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001254 try:
1255 for tarinfo in tar:
1256 self.assertEqual(tarinfo.uid, 123)
1257 self.assertEqual(tarinfo.uname, "foo")
1258 self.assertEqual(len(tar.getmembers()), 3)
1259 finally:
1260 tar.close()
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001261 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001262 support.rmtree(tempdir)
Lars Gustäbel049d2aa2009-09-12 10:44:00 +00001263
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001264 # Guarantee that stored pathnames are not modified. Don't
1265 # remove ./ or ../ or double slashes. Still make absolute
1266 # pathnames relative.
1267 # For details see bug #6054.
1268 def _test_pathname(self, path, cmp_path=None, dir=False):
1269 # Create a tarfile with an empty member named path
1270 # and compare the stored name with the original.
1271 foo = os.path.join(TEMPDIR, "foo")
1272 if not dir:
Victor Stinnerbf816222011-06-30 23:25:47 +02001273 support.create_empty_file(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001274 else:
1275 os.mkdir(foo)
1276
1277 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001278 try:
1279 tar.add(foo, arcname=path)
1280 finally:
1281 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001282
1283 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001284 try:
1285 t = tar.next()
1286 finally:
1287 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001288
1289 if not dir:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001290 support.unlink(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001291 else:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001292 support.rmdir(foo)
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001293
1294 self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/"))
1295
Senthil Kumaranbe5dbeb2011-04-30 06:09:51 +08001296
1297 @support.skip_unless_symlink
Senthil Kumaran123932f2011-04-28 15:38:12 +08001298 def test_extractall_symlinks(self):
1299 # Test if extractall works properly when tarfile contains symlinks
1300 tempdir = os.path.join(TEMPDIR, "testsymlinks")
1301 temparchive = os.path.join(TEMPDIR, "testsymlinks.tar")
1302 os.mkdir(tempdir)
1303 try:
1304 source_file = os.path.join(tempdir,'source')
1305 target_file = os.path.join(tempdir,'symlink')
1306 with open(source_file,'w') as f:
1307 f.write('something\n')
1308 os.symlink(source_file, target_file)
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001309 with tarfile.open(temparchive, 'w') as tar:
1310 tar.add(source_file)
1311 tar.add(target_file)
Senthil Kumaran123932f2011-04-28 15:38:12 +08001312 # Let's extract it to the location which contains the symlink
Serhiy Storchaka9e4861f2019-03-05 10:05:57 +02001313 with tarfile.open(temparchive) as tar:
1314 # this should not raise OSError: [Errno 17] File exists
1315 try:
1316 tar.extractall(path=tempdir)
1317 except OSError:
1318 self.fail("extractall failed with symlinked files")
Senthil Kumaran123932f2011-04-28 15:38:12 +08001319 finally:
Tim Goldene0bd2c52014-05-06 13:24:26 +01001320 support.unlink(temparchive)
1321 support.rmtree(tempdir)
Martin v. Löwis5dbdc592005-08-27 10:07:56 +00001322
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001323 def test_pathnames(self):
1324 self._test_pathname("foo")
1325 self._test_pathname(os.path.join("foo", ".", "bar"))
1326 self._test_pathname(os.path.join("foo", "..", "bar"))
1327 self._test_pathname(os.path.join(".", "foo"))
1328 self._test_pathname(os.path.join(".", "foo", "."))
1329 self._test_pathname(os.path.join(".", "foo", ".", "bar"))
1330 self._test_pathname(os.path.join(".", "foo", "..", "bar"))
1331 self._test_pathname(os.path.join(".", "foo", "..", "bar"))
1332 self._test_pathname(os.path.join("..", "foo"))
1333 self._test_pathname(os.path.join("..", "foo", ".."))
1334 self._test_pathname(os.path.join("..", "foo", ".", "bar"))
1335 self._test_pathname(os.path.join("..", "foo", "..", "bar"))
1336
1337 self._test_pathname("foo" + os.sep + os.sep + "bar")
1338 self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True)
1339
1340 def test_abs_pathnames(self):
1341 if sys.platform == "win32":
1342 self._test_pathname("C:\\foo", "foo")
1343 else:
1344 self._test_pathname("/foo", "foo")
1345 self._test_pathname("///foo", "foo")
1346
1347 def test_cwd(self):
1348 # Test adding the current working directory.
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001349 with support.change_cwd(TEMPDIR):
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001350 tar = tarfile.open(tmpname, self.mode)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001351 try:
1352 tar.add(".")
1353 finally:
1354 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001355
1356 tar = tarfile.open(tmpname, "r")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001357 try:
1358 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001359 if t.name != ".":
1360 self.assertTrue(t.name.startswith("./"), t.name)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001361 finally:
1362 tar.close()
Lars Gustäbelbfdfdda2009-08-28 19:59:59 +00001363
Serhiy Storchakac2d01422014-01-18 16:14:10 +02001364 def test_open_nonwritable_fileobj(self):
1365 for exctype in OSError, EOFError, RuntimeError:
1366 class BadFile(io.BytesIO):
1367 first = True
1368 def write(self, data):
1369 if self.first:
1370 self.first = False
1371 raise exctype
1372
1373 f = BadFile()
1374 with self.assertRaises(exctype):
1375 tar = tarfile.open(tmpname, self.mode, fileobj=f,
1376 format=tarfile.PAX_FORMAT,
1377 pax_headers={'non': 'empty'})
1378 self.assertFalse(f.closed)
1379
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001380class GzipWriteTest(GzipTest, WriteTest):
1381 pass
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001382
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001383class Bz2WriteTest(Bz2Test, WriteTest):
1384 pass
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001385
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001386class LzmaWriteTest(LzmaTest, WriteTest):
1387 pass
1388
1389
1390class StreamWriteTest(WriteTestBase, unittest.TestCase):
1391
1392 prefix = "w|"
1393 decompressor = None
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001394
Guido van Rossumd8faa362007-04-27 19:54:29 +00001395 def test_stream_padding(self):
1396 # Test for bug #1543303.
1397 tar = tarfile.open(tmpname, self.mode)
1398 tar.close()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001399 if self.decompressor:
1400 dec = self.decompressor()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001401 with open(tmpname, "rb") as fobj:
1402 data = fobj.read()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001403 data = dec.decompress(data)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001404 self.assertFalse(dec.unused_data, "found trailing data")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001405 else:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001406 with self.open(tmpname) as fobj:
Antoine Pitrou95f55602010-09-23 18:36:46 +00001407 data = fobj.read()
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001408 self.assertEqual(data.count(b"\0"), tarfile.RECORDSIZE,
1409 "incorrect zero padding")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001410
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001411 @unittest.skipUnless(sys.platform != "win32" and hasattr(os, "umask"),
1412 "Missing umask implementation")
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001413 def test_file_mode(self):
1414 # Test for issue #8464: Create files with correct
1415 # permissions.
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001416 if os.path.exists(tmpname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01001417 support.unlink(tmpname)
Lars Gustäbeld6eb70b2010-04-29 15:37:02 +00001418
1419 original_umask = os.umask(0o022)
1420 try:
1421 tar = tarfile.open(tmpname, self.mode)
1422 tar.close()
1423 mode = os.stat(tmpname).st_mode & 0o777
1424 self.assertEqual(mode, 0o644, "wrong file permissions")
1425 finally:
1426 os.umask(original_umask)
1427
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001428class GzipStreamWriteTest(GzipTest, StreamWriteTest):
1429 pass
1430
1431class Bz2StreamWriteTest(Bz2Test, StreamWriteTest):
1432 decompressor = bz2.BZ2Decompressor if bz2 else None
1433
1434class LzmaStreamWriteTest(LzmaTest, StreamWriteTest):
1435 decompressor = lzma.LZMADecompressor if lzma else None
1436
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001437
Guido van Rossumd8faa362007-04-27 19:54:29 +00001438class GNUWriteTest(unittest.TestCase):
1439 # This testcase checks for correct creation of GNU Longname
1440 # and Longlink extended headers (cp. bug #812325).
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001441
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001442 def _length(self, s):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001443 blocks = len(s) // 512 + 1
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001444 return blocks * 512
1445
1446 def _calc_size(self, name, link=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001447 # Initial tar header
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001448 count = 512
1449
1450 if len(name) > tarfile.LENGTH_NAME:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001451 # GNU longname extended header + longname
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001452 count += 512
1453 count += self._length(name)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001454 if link is not None and len(link) > tarfile.LENGTH_LINK:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001455 # GNU longlink extended header + longlink
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001456 count += 512
1457 count += self._length(link)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001458 return count
1459
1460 def _test(self, name, link=None):
1461 tarinfo = tarfile.TarInfo(name)
1462 if link:
1463 tarinfo.linkname = link
1464 tarinfo.type = tarfile.LNKTYPE
1465
Guido van Rossumd8faa362007-04-27 19:54:29 +00001466 tar = tarfile.open(tmpname, "w")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001467 try:
1468 tar.format = tarfile.GNU_FORMAT
1469 tar.addfile(tarinfo)
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001470
Antoine Pitrou95f55602010-09-23 18:36:46 +00001471 v1 = self._calc_size(name, link)
1472 v2 = tar.offset
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001473 self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001474 finally:
1475 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001476
Guido van Rossumd8faa362007-04-27 19:54:29 +00001477 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001478 try:
1479 member = tar.next()
1480 self.assertIsNotNone(member,
1481 "unable to read longname member")
1482 self.assertEqual(tarinfo.name, member.name,
1483 "unable to read longname member")
1484 self.assertEqual(tarinfo.linkname, member.linkname,
1485 "unable to read longname member")
1486 finally:
1487 tar.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +00001488
Neal Norwitz0662f8a2004-07-20 21:54:18 +00001489 def test_longname_1023(self):
1490 self._test(("longnam/" * 127) + "longnam")
1491
1492 def test_longname_1024(self):
1493 self._test(("longnam/" * 127) + "longname")
1494
1495 def test_longname_1025(self):
1496 self._test(("longnam/" * 127) + "longname_")
1497
1498 def test_longlink_1023(self):
1499 self._test("name", ("longlnk/" * 127) + "longlnk")
1500
1501 def test_longlink_1024(self):
1502 self._test("name", ("longlnk/" * 127) + "longlink")
1503
1504 def test_longlink_1025(self):
1505 self._test("name", ("longlnk/" * 127) + "longlink_")
1506
1507 def test_longnamelink_1023(self):
1508 self._test(("longnam/" * 127) + "longnam",
1509 ("longlnk/" * 127) + "longlnk")
1510
1511 def test_longnamelink_1024(self):
1512 self._test(("longnam/" * 127) + "longname",
1513 ("longlnk/" * 127) + "longlink")
1514
1515 def test_longnamelink_1025(self):
1516 self._test(("longnam/" * 127) + "longname_",
1517 ("longlnk/" * 127) + "longlink_")
1518
Guido van Rossumd8faa362007-04-27 19:54:29 +00001519
Lars Gustäbel20703c62015-05-27 12:53:44 +02001520class CreateTest(WriteTestBase, unittest.TestCase):
Berker Peksag0fe63252015-02-13 21:02:12 +02001521
1522 prefix = "x:"
1523
1524 file_path = os.path.join(TEMPDIR, "spameggs42")
1525
1526 def setUp(self):
1527 support.unlink(tmpname)
1528
1529 @classmethod
1530 def setUpClass(cls):
1531 with open(cls.file_path, "wb") as fobj:
1532 fobj.write(b"aaa")
1533
1534 @classmethod
1535 def tearDownClass(cls):
1536 support.unlink(cls.file_path)
1537
1538 def test_create(self):
1539 with tarfile.open(tmpname, self.mode) as tobj:
1540 tobj.add(self.file_path)
1541
1542 with self.taropen(tmpname) as tobj:
1543 names = tobj.getnames()
1544 self.assertEqual(len(names), 1)
1545 self.assertIn('spameggs42', names[0])
1546
1547 def test_create_existing(self):
1548 with tarfile.open(tmpname, self.mode) as tobj:
1549 tobj.add(self.file_path)
1550
1551 with self.assertRaises(FileExistsError):
1552 tobj = tarfile.open(tmpname, self.mode)
1553
1554 with self.taropen(tmpname) as tobj:
1555 names = tobj.getnames()
1556 self.assertEqual(len(names), 1)
1557 self.assertIn('spameggs42', names[0])
1558
1559 def test_create_taropen(self):
1560 with self.taropen(tmpname, "x") as tobj:
1561 tobj.add(self.file_path)
1562
1563 with self.taropen(tmpname) as tobj:
1564 names = tobj.getnames()
1565 self.assertEqual(len(names), 1)
1566 self.assertIn('spameggs42', names[0])
1567
1568 def test_create_existing_taropen(self):
1569 with self.taropen(tmpname, "x") as tobj:
1570 tobj.add(self.file_path)
1571
1572 with self.assertRaises(FileExistsError):
1573 with self.taropen(tmpname, "x"):
1574 pass
1575
1576 with self.taropen(tmpname) as tobj:
1577 names = tobj.getnames()
1578 self.assertEqual(len(names), 1)
1579 self.assertIn("spameggs42", names[0])
1580
Serhiy Storchakac45cd162017-03-08 10:32:44 +02001581 def test_create_pathlike_name(self):
1582 with tarfile.open(pathlib.Path(tmpname), self.mode) as tobj:
1583 self.assertIsInstance(tobj.name, str)
1584 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1585 tobj.add(pathlib.Path(self.file_path))
1586 names = tobj.getnames()
1587 self.assertEqual(len(names), 1)
1588 self.assertIn('spameggs42', names[0])
1589
1590 with self.taropen(tmpname) as tobj:
1591 names = tobj.getnames()
1592 self.assertEqual(len(names), 1)
1593 self.assertIn('spameggs42', names[0])
1594
1595 def test_create_taropen_pathlike_name(self):
1596 with self.taropen(pathlib.Path(tmpname), "x") as tobj:
1597 self.assertIsInstance(tobj.name, str)
1598 self.assertEqual(tobj.name, os.path.abspath(tmpname))
1599 tobj.add(pathlib.Path(self.file_path))
1600 names = tobj.getnames()
1601 self.assertEqual(len(names), 1)
1602 self.assertIn('spameggs42', names[0])
1603
1604 with self.taropen(tmpname) as tobj:
1605 names = tobj.getnames()
1606 self.assertEqual(len(names), 1)
1607 self.assertIn('spameggs42', names[0])
1608
Berker Peksag0fe63252015-02-13 21:02:12 +02001609
1610class GzipCreateTest(GzipTest, CreateTest):
1611 pass
1612
1613
1614class Bz2CreateTest(Bz2Test, CreateTest):
1615 pass
1616
1617
1618class LzmaCreateTest(LzmaTest, CreateTest):
1619 pass
1620
1621
1622class CreateWithXModeTest(CreateTest):
1623
1624 prefix = "x"
1625
1626 test_create_taropen = None
1627 test_create_existing_taropen = None
1628
1629
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001630@unittest.skipUnless(hasattr(os, "link"), "Missing hardlink implementation")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001631class HardlinkTest(unittest.TestCase):
1632 # Test the creation of LNKTYPE (hardlink) members in an archive.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001633
1634 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001635 self.foo = os.path.join(TEMPDIR, "foo")
1636 self.bar = os.path.join(TEMPDIR, "bar")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001637
Antoine Pitrou95f55602010-09-23 18:36:46 +00001638 with open(self.foo, "wb") as fobj:
1639 fobj.write(b"foo")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001640
xdegayed7d4fea2017-11-12 18:02:06 +01001641 try:
1642 os.link(self.foo, self.bar)
1643 except PermissionError as e:
1644 self.skipTest('os.link(): %s' % e)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001645
Guido van Rossumd8faa362007-04-27 19:54:29 +00001646 self.tar = tarfile.open(tmpname, "w")
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001647 self.tar.add(self.foo)
1648
Guido van Rossumd8faa362007-04-27 19:54:29 +00001649 def tearDown(self):
Hirokazu Yamamotoaf079d42008-09-21 11:50:03 +00001650 self.tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001651 support.unlink(self.foo)
1652 support.unlink(self.bar)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001653
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001654 def test_add_twice(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001655 # The same name will be added as a REGTYPE every
1656 # time regardless of st_nlink.
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001657 tarinfo = self.tar.gettarinfo(self.foo)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001658 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001659 "add file as regular failed")
1660
1661 def test_add_hardlink(self):
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001662 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001663 self.assertEqual(tarinfo.type, tarfile.LNKTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001664 "add file as hardlink failed")
1665
1666 def test_dereference_hardlink(self):
1667 self.tar.dereference = True
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001668 tarinfo = self.tar.gettarinfo(self.bar)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001669 self.assertEqual(tarinfo.type, tarfile.REGTYPE,
Neal Norwitzb0e32e22005-10-20 04:50:13 +00001670 "dereferencing hardlink failed")
1671
Neal Norwitza4f651a2004-07-20 22:07:44 +00001672
Guido van Rossumd8faa362007-04-27 19:54:29 +00001673class PaxWriteTest(GNUWriteTest):
Martin v. Löwis78be7df2005-03-05 12:47:42 +00001674
Guido van Rossumd8faa362007-04-27 19:54:29 +00001675 def _test(self, name, link=None):
1676 # See GNUWriteTest.
1677 tarinfo = tarfile.TarInfo(name)
1678 if link:
1679 tarinfo.linkname = link
1680 tarinfo.type = tarfile.LNKTYPE
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001681
Guido van Rossumd8faa362007-04-27 19:54:29 +00001682 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001683 try:
1684 tar.addfile(tarinfo)
1685 finally:
1686 tar.close()
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +00001687
Guido van Rossumd8faa362007-04-27 19:54:29 +00001688 tar = tarfile.open(tmpname)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001689 try:
1690 if link:
1691 l = tar.getmembers()[0].linkname
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001692 self.assertEqual(link, l, "PAX longlink creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001693 else:
1694 n = tar.getmembers()[0].name
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001695 self.assertEqual(name, n, "PAX longname creation failed")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001696 finally:
1697 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001698
Guido van Rossume7ba4952007-06-06 23:52:48 +00001699 def test_pax_global_header(self):
1700 pax_headers = {
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001701 "foo": "bar",
1702 "uid": "0",
1703 "mtime": "1.23",
Guido van Rossuma0557702007-08-07 23:19:53 +00001704 "test": "\xe4\xf6\xfc",
1705 "\xe4\xf6\xfc": "test"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001706
Benjamin Peterson886af962010-03-21 23:13:07 +00001707 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
Guido van Rossume7ba4952007-06-06 23:52:48 +00001708 pax_headers=pax_headers)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001709 try:
1710 tar.addfile(tarfile.TarInfo("test"))
1711 finally:
1712 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001713
1714 # Test if the global header was written correctly.
1715 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001716 try:
1717 self.assertEqual(tar.pax_headers, pax_headers)
1718 self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers)
1719 # Test if all the fields are strings.
1720 for key, val in tar.pax_headers.items():
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001721 self.assertIsNot(type(key), bytes)
1722 self.assertIsNot(type(val), bytes)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001723 if key in tarfile.PAX_NUMBER_FIELDS:
1724 try:
1725 tarfile.PAX_NUMBER_FIELDS[key](val)
1726 except (TypeError, ValueError):
1727 self.fail("unable to convert pax header field")
1728 finally:
1729 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001730
1731 def test_pax_extended_header(self):
1732 # The fields from the pax header have priority over the
1733 # TarInfo.
Guido van Rossum9cbfffd2007-06-07 00:54:15 +00001734 pax_headers = {"path": "foo", "uid": "123"}
Guido van Rossume7ba4952007-06-06 23:52:48 +00001735
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001736 tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
1737 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001738 try:
1739 t = tarfile.TarInfo()
1740 t.name = "\xe4\xf6\xfc" # non-ASCII
1741 t.uid = 8**8 # too large
1742 t.pax_headers = pax_headers
1743 tar.addfile(t)
1744 finally:
1745 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001746
1747 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001748 try:
1749 t = tar.getmembers()[0]
1750 self.assertEqual(t.pax_headers, pax_headers)
1751 self.assertEqual(t.name, "foo")
1752 self.assertEqual(t.uid, 123)
1753 finally:
1754 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001755
1756
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001757class UnicodeTest:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001758
1759 def test_iso8859_1_filename(self):
1760 self._test_unicode_filename("iso8859-1")
1761
1762 def test_utf7_filename(self):
1763 self._test_unicode_filename("utf7")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001764
1765 def test_utf8_filename(self):
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00001766 self._test_unicode_filename("utf-8")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001767
Guido van Rossumd8faa362007-04-27 19:54:29 +00001768 def _test_unicode_filename(self, encoding):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001769 tar = tarfile.open(tmpname, "w", format=self.format,
1770 encoding=encoding, errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001771 try:
1772 name = "\xe4\xf6\xfc"
1773 tar.addfile(tarfile.TarInfo(name))
1774 finally:
1775 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001776
1777 tar = tarfile.open(tmpname, encoding=encoding)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001778 try:
1779 self.assertEqual(tar.getmembers()[0].name, name)
1780 finally:
1781 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001782
1783 def test_unicode_filename_error(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001784 tar = tarfile.open(tmpname, "w", format=self.format,
1785 encoding="ascii", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001786 try:
1787 tarinfo = tarfile.TarInfo()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001788
Antoine Pitrou95f55602010-09-23 18:36:46 +00001789 tarinfo.name = "\xe4\xf6\xfc"
1790 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001791
Antoine Pitrou95f55602010-09-23 18:36:46 +00001792 tarinfo.name = "foo"
1793 tarinfo.uname = "\xe4\xf6\xfc"
1794 self.assertRaises(UnicodeError, tar.addfile, tarinfo)
1795 finally:
1796 tar.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001797
1798 def test_unicode_argument(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001799 tar = tarfile.open(tarname, "r",
1800 encoding="iso8859-1", errors="strict")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001801 try:
1802 for t in tar:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001803 self.assertIs(type(t.name), str)
1804 self.assertIs(type(t.linkname), str)
1805 self.assertIs(type(t.uname), str)
1806 self.assertIs(type(t.gname), str)
Antoine Pitrou95f55602010-09-23 18:36:46 +00001807 finally:
1808 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001809
Guido van Rossume7ba4952007-06-06 23:52:48 +00001810 def test_uname_unicode(self):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001811 t = tarfile.TarInfo("foo")
1812 t.uname = "\xe4\xf6\xfc"
1813 t.gname = "\xe4\xf6\xfc"
Guido van Rossumd8faa362007-04-27 19:54:29 +00001814
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001815 tar = tarfile.open(tmpname, mode="w", format=self.format,
1816 encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001817 try:
1818 tar.addfile(t)
1819 finally:
1820 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001821
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001822 tar = tarfile.open(tmpname, encoding="iso8859-1")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001823 try:
Guido van Rossume7ba4952007-06-06 23:52:48 +00001824 t = tar.getmember("foo")
Antoine Pitrou95f55602010-09-23 18:36:46 +00001825 self.assertEqual(t.uname, "\xe4\xf6\xfc")
1826 self.assertEqual(t.gname, "\xe4\xf6\xfc")
1827
1828 if self.format != tarfile.PAX_FORMAT:
Antoine Pitrouab58b5f2010-09-23 19:39:35 +00001829 tar.close()
Antoine Pitrou95f55602010-09-23 18:36:46 +00001830 tar = tarfile.open(tmpname, encoding="ascii")
1831 t = tar.getmember("foo")
1832 self.assertEqual(t.uname, "\udce4\udcf6\udcfc")
1833 self.assertEqual(t.gname, "\udce4\udcf6\udcfc")
1834 finally:
1835 tar.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001836
Lars Gustäbelb506dc32007-08-07 18:36:16 +00001837
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001838class UstarUnicodeTest(UnicodeTest, unittest.TestCase):
1839
1840 format = tarfile.USTAR_FORMAT
1841
1842 # Test whether the utf-8 encoded version of a filename exceeds the 100
1843 # bytes name field limit (every occurrence of '\xff' will be expanded to 2
1844 # bytes).
1845 def test_unicode_name1(self):
1846 self._test_ustar_name("0123456789" * 10)
1847 self._test_ustar_name("0123456789" * 10 + "0", ValueError)
1848 self._test_ustar_name("0123456789" * 9 + "01234567\xff")
1849 self._test_ustar_name("0123456789" * 9 + "012345678\xff", ValueError)
1850
1851 def test_unicode_name2(self):
1852 self._test_ustar_name("0123456789" * 9 + "012345\xff\xff")
1853 self._test_ustar_name("0123456789" * 9 + "0123456\xff\xff", ValueError)
1854
1855 # Test whether the utf-8 encoded version of a filename exceeds the 155
1856 # bytes prefix + '/' + 100 bytes name limit.
1857 def test_unicode_longname1(self):
1858 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 10)
1859 self._test_ustar_name("0123456789" * 15 + "0123/4" + "0123456789" * 10, ValueError)
1860 self._test_ustar_name("0123456789" * 15 + "012\xff/" + "0123456789" * 10)
1861 self._test_ustar_name("0123456789" * 15 + "0123\xff/" + "0123456789" * 10, ValueError)
1862
1863 def test_unicode_longname2(self):
1864 self._test_ustar_name("0123456789" * 15 + "01\xff/2" + "0123456789" * 10, ValueError)
1865 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/" + "0123456789" * 10, ValueError)
1866
1867 def test_unicode_longname3(self):
1868 self._test_ustar_name("0123456789" * 15 + "01\xff\xff/2" + "0123456789" * 10, ValueError)
1869 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "01234567\xff")
1870 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345678\xff", ValueError)
1871
1872 def test_unicode_longname4(self):
1873 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "012345\xff\xff")
1874 self._test_ustar_name("0123456789" * 15 + "01234/" + "0123456789" * 9 + "0123456\xff\xff", ValueError)
1875
1876 def _test_ustar_name(self, name, exc=None):
1877 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1878 t = tarfile.TarInfo(name)
1879 if exc is None:
1880 tar.addfile(t)
1881 else:
1882 self.assertRaises(exc, tar.addfile, t)
1883
1884 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001885 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001886 for t in tar:
1887 self.assertEqual(name, t.name)
1888 break
1889
1890 # Test the same as above for the 100 bytes link field.
1891 def test_unicode_link1(self):
1892 self._test_ustar_link("0123456789" * 10)
1893 self._test_ustar_link("0123456789" * 10 + "0", ValueError)
1894 self._test_ustar_link("0123456789" * 9 + "01234567\xff")
1895 self._test_ustar_link("0123456789" * 9 + "012345678\xff", ValueError)
1896
1897 def test_unicode_link2(self):
1898 self._test_ustar_link("0123456789" * 9 + "012345\xff\xff")
1899 self._test_ustar_link("0123456789" * 9 + "0123456\xff\xff", ValueError)
1900
1901 def _test_ustar_link(self, name, exc=None):
1902 with tarfile.open(tmpname, "w", format=self.format, encoding="utf-8") as tar:
1903 t = tarfile.TarInfo("foo")
1904 t.linkname = name
1905 if exc is None:
1906 tar.addfile(t)
1907 else:
1908 self.assertRaises(exc, tar.addfile, t)
1909
1910 if exc is None:
Lars Gustäbelddd99172016-04-19 11:58:41 +02001911 with tarfile.open(tmpname, "r", encoding="utf-8") as tar:
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001912 for t in tar:
1913 self.assertEqual(name, t.linkname)
1914 break
1915
1916
1917class GNUUnicodeTest(UnicodeTest, unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001918
Guido van Rossume7ba4952007-06-06 23:52:48 +00001919 format = tarfile.GNU_FORMAT
Guido van Rossumd8faa362007-04-27 19:54:29 +00001920
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001921 def test_bad_pax_header(self):
1922 # Test for issue #8633. GNU tar <= 1.23 creates raw binary fields
1923 # without a hdrcharset=BINARY header.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001924 for encoding, name in (
1925 ("utf-8", "pax/bad-pax-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001926 ("iso8859-1", "pax/bad-pax-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001927 with tarfile.open(tarname, encoding=encoding,
1928 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001929 try:
1930 t = tar.getmember(name)
1931 except KeyError:
1932 self.fail("unable to read bad GNU tar pax header")
1933
Guido van Rossumd8faa362007-04-27 19:54:29 +00001934
Lars Gustäbel0f450ab2016-04-19 08:43:17 +02001935class PAXUnicodeTest(UnicodeTest, unittest.TestCase):
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001936
1937 format = tarfile.PAX_FORMAT
1938
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001939 # PAX_FORMAT ignores encoding in write mode.
1940 test_unicode_filename_error = None
1941
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001942 def test_binary_header(self):
1943 # Test a POSIX.1-2008 compatible header with a hdrcharset=BINARY field.
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001944 for encoding, name in (
1945 ("utf-8", "pax/hdrcharset-\udce4\udcf6\udcfc"),
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001946 ("iso8859-1", "pax/hdrcharset-\xe4\xf6\xfc"),):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001947 with tarfile.open(tarname, encoding=encoding,
1948 errors="surrogateescape") as tar:
Lars Gustäbel1465cc22010-05-17 18:02:50 +00001949 try:
1950 t = tar.getmember(name)
1951 except KeyError:
1952 self.fail("unable to read POSIX.1-2008 binary header")
1953
Lars Gustäbel3741eff2007-08-21 12:17:05 +00001954
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001955class AppendTestBase:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001956 # Test append mode (cp. patch #1652681).
Thomas Wouters902d6eb2007-01-09 23:18:33 +00001957
Guido van Rossumd8faa362007-04-27 19:54:29 +00001958 def setUp(self):
1959 self.tarname = tmpname
1960 if os.path.exists(self.tarname):
Tim Goldene0bd2c52014-05-06 13:24:26 +01001961 support.unlink(self.tarname)
Thomas Wouters902d6eb2007-01-09 23:18:33 +00001962
Guido van Rossumd8faa362007-04-27 19:54:29 +00001963 def _create_testtar(self, mode="w:"):
Antoine Pitrou95f55602010-09-23 18:36:46 +00001964 with tarfile.open(tarname, encoding="iso8859-1") as src:
1965 t = src.getmember("ustar/regtype")
1966 t.name = "foo"
Lars Gustäbel7a919e92012-05-05 18:15:03 +02001967 with src.extractfile(t) as f:
Antoine Pitroue1eca4e2010-10-29 23:49:49 +00001968 with tarfile.open(self.tarname, mode) as tar:
1969 tar.addfile(t, f)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001970
Serhiy Storchaka8b562922013-06-17 15:38:50 +03001971 def test_append_compressed(self):
1972 self._create_testtar("w:" + self.suffix)
1973 self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a")
1974
1975class AppendTest(AppendTestBase, unittest.TestCase):
1976 test_append_compressed = None
1977
1978 def _add_testfile(self, fileobj=None):
1979 with tarfile.open(self.tarname, "a", fileobj=fileobj) as tar:
1980 tar.addfile(tarfile.TarInfo("bar"))
1981
Guido van Rossumd8faa362007-04-27 19:54:29 +00001982 def _test(self, names=["bar"], fileobj=None):
Antoine Pitrou95f55602010-09-23 18:36:46 +00001983 with tarfile.open(self.tarname, fileobj=fileobj) as tar:
1984 self.assertEqual(tar.getnames(), names)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001985
1986 def test_non_existing(self):
1987 self._add_testfile()
1988 self._test()
1989
1990 def test_empty(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00001991 tarfile.open(self.tarname, "w:").close()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001992 self._add_testfile()
1993 self._test()
1994
1995 def test_empty_fileobj(self):
Lars Gustäbel9520a432009-11-22 18:48:49 +00001996 fobj = io.BytesIO(b"\0" * 1024)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001997 self._add_testfile(fobj)
1998 fobj.seek(0)
1999 self._test(fileobj=fobj)
2000
2001 def test_fileobj(self):
2002 self._create_testtar()
Antoine Pitrou95f55602010-09-23 18:36:46 +00002003 with open(self.tarname, "rb") as fobj:
2004 data = fobj.read()
Guido van Rossum34d19282007-08-09 01:03:29 +00002005 fobj = io.BytesIO(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002006 self._add_testfile(fobj)
2007 fobj.seek(0)
2008 self._test(names=["foo", "bar"], fileobj=fobj)
2009
2010 def test_existing(self):
2011 self._create_testtar()
2012 self._add_testfile()
2013 self._test(names=["foo", "bar"])
2014
Lars Gustäbel9520a432009-11-22 18:48:49 +00002015 # Append mode is supposed to fail if the tarfile to append to
2016 # does not end with a zero block.
2017 def _test_error(self, data):
Antoine Pitrou95f55602010-09-23 18:36:46 +00002018 with open(self.tarname, "wb") as fobj:
2019 fobj.write(data)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002020 self.assertRaises(tarfile.ReadError, self._add_testfile)
2021
2022 def test_null(self):
2023 self._test_error(b"")
2024
2025 def test_incomplete(self):
2026 self._test_error(b"\0" * 13)
2027
2028 def test_premature_eof(self):
2029 data = tarfile.TarInfo("foo").tobuf()
2030 self._test_error(data)
2031
2032 def test_trailing_garbage(self):
2033 data = tarfile.TarInfo("foo").tobuf()
2034 self._test_error(data + b"\0" * 13)
2035
2036 def test_invalid(self):
2037 self._test_error(b"a" * 512)
2038
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002039class GzipAppendTest(GzipTest, AppendTestBase, unittest.TestCase):
2040 pass
2041
2042class Bz2AppendTest(Bz2Test, AppendTestBase, unittest.TestCase):
2043 pass
2044
2045class LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase):
2046 pass
2047
Guido van Rossumd8faa362007-04-27 19:54:29 +00002048
2049class LimitsTest(unittest.TestCase):
2050
2051 def test_ustar_limits(self):
2052 # 100 char name
2053 tarinfo = tarfile.TarInfo("0123456789" * 10)
Guido van Rossume7ba4952007-06-06 23:52:48 +00002054 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002055
2056 # 101 char name that cannot be stored
2057 tarinfo = tarfile.TarInfo("0123456789" * 10 + "0")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002058 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002059
2060 # 256 char name with a slash at pos 156
2061 tarinfo = tarfile.TarInfo("123/" * 62 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002062 tarinfo.tobuf(tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002063
2064 # 256 char name that cannot be stored
2065 tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002066 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002067
2068 # 512 char name
2069 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002070 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002071
2072 # 512 char linkname
2073 tarinfo = tarfile.TarInfo("longlink")
2074 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002075 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002076
2077 # uid > 8 digits
2078 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002079 tarinfo.uid = 0o10000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002080 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002081
2082 def test_gnu_limits(self):
2083 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002084 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002085
2086 tarinfo = tarfile.TarInfo("longlink")
2087 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002088 tarinfo.tobuf(tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002089
2090 # uid >= 256 ** 7
2091 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002092 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002093 self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002094
2095 def test_pax_limits(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002096 tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
Guido van Rossume7ba4952007-06-06 23:52:48 +00002097 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002098
2099 tarinfo = tarfile.TarInfo("longlink")
2100 tarinfo.linkname = "123/" * 126 + "longname"
Guido van Rossume7ba4952007-06-06 23:52:48 +00002101 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002102
2103 tarinfo = tarfile.TarInfo("name")
Guido van Rossumcd16bf62007-06-13 18:07:49 +00002104 tarinfo.uid = 0o4000000000000000000
Guido van Rossume7ba4952007-06-06 23:52:48 +00002105 tarinfo.tobuf(tarfile.PAX_FORMAT)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002106
2107
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002108class MiscTest(unittest.TestCase):
2109
2110 def test_char_fields(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002111 self.assertEqual(tarfile.stn("foo", 8, "ascii", "strict"),
2112 b"foo\0\0\0\0\0")
2113 self.assertEqual(tarfile.stn("foobar", 3, "ascii", "strict"),
2114 b"foo")
2115 self.assertEqual(tarfile.nts(b"foo\0\0\0\0\0", "ascii", "strict"),
2116 "foo")
2117 self.assertEqual(tarfile.nts(b"foo\0bar\0", "ascii", "strict"),
2118 "foo")
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002119
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002120 def test_read_number_fields(self):
2121 # Issue 13158: Test if GNU tar specific base-256 number fields
2122 # are decoded correctly.
2123 self.assertEqual(tarfile.nti(b"0000001\x00"), 1)
2124 self.assertEqual(tarfile.nti(b"7777777\x00"), 0o7777777)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002125 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\x00\x20\x00\x00"),
2126 0o10000000)
2127 self.assertEqual(tarfile.nti(b"\x80\x00\x00\x00\xff\xff\xff\xff"),
2128 0xffffffff)
2129 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\xff"),
2130 -1)
2131 self.assertEqual(tarfile.nti(b"\xff\xff\xff\xff\xff\xff\xff\x9c"),
2132 -100)
2133 self.assertEqual(tarfile.nti(b"\xff\x00\x00\x00\x00\x00\x00\x00"),
2134 -0x100000000000000)
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002135
Lars Gustäbelb7a688b2015-07-02 19:38:38 +02002136 # Issue 24514: Test if empty number fields are converted to zero.
2137 self.assertEqual(tarfile.nti(b"\0"), 0)
2138 self.assertEqual(tarfile.nti(b" \0"), 0)
2139
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002140 def test_write_number_fields(self):
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002141 self.assertEqual(tarfile.itn(1), b"0000001\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002142 self.assertEqual(tarfile.itn(0o7777777), b"7777777\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002143 self.assertEqual(tarfile.itn(0o10000000, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002144 b"\x80\x00\x00\x00\x00\x20\x00\x00")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002145 self.assertEqual(tarfile.itn(0xffffffff, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002146 b"\x80\x00\x00\x00\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002147 self.assertEqual(tarfile.itn(-1, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002148 b"\xff\xff\xff\xff\xff\xff\xff\xff")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002149 self.assertEqual(tarfile.itn(-100, format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002150 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
CAM Gerlache680c3d2019-03-21 09:44:51 -05002151 self.assertEqual(tarfile.itn(-0x100000000000000,
2152 format=tarfile.GNU_FORMAT),
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002153 b"\xff\x00\x00\x00\x00\x00\x00\x00")
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002154
Joffrey F72d9b2b2018-02-26 16:02:21 -08002155 # Issue 32713: Test if itn() supports float values outside the
2156 # non-GNU format range
2157 self.assertEqual(tarfile.itn(-100.0, format=tarfile.GNU_FORMAT),
2158 b"\xff\xff\xff\xff\xff\xff\xff\x9c")
2159 self.assertEqual(tarfile.itn(8 ** 12 + 0.0, format=tarfile.GNU_FORMAT),
2160 b"\x80\x00\x00\x10\x00\x00\x00\x00")
2161 self.assertEqual(tarfile.nti(tarfile.itn(-0.1, format=tarfile.GNU_FORMAT)), 0)
2162
Lars Gustäbelac3d1372011-10-14 12:46:40 +02002163 def test_number_field_limits(self):
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002164 with self.assertRaises(ValueError):
2165 tarfile.itn(-1, 8, tarfile.USTAR_FORMAT)
2166 with self.assertRaises(ValueError):
2167 tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT)
2168 with self.assertRaises(ValueError):
2169 tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT)
2170 with self.assertRaises(ValueError):
2171 tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT)
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002172
Martin Panter104dcda2016-01-16 06:59:13 +00002173 def test__all__(self):
Martin Panter5318d102016-01-16 11:01:14 +00002174 blacklist = {'version', 'grp', 'pwd', 'symlink_exception',
Martin Panter104dcda2016-01-16 06:59:13 +00002175 'NUL', 'BLOCKSIZE', 'RECORDSIZE', 'GNU_MAGIC',
2176 'POSIX_MAGIC', 'LENGTH_NAME', 'LENGTH_LINK',
2177 'LENGTH_PREFIX', 'REGTYPE', 'AREGTYPE', 'LNKTYPE',
2178 'SYMTYPE', 'CHRTYPE', 'BLKTYPE', 'DIRTYPE', 'FIFOTYPE',
2179 'CONTTYPE', 'GNUTYPE_LONGNAME', 'GNUTYPE_LONGLINK',
2180 'GNUTYPE_SPARSE', 'XHDTYPE', 'XGLTYPE', 'SOLARIS_XHDTYPE',
2181 'SUPPORTED_TYPES', 'REGULAR_TYPES', 'GNU_TYPES',
2182 'PAX_FIELDS', 'PAX_NAME_FIELDS', 'PAX_NUMBER_FIELDS',
2183 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 'copyfileobj',
2184 'filemode',
2185 'EmptyHeaderError', 'TruncatedHeaderError',
2186 'EOFHeaderError', 'InvalidHeaderError',
Serhiy Storchaka2c1d3e32016-01-16 11:05:11 +02002187 'SubsequentHeaderError', 'ExFileObject',
Martin Panter104dcda2016-01-16 06:59:13 +00002188 'main'}
2189 support.check__all__(self, tarfile, blacklist=blacklist)
2190
Lars Gustäbelb506dc32007-08-07 18:36:16 +00002191
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002192class CommandLineTest(unittest.TestCase):
2193
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002194 def tarfilecmd(self, *args, **kwargs):
2195 rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args,
2196 **kwargs)
Antoine Pitrou3b7b1e52013-11-24 01:55:05 +01002197 return out.replace(os.linesep.encode(), b'\n')
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002198
2199 def tarfilecmd_failure(self, *args):
2200 return script_helper.assert_python_failure('-m', 'tarfile', *args)
2201
2202 def make_simple_tarfile(self, tar_name):
2203 files = [support.findfile('tokenize_tests.txt'),
2204 support.findfile('tokenize_tests-no-coding-cookie-'
2205 'and-utf8-bom-sig-only.txt')]
2206 self.addCleanup(support.unlink, tar_name)
2207 with tarfile.open(tar_name, 'w') as tf:
2208 for tardata in files:
2209 tf.add(tardata, arcname=os.path.basename(tardata))
2210
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002211 def test_bad_use(self):
2212 rc, out, err = self.tarfilecmd_failure()
2213 self.assertEqual(out, b'')
2214 self.assertIn(b'usage', err.lower())
2215 self.assertIn(b'error', err.lower())
2216 self.assertIn(b'required', err.lower())
2217 rc, out, err = self.tarfilecmd_failure('-l', '')
2218 self.assertEqual(out, b'')
2219 self.assertNotEqual(err.strip(), b'')
2220
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002221 def test_test_command(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002222 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002223 for opt in '-t', '--test':
2224 out = self.tarfilecmd(opt, tar_name)
2225 self.assertEqual(out, b'')
2226
2227 def test_test_command_verbose(self):
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002228 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002229 for opt in '-v', '--verbose':
2230 out = self.tarfilecmd(opt, '-t', tar_name)
2231 self.assertIn(b'is a tar archive.\n', out)
2232
2233 def test_test_command_invalid_file(self):
2234 zipname = support.findfile('zipdir.zip')
2235 rc, out, err = self.tarfilecmd_failure('-t', zipname)
2236 self.assertIn(b' is not a tar archive.', err)
2237 self.assertEqual(out, b'')
2238 self.assertEqual(rc, 1)
2239
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002240 for tar_name in testtarnames:
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002241 with self.subTest(tar_name=tar_name):
2242 with open(tar_name, 'rb') as f:
2243 data = f.read()
2244 try:
2245 with open(tmpname, 'wb') as f:
2246 f.write(data[:511])
2247 rc, out, err = self.tarfilecmd_failure('-t', tmpname)
2248 self.assertEqual(out, b'')
2249 self.assertEqual(rc, 1)
2250 finally:
2251 support.unlink(tmpname)
2252
2253 def test_list_command(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002254 for tar_name in testtarnames:
2255 with support.captured_stdout() as t:
2256 with tarfile.open(tar_name, 'r') as tf:
2257 tf.list(verbose=False)
2258 expected = t.getvalue().encode('ascii', 'backslashreplace')
2259 for opt in '-l', '--list':
2260 out = self.tarfilecmd(opt, tar_name,
2261 PYTHONIOENCODING='ascii')
2262 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002263
2264 def test_list_command_verbose(self):
Serhiy Storchaka255493c2014-02-05 20:54:43 +02002265 for tar_name in testtarnames:
2266 with support.captured_stdout() as t:
2267 with tarfile.open(tar_name, 'r') as tf:
2268 tf.list(verbose=True)
2269 expected = t.getvalue().encode('ascii', 'backslashreplace')
2270 for opt in '-v', '--verbose':
2271 out = self.tarfilecmd(opt, '-l', tar_name,
2272 PYTHONIOENCODING='ascii')
2273 self.assertEqual(out, expected)
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002274
2275 def test_list_command_invalid_file(self):
2276 zipname = support.findfile('zipdir.zip')
2277 rc, out, err = self.tarfilecmd_failure('-l', zipname)
2278 self.assertIn(b' is not a tar archive.', err)
2279 self.assertEqual(out, b'')
2280 self.assertEqual(rc, 1)
2281
2282 def test_create_command(self):
2283 files = [support.findfile('tokenize_tests.txt'),
2284 support.findfile('tokenize_tests-no-coding-cookie-'
2285 'and-utf8-bom-sig-only.txt')]
2286 for opt in '-c', '--create':
2287 try:
2288 out = self.tarfilecmd(opt, tmpname, *files)
2289 self.assertEqual(out, b'')
2290 with tarfile.open(tmpname) as tar:
2291 tar.getmembers()
2292 finally:
2293 support.unlink(tmpname)
2294
2295 def test_create_command_verbose(self):
2296 files = [support.findfile('tokenize_tests.txt'),
2297 support.findfile('tokenize_tests-no-coding-cookie-'
2298 'and-utf8-bom-sig-only.txt')]
2299 for opt in '-v', '--verbose':
2300 try:
2301 out = self.tarfilecmd(opt, '-c', tmpname, *files)
2302 self.assertIn(b' file created.', out)
2303 with tarfile.open(tmpname) as tar:
2304 tar.getmembers()
2305 finally:
2306 support.unlink(tmpname)
2307
2308 def test_create_command_dotless_filename(self):
2309 files = [support.findfile('tokenize_tests.txt')]
2310 try:
2311 out = self.tarfilecmd('-c', dotlessname, *files)
2312 self.assertEqual(out, b'')
2313 with tarfile.open(dotlessname) as tar:
2314 tar.getmembers()
2315 finally:
2316 support.unlink(dotlessname)
2317
2318 def test_create_command_dot_started_filename(self):
2319 tar_name = os.path.join(TEMPDIR, ".testtar")
2320 files = [support.findfile('tokenize_tests.txt')]
2321 try:
2322 out = self.tarfilecmd('-c', tar_name, *files)
2323 self.assertEqual(out, b'')
2324 with tarfile.open(tar_name) as tar:
2325 tar.getmembers()
2326 finally:
2327 support.unlink(tar_name)
2328
Serhiy Storchaka832dd5f2015-02-10 08:45:53 +02002329 def test_create_command_compressed(self):
2330 files = [support.findfile('tokenize_tests.txt'),
2331 support.findfile('tokenize_tests-no-coding-cookie-'
2332 'and-utf8-bom-sig-only.txt')]
2333 for filetype in (GzipTest, Bz2Test, LzmaTest):
2334 if not filetype.open:
2335 continue
2336 try:
2337 tar_name = tmpname + '.' + filetype.suffix
2338 out = self.tarfilecmd('-c', tar_name, *files)
2339 with filetype.taropen(tar_name) as tar:
2340 tar.getmembers()
2341 finally:
2342 support.unlink(tar_name)
2343
Serhiy Storchakad27b4552013-11-24 01:53:29 +02002344 def test_extract_command(self):
2345 self.make_simple_tarfile(tmpname)
2346 for opt in '-e', '--extract':
2347 try:
2348 with support.temp_cwd(tarextdir):
2349 out = self.tarfilecmd(opt, tmpname)
2350 self.assertEqual(out, b'')
2351 finally:
2352 support.rmtree(tarextdir)
2353
2354 def test_extract_command_verbose(self):
2355 self.make_simple_tarfile(tmpname)
2356 for opt in '-v', '--verbose':
2357 try:
2358 with support.temp_cwd(tarextdir):
2359 out = self.tarfilecmd(opt, '-e', tmpname)
2360 self.assertIn(b' file is extracted.', out)
2361 finally:
2362 support.rmtree(tarextdir)
2363
2364 def test_extract_command_different_directory(self):
2365 self.make_simple_tarfile(tmpname)
2366 try:
2367 with support.temp_cwd(tarextdir):
2368 out = self.tarfilecmd('-e', tmpname, 'spamdir')
2369 self.assertEqual(out, b'')
2370 finally:
2371 support.rmtree(tarextdir)
2372
2373 def test_extract_command_invalid_file(self):
2374 zipname = support.findfile('zipdir.zip')
2375 with support.temp_cwd(tarextdir):
2376 rc, out, err = self.tarfilecmd_failure('-e', zipname)
2377 self.assertIn(b' is not a tar archive.', err)
2378 self.assertEqual(out, b'')
2379 self.assertEqual(rc, 1)
2380
2381
Lars Gustäbel01385812010-03-03 12:08:54 +00002382class ContextManagerTest(unittest.TestCase):
2383
2384 def test_basic(self):
2385 with tarfile.open(tarname) as tar:
2386 self.assertFalse(tar.closed, "closed inside runtime context")
2387 self.assertTrue(tar.closed, "context manager failed")
2388
2389 def test_closed(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002390 # The __enter__() method is supposed to raise OSError
Lars Gustäbel01385812010-03-03 12:08:54 +00002391 # if the TarFile object is already closed.
2392 tar = tarfile.open(tarname)
2393 tar.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002394 with self.assertRaises(OSError):
Lars Gustäbel01385812010-03-03 12:08:54 +00002395 with tar:
2396 pass
2397
2398 def test_exception(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002399 # Test if the OSError exception is passed through properly.
Lars Gustäbel01385812010-03-03 12:08:54 +00002400 with self.assertRaises(Exception) as exc:
2401 with tarfile.open(tarname) as tar:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02002402 raise OSError
2403 self.assertIsInstance(exc.exception, OSError,
Lars Gustäbel01385812010-03-03 12:08:54 +00002404 "wrong exception raised in context manager")
2405 self.assertTrue(tar.closed, "context manager failed")
2406
2407 def test_no_eof(self):
2408 # __exit__() must not write end-of-archive blocks if an
2409 # exception was raised.
2410 try:
2411 with tarfile.open(tmpname, "w") as tar:
2412 raise Exception
2413 except:
2414 pass
2415 self.assertEqual(os.path.getsize(tmpname), 0,
2416 "context manager wrote an end-of-archive block")
2417 self.assertTrue(tar.closed, "context manager failed")
2418
2419 def test_eof(self):
2420 # __exit__() must write end-of-archive blocks, i.e. call
2421 # TarFile.close() if there was no error.
2422 with tarfile.open(tmpname, "w"):
2423 pass
2424 self.assertNotEqual(os.path.getsize(tmpname), 0,
2425 "context manager wrote no end-of-archive block")
2426
2427 def test_fileobj(self):
2428 # Test that __exit__() did not close the external file
2429 # object.
Antoine Pitrou95f55602010-09-23 18:36:46 +00002430 with open(tmpname, "wb") as fobj:
2431 try:
2432 with tarfile.open(fileobj=fobj, mode="w") as tar:
2433 raise Exception
2434 except:
2435 pass
2436 self.assertFalse(fobj.closed, "external file object was closed")
2437 self.assertTrue(tar.closed, "context manager failed")
Lars Gustäbel01385812010-03-03 12:08:54 +00002438
2439
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002440@unittest.skipIf(hasattr(os, "link"), "requires os.link to be missing")
2441class LinkEmulationTest(ReadTest, unittest.TestCase):
Lars Gustäbel1b512722010-06-03 12:45:16 +00002442
2443 # Test for issue #8741 regression. On platforms that do not support
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002444 # symbolic or hard links tarfile tries to extract these types of members
2445 # as the regular files they point to.
Lars Gustäbel1b512722010-06-03 12:45:16 +00002446 def _test_link_extraction(self, name):
2447 self.tar.extract(name, TEMPDIR)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002448 with open(os.path.join(TEMPDIR, name), "rb") as f:
2449 data = f.read()
Miss Islington (bot)66cd0412019-09-25 08:50:31 -07002450 self.assertEqual(sha256sum(data), sha256_regtype)
Lars Gustäbel1b512722010-06-03 12:45:16 +00002451
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002452 # See issues #1578269, #8879, and #17689 for some history on these skips
Brian Curtind40e6f72010-07-08 21:39:08 +00002453 @unittest.skipIf(hasattr(os.path, "islink"),
2454 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002455 def test_hardlink_extraction1(self):
2456 self._test_link_extraction("ustar/lnktype")
2457
Brian Curtind40e6f72010-07-08 21:39:08 +00002458 @unittest.skipIf(hasattr(os.path, "islink"),
2459 "Skip emulation - has os.path.islink but not os.link")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002460 def test_hardlink_extraction2(self):
2461 self._test_link_extraction("./ustar/linktest2/lnktype")
2462
Brian Curtin74e45612010-07-09 15:58:59 +00002463 @unittest.skipIf(hasattr(os, "symlink"),
2464 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002465 def test_symlink_extraction1(self):
2466 self._test_link_extraction("ustar/symtype")
2467
Brian Curtin74e45612010-07-09 15:58:59 +00002468 @unittest.skipIf(hasattr(os, "symlink"),
2469 "Skip emulation if symlink exists")
Lars Gustäbel1b512722010-06-03 12:45:16 +00002470 def test_symlink_extraction2(self):
2471 self._test_link_extraction("./ustar/linktest2/symtype")
2472
2473
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002474class Bz2PartialReadTest(Bz2Test, unittest.TestCase):
Lars Gustäbel42e00912009-03-22 20:34:29 +00002475 # Issue5068: The _BZ2Proxy.read() method loops forever
2476 # on an empty or partial bzipped file.
2477
2478 def _test_partial_input(self, mode):
2479 class MyBytesIO(io.BytesIO):
2480 hit_eof = False
2481 def read(self, n):
2482 if self.hit_eof:
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002483 raise AssertionError("infinite loop detected in "
2484 "tarfile.open()")
Lars Gustäbel42e00912009-03-22 20:34:29 +00002485 self.hit_eof = self.tell() == len(self.getvalue())
2486 return super(MyBytesIO, self).read(n)
Lars Gustäbel9520a432009-11-22 18:48:49 +00002487 def seek(self, *args):
2488 self.hit_eof = False
2489 return super(MyBytesIO, self).seek(*args)
Lars Gustäbel42e00912009-03-22 20:34:29 +00002490
2491 data = bz2.compress(tarfile.TarInfo("foo").tobuf())
2492 for x in range(len(data) + 1):
Lars Gustäbel9520a432009-11-22 18:48:49 +00002493 try:
2494 tarfile.open(fileobj=MyBytesIO(data[:x]), mode=mode)
2495 except tarfile.ReadError:
2496 pass # we have no interest in ReadErrors
Lars Gustäbel42e00912009-03-22 20:34:29 +00002497
2498 def test_partial_input(self):
2499 self._test_partial_input("r")
2500
2501 def test_partial_input_bz2(self):
2502 self._test_partial_input("r:bz2")
2503
2504
Eric V. Smith7a803892015-04-15 10:27:58 -04002505def root_is_uid_gid_0():
2506 try:
2507 import pwd, grp
2508 except ImportError:
2509 return False
2510 if pwd.getpwuid(0)[0] != 'root':
2511 return False
2512 if grp.getgrgid(0)[0] != 'root':
2513 return False
2514 return True
2515
2516
Zachary Waread3e27a2015-05-12 23:57:21 -05002517@unittest.skipUnless(hasattr(os, 'chown'), "missing os.chown")
2518@unittest.skipUnless(hasattr(os, 'geteuid'), "missing os.geteuid")
Eric V. Smith7a803892015-04-15 10:27:58 -04002519class NumericOwnerTest(unittest.TestCase):
2520 # mock the following:
2521 # os.chown: so we can test what's being called
2522 # os.chmod: so the modes are not actually changed. if they are, we can't
2523 # delete the files/directories
2524 # os.geteuid: so we can lie and say we're root (uid = 0)
2525
2526 @staticmethod
2527 def _make_test_archive(filename_1, dirname_1, filename_2):
2528 # the file contents to write
2529 fobj = io.BytesIO(b"content")
2530
2531 # create a tar file with a file, a directory, and a file within that
2532 # directory. Assign various .uid/.gid values to them
2533 items = [(filename_1, 99, 98, tarfile.REGTYPE, fobj),
2534 (dirname_1, 77, 76, tarfile.DIRTYPE, None),
2535 (filename_2, 88, 87, tarfile.REGTYPE, fobj),
2536 ]
2537 with tarfile.open(tmpname, 'w') as tarfl:
2538 for name, uid, gid, typ, contents in items:
2539 t = tarfile.TarInfo(name)
2540 t.uid = uid
2541 t.gid = gid
2542 t.uname = 'root'
2543 t.gname = 'root'
2544 t.type = typ
2545 tarfl.addfile(t, contents)
2546
2547 # return the full pathname to the tar file
2548 return tmpname
2549
2550 @staticmethod
2551 @contextmanager
2552 def _setup_test(mock_geteuid):
2553 mock_geteuid.return_value = 0 # lie and say we're root
2554 fname = 'numeric-owner-testfile'
2555 dirname = 'dir'
2556
2557 # the names we want stored in the tarfile
2558 filename_1 = fname
2559 dirname_1 = dirname
2560 filename_2 = os.path.join(dirname, fname)
2561
2562 # create the tarfile with the contents we're after
2563 tar_filename = NumericOwnerTest._make_test_archive(filename_1,
2564 dirname_1,
2565 filename_2)
2566
2567 # open the tarfile for reading. yield it and the names of the items
2568 # we stored into the file
2569 with tarfile.open(tar_filename) as tarfl:
2570 yield tarfl, filename_1, dirname_1, filename_2
2571
2572 @unittest.mock.patch('os.chown')
2573 @unittest.mock.patch('os.chmod')
2574 @unittest.mock.patch('os.geteuid')
2575 def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod,
2576 mock_chown):
2577 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _,
2578 filename_2):
2579 tarfl.extract(filename_1, TEMPDIR, numeric_owner=True)
2580 tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True)
2581
2582 # convert to filesystem paths
2583 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2584 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2585
2586 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2587 unittest.mock.call(f_filename_2, 88, 87),
2588 ],
2589 any_order=True)
2590
2591 @unittest.mock.patch('os.chown')
2592 @unittest.mock.patch('os.chmod')
2593 @unittest.mock.patch('os.geteuid')
2594 def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod,
2595 mock_chown):
2596 with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1,
2597 filename_2):
2598 tarfl.extractall(TEMPDIR, numeric_owner=True)
2599
2600 # convert to filesystem paths
2601 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2602 f_dirname_1 = os.path.join(TEMPDIR, dirname_1)
2603 f_filename_2 = os.path.join(TEMPDIR, filename_2)
2604
2605 mock_chown.assert_has_calls([unittest.mock.call(f_filename_1, 99, 98),
2606 unittest.mock.call(f_dirname_1, 77, 76),
2607 unittest.mock.call(f_filename_2, 88, 87),
2608 ],
2609 any_order=True)
2610
2611 # this test requires that uid=0 and gid=0 really be named 'root'. that's
2612 # because the uname and gname in the test file are 'root', and extract()
2613 # will look them up using pwd and grp to find their uid and gid, which we
2614 # test here to be 0.
2615 @unittest.skipUnless(root_is_uid_gid_0(),
2616 'uid=0,gid=0 must be named "root"')
2617 @unittest.mock.patch('os.chown')
2618 @unittest.mock.patch('os.chmod')
2619 @unittest.mock.patch('os.geteuid')
2620 def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod,
2621 mock_chown):
2622 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2623 tarfl.extract(filename_1, TEMPDIR, numeric_owner=False)
2624
2625 # convert to filesystem paths
2626 f_filename_1 = os.path.join(TEMPDIR, filename_1)
2627
2628 mock_chown.assert_called_with(f_filename_1, 0, 0)
2629
2630 @unittest.mock.patch('os.geteuid')
2631 def test_keyword_only(self, mock_geteuid):
2632 with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
2633 self.assertRaises(TypeError,
2634 tarfl.extract, filename_1, TEMPDIR, False, True)
2635
2636
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002637def setUpModule():
Antoine Pitrou95f55602010-09-23 18:36:46 +00002638 support.unlink(TEMPDIR)
Antoine Pitrou941ee882009-11-11 20:59:38 +00002639 os.makedirs(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002640
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002641 global testtarnames
2642 testtarnames = [tarname]
Antoine Pitrou95f55602010-09-23 18:36:46 +00002643 with open(tarname, "rb") as fobj:
2644 data = fobj.read()
Neal Norwitza4f651a2004-07-20 22:07:44 +00002645
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002646 # Create compressed tarfiles.
2647 for c in GzipTest, Bz2Test, LzmaTest:
2648 if c.open:
2649 support.unlink(c.tarname)
Serhiy Storchaka5e8c8092013-11-24 02:30:59 +02002650 testtarnames.append(c.tarname)
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002651 with c.open(c.tarname, "wb") as tar:
2652 tar.write(data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002653
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002654def tearDownModule():
2655 if os.path.exists(TEMPDIR):
Tim Goldene0bd2c52014-05-06 13:24:26 +01002656 support.rmtree(TEMPDIR)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00002657
Neal Norwitz996acf12003-02-17 14:51:41 +00002658if __name__ == "__main__":
Serhiy Storchaka8b562922013-06-17 15:38:50 +03002659 unittest.main()