Issue #10184: Touch directories only once when extracting a tarfile.
This commit is contained in:
parent
bbea35f194
commit
16f344df36
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue