Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(48990)

Delta Between Two Patch Sets: Lib/test/test_tarfile.py

Issue 19974: tarfile doesn't overwrite symlink by directory
Left Patch Set: Created 5 years, 8 months ago
Right Patch Set: Created 5 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« Lib/tarfile.py ('K') | « Lib/tarfile.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 import sys 1 import sys
2 import os 2 import os
3 import io 3 import io
4 import shutil 4 import shutil
5 import errno
5 from hashlib import md5 6 from hashlib import md5
6 7
7 import unittest 8 import unittest
8 import tarfile 9 import tarfile
9 10
10 from test import support, script_helper 11 from test import support, script_helper
11 12
12 # Check for our compression modules. 13 # Check for our compression modules.
13 try: 14 try:
14 import gzip 15 import gzip
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 class GzipUstarReadTest(GzipTest, UstarReadTest): 213 class GzipUstarReadTest(GzipTest, UstarReadTest):
213 pass 214 pass
214 215
215 class Bz2UstarReadTest(Bz2Test, UstarReadTest): 216 class Bz2UstarReadTest(Bz2Test, UstarReadTest):
216 pass 217 pass
217 218
218 class LzmaUstarReadTest(LzmaTest, UstarReadTest): 219 class LzmaUstarReadTest(LzmaTest, UstarReadTest):
219 pass 220 pass
220 221
221 222
223 class ListTest(ReadTest, unittest.TestCase):
224
225 # Override setUp to use default encoding (UTF-8)
226 def setUp(self):
227 self.tar = tarfile.open(self.tarname, mode=self.mode)
228
229 def test_list(self):
230 tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
231 with support.swap_attr(sys, 'stdout', tio):
232 self.tar.list(verbose=False)
233 out = tio.detach().getvalue()
234 self.assertIn(b'ustar/conttype', out)
235 self.assertIn(b'ustar/regtype', out)
236 self.assertIn(b'ustar/lnktype', out)
237 self.assertIn(b'ustar' + (b'/12345' * 40) + b'67/longname', out)
238 self.assertIn(b'./ustar/linktest2/symtype', out)
239 self.assertIn(b'./ustar/linktest2/lnktype', out)
240 # Make sure it puts trailing slash for directory
241 self.assertIn(b'ustar/dirtype/', out)
242 self.assertIn(b'ustar/dirtype-with-size/', out)
243 # Make sure it is able to print unencodable characters
244 def conv(b):
245 s = b.decode(self.tar.encoding, 'surrogateescape')
246 return s.encode('ascii', 'backslashreplace')
247 self.assertIn(conv(b'ustar/umlauts-\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out)
248 self.assertIn(conv(b'misc/regtype-hpux-signed-chksum-'
249 b'\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out)
250 self.assertIn(conv(b'misc/regtype-old-v7-signed-chksum-'
251 b'\xc4\xd6\xdc\xe4\xf6\xfc\xdf'), out)
252 self.assertIn(conv(b'pax/bad-pax-\xe4\xf6\xfc'), out)
253 self.assertIn(conv(b'pax/hdrcharset-\xe4\xf6\xfc'), out)
254 # Make sure it prints files separated by one newline without any
255 # 'ls -l'-like accessories if verbose flag is not being used
256 # ...
257 # ustar/conttype
258 # ustar/regtype
259 # ...
260 self.assertRegex(out, br'ustar/conttype ?\r?\n'
261 br'ustar/regtype ?\r?\n')
262 # Make sure it does not print the source of link without verbose flag
263 self.assertNotIn(b'link to', out)
264 self.assertNotIn(b'->', out)
265
266 def test_list_verbose(self):
267 tio = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
268 with support.swap_attr(sys, 'stdout', tio):
269 self.tar.list(verbose=True)
270 out = tio.detach().getvalue()
271 # Make sure it prints files separated by one newline with 'ls -l'-like
272 # accessories if verbose flag is being used
273 # ...
274 # ?rw-r--r-- tarfile/tarfile 7011 2003-01-06 07:19:43 ustar/conttype
275 # ?rw-r--r-- tarfile/tarfile 7011 2003-01-06 07:19:43 ustar/regtype
276 # ...
277 self.assertRegex(out, (br'\?rw-r--r-- tarfile/tarfile\s+7011 '
278 br'\d{4}-\d\d-\d\d\s+\d\d:\d\d:\d\d '
279 br'ustar/\w+type ?\r?\n') * 2)
280 # Make sure it prints the source of link with verbose flag
281 self.assertIn(b'ustar/symtype -> regtype', out)
282 self.assertIn(b'./ustar/linktest2/symtype -> ../linktest1/regtype', out)
283 self.assertIn(b'./ustar/linktest2/lnktype link to '
284 b'./ustar/linktest1/regtype', out)
285 self.assertIn(b'gnu' + (b'/123' * 125) + b'/longlink link to gnu' +
286 (b'/123' * 125) + b'/longname', out)
287 self.assertIn(b'pax' + (b'/123' * 125) + b'/longlink link to pax' +
288 (b'/123' * 125) + b'/longname', out)
289
290
291 class GzipListTest(GzipTest, ListTest):
292 pass
293
294
295 class Bz2ListTest(Bz2Test, ListTest):
296 pass
297
298
299 class LzmaListTest(LzmaTest, ListTest):
300 pass
301
302
222 class CommonReadTest(ReadTest): 303 class CommonReadTest(ReadTest):
223 304
224 def test_empty_tarfile(self): 305 def test_empty_tarfile(self):
225 # Test for issue6123: Allow opening empty archives. 306 # Test for issue6123: Allow opening empty archives.
226 # This test checks if tarfile.open() is able to open an empty tar 307 # This test checks if tarfile.open() is able to open an empty tar
227 # archive successfully. Note that an empty tar archive is not the 308 # archive successfully. Note that an empty tar archive is not the
228 # same as an empty file! 309 # same as an empty file!
229 with tarfile.open(tmpname, self.mode.replace("r", "w")): 310 with tarfile.open(tmpname, self.mode.replace("r", "w")):
230 pass 311 pass
231 try: 312 try:
(...skipping 843 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 finally: 1156 finally:
1076 tar.close() 1157 tar.close()
1077 1158
1078 if not dir: 1159 if not dir:
1079 os.remove(foo) 1160 os.remove(foo)
1080 else: 1161 else:
1081 os.rmdir(foo) 1162 os.rmdir(foo)
1082 1163
1083 self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/")) 1164 self.assertEqual(t.name, cmp_path or path.replace(os.sep, "/"))
1084 1165
1166 def test_extractall_current_directory(self):
1167 tempdir = os.path.join(TEMPDIR, "testcurdir")
1168 temparchive = os.path.join(TEMPDIR, "testcurdir.tar")
1169 os.mkdir(tempdir)
1170 try:
1171 source_file = os.path.join(tempdir, 'source')
1172 with open(source_file,'w') as f:
1173 f.write('source file content\n')
1174 tar = tarfile.open(temparchive,'w')
1175 try:
1176 # We don't want to add absolute path to tar file because
1177 # we don't want nested directory after extracting the file.
1178 with support.change_cwd(tempdir):
1179 tar.add('./')
1180 finally:
1181 tar.close()
1182 os.remove(source_file)
1183 tar = tarfile.open(temparchive,'r')
1184 try:
1185 tar.extractall(path=tempdir)
1186 with open(source_file) as f:
1187 self.assertEqual(f.read(), 'source file content\n')
1188 except OSError:
1189 self.fail("extractall failed with ./ file")
1190 finally:
1191 tar.close()
1192 finally:
1193 os.unlink(temparchive)
1194 shutil.rmtree(tempdir)
1195
1196 def test_extractall_non_directory_overwrites_directory(self):
1197 tempdir = os.path.join(TEMPDIR, "testnotdiroverwritesdir")
1198 temparchive = os.path.join(TEMPDIR, "testnotdiroverwritesdir.tar")
1199 os.mkdir(tempdir)
1200 try:
1201 source_file = os.path.join(tempdir, 'source')
1202 with open(source_file,'w') as f:
1203 f.write('source file content\n')
1204 tar = tarfile.open(temparchive,'w')
Claudiu.Popa 2014/03/19 19:14:17 I guess the code could be simpler if you use conte
1205 try:
1206 # We don't want to add absolute path to tar file because
1207 # we don't want nested directory after extracting the file.
1208 with support.change_cwd(tempdir):
1209 tar.add('source')
1210 finally:
1211 tar.close()
1212 os.remove(source_file)
1213 os.mkdir(source_file)
1214 tar = tarfile.open(temparchive,'r')
1215 try:
1216 tar.extractall(path=tempdir)
1217 # Non-directory file should be able to overwrites empty
1218 # directory
1219 with open(source_file) as f:
1220 self.assertEqual(f.read(), 'source file content\n')
1221 except OSError:
1222 self.fail("extractall failed with non-directory files")
1223 finally:
1224 tar.close()
1225 os.remove(source_file)
1226 os.mkdir(source_file)
1227 os.mkdir(os.path.join(source_file, 'inner_source'))
1228 tar = tarfile.open(temparchive,'r')
1229 try:
1230 tar.extractall(path=tempdir)
1231 # Non-directory file should not be able to overwrites non-empty
1232 # directory
1233 self.fail("extractall failed with file overwriting non-empty "
1234 "directory")
1235 # This should raise OSError: [Errno 21] Is a directory
1236 except OSError as e:
1237 self.assertEqual(e.errno, errno.EISDIR)
1238 finally:
1239 tar.close()
1240 finally:
1241 os.unlink(temparchive)
1242 shutil.rmtree(tempdir)
1243
1244 def test_extractall_not_empty_directory(self):
1245 tempdir = os.path.join(TEMPDIR, "testnotemptydir")
1246 temparchive = os.path.join(TEMPDIR, "testnotemptydir.tar")
1247 os.mkdir(tempdir)
1248 try:
1249 dir_A = os.path.join(tempdir, 'A')
1250 dir_B = os.path.join(tempdir, 'B')
1251 dir_C = os.path.join(dir_A, 'C')
1252 os.mkdir(dir_A)
1253 os.mkdir(dir_B)
1254 os.mkdir(dir_C)
1255 tar = tarfile.open(temparchive,'w')
1256 try:
1257 # We don't want to add absolute path to tar file because
1258 # we don't want nested directory after extracting the file.
1259 with support.change_cwd(tempdir):
1260 tar.add('A')
1261 tar.add('B')
1262 finally:
1263 tar.close()
1264 os.rmdir(dir_C)
1265 dir_D = os.path.join(dir_A, 'D')
1266 os.mkdir(dir_D)
1267 tar = tarfile.open(temparchive,'r')
1268 try:
1269 tar.extractall(path=tempdir)
1270 self.assertEqual(sorted(os.listdir(dir_A)), ['C', 'D'])
1271 except OSError:
1272 self.fail("extractall failed with not empty directory")
1273 finally:
1274 tar.close()
1275 finally:
1276 os.unlink(temparchive)
1277 shutil.rmtree(tempdir)
1085 1278
1086 @support.skip_unless_symlink 1279 @support.skip_unless_symlink
1087 def test_extractall_symlinks(self): 1280 def test_extractall_symlinks(self):
1088 # Test if extractall works properly when tarfile contains symlinks 1281 # Test if extractall works properly when tarfile contains symlinks
1089 tempdir = os.path.join(TEMPDIR, "testsymlinks") 1282 tempdir = os.path.join(TEMPDIR, "testsymlinks")
1090 temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") 1283 temparchive = os.path.join(TEMPDIR, "testsymlinks.tar")
1091 os.mkdir(tempdir) 1284 os.mkdir(tempdir)
1092 try: 1285 try:
1093 # File symlink 1286 # File symlink
1094 source_file = os.path.join(tempdir, 'source') 1287 source_file = os.path.join(tempdir, 'source')
(...skipping 696 matching lines...) Expand 10 before | Expand all | Expand 10 after
1791 with self.assertRaises(ValueError): 1984 with self.assertRaises(ValueError):
1792 tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT) 1985 tarfile.itn(0o10000000, 8, tarfile.USTAR_FORMAT)
1793 with self.assertRaises(ValueError): 1986 with self.assertRaises(ValueError):
1794 tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT) 1987 tarfile.itn(-0x10000000001, 6, tarfile.GNU_FORMAT)
1795 with self.assertRaises(ValueError): 1988 with self.assertRaises(ValueError):
1796 tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT) 1989 tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT)
1797 1990
1798 1991
1799 class CommandLineTest(unittest.TestCase): 1992 class CommandLineTest(unittest.TestCase):
1800 1993
1801 def tarfilecmd(self, *args): 1994 def tarfilecmd(self, *args, **kwargs):
1802 rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args) 1995 rc, out, err = script_helper.assert_python_ok('-m', 'tarfile', *args,
1996 **kwargs)
1803 return out.replace(os.linesep.encode(), b'\n') 1997 return out.replace(os.linesep.encode(), b'\n')
1804 1998
1805 def tarfilecmd_failure(self, *args): 1999 def tarfilecmd_failure(self, *args):
1806 return script_helper.assert_python_failure('-m', 'tarfile', *args) 2000 return script_helper.assert_python_failure('-m', 'tarfile', *args)
1807 2001
1808 def make_simple_tarfile(self, tar_name): 2002 def make_simple_tarfile(self, tar_name):
1809 files = [support.findfile('tokenize_tests.txt'), 2003 files = [support.findfile('tokenize_tests.txt'),
1810 support.findfile('tokenize_tests-no-coding-cookie-' 2004 support.findfile('tokenize_tests-no-coding-cookie-'
1811 'and-utf8-bom-sig-only.txt')] 2005 'and-utf8-bom-sig-only.txt')]
1812 self.addCleanup(support.unlink, tar_name) 2006 self.addCleanup(support.unlink, tar_name)
(...skipping 27 matching lines...) Expand all
1840 try: 2034 try:
1841 with open(tmpname, 'wb') as f: 2035 with open(tmpname, 'wb') as f:
1842 f.write(data[:511]) 2036 f.write(data[:511])
1843 rc, out, err = self.tarfilecmd_failure('-t', tmpname) 2037 rc, out, err = self.tarfilecmd_failure('-t', tmpname)
1844 self.assertEqual(out, b'') 2038 self.assertEqual(out, b'')
1845 self.assertEqual(rc, 1) 2039 self.assertEqual(rc, 1)
1846 finally: 2040 finally:
1847 support.unlink(tmpname) 2041 support.unlink(tmpname)
1848 2042
1849 def test_list_command(self): 2043 def test_list_command(self):
1850 self.make_simple_tarfile(tmpname) 2044 for tar_name in testtarnames:
1851 with support.captured_stdout() as t: 2045 with support.captured_stdout() as t:
1852 with tarfile.open(tmpname, 'r') as tf: 2046 with tarfile.open(tar_name, 'r') as tf:
1853 tf.list(verbose=False) 2047 tf.list(verbose=False)
1854 expected = t.getvalue().encode(sys.getfilesystemencoding()) 2048 expected = t.getvalue().encode('ascii', 'backslashreplace')
1855 for opt in '-l', '--list': 2049 for opt in '-l', '--list':
1856 out = self.tarfilecmd(opt, tmpname) 2050 out = self.tarfilecmd(opt, tar_name,
1857 self.assertEqual(out, expected) 2051 PYTHONIOENCODING='ascii')
2052 self.assertEqual(out, expected)
1858 2053
1859 def test_list_command_verbose(self): 2054 def test_list_command_verbose(self):
1860 self.make_simple_tarfile(tmpname) 2055 for tar_name in testtarnames:
1861 with support.captured_stdout() as t: 2056 with support.captured_stdout() as t:
1862 with tarfile.open(tmpname, 'r') as tf: 2057 with tarfile.open(tar_name, 'r') as tf:
1863 tf.list(verbose=True) 2058 tf.list(verbose=True)
1864 expected = t.getvalue().encode(sys.getfilesystemencoding()) 2059 expected = t.getvalue().encode('ascii', 'backslashreplace')
1865 for opt in '-v', '--verbose': 2060 for opt in '-v', '--verbose':
1866 out = self.tarfilecmd(opt, '-l', tmpname) 2061 out = self.tarfilecmd(opt, '-l', tar_name,
1867 self.assertEqual(out, expected) 2062 PYTHONIOENCODING='ascii')
2063 self.assertEqual(out, expected)
1868 2064
1869 def test_list_command_invalid_file(self): 2065 def test_list_command_invalid_file(self):
1870 zipname = support.findfile('zipdir.zip') 2066 zipname = support.findfile('zipdir.zip')
1871 rc, out, err = self.tarfilecmd_failure('-l', zipname) 2067 rc, out, err = self.tarfilecmd_failure('-l', zipname)
1872 self.assertIn(b' is not a tar archive.', err) 2068 self.assertIn(b' is not a tar archive.', err)
1873 self.assertEqual(out, b'') 2069 self.assertEqual(out, b'')
1874 self.assertEqual(rc, 1) 2070 self.assertEqual(rc, 1)
1875 2071
1876 def test_create_command(self): 2072 def test_create_command(self):
1877 files = [support.findfile('tokenize_tests.txt'), 2073 files = [support.findfile('tokenize_tests.txt'),
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
2097 testtarnames.append(c.tarname) 2293 testtarnames.append(c.tarname)
2098 with c.open(c.tarname, "wb") as tar: 2294 with c.open(c.tarname, "wb") as tar:
2099 tar.write(data) 2295 tar.write(data)
2100 2296
2101 def tearDownModule(): 2297 def tearDownModule():
2102 if os.path.exists(TEMPDIR): 2298 if os.path.exists(TEMPDIR):
2103 shutil.rmtree(TEMPDIR) 2299 shutil.rmtree(TEMPDIR)
2104 2300
2105 if __name__ == "__main__": 2301 if __name__ == "__main__":
2106 unittest.main() 2302 unittest.main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+