mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00

svn+ssh://pythondev@svn.python.org/python/branches/p3yk ................ r55636 | neal.norwitz | 2007-05-29 00:06:39 -0700 (Tue, 29 May 2007) | 149 lines Merged revisions 55506-55635 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r55507 | georg.brandl | 2007-05-22 07:28:17 -0700 (Tue, 22 May 2007) | 2 lines Remove the "panel" module doc file which has been ignored since 1994. ........ r55522 | mark.hammond | 2007-05-22 19:04:28 -0700 (Tue, 22 May 2007) | 4 lines Remove definition of PY_UNICODE_TYPE from pyconfig.h, allowing the definition in unicodeobject.h to be used, giving us the desired wchar_t in place of 'unsigned short'. As discussed on python-dev. ........ r55525 | neal.norwitz | 2007-05-22 23:35:32 -0700 (Tue, 22 May 2007) | 6 lines Add -3 option to the interpreter to warn about features that are deprecated and will be changed/removed in Python 3.0. This patch is mostly from Anthony. I tweaked some format and added a little doc. ........ r55527 | neal.norwitz | 2007-05-22 23:57:35 -0700 (Tue, 22 May 2007) | 1 line Whitespace cleanup ........ r55528 | neal.norwitz | 2007-05-22 23:58:36 -0700 (Tue, 22 May 2007) | 1 line Add a bunch more deprecation warnings for builtins that are going away in 3.0 ........ r55549 | georg.brandl | 2007-05-24 09:49:29 -0700 (Thu, 24 May 2007) | 2 lines shlex.split() now has an optional "posix" parameter. ........ r55550 | georg.brandl | 2007-05-24 10:33:33 -0700 (Thu, 24 May 2007) | 2 lines Fix parameter passing. ........ r55555 | facundo.batista | 2007-05-24 10:50:54 -0700 (Thu, 24 May 2007) | 6 lines Added an optional timeout parameter to urllib.ftpwrapper, with tests (for this and a basic one, because there weren't any). Changed also NEWS, but didn't find documentation for this function, assumed it wasn't public... ........ r55563 | facundo.batista | 2007-05-24 13:01:59 -0700 (Thu, 24 May 2007) | 4 lines Removed the .recv() in the test, is not necessary, and was causing problems that didn't have anything to do with was actually being tested... ........ r55564 | facundo.batista | 2007-05-24 13:51:19 -0700 (Thu, 24 May 2007) | 5 lines Let's see if reading exactly what is written allow this live test to pass (now I know why there were so few tests in ftp, http, etc, :( ). ........ r55567 | facundo.batista | 2007-05-24 20:10:28 -0700 (Thu, 24 May 2007) | 4 lines Trying to make the tests work in Windows and Solaris, everywhere else just works ........ r55568 | facundo.batista | 2007-05-24 20:47:19 -0700 (Thu, 24 May 2007) | 4 lines Fixing stupid error, and introducing a sleep, to see if the other thread is awakened and finish sending data. ........ r55569 | facundo.batista | 2007-05-24 21:20:22 -0700 (Thu, 24 May 2007) | 4 lines Commenting out the tests until find out who can test them in one of the problematic enviroments. ........ r55570 | neal.norwitz | 2007-05-24 22:13:40 -0700 (Thu, 24 May 2007) | 2 lines Get test passing again by commenting out the reference to the test class. ........ r55575 | vinay.sajip | 2007-05-25 00:05:59 -0700 (Fri, 25 May 2007) | 1 line Updated docstring for SysLogHandler (#1720726). ........ r55576 | vinay.sajip | 2007-05-25 00:06:55 -0700 (Fri, 25 May 2007) | 1 line Updated documentation for SysLogHandler (#1720726). ........ r55592 | brett.cannon | 2007-05-25 13:17:15 -0700 (Fri, 25 May 2007) | 3 lines Remove direct call's to file's constructor and replace them with calls to open() as ths is considered best practice. ........ r55601 | kristjan.jonsson | 2007-05-26 12:19:50 -0700 (Sat, 26 May 2007) | 1 line Remove the rgbimgmodule from PCBuild8 ........ r55602 | kristjan.jonsson | 2007-05-26 12:31:39 -0700 (Sat, 26 May 2007) | 1 line Include <windows.h> after python.h, so that WINNT is properly set before windows.h is included. Fixes warnings in PC builds. ........ r55603 | walter.doerwald | 2007-05-26 14:04:13 -0700 (Sat, 26 May 2007) | 2 lines Fix typo. ........ r55604 | peter.astrand | 2007-05-26 15:18:20 -0700 (Sat, 26 May 2007) | 1 line Applied patch 1669481, slightly modified: Support close_fds on Win32 ........ r55606 | neal.norwitz | 2007-05-26 21:08:54 -0700 (Sat, 26 May 2007) | 2 lines Add the new function object attribute names from py3k. ........ r55617 | lars.gustaebel | 2007-05-27 12:49:30 -0700 (Sun, 27 May 2007) | 20 lines Added errors argument to TarFile class that allows the user to specify an error handling scheme for character conversion. Additional scheme "utf-8" in read mode. Unicode input filenames are now supported by design. The values of the pax_headers dictionary are now limited to unicode objects. Fixed: The prefix field is no longer used in PAX_FORMAT (in conformance with POSIX). Fixed: In read mode use a possible pax header size field. Fixed: Strip trailing slashes from pax header name values. Fixed: Give values in user-specified pax_headers precedence when writing. Added unicode tests. Added pax/regtype4 member to testtar.tar all possible number fields in a pax header. Added two chapters to the documentation about the different formats tarfile.py supports and how unicode issues are handled. ........ r55618 | raymond.hettinger | 2007-05-27 22:23:22 -0700 (Sun, 27 May 2007) | 1 line Explain when groupby() issues a new group. ........ r55634 | martin.v.loewis | 2007-05-28 21:01:29 -0700 (Mon, 28 May 2007) | 2 lines Test pre-commit hook for a link to a .py file. ........ r55635 | martin.v.loewis | 2007-05-28 21:02:03 -0700 (Mon, 28 May 2007) | 2 lines Revert 55634. ........ ................ r55639 | neal.norwitz | 2007-05-29 00:58:11 -0700 (Tue, 29 May 2007) | 1 line Remove sys.exc_{type,exc_value,exc_traceback} ................ r55641 | neal.norwitz | 2007-05-29 01:03:50 -0700 (Tue, 29 May 2007) | 1 line Missed one sys.exc_type. I wonder why exc_{value,traceback} were already gone ................ r55642 | neal.norwitz | 2007-05-29 01:08:33 -0700 (Tue, 29 May 2007) | 1 line Missed more doc for sys.exc_* attrs. ................ r55643 | neal.norwitz | 2007-05-29 01:18:19 -0700 (Tue, 29 May 2007) | 1 line Remove sys.exc_clear() ................ r55665 | guido.van.rossum | 2007-05-29 19:45:43 -0700 (Tue, 29 May 2007) | 4 lines Make None, True, False keywords. We can now also delete all the other places that explicitly forbid assignment to None, but I'm not going to bother right now. ................ r55666 | guido.van.rossum | 2007-05-29 20:01:51 -0700 (Tue, 29 May 2007) | 3 lines Found another place that needs check for forbidden names. Fixed test_syntax.py accordingly (it helped me find that one). ................ r55668 | guido.van.rossum | 2007-05-29 20:41:48 -0700 (Tue, 29 May 2007) | 2 lines Mark None, True, False as keywords. ................ r55673 | neal.norwitz | 2007-05-29 23:28:25 -0700 (Tue, 29 May 2007) | 3 lines Get the dis module working on modules again after changing dicts to not return lists and also new-style classes. Add a test. ................ r55674 | neal.norwitz | 2007-05-29 23:35:45 -0700 (Tue, 29 May 2007) | 1 line Umm, it helps to add the module that the test uses ................ r55675 | neal.norwitz | 2007-05-29 23:53:05 -0700 (Tue, 29 May 2007) | 4 lines Try to fix up all the other places that were assigning to True/False. There's at least one more problem in test.test_xmlrpc. I have other changes in that file and that should be fixed soon (I hope). ................ r55679 | neal.norwitz | 2007-05-30 00:31:55 -0700 (Wed, 30 May 2007) | 1 line Fix up another place that was assigning to True/False. ................ r55688 | brett.cannon | 2007-05-30 14:19:47 -0700 (Wed, 30 May 2007) | 2 lines Ditch MimeWriter. ................ r55692 | brett.cannon | 2007-05-30 14:52:00 -0700 (Wed, 30 May 2007) | 2 lines Remove the mimify module. ................ r55707 | guido.van.rossum | 2007-05-31 05:08:45 -0700 (Thu, 31 May 2007) | 2 lines Backport the addition of show_code() to dis.py -- it's too handy. ................ r55708 | guido.van.rossum | 2007-05-31 06:22:57 -0700 (Thu, 31 May 2007) | 7 lines Fix a fairly long-standing bug in the check for assignment to None (and other keywords, these days). In 2.5, you could write foo(None=1) without getting a SyntaxError (although foo()'s definition would have to use **kwds to avoid getting a runtime error complaining about an unknown keyword of course). This ought to be backported to 2.5.2 or at least 2.6. ................ r55724 | brett.cannon | 2007-05-31 19:32:41 -0700 (Thu, 31 May 2007) | 2 lines Remove the cfmfile. ................ r55727 | neal.norwitz | 2007-05-31 22:19:44 -0700 (Thu, 31 May 2007) | 1 line Remove reload() builtin. ................ r55729 | neal.norwitz | 2007-05-31 22:51:30 -0700 (Thu, 31 May 2007) | 59 lines Merged revisions 55636-55728 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r55637 | georg.brandl | 2007-05-29 00:16:47 -0700 (Tue, 29 May 2007) | 2 lines Fix rst markup. ........ r55638 | neal.norwitz | 2007-05-29 00:51:39 -0700 (Tue, 29 May 2007) | 1 line Fix typo in doc ........ r55671 | neal.norwitz | 2007-05-29 21:53:41 -0700 (Tue, 29 May 2007) | 1 line Fix indentation (whitespace only). ........ r55676 | thomas.heller | 2007-05-29 23:58:30 -0700 (Tue, 29 May 2007) | 1 line Fix compiler warnings. ........ r55677 | thomas.heller | 2007-05-30 00:01:25 -0700 (Wed, 30 May 2007) | 2 lines Correct the name of a field in the WIN32_FIND_DATAA and WIN32_FIND_DATAW structures. Closes bug #1726026. ........ r55686 | brett.cannon | 2007-05-30 13:46:26 -0700 (Wed, 30 May 2007) | 2 lines Have MimeWriter raise a DeprecationWarning as per PEP 4 and its documentation. ........ r55690 | brett.cannon | 2007-05-30 14:48:58 -0700 (Wed, 30 May 2007) | 3 lines Have mimify raise a DeprecationWarning. The docs and PEP 4 have listed the module as deprecated for a while. ........ r55696 | brett.cannon | 2007-05-30 15:24:28 -0700 (Wed, 30 May 2007) | 2 lines Have md5 raise a DeprecationWarning as per PEP 4. ........ r55705 | neal.norwitz | 2007-05-30 21:14:22 -0700 (Wed, 30 May 2007) | 1 line Add some spaces in the example code. ........ r55716 | brett.cannon | 2007-05-31 12:20:00 -0700 (Thu, 31 May 2007) | 2 lines Have the sha module raise a DeprecationWarning as specified in PEP 4. ........ r55719 | brett.cannon | 2007-05-31 12:40:42 -0700 (Thu, 31 May 2007) | 2 lines Cause buildtools to raise a DeprecationWarning. ........ r55721 | brett.cannon | 2007-05-31 13:01:11 -0700 (Thu, 31 May 2007) | 2 lines Have cfmfile raise a DeprecationWarning as per PEP 4. ........ r55726 | neal.norwitz | 2007-05-31 21:56:47 -0700 (Thu, 31 May 2007) | 1 line Mail if there is an installation failure. ........ ................ r55730 | neal.norwitz | 2007-05-31 23:22:07 -0700 (Thu, 31 May 2007) | 2 lines Remove the code that was missed in rev 55303. ................ r55738 | neal.norwitz | 2007-06-01 19:10:43 -0700 (Fri, 01 Jun 2007) | 1 line Fix doc breakage ................ r55741 | neal.norwitz | 2007-06-02 00:41:58 -0700 (Sat, 02 Jun 2007) | 1 line Remove timing module (plus some remnants of other modules). ................ r55742 | neal.norwitz | 2007-06-02 00:51:44 -0700 (Sat, 02 Jun 2007) | 1 line Remove posixfile module (plus some remnants of other modules). ................ r55744 | neal.norwitz | 2007-06-02 10:18:56 -0700 (Sat, 02 Jun 2007) | 1 line Fix doc breakage. ................ r55745 | neal.norwitz | 2007-06-02 11:32:16 -0700 (Sat, 02 Jun 2007) | 1 line Make a whatsnew 3.0 template. ................ r55754 | neal.norwitz | 2007-06-03 23:24:18 -0700 (Sun, 03 Jun 2007) | 1 line SF #1730441, os._execvpe raises UnboundLocal due to new try/except semantics ................ r55755 | neal.norwitz | 2007-06-03 23:26:00 -0700 (Sun, 03 Jun 2007) | 1 line Get rid of extra whitespace ................ r55794 | guido.van.rossum | 2007-06-06 15:29:22 -0700 (Wed, 06 Jun 2007) | 3 lines Make this compile in GCC 2.96, which does not allow interspersing declarations and code. ................
1104 lines
36 KiB
Python
1104 lines
36 KiB
Python
# -*- coding: iso-8859-15 -*-
|
||
|
||
import sys
|
||
import os
|
||
import shutil
|
||
import tempfile
|
||
import StringIO
|
||
from hashlib import md5
|
||
import errno
|
||
|
||
import unittest
|
||
import tarfile
|
||
|
||
from test import test_support
|
||
|
||
# Check for our compression modules.
|
||
try:
|
||
import gzip
|
||
gzip.GzipFile
|
||
except (ImportError, AttributeError):
|
||
gzip = None
|
||
try:
|
||
import bz2
|
||
except ImportError:
|
||
bz2 = None
|
||
|
||
def md5sum(data):
|
||
return md5(data).hexdigest()
|
||
|
||
def path(path):
|
||
return test_support.findfile(path)
|
||
|
||
TEMPDIR = os.path.join(tempfile.gettempdir(), "test_tarfile_tmp")
|
||
tarname = path("testtar.tar")
|
||
gzipname = os.path.join(TEMPDIR, "testtar.tar.gz")
|
||
bz2name = os.path.join(TEMPDIR, "testtar.tar.bz2")
|
||
tmpname = os.path.join(TEMPDIR, "tmp.tar")
|
||
|
||
md5_regtype = "65f477c818ad9e15f7feab0c6d37742f"
|
||
md5_sparse = "a54fbc4ca4f4399a90e1b27164012fc6"
|
||
|
||
|
||
class ReadTest(unittest.TestCase):
|
||
|
||
tarname = tarname
|
||
mode = "r:"
|
||
|
||
def setUp(self):
|
||
self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1")
|
||
|
||
def tearDown(self):
|
||
self.tar.close()
|
||
|
||
|
||
class UstarReadTest(ReadTest):
|
||
|
||
def test_fileobj_regular_file(self):
|
||
tarinfo = self.tar.getmember("ustar/regtype")
|
||
fobj = self.tar.extractfile(tarinfo)
|
||
data = fobj.read()
|
||
self.assert_((len(data), md5sum(data)) == (tarinfo.size, md5_regtype),
|
||
"regular file extraction failed")
|
||
|
||
def test_fileobj_readlines(self):
|
||
self.tar.extract("ustar/regtype", TEMPDIR)
|
||
tarinfo = self.tar.getmember("ustar/regtype")
|
||
fobj1 = open(os.path.join(TEMPDIR, "ustar/regtype"), "rU")
|
||
fobj2 = self.tar.extractfile(tarinfo)
|
||
|
||
lines1 = fobj1.readlines()
|
||
lines2 = fobj2.readlines()
|
||
self.assert_(lines1 == lines2,
|
||
"fileobj.readlines() failed")
|
||
self.assert_(len(lines2) == 114,
|
||
"fileobj.readlines() failed")
|
||
self.assert_(lines2[83] == \
|
||
"I will gladly admit that Python is not the fastest running scripting language.\n",
|
||
"fileobj.readlines() failed")
|
||
|
||
def test_fileobj_iter(self):
|
||
self.tar.extract("ustar/regtype", TEMPDIR)
|
||
tarinfo = self.tar.getmember("ustar/regtype")
|
||
fobj1 = open(os.path.join(TEMPDIR, "ustar/regtype"), "rU")
|
||
fobj2 = self.tar.extractfile(tarinfo)
|
||
lines1 = fobj1.readlines()
|
||
lines2 = [line for line in fobj2]
|
||
self.assert_(lines1 == lines2,
|
||
"fileobj.__iter__() failed")
|
||
|
||
def test_fileobj_seek(self):
|
||
self.tar.extract("ustar/regtype", TEMPDIR)
|
||
fobj = open(os.path.join(TEMPDIR, "ustar/regtype"), "rb")
|
||
data = fobj.read()
|
||
fobj.close()
|
||
|
||
tarinfo = self.tar.getmember("ustar/regtype")
|
||
fobj = self.tar.extractfile(tarinfo)
|
||
|
||
text = fobj.read()
|
||
fobj.seek(0)
|
||
self.assert_(0 == fobj.tell(),
|
||
"seek() to file's start failed")
|
||
fobj.seek(2048, 0)
|
||
self.assert_(2048 == fobj.tell(),
|
||
"seek() to absolute position failed")
|
||
fobj.seek(-1024, 1)
|
||
self.assert_(1024 == fobj.tell(),
|
||
"seek() to negative relative position failed")
|
||
fobj.seek(1024, 1)
|
||
self.assert_(2048 == fobj.tell(),
|
||
"seek() to positive relative position failed")
|
||
s = fobj.read(10)
|
||
self.assert_(s == data[2048:2058],
|
||
"read() after seek failed")
|
||
fobj.seek(0, 2)
|
||
self.assert_(tarinfo.size == fobj.tell(),
|
||
"seek() to file's end failed")
|
||
self.assert_(fobj.read() == "",
|
||
"read() at file's end did not return empty string")
|
||
fobj.seek(-tarinfo.size, 2)
|
||
self.assert_(0 == fobj.tell(),
|
||
"relative seek() to file's start failed")
|
||
fobj.seek(512)
|
||
s1 = fobj.readlines()
|
||
fobj.seek(512)
|
||
s2 = fobj.readlines()
|
||
self.assert_(s1 == s2,
|
||
"readlines() after seek failed")
|
||
fobj.seek(0)
|
||
self.assert_(len(fobj.readline()) == fobj.tell(),
|
||
"tell() after readline() failed")
|
||
fobj.seek(512)
|
||
self.assert_(len(fobj.readline()) + 512 == fobj.tell(),
|
||
"tell() after seek() and readline() failed")
|
||
fobj.seek(0)
|
||
line = fobj.readline()
|
||
self.assert_(fobj.read() == data[len(line):],
|
||
"read() after readline() failed")
|
||
fobj.close()
|
||
|
||
|
||
class MiscReadTest(ReadTest):
|
||
|
||
def test_no_filename(self):
|
||
fobj = open(self.tarname, "rb")
|
||
tar = tarfile.open(fileobj=fobj, mode=self.mode)
|
||
self.assertEqual(tar.name, os.path.abspath(fobj.name))
|
||
|
||
def test_fail_comp(self):
|
||
# For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file.
|
||
if self.mode == "r:":
|
||
return
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tarname, self.mode)
|
||
fobj = open(tarname, "rb")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, fileobj=fobj, mode=self.mode)
|
||
|
||
def test_v7_dirtype(self):
|
||
# Test old style dirtype member (bug #1336623):
|
||
# Old V7 tars create directory members using an AREGTYPE
|
||
# header with a "/" appended to the filename field.
|
||
tarinfo = self.tar.getmember("misc/dirtype-old-v7")
|
||
self.assert_(tarinfo.type == tarfile.DIRTYPE,
|
||
"v7 dirtype failed")
|
||
|
||
def test_check_members(self):
|
||
for tarinfo in self.tar:
|
||
self.assert_(int(tarinfo.mtime) == 07606136617,
|
||
"wrong mtime for %s" % tarinfo.name)
|
||
if not tarinfo.name.startswith("ustar/"):
|
||
continue
|
||
self.assert_(tarinfo.uname == "tarfile",
|
||
"wrong uname for %s" % tarinfo.name)
|
||
|
||
def test_find_members(self):
|
||
self.assert_(self.tar.getmembers()[-1].name == "misc/eof",
|
||
"could not find all members")
|
||
|
||
def test_extract_hardlink(self):
|
||
# Test hardlink extraction (e.g. bug #857297).
|
||
tar = tarfile.open(tarname, errorlevel=1, encoding="iso8859-1")
|
||
|
||
tar.extract("ustar/regtype", TEMPDIR)
|
||
try:
|
||
tar.extract("ustar/lnktype", TEMPDIR)
|
||
except EnvironmentError as e:
|
||
if e.errno == errno.ENOENT:
|
||
self.fail("hardlink not extracted properly")
|
||
|
||
data = open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb").read()
|
||
self.assertEqual(md5sum(data), md5_regtype)
|
||
|
||
try:
|
||
tar.extract("ustar/symtype", TEMPDIR)
|
||
except EnvironmentError as e:
|
||
if e.errno == errno.ENOENT:
|
||
self.fail("symlink not extracted properly")
|
||
|
||
data = open(os.path.join(TEMPDIR, "ustar/symtype"), "rb").read()
|
||
self.assertEqual(md5sum(data), md5_regtype)
|
||
|
||
|
||
class StreamReadTest(ReadTest):
|
||
|
||
mode="r|"
|
||
|
||
def test_fileobj_regular_file(self):
|
||
tarinfo = self.tar.next() # get "regtype" (can't use getmember)
|
||
fobj = self.tar.extractfile(tarinfo)
|
||
data = fobj.read()
|
||
self.assert_((len(data), md5sum(data)) == (tarinfo.size, md5_regtype),
|
||
"regular file extraction failed")
|
||
|
||
def test_provoke_stream_error(self):
|
||
tarinfos = self.tar.getmembers()
|
||
f = self.tar.extractfile(tarinfos[0]) # read the first member
|
||
self.assertRaises(tarfile.StreamError, f.read)
|
||
|
||
def test_compare_members(self):
|
||
tar1 = tarfile.open(tarname, encoding="iso8859-1")
|
||
tar2 = self.tar
|
||
|
||
while True:
|
||
t1 = tar1.next()
|
||
t2 = tar2.next()
|
||
if t1 is None:
|
||
break
|
||
self.assert_(t2 is not None, "stream.next() failed.")
|
||
|
||
if t2.islnk() or t2.issym():
|
||
self.assertRaises(tarfile.StreamError, tar2.extractfile, t2)
|
||
continue
|
||
|
||
v1 = tar1.extractfile(t1)
|
||
v2 = tar2.extractfile(t2)
|
||
if v1 is None:
|
||
continue
|
||
self.assert_(v2 is not None, "stream.extractfile() failed")
|
||
self.assert_(v1.read() == v2.read(), "stream extraction failed")
|
||
|
||
tar1.close()
|
||
|
||
|
||
class DetectReadTest(unittest.TestCase):
|
||
|
||
def _testfunc_file(self, name, mode):
|
||
try:
|
||
tarfile.open(name, mode)
|
||
except tarfile.ReadError:
|
||
self.fail()
|
||
|
||
def _testfunc_fileobj(self, name, mode):
|
||
try:
|
||
tarfile.open(name, mode, fileobj=open(name, "rb"))
|
||
except tarfile.ReadError:
|
||
self.fail()
|
||
|
||
def _test_modes(self, testfunc):
|
||
testfunc(tarname, "r")
|
||
testfunc(tarname, "r:")
|
||
testfunc(tarname, "r:*")
|
||
testfunc(tarname, "r|")
|
||
testfunc(tarname, "r|*")
|
||
|
||
if gzip:
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r:gz")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r|gz")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, gzipname, mode="r:")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, gzipname, mode="r|")
|
||
|
||
testfunc(gzipname, "r")
|
||
testfunc(gzipname, "r:*")
|
||
testfunc(gzipname, "r:gz")
|
||
testfunc(gzipname, "r|*")
|
||
testfunc(gzipname, "r|gz")
|
||
|
||
if bz2:
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r:bz2")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tarname, mode="r|bz2")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, bz2name, mode="r:")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, bz2name, mode="r|")
|
||
|
||
testfunc(bz2name, "r")
|
||
testfunc(bz2name, "r:*")
|
||
testfunc(bz2name, "r:bz2")
|
||
testfunc(bz2name, "r|*")
|
||
testfunc(bz2name, "r|bz2")
|
||
|
||
def test_detect_file(self):
|
||
self._test_modes(self._testfunc_file)
|
||
|
||
def test_detect_fileobj(self):
|
||
self._test_modes(self._testfunc_fileobj)
|
||
|
||
|
||
class MemberReadTest(ReadTest):
|
||
|
||
def _test_member(self, tarinfo, chksum=None, **kwargs):
|
||
if chksum is not None:
|
||
self.assert_(md5sum(self.tar.extractfile(tarinfo).read()) == chksum,
|
||
"wrong md5sum for %s" % tarinfo.name)
|
||
|
||
kwargs["mtime"] = 07606136617
|
||
kwargs["uid"] = 1000
|
||
kwargs["gid"] = 100
|
||
if "old-v7" not in tarinfo.name:
|
||
# V7 tar can't handle alphabetic owners.
|
||
kwargs["uname"] = "tarfile"
|
||
kwargs["gname"] = "tarfile"
|
||
for k, v in kwargs.items():
|
||
self.assert_(getattr(tarinfo, k) == v,
|
||
"wrong value in %s field of %s" % (k, tarinfo.name))
|
||
|
||
def test_find_regtype(self):
|
||
tarinfo = self.tar.getmember("ustar/regtype")
|
||
self._test_member(tarinfo, size=7011, chksum=md5_regtype)
|
||
|
||
def test_find_conttype(self):
|
||
tarinfo = self.tar.getmember("ustar/conttype")
|
||
self._test_member(tarinfo, size=7011, chksum=md5_regtype)
|
||
|
||
def test_find_dirtype(self):
|
||
tarinfo = self.tar.getmember("ustar/dirtype")
|
||
self._test_member(tarinfo, size=0)
|
||
|
||
def test_find_dirtype_with_size(self):
|
||
tarinfo = self.tar.getmember("ustar/dirtype-with-size")
|
||
self._test_member(tarinfo, size=255)
|
||
|
||
def test_find_lnktype(self):
|
||
tarinfo = self.tar.getmember("ustar/lnktype")
|
||
self._test_member(tarinfo, size=0, linkname="ustar/regtype")
|
||
|
||
def test_find_symtype(self):
|
||
tarinfo = self.tar.getmember("ustar/symtype")
|
||
self._test_member(tarinfo, size=0, linkname="regtype")
|
||
|
||
def test_find_blktype(self):
|
||
tarinfo = self.tar.getmember("ustar/blktype")
|
||
self._test_member(tarinfo, size=0, devmajor=3, devminor=0)
|
||
|
||
def test_find_chrtype(self):
|
||
tarinfo = self.tar.getmember("ustar/chrtype")
|
||
self._test_member(tarinfo, size=0, devmajor=1, devminor=3)
|
||
|
||
def test_find_fifotype(self):
|
||
tarinfo = self.tar.getmember("ustar/fifotype")
|
||
self._test_member(tarinfo, size=0)
|
||
|
||
def test_find_sparse(self):
|
||
tarinfo = self.tar.getmember("ustar/sparse")
|
||
self._test_member(tarinfo, size=86016, chksum=md5_sparse)
|
||
|
||
def test_find_umlauts(self):
|
||
tarinfo = self.tar.getmember("ustar/umlauts-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
||
self._test_member(tarinfo, size=7011, chksum=md5_regtype)
|
||
|
||
def test_find_ustar_longname(self):
|
||
name = "ustar/" + "12345/" * 39 + "1234567/longname"
|
||
self.assert_(name in self.tar.getnames())
|
||
|
||
def test_find_regtype_oldv7(self):
|
||
tarinfo = self.tar.getmember("misc/regtype-old-v7")
|
||
self._test_member(tarinfo, size=7011, chksum=md5_regtype)
|
||
|
||
def test_find_pax_umlauts(self):
|
||
self.tar = tarfile.open(self.tarname, mode=self.mode, encoding="iso8859-1")
|
||
tarinfo = self.tar.getmember("pax/umlauts-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
||
self._test_member(tarinfo, size=7011, chksum=md5_regtype)
|
||
|
||
|
||
class LongnameTest(ReadTest):
|
||
|
||
def test_read_longname(self):
|
||
# Test reading of longname (bug #1471427).
|
||
longname = self.subdir + "/" + "123/" * 125 + "longname"
|
||
try:
|
||
tarinfo = self.tar.getmember(longname)
|
||
except KeyError:
|
||
self.fail("longname not found")
|
||
self.assert_(tarinfo.type != tarfile.DIRTYPE, "read longname as dirtype")
|
||
|
||
def test_read_longlink(self):
|
||
longname = self.subdir + "/" + "123/" * 125 + "longname"
|
||
longlink = self.subdir + "/" + "123/" * 125 + "longlink"
|
||
try:
|
||
tarinfo = self.tar.getmember(longlink)
|
||
except KeyError:
|
||
self.fail("longlink not found")
|
||
self.assert_(tarinfo.linkname == longname, "linkname wrong")
|
||
|
||
def test_truncated_longname(self):
|
||
longname = self.subdir + "/" + "123/" * 125 + "longname"
|
||
tarinfo = self.tar.getmember(longname)
|
||
offset = tarinfo.offset
|
||
self.tar.fileobj.seek(offset)
|
||
fobj = StringIO.StringIO(self.tar.fileobj.read(3 * 512))
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, name="foo.tar", fileobj=fobj)
|
||
|
||
def test_header_offset(self):
|
||
# Test if the start offset of the TarInfo object includes
|
||
# the preceding extended header.
|
||
longname = self.subdir + "/" + "123/" * 125 + "longname"
|
||
offset = self.tar.getmember(longname).offset
|
||
fobj = open(tarname)
|
||
fobj.seek(offset)
|
||
tarinfo = tarfile.TarInfo.frombuf(fobj.read(512))
|
||
self.assertEqual(tarinfo.type, self.longnametype)
|
||
|
||
|
||
class GNUReadTest(LongnameTest):
|
||
|
||
subdir = "gnu"
|
||
longnametype = tarfile.GNUTYPE_LONGNAME
|
||
|
||
def test_sparse_file(self):
|
||
tarinfo1 = self.tar.getmember("ustar/sparse")
|
||
fobj1 = self.tar.extractfile(tarinfo1)
|
||
tarinfo2 = self.tar.getmember("gnu/sparse")
|
||
fobj2 = self.tar.extractfile(tarinfo2)
|
||
self.assert_(fobj1.read() == fobj2.read(),
|
||
"sparse file extraction failed")
|
||
|
||
|
||
class PaxReadTest(LongnameTest):
|
||
|
||
subdir = "pax"
|
||
longnametype = tarfile.XHDTYPE
|
||
|
||
def test_pax_global_headers(self):
|
||
tar = tarfile.open(tarname, encoding="iso8859-1")
|
||
|
||
tarinfo = tar.getmember("pax/regtype1")
|
||
self.assertEqual(tarinfo.uname, "foo")
|
||
self.assertEqual(tarinfo.gname, "bar")
|
||
self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), u"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
||
|
||
tarinfo = tar.getmember("pax/regtype2")
|
||
self.assertEqual(tarinfo.uname, "")
|
||
self.assertEqual(tarinfo.gname, "bar")
|
||
self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), u"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
||
|
||
tarinfo = tar.getmember("pax/regtype3")
|
||
self.assertEqual(tarinfo.uname, "tarfile")
|
||
self.assertEqual(tarinfo.gname, "tarfile")
|
||
self.assertEqual(tarinfo.pax_headers.get("VENDOR.umlauts"), u"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
||
|
||
def test_pax_number_fields(self):
|
||
# All following number fields are read from the pax header.
|
||
tar = tarfile.open(tarname, encoding="iso8859-1")
|
||
tarinfo = tar.getmember("pax/regtype4")
|
||
self.assertEqual(tarinfo.size, 7011)
|
||
self.assertEqual(tarinfo.uid, 123)
|
||
self.assertEqual(tarinfo.gid, 123)
|
||
self.assertEqual(tarinfo.mtime, 1041808783.0)
|
||
self.assertEqual(type(tarinfo.mtime), float)
|
||
self.assertEqual(float(tarinfo.pax_headers["atime"]), 1041808783.0)
|
||
self.assertEqual(float(tarinfo.pax_headers["ctime"]), 1041808783.0)
|
||
|
||
|
||
class WriteTest(unittest.TestCase):
|
||
|
||
mode = "w:"
|
||
|
||
def test_100_char_name(self):
|
||
# The name field in a tar header stores strings of at most 100 chars.
|
||
# If a string is shorter than 100 chars it has to be padded with '\0',
|
||
# which implies that a string of exactly 100 chars is stored without
|
||
# a trailing '\0'.
|
||
name = "0123456789" * 10
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
t = tarfile.TarInfo(name)
|
||
tar.addfile(t)
|
||
tar.close()
|
||
|
||
tar = tarfile.open(tmpname)
|
||
self.assert_(tar.getnames()[0] == name,
|
||
"failed to store 100 char filename")
|
||
tar.close()
|
||
|
||
def test_tar_size(self):
|
||
# Test for bug #1013882.
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
path = os.path.join(TEMPDIR, "file")
|
||
fobj = open(path, "wb")
|
||
fobj.write("aaa")
|
||
fobj.close()
|
||
tar.add(path)
|
||
tar.close()
|
||
self.assert_(os.path.getsize(tmpname) > 0,
|
||
"tarfile is empty")
|
||
|
||
# The test_*_size tests test for bug #1167128.
|
||
def test_file_size(self):
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
|
||
path = os.path.join(TEMPDIR, "file")
|
||
fobj = open(path, "wb")
|
||
fobj.close()
|
||
tarinfo = tar.gettarinfo(path)
|
||
self.assertEqual(tarinfo.size, 0)
|
||
|
||
fobj = open(path, "wb")
|
||
fobj.write("aaa")
|
||
fobj.close()
|
||
tarinfo = tar.gettarinfo(path)
|
||
self.assertEqual(tarinfo.size, 3)
|
||
|
||
tar.close()
|
||
|
||
def test_directory_size(self):
|
||
path = os.path.join(TEMPDIR, "directory")
|
||
os.mkdir(path)
|
||
try:
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
tarinfo = tar.gettarinfo(path)
|
||
self.assertEqual(tarinfo.size, 0)
|
||
finally:
|
||
os.rmdir(path)
|
||
|
||
def test_link_size(self):
|
||
if hasattr(os, "link"):
|
||
link = os.path.join(TEMPDIR, "link")
|
||
target = os.path.join(TEMPDIR, "link_target")
|
||
open(target, "wb").close()
|
||
os.link(target, link)
|
||
try:
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
tarinfo = tar.gettarinfo(link)
|
||
self.assertEqual(tarinfo.size, 0)
|
||
finally:
|
||
os.remove(target)
|
||
os.remove(link)
|
||
|
||
def test_symlink_size(self):
|
||
if hasattr(os, "symlink"):
|
||
path = os.path.join(TEMPDIR, "symlink")
|
||
os.symlink("link_target", path)
|
||
try:
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
tarinfo = tar.gettarinfo(path)
|
||
self.assertEqual(tarinfo.size, 0)
|
||
finally:
|
||
os.remove(path)
|
||
|
||
def test_add_self(self):
|
||
# Test for #1257255.
|
||
dstname = os.path.abspath(tmpname)
|
||
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
self.assert_(tar.name == dstname, "archive name must be absolute")
|
||
|
||
tar.add(dstname)
|
||
self.assert_(tar.getnames() == [], "added the archive to itself")
|
||
|
||
cwd = os.getcwd()
|
||
os.chdir(TEMPDIR)
|
||
tar.add(dstname)
|
||
os.chdir(cwd)
|
||
self.assert_(tar.getnames() == [], "added the archive to itself")
|
||
|
||
|
||
class StreamWriteTest(unittest.TestCase):
|
||
|
||
mode = "w|"
|
||
|
||
def test_stream_padding(self):
|
||
# Test for bug #1543303.
|
||
tar = tarfile.open(tmpname, self.mode)
|
||
tar.close()
|
||
|
||
if self.mode.endswith("gz"):
|
||
fobj = gzip.GzipFile(tmpname)
|
||
data = fobj.read()
|
||
fobj.close()
|
||
elif self.mode.endswith("bz2"):
|
||
dec = bz2.BZ2Decompressor()
|
||
data = open(tmpname, "rb").read()
|
||
data = dec.decompress(data)
|
||
self.assert_(len(dec.unused_data) == 0,
|
||
"found trailing data")
|
||
else:
|
||
fobj = open(tmpname, "rb")
|
||
data = fobj.read()
|
||
fobj.close()
|
||
|
||
self.assert_(data.count("\0") == tarfile.RECORDSIZE,
|
||
"incorrect zero padding")
|
||
|
||
|
||
class GNUWriteTest(unittest.TestCase):
|
||
# This testcase checks for correct creation of GNU Longname
|
||
# and Longlink extended headers (cp. bug #812325).
|
||
|
||
def _length(self, s):
|
||
blocks, remainder = divmod(len(s) + 1, 512)
|
||
if remainder:
|
||
blocks += 1
|
||
return blocks * 512
|
||
|
||
def _calc_size(self, name, link=None):
|
||
# Initial tar header
|
||
count = 512
|
||
|
||
if len(name) > tarfile.LENGTH_NAME:
|
||
# GNU longname extended header + longname
|
||
count += 512
|
||
count += self._length(name)
|
||
if link is not None and len(link) > tarfile.LENGTH_LINK:
|
||
# GNU longlink extended header + longlink
|
||
count += 512
|
||
count += self._length(link)
|
||
return count
|
||
|
||
def _test(self, name, link=None):
|
||
tarinfo = tarfile.TarInfo(name)
|
||
if link:
|
||
tarinfo.linkname = link
|
||
tarinfo.type = tarfile.LNKTYPE
|
||
|
||
tar = tarfile.open(tmpname, "w")
|
||
tar.format = tarfile.GNU_FORMAT
|
||
tar.addfile(tarinfo)
|
||
|
||
v1 = self._calc_size(name, link)
|
||
v2 = tar.offset
|
||
self.assert_(v1 == v2, "GNU longname/longlink creation failed")
|
||
|
||
tar.close()
|
||
|
||
tar = tarfile.open(tmpname)
|
||
member = tar.next()
|
||
self.failIf(member is None, "unable to read longname member")
|
||
self.assert_(tarinfo.name == member.name and \
|
||
tarinfo.linkname == member.linkname, \
|
||
"unable to read longname member")
|
||
|
||
def test_longname_1023(self):
|
||
self._test(("longnam/" * 127) + "longnam")
|
||
|
||
def test_longname_1024(self):
|
||
self._test(("longnam/" * 127) + "longname")
|
||
|
||
def test_longname_1025(self):
|
||
self._test(("longnam/" * 127) + "longname_")
|
||
|
||
def test_longlink_1023(self):
|
||
self._test("name", ("longlnk/" * 127) + "longlnk")
|
||
|
||
def test_longlink_1024(self):
|
||
self._test("name", ("longlnk/" * 127) + "longlink")
|
||
|
||
def test_longlink_1025(self):
|
||
self._test("name", ("longlnk/" * 127) + "longlink_")
|
||
|
||
def test_longnamelink_1023(self):
|
||
self._test(("longnam/" * 127) + "longnam",
|
||
("longlnk/" * 127) + "longlnk")
|
||
|
||
def test_longnamelink_1024(self):
|
||
self._test(("longnam/" * 127) + "longname",
|
||
("longlnk/" * 127) + "longlink")
|
||
|
||
def test_longnamelink_1025(self):
|
||
self._test(("longnam/" * 127) + "longname_",
|
||
("longlnk/" * 127) + "longlink_")
|
||
|
||
|
||
class HardlinkTest(unittest.TestCase):
|
||
# Test the creation of LNKTYPE (hardlink) members in an archive.
|
||
|
||
def setUp(self):
|
||
self.foo = os.path.join(TEMPDIR, "foo")
|
||
self.bar = os.path.join(TEMPDIR, "bar")
|
||
|
||
fobj = open(self.foo, "wb")
|
||
fobj.write("foo")
|
||
fobj.close()
|
||
|
||
os.link(self.foo, self.bar)
|
||
|
||
self.tar = tarfile.open(tmpname, "w")
|
||
self.tar.add(self.foo)
|
||
|
||
def tearDown(self):
|
||
os.remove(self.foo)
|
||
os.remove(self.bar)
|
||
|
||
def test_add_twice(self):
|
||
# The same name will be added as a REGTYPE every
|
||
# time regardless of st_nlink.
|
||
tarinfo = self.tar.gettarinfo(self.foo)
|
||
self.assert_(tarinfo.type == tarfile.REGTYPE,
|
||
"add file as regular failed")
|
||
|
||
def test_add_hardlink(self):
|
||
tarinfo = self.tar.gettarinfo(self.bar)
|
||
self.assert_(tarinfo.type == tarfile.LNKTYPE,
|
||
"add file as hardlink failed")
|
||
|
||
def test_dereference_hardlink(self):
|
||
self.tar.dereference = True
|
||
tarinfo = self.tar.gettarinfo(self.bar)
|
||
self.assert_(tarinfo.type == tarfile.REGTYPE,
|
||
"dereferencing hardlink failed")
|
||
|
||
|
||
class PaxWriteTest(GNUWriteTest):
|
||
|
||
def _test(self, name, link=None):
|
||
# See GNUWriteTest.
|
||
tarinfo = tarfile.TarInfo(name)
|
||
if link:
|
||
tarinfo.linkname = link
|
||
tarinfo.type = tarfile.LNKTYPE
|
||
|
||
tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT)
|
||
tar.addfile(tarinfo)
|
||
tar.close()
|
||
|
||
tar = tarfile.open(tmpname)
|
||
if link:
|
||
l = tar.getmembers()[0].linkname
|
||
self.assert_(link == l, "PAX longlink creation failed")
|
||
else:
|
||
n = tar.getmembers()[0].name
|
||
self.assert_(name == n, "PAX longname creation failed")
|
||
|
||
def test_pax_global_header(self):
|
||
pax_headers = {
|
||
u"foo": u"bar",
|
||
u"uid": u"0",
|
||
u"mtime": u"1.23",
|
||
u"test": u"<EFBFBD><EFBFBD><EFBFBD>",
|
||
u"<EFBFBD><EFBFBD><EFBFBD>": u"test"}
|
||
|
||
tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, \
|
||
pax_headers=pax_headers)
|
||
tar.addfile(tarfile.TarInfo("test"))
|
||
tar.close()
|
||
|
||
# Test if the global header was written correctly.
|
||
tar = tarfile.open(tmpname, encoding="iso8859-1")
|
||
self.assertEqual(tar.pax_headers, pax_headers)
|
||
self.assertEqual(tar.getmembers()[0].pax_headers, pax_headers)
|
||
|
||
# Test if all the fields are unicode.
|
||
for key, val in tar.pax_headers.items():
|
||
self.assert_(type(key) is unicode)
|
||
self.assert_(type(val) is unicode)
|
||
if key in tarfile.PAX_NUMBER_FIELDS:
|
||
try:
|
||
tarfile.PAX_NUMBER_FIELDS[key](val)
|
||
except (TypeError, ValueError):
|
||
self.fail("unable to convert pax header field")
|
||
|
||
def test_pax_extended_header(self):
|
||
# The fields from the pax header have priority over the
|
||
# TarInfo.
|
||
pax_headers = {u"path": u"foo", u"uid": u"123"}
|
||
|
||
tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT, encoding="iso8859-1")
|
||
t = tarfile.TarInfo()
|
||
t.name = u"<EFBFBD><EFBFBD><EFBFBD>" # non-ASCII
|
||
t.uid = 8**8 # too large
|
||
t.pax_headers = pax_headers
|
||
tar.addfile(t)
|
||
tar.close()
|
||
|
||
tar = tarfile.open(tmpname, encoding="iso8859-1")
|
||
t = tar.getmembers()[0]
|
||
self.assertEqual(t.pax_headers, pax_headers)
|
||
self.assertEqual(t.name, "foo")
|
||
self.assertEqual(t.uid, 123)
|
||
|
||
|
||
class UstarUnicodeTest(unittest.TestCase):
|
||
# All *UnicodeTests FIXME
|
||
|
||
format = tarfile.USTAR_FORMAT
|
||
|
||
def test_iso8859_1_filename(self):
|
||
self._test_unicode_filename("iso8859-1")
|
||
|
||
def test_utf7_filename(self):
|
||
self._test_unicode_filename("utf7")
|
||
|
||
def test_utf8_filename(self):
|
||
self._test_unicode_filename("utf8")
|
||
|
||
def _test_unicode_filename(self, encoding):
|
||
tar = tarfile.open(tmpname, "w", format=self.format, encoding=encoding, errors="strict")
|
||
name = "<EFBFBD><EFBFBD><EFBFBD>"
|
||
tar.addfile(tarfile.TarInfo(name))
|
||
tar.close()
|
||
|
||
tar = tarfile.open(tmpname, encoding=encoding)
|
||
self.assert_(type(tar.getnames()[0]) is not unicode)
|
||
self.assertEqual(tar.getmembers()[0].name, name.encode(encoding))
|
||
tar.close()
|
||
|
||
def test_unicode_filename_error(self):
|
||
tar = tarfile.open(tmpname, "w", format=self.format, encoding="ascii", errors="strict")
|
||
tarinfo = tarfile.TarInfo()
|
||
|
||
tarinfo.name = "<EFBFBD><EFBFBD><EFBFBD>"
|
||
if self.format == tarfile.PAX_FORMAT:
|
||
self.assertRaises(UnicodeError, tar.addfile, tarinfo)
|
||
else:
|
||
tar.addfile(tarinfo)
|
||
|
||
tarinfo.name = u"<EFBFBD><EFBFBD><EFBFBD>"
|
||
self.assertRaises(UnicodeError, tar.addfile, tarinfo)
|
||
|
||
tarinfo.name = "foo"
|
||
tarinfo.uname = u"<EFBFBD><EFBFBD><EFBFBD>"
|
||
self.assertRaises(UnicodeError, tar.addfile, tarinfo)
|
||
|
||
def test_unicode_argument(self):
|
||
tar = tarfile.open(tarname, "r", encoding="iso8859-1", errors="strict")
|
||
for t in tar:
|
||
self.assert_(type(t.name) is str)
|
||
self.assert_(type(t.linkname) is str)
|
||
self.assert_(type(t.uname) is str)
|
||
self.assert_(type(t.gname) is str)
|
||
tar.close()
|
||
|
||
def test_uname_unicode(self):
|
||
for name in (u"<EFBFBD><EFBFBD><EFBFBD>", "<EFBFBD><EFBFBD><EFBFBD>"):
|
||
t = tarfile.TarInfo("foo")
|
||
t.uname = name
|
||
t.gname = name
|
||
|
||
fobj = StringIO.StringIO()
|
||
tar = tarfile.open("foo.tar", mode="w", fileobj=fobj, format=self.format, encoding="iso8859-1")
|
||
tar.addfile(t)
|
||
tar.close()
|
||
fobj.seek(0)
|
||
|
||
tar = tarfile.open("foo.tar", fileobj=fobj, encoding="iso8859-1")
|
||
t = tar.getmember("foo")
|
||
self.assertEqual(t.uname, "<EFBFBD><EFBFBD><EFBFBD>")
|
||
self.assertEqual(t.gname, "<EFBFBD><EFBFBD><EFBFBD>")
|
||
|
||
class GNUUnicodeTest(UstarUnicodeTest):
|
||
|
||
format = tarfile.GNU_FORMAT
|
||
|
||
|
||
class PaxUnicodeTest(UstarUnicodeTest):
|
||
|
||
format = tarfile.PAX_FORMAT
|
||
|
||
def _create_unicode_name(self, name):
|
||
tar = tarfile.open(tmpname, "w", format=self.format)
|
||
t = tarfile.TarInfo()
|
||
t.pax_headers["path"] = name
|
||
tar.addfile(t)
|
||
tar.close()
|
||
|
||
def test_error_handlers(self):
|
||
# Test if the unicode error handlers work correctly for characters
|
||
# that cannot be expressed in a given encoding.
|
||
self._create_unicode_name(u"<EFBFBD><EFBFBD><EFBFBD>")
|
||
|
||
for handler, name in (("utf-8", u"<EFBFBD><EFBFBD><EFBFBD>".encode("utf8")),
|
||
("replace", "???"), ("ignore", "")):
|
||
tar = tarfile.open(tmpname, format=self.format, encoding="ascii",
|
||
errors=handler)
|
||
self.assertEqual(tar.getnames()[0], name)
|
||
|
||
self.assertRaises(UnicodeError, tarfile.open, tmpname,
|
||
encoding="ascii", errors="strict")
|
||
|
||
def test_error_handler_utf8(self):
|
||
# Create a pathname that has one component representable using
|
||
# iso8859-1 and the other only in iso8859-15.
|
||
self._create_unicode_name(u"<EFBFBD><EFBFBD><EFBFBD>/<2F>")
|
||
|
||
tar = tarfile.open(tmpname, format=self.format, encoding="iso8859-1",
|
||
errors="utf-8")
|
||
self.assertEqual(tar.getnames()[0], "<EFBFBD><EFBFBD><EFBFBD>/" + u"<EFBFBD>".encode("utf8"))
|
||
|
||
|
||
class AppendTest(unittest.TestCase):
|
||
# Test append mode (cp. patch #1652681).
|
||
|
||
def setUp(self):
|
||
self.tarname = tmpname
|
||
if os.path.exists(self.tarname):
|
||
os.remove(self.tarname)
|
||
|
||
def _add_testfile(self, fileobj=None):
|
||
tar = tarfile.open(self.tarname, "a", fileobj=fileobj)
|
||
tar.addfile(tarfile.TarInfo("bar"))
|
||
tar.close()
|
||
|
||
def _create_testtar(self, mode="w:"):
|
||
src = tarfile.open(tarname, encoding="iso8859-1")
|
||
t = src.getmember("ustar/regtype")
|
||
t.name = "foo"
|
||
f = src.extractfile(t)
|
||
tar = tarfile.open(self.tarname, mode)
|
||
tar.addfile(t, f)
|
||
tar.close()
|
||
|
||
def _test(self, names=["bar"], fileobj=None):
|
||
tar = tarfile.open(self.tarname, fileobj=fileobj)
|
||
self.assertEqual(tar.getnames(), names)
|
||
|
||
def test_non_existing(self):
|
||
self._add_testfile()
|
||
self._test()
|
||
|
||
def test_empty(self):
|
||
open(self.tarname, "w").close()
|
||
self._add_testfile()
|
||
self._test()
|
||
|
||
def test_empty_fileobj(self):
|
||
fobj = StringIO.StringIO()
|
||
self._add_testfile(fobj)
|
||
fobj.seek(0)
|
||
self._test(fileobj=fobj)
|
||
|
||
def test_fileobj(self):
|
||
self._create_testtar()
|
||
data = open(self.tarname).read()
|
||
fobj = StringIO.StringIO(data)
|
||
self._add_testfile(fobj)
|
||
fobj.seek(0)
|
||
self._test(names=["foo", "bar"], fileobj=fobj)
|
||
|
||
def test_existing(self):
|
||
self._create_testtar()
|
||
self._add_testfile()
|
||
self._test(names=["foo", "bar"])
|
||
|
||
def test_append_gz(self):
|
||
if gzip is None:
|
||
return
|
||
self._create_testtar("w:gz")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a")
|
||
|
||
def test_append_bz2(self):
|
||
if bz2 is None:
|
||
return
|
||
self._create_testtar("w:bz2")
|
||
self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, "a")
|
||
|
||
|
||
class LimitsTest(unittest.TestCase):
|
||
|
||
def test_ustar_limits(self):
|
||
# 100 char name
|
||
tarinfo = tarfile.TarInfo("0123456789" * 10)
|
||
tarinfo.tobuf(tarfile.USTAR_FORMAT)
|
||
|
||
# 101 char name that cannot be stored
|
||
tarinfo = tarfile.TarInfo("0123456789" * 10 + "0")
|
||
self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
|
||
|
||
# 256 char name with a slash at pos 156
|
||
tarinfo = tarfile.TarInfo("123/" * 62 + "longname")
|
||
tarinfo.tobuf(tarfile.USTAR_FORMAT)
|
||
|
||
# 256 char name that cannot be stored
|
||
tarinfo = tarfile.TarInfo("1234567/" * 31 + "longname")
|
||
self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
|
||
|
||
# 512 char name
|
||
tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
|
||
self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
|
||
|
||
# 512 char linkname
|
||
tarinfo = tarfile.TarInfo("longlink")
|
||
tarinfo.linkname = "123/" * 126 + "longname"
|
||
self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
|
||
|
||
# uid > 8 digits
|
||
tarinfo = tarfile.TarInfo("name")
|
||
tarinfo.uid = 010000000
|
||
self.assertRaises(ValueError, tarinfo.tobuf, tarfile.USTAR_FORMAT)
|
||
|
||
def test_gnu_limits(self):
|
||
tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
|
||
tarinfo.tobuf(tarfile.GNU_FORMAT)
|
||
|
||
tarinfo = tarfile.TarInfo("longlink")
|
||
tarinfo.linkname = "123/" * 126 + "longname"
|
||
tarinfo.tobuf(tarfile.GNU_FORMAT)
|
||
|
||
# uid >= 256 ** 7
|
||
tarinfo = tarfile.TarInfo("name")
|
||
tarinfo.uid = 04000000000000000000
|
||
self.assertRaises(ValueError, tarinfo.tobuf, tarfile.GNU_FORMAT)
|
||
|
||
def test_pax_limits(self):
|
||
tarinfo = tarfile.TarInfo("123/" * 126 + "longname")
|
||
tarinfo.tobuf(tarfile.PAX_FORMAT)
|
||
|
||
tarinfo = tarfile.TarInfo("longlink")
|
||
tarinfo.linkname = "123/" * 126 + "longname"
|
||
tarinfo.tobuf(tarfile.PAX_FORMAT)
|
||
|
||
tarinfo = tarfile.TarInfo("name")
|
||
tarinfo.uid = 04000000000000000000
|
||
tarinfo.tobuf(tarfile.PAX_FORMAT)
|
||
|
||
|
||
class GzipMiscReadTest(MiscReadTest):
|
||
tarname = gzipname
|
||
mode = "r:gz"
|
||
class GzipUstarReadTest(UstarReadTest):
|
||
tarname = gzipname
|
||
mode = "r:gz"
|
||
class GzipStreamReadTest(StreamReadTest):
|
||
tarname = gzipname
|
||
mode = "r|gz"
|
||
class GzipWriteTest(WriteTest):
|
||
mode = "w:gz"
|
||
class GzipStreamWriteTest(StreamWriteTest):
|
||
mode = "w|gz"
|
||
|
||
|
||
class Bz2MiscReadTest(MiscReadTest):
|
||
tarname = bz2name
|
||
mode = "r:bz2"
|
||
class Bz2UstarReadTest(UstarReadTest):
|
||
tarname = bz2name
|
||
mode = "r:bz2"
|
||
class Bz2StreamReadTest(StreamReadTest):
|
||
tarname = bz2name
|
||
mode = "r|bz2"
|
||
class Bz2WriteTest(WriteTest):
|
||
mode = "w:bz2"
|
||
class Bz2StreamWriteTest(StreamWriteTest):
|
||
mode = "w|bz2"
|
||
|
||
def test_main():
|
||
if not os.path.exists(TEMPDIR):
|
||
os.mkdir(TEMPDIR)
|
||
|
||
tests = [
|
||
UstarReadTest,
|
||
MiscReadTest,
|
||
StreamReadTest,
|
||
DetectReadTest,
|
||
MemberReadTest,
|
||
GNUReadTest,
|
||
PaxReadTest,
|
||
WriteTest,
|
||
StreamWriteTest,
|
||
GNUWriteTest,
|
||
PaxWriteTest,
|
||
UstarUnicodeTest,
|
||
GNUUnicodeTest,
|
||
PaxUnicodeTest,
|
||
AppendTest,
|
||
LimitsTest,
|
||
]
|
||
|
||
if hasattr(os, "link"):
|
||
tests.append(HardlinkTest)
|
||
|
||
fobj = open(tarname, "rb")
|
||
data = fobj.read()
|
||
fobj.close()
|
||
|
||
if gzip:
|
||
# Create testtar.tar.gz and add gzip-specific tests.
|
||
tar = gzip.open(gzipname, "wb")
|
||
tar.write(data)
|
||
tar.close()
|
||
|
||
tests += [
|
||
GzipMiscReadTest,
|
||
GzipUstarReadTest,
|
||
GzipStreamReadTest,
|
||
GzipWriteTest,
|
||
GzipStreamWriteTest,
|
||
]
|
||
|
||
if bz2:
|
||
# Create testtar.tar.bz2 and add bz2-specific tests.
|
||
tar = bz2.BZ2File(bz2name, "wb")
|
||
tar.write(data)
|
||
tar.close()
|
||
|
||
tests += [
|
||
Bz2MiscReadTest,
|
||
Bz2UstarReadTest,
|
||
Bz2StreamReadTest,
|
||
Bz2WriteTest,
|
||
Bz2StreamWriteTest,
|
||
]
|
||
|
||
try:
|
||
test_support.run_unittest(*tests)
|
||
finally:
|
||
if os.path.exists(TEMPDIR):
|
||
shutil.rmtree(TEMPDIR)
|
||
|
||
if __name__ == "__main__":
|
||
test_main()
|