From b3f13364d8f346510bd3f86830b1b0a7d69ddc7b Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher Date: Thu, 9 May 2019 02:43:48 -0700 Subject: [PATCH 1/2] bpo-12800: 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. Tests are included. --- Lib/tarfile.py | 3 ++ Lib/test/test_tarfile.py | 64 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 2c06f9160c658a..6837a4e7e9ee99 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2226,6 +2226,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 7e32cbccd6c56d..cd3c9724d2f832 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -2498,6 +2498,70 @@ 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): + tmpdir = support.temp_cwd('overwrite_symlink') + source = 'source' + link = 'link' + try: + 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) + finally: + try: + os.unlink(link) + except: + pass + + try: + os.unlink(source) + except: + pass + + @support.skip_unless_symlink + def test_overwrite_file_with_symlink(self): + tmpdir = support.temp_cwd('overwrite_file_with_symlink') + source = 'source' + link = 'link' + try: + 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) + finally: + try: + os.unlink(link) + except: + pass + + try: + os.unlink(source) + except: + pass + + def root_is_uid_gid_0(): try: import pwd, grp From 66ffbac51759d79b729b871cd1cd5467a777037a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" Date: Thu, 9 May 2019 18:37:38 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2019-05-09-18-37-37.bpo-12800.TyjRQq.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2019-05-09-18-37-37.bpo-12800.TyjRQq.rst 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