summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSenthil Kumaran <senthil@uthcode.com>2011-05-17 10:12:18 +0800
committerSenthil Kumaran <senthil@uthcode.com>2011-05-17 10:12:18 +0800
commitaa749990f44691d71834e2929ab6e17568947642 (patch)
tree9416ee560cdc3d50f1bbba15fcae76fdba8d863c
parentcebe95af0c56d8ee53702947c4a131e2e486c14f (diff)
downloadcpython-aa749990f44691d71834e2929ab6e17568947642.tar.gz
Fix closes issue #12088 - fixes the tarfile.extractall issue when the
symlinks/hardlink was broken. It handles now in a graceful manner (No exception is raised, behavior similar GNU tar).
-rw-r--r--Lib/tarfile.py4
-rw-r--r--Lib/test/test_tarfile.py60
2 files changed, 63 insertions, 1 deletions
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 105a75880d..6b9303e898 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -2239,12 +2239,14 @@ class TarFile(object):
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)
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index f78f9ce03f..6962f8e2d7 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -872,6 +872,66 @@ class WriteTest(WriteTestBase):
os.unlink(temparchive)
shutil.rmtree(tempdir)
+ @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink")
+ def test_extractall_broken_symlinks(self):
+ # Test if extractall works properly when tarfile contains broken
+ # symlinks
+ 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')
+ with open(source_file,'w') as f:
+ 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 file
+ os.unlink(source_file)
+ # Let's extract it to the location which contains the symlink
+ tar = tarfile.open(temparchive,'r')
+ # this should not raise OSError: [Errno 17] File exists
+ try:
+ tar.extractall(path=tempdir)
+ except OSError:
+ self.fail("extractall failed with broken symlinked files")
+ finally:
+ tar.close()
+ finally:
+ os.unlink(temparchive)
+ shutil.rmtree(tempdir)
+
+ @unittest.skipUnless(hasattr(os, 'link'), "needs os.link")
+ def test_extractall_hardlinks(self):
+ # Test if extractall works properly when tarfile contains symlinks
+ 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')
+ with open(source_file,'w') as f:
+ 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 symlink
+ tar = tarfile.open(temparchive,'r')
+ # this should not raise OSError: [Errno 17] File exists
+ try:
+ tar.extractall(path=tempdir)
+ except OSError:
+ self.fail("extractall failed with linked files")
+ finally:
+ tar.close()
+ finally:
+ os.unlink(temparchive)
+ shutil.rmtree(tempdir)
+
class StreamWriteTest(WriteTestBase):
mode = "w|"