Issue #10184: Touch directories only once when extracting a tarfile.

This commit is contained in:
Martin v. Löwis 2010-11-01 21:39:13 +00:00
parent bbea35f194
commit 16f344df36
4 changed files with 29 additions and 11 deletions

View File

@ -336,12 +336,13 @@ be finalized; only the internally used file object will be closed. See the
dots ``".."``.
.. method:: TarFile.extract(member, path="")
.. method:: TarFile.extract(member, path="", set_attrs=True)
Extract a member from the archive to the current working directory, using its
full name. Its file information is extracted as accurately as possible. *member*
may be a filename or a :class:`TarInfo` object. You can specify a different
directory using *path*.
directory using *path*. File attributes (owner, mtime, mode) are set unless
*set_attrs* is False.
.. note::
@ -352,6 +353,8 @@ be finalized; only the internally used file object will be closed. See the
See the warning for :meth:`extractall`.
.. versionchanged:: 3.2
Added the *set_attrs* parameter.
.. method:: TarFile.extractfile(member)

View File

@ -2131,7 +2131,8 @@ class TarFile(object):
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 0o700
self.extract(tarinfo, path)
# Do not set_attrs directories, as we will do that further down
self.extract(tarinfo, path, set_attrs=not tarinfo.isdir())
# Reverse sort directories.
directories.sort(key=lambda a: a.name)
@ -2150,11 +2151,12 @@ class TarFile(object):
else:
self._dbg(1, "tarfile: %s" % e)
def extract(self, member, path=""):
def extract(self, member, path="", set_attrs=True):
"""Extract a member from the archive to the current working directory,
using its full name. Its file information is extracted as accurately
as possible. `member' may be a filename or a TarInfo object. You can
specify a different directory using `path'.
specify a different directory using `path'. File attributes (owner,
mtime, mode) are set unless `set_attrs' is False.
"""
self._check("r")
@ -2168,7 +2170,8 @@ class TarFile(object):
tarinfo._link_target = os.path.join(path, tarinfo.linkname)
try:
self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
self._extract_member(tarinfo, os.path.join(path, tarinfo.name),
set_attrs=set_attrs)
except EnvironmentError as e:
if self.errorlevel > 0:
raise
@ -2221,7 +2224,7 @@ class TarFile(object):
# blkdev, etc.), return None instead of a file object.
return None
def _extract_member(self, tarinfo, targetpath):
def _extract_member(self, tarinfo, targetpath, set_attrs=True):
"""Extract the TarInfo object tarinfo to a physical
file called targetpath.
"""
@ -2258,10 +2261,11 @@ class TarFile(object):
else:
self.makefile(tarinfo, targetpath)
self.chown(tarinfo, targetpath)
if not tarinfo.issym():
self.chmod(tarinfo, targetpath)
self.utime(tarinfo, targetpath)
if set_attrs:
self.chown(tarinfo, targetpath)
if not tarinfo.issym():
self.chmod(tarinfo, targetpath)
self.utime(tarinfo, targetpath)
#--------------------------------------------------------------------------
# Below are the different file methods. They are called via

View File

@ -377,6 +377,15 @@ class MiscReadTest(CommonReadTest):
finally:
tar.close()
def test_extract_directory(self):
dirtype = "ustar/dirtype"
with tarfile.open(tarname, encoding="iso8859-1") as tar:
tarinfo = tar.getmember(dirtype)
tar.extract(tarinfo)
self.assertEqual(os.path.getmtime(dirtype), tarinfo.mtime)
if sys.platform != "win32":
self.assertEqual(os.stat(dirtype).st_mode & 0o777, 0o755)
def test_init_close_fobj(self):
# Issue #7341: Close the internal file object in the TarFile
# constructor in case of an error. For the test we rely on

View File

@ -59,6 +59,8 @@ Core and Builtins
Library
-------
- Issue #10184: Touch directories only once when extracting a tarfile.
- Issue #10199: New package, ``turtledemo`` now contains selected demo
scripts that were formerly found under Demo/turtle.