You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
tarfile.extractall fails to overwrite symlinks #54970
tarfile.extractall overwrites normal files and directories, yet it fails to overwrite symlinks:
[..]
tf.extractall()
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2046, in extractall
self.extract(tarinfo, path)
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2083, in extract
self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2167, in _extract_member
self.makelink(tarinfo, targetpath)
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2243, in makelink
os.symlink(tarinfo.linkname, targetpath)
OSError: [Errno 17] File exists
To reproduce, use a .tar.gz file containing relative (i.e., in the same directory) symlinks.
Perhaps it should delete targetpath before attempting to create a symlink.
---Lib/tarfile.py 2011-04-26 20:36:33 UTC (rev 49502)+++Lib/tarfile.py 2011-04-26 21:01:24 UTC (rev 49503)@@ -2239,6 +2239,8 @@
if hasattr(os, "symlink") and hasattr(os, "link"):
# For systems that support symbolic and hard links.
if tarinfo.issym():
+ if os.path.exists(targetpath):+ os.unlink(targetpath)
os.symlink(tarinfo.linkname, targetpath)
else:
# See extract().
I had tried/tested against 3.x branch and did not find the problem. Later realized that it was only again 2.7. Pushed in the changes and the tests. I shall the tests only in 3.x codeline.
I had wrapped skipUnless decorator for the wrong test (test_extractall
instead of test_extractall_symlinks) in the 3.x code. Corrected it
and waiting for next bb reports.
It turns out that my fix was at least one byte short of complete. If the target pathname is a broken symlink, os.path.exists() returns False, and the OSError is raised. I should have used os.path.lexists(). Also, I believe the same problem exists for the hardlink case a few lines below.
ScottLeerssen commented on May 13, 2011
ScottLeerssenmannequin
Mannequin
More actions
here is a diff of a better fix based on the previous patch:
--- tarfile.py (revision 49758)+++ tarfile.py (working copy)@@ -2239,12 +2239,14 @@
if hasattr(os, "symlink") and hasattr(os, "link"):
# For systems that support symbolic and hard links.
if tarinfo.issym():
- if os.path.exists(targetpath):+ if os.path.lexists(targetpath):
os.unlink(targetpath)
os.symlink(tarinfo.linkname, targetpath)
else:
# See extract().
if os.path.exists(tarinfo._link_target):
+ if os.path.lexists(targetpath):+ os.unlink(targetpath)
os.link(tarinfo._link_target, targetpath)
else:
self._extract_member(self._find_link_target(tarinfo), targetpath)
ScottLeerssen commented on May 13, 2011
ScottLeerssenmannequin
Mannequin
More actions
tests that verify the bug/fix:
deftest_extractall_broken_symlinks(self):
# Test if extractall works properly when tarfile contains symlinkstempdir=os.path.join(TEMPDIR, "testsymlinks")
temparchive=os.path.join(TEMPDIR, "testsymlinks.tar")
os.mkdir(tempdir)
try:
source_file=os.path.join(tempdir,'source')
target_file=os.path.join(tempdir,'symlink')
withopen(source_file,'w') asf:
f.write('something\n')
os.symlink(source_file, target_file)
tar=tarfile.open(temparchive,'w')
tar.add(target_file, arcname=os.path.basename(target_file))
tar.close()
# remove the real fileos.unlink(source_file)
# Let's extract it to the location which contains the symlinktar=tarfile.open(temparchive,'r')
# this should not raise OSError: [Errno 17] File existstry:
tar.extractall(path=tempdir)
exceptOSError:
self.fail("extractall failed with broken symlinked files")
finally:
tar.close()
finally:
os.unlink(temparchive)
shutil.rmtree(TEMPDIR)
deftest_extractall_hardlinks(self):
# Test if extractall works properly when tarfile contains symlinksTEMPDIR=tempfile.mkdtemp()
tempdir=os.path.join(TEMPDIR, "testsymlinks")
temparchive=os.path.join(TEMPDIR, "testsymlinks.tar")
os.mkdir(tempdir)
try:
source_file=os.path.join(tempdir,'source')
target_file=os.path.join(tempdir,'symlink')
withopen(source_file,'w') asf:
f.write('something\n')
os.link(source_file, target_file)
tar=tarfile.open(temparchive,'w')
tar.add(source_file, arcname=os.path.basename(source_file))
tar.add(target_file, arcname=os.path.basename(target_file))
tar.close()
# Let's extract it to the location which contains the symlinktar=tarfile.open(temparchive,'r')
# this should not raise OSError: [Errno 17] File existstry:
tar.extractall(path=tempdir)
exceptOSError:
self.fail("extractall failed with linked files")
finally:
tar.close()
finally:
os.unlink(temparchive)
shutil.rmtree(TEMPDIR)
ScottLeerssen commented on May 13, 2011
ScottLeerssenmannequin
Mannequin
More actions
oops... I left some of my local edits in those tests. be sure to fix the TEMPDIR use if you add these into the tarfile tests.
Activity
srid commentedon Dec 23, 2010
tarfile.extractall overwrites normal files and directories, yet it fails to overwrite symlinks:
[..]
tf.extractall()
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2046, in extractall
self.extract(tarinfo, path)
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2083, in extract
self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2167, in _extract_member
self.makelink(tarinfo, targetpath)
File "/opt/ActivePython-2.7/lib/python2.7/tarfile.py", line 2243, in makelink
os.symlink(tarinfo.linkname, targetpath)
OSError: [Errno 17] File exists
To reproduce, use a .tar.gz file containing relative (i.e., in the same directory) symlinks.
Perhaps it should delete
targetpathbefore attempting to create a symlink.ScottLeerssen commentedon Apr 26, 2011
I just hit the same issue. This seems to work:
Modified:Lib/tarfile.py
===================================================================
orsenthil commentedon Apr 26, 2011
Scott- which platform did you observe this? I can't reproduce this on the 2.7 code on Linux.
ScottLeerssen commentedon Apr 27, 2011
It happens on RedHat and CentOS 5, but I suspect it would happen on any Unix variant. Here's a test that exacerbates the issue:
# test_tarfile.py
# Description:
# tests for python tarfile module
#$Id$
python-dev commentedon Apr 28, 2011
New changeset 0c8bc3a0130a by Senthil Kumaran in branch '2.7':
Fix closes bpo-10761: tarfile.extractall failure when symlinked files are present.
http://hg.python.org/cpython/rev/0c8bc3a0130a
orsenthil commentedon Apr 28, 2011
I had tried/tested against 3.x branch and did not find the problem. Later realized that it was only again 2.7. Pushed in the changes and the tests. I shall the tests only in 3.x codeline.
pitrou commentedon Apr 29, 2011
Senthil, Windows buildbots on 3.1, 3.2 and 3.x show test failures.
See e.g. http://www.python.org/dev/buildbot/all/builders/x86%20XP-4%203.1/builds/1780/steps/test/logs/stdio
python-dev commentedon Apr 29, 2011
New changeset 2665a28643b8 by Senthil Kumaran in branch 'default':
Wrap the correct test with the skip decorator for the bpo-10761.
http://hg.python.org/cpython/rev/2665a28643b8
orsenthil commentedon Apr 29, 2011
I had wrapped skipUnless decorator for the wrong test (test_extractall
instead of test_extractall_symlinks) in the 3.x code. Corrected it
and waiting for next bb reports.
Thank you.
orsenthil commentedon Apr 30, 2011
buildbots are green again.
ScottLeerssen commentedon May 13, 2011
It turns out that my fix was at least one byte short of complete. If the target pathname is a broken symlink, os.path.exists() returns False, and the OSError is raised. I should have used os.path.lexists(). Also, I believe the same problem exists for the hardlink case a few lines below.
ScottLeerssen commentedon May 13, 2011
here is a diff of a better fix based on the previous patch:
Index: tarfile.py
===================================================================
ScottLeerssen commentedon May 13, 2011
tests that verify the bug/fix:
ScottLeerssen commentedon May 13, 2011
oops... I left some of my local edits in those tests. be sure to fix the TEMPDIR use if you add these into the tarfile tests.