diff -r 51dddfead80a Lib/tarfile.py --- a/Lib/tarfile.py Sun Dec 15 20:33:02 2013 +1000 +++ b/Lib/tarfile.py Sun Dec 15 22:09:46 2013 +0800 @@ -1996,8 +1996,21 @@ tarinfo._link_target = os.path.join(path, tarinfo.linkname) try: - self._extract_member(tarinfo, os.path.join(path, tarinfo.name), - set_attrs=set_attrs) + drv, normalized_path = os.path.splitdrive(path) + normalized_path = normalized_path.replace(os.sep, '/') + joined_path = '/' + tarinfo.name + # We don't want to join '/home/user' and 'home/user/file' to avoid + # '/home/user/home/user/file'. + native_tarinfo_name = tarinfo.name.replace('/', os.sep) + if normalized_path != joined_path[:len(normalized_path)]: + joined_path = os.path.join(path, native_tarinfo_name) + else: + # tarinfo.name is an absolute path + if os.name == 'nt': + joined_path = drv + os.sep + native_tarinfo_name + else: + joined_path = os.sep + native_tarinfo_name + self._extract_member(tarinfo, joined_path, set_attrs=set_attrs) except OSError as e: if self.errorlevel > 0: raise @@ -2155,7 +2168,12 @@ try: # For systems that support symbolic and hard links. if tarinfo.issym(): - os.symlink(tarinfo.linkname, targetpath) + if os.path.exists(targetpath): + os.unlink(targetpath) + if os.name == 'nt' and os.path.isdir(tarinfo.linkname): + os.symlink(tarinfo.linkname, targetpath, target_is_directory=True) + else: + os.symlink(tarinfo.linkname, targetpath) else: # See extract(). if os.path.exists(tarinfo._link_target): diff -r 51dddfead80a Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py Sun Dec 15 20:33:02 2013 +1000 +++ b/Lib/test/test_tarfile.py Sun Dec 15 22:09:46 2013 +0800 @@ -1068,20 +1068,28 @@ temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") os.mkdir(tempdir) try: - source_file = os.path.join(tempdir,'source') + source_file = os.path.join(tempdir, 'source') + other_source_file = os.path.join(tempdir, 'other_source') target_file = os.path.join(tempdir,'symlink') - with open(source_file,'w') as f: - f.write('something\n') + open(source_file, 'w').close() + open(other_source_file, 'w').close() os.symlink(source_file, target_file) tar = tarfile.open(temparchive,'w') tar.add(source_file) tar.add(target_file) tar.close() + # Point target_file to other_source_file to exercise overwriting + # behavior. + os.unlink(target_file) + os.symlink(other_source_file, target_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 + # This should not raise OSError: [Errno 17] File exists try: tar.extractall(path=tempdir) + # target_file that symlinked to other_source_file now symlinks + # back to source_file. + self.assertEqual(os.readlink(target_file), source_file) except OSError: self.fail("extractall failed with symlinked files") finally: