diff --git a/Lib/tarfile.py b/Lib/tarfile.py index e2b60532f693d4..633251f2abdbec 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2232,6 +2232,9 @@ def makelink(self, tarinfo, targetpath): try: # For systems that support symbolic and hard links. if tarinfo.issym(): + if os.path.islink(targetpath) or os.path.isfile(targetpath): + os.unlink(targetpath) + os.symlink(tarinfo.linkname, targetpath) else: # See extract(). diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index be66f1f89e6f39..deab9eac99ade2 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -2580,6 +2580,47 @@ def test_partial_input_bz2(self): self._test_partial_input("r:bz2") +class SymlinkOverwriteTest(unittest.TestCase): + # The testcase checks for correct overwriting of an + # existing symlink (issue #12800) + + @support.skip_unless_symlink + def test_overwrite_symlink(self): + with support.temp_cwd('overwrite_symlink'): + source = 'source' + link = 'link' + with open(source, 'wb'): + pass + os.symlink(source, link) + with tarfile.open(tmpname, 'w') as tar: + tar.add(source, arcname=os.path.basename(source)) + tar.add(link, arcname=os.path.basename(link)) + + with open(tmpname, 'rb') as fileobj: + with tarfile.open(fileobj=fileobj, mode='r|') as tar: + tar.extractall(path=support.SAVEDCWD) + + @support.skip_unless_symlink + def test_overwrite_file_with_symlink(self): + with support.temp_cwd('overwrite_file_with_symlink'): + source = 'source' + link = 'link' + with open(source, 'wb'): + pass + os.symlink(source, link) + with tarfile.open(tmpname, 'w') as tar: + tar.add(source, arcname=os.path.basename(source)) + tar.add(link, arcname=os.path.basename(link)) + + os.unlink(link) + + with open(link, 'wb'): + pass + + with open(tmpname, 'rb') as fileobj: + with tarfile.open(fileobj=fileobj, mode='r|') as tar: + tar.extractall(path=support.SAVEDCWD) + def root_is_uid_gid_0(): try: import pwd, grp diff --git a/Misc/NEWS.d/next/Library/2019-05-09-18-37-37.bpo-12800.TyjRQq.rst b/Misc/NEWS.d/next/Library/2019-05-09-18-37-37.bpo-12800.TyjRQq.rst new file mode 100644 index 00000000000000..a1208cb176746a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-05-09-18-37-37.bpo-12800.TyjRQq.rst @@ -0,0 +1 @@ +Extracting a symlink from a tarball using the tarfile module in stream mode ('r|') fails with an exception when a file or symlink of the same name already exists. The fix is to remove the existing file or symlink before extraction. \ No newline at end of file