diff -r 4d56006133f1 Lib/tarfile.py --- a/Lib/tarfile.py Sat Jan 18 22:57:05 2014 -0500 +++ b/Lib/tarfile.py Sun Jan 19 22:29:25 2014 +0800 @@ -2079,6 +2079,11 @@ else: self._dbg(1, tarinfo.name) + if os.path.exists(targetpath): + if os.path.isdir(targetpath) and not os.path.islink(targetpath): + os.rmdir(targetpath) + else: + os.remove(targetpath) if tarinfo.isreg(): self.makefile(tarinfo, targetpath) elif tarinfo.isdir(): @@ -2169,7 +2174,10 @@ try: # For systems that support symbolic and hard links. if tarinfo.issym(): - os.symlink(tarinfo.linkname, 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 4d56006133f1 Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py Sat Jan 18 22:57:05 2014 -0500 +++ b/Lib/test/test_tarfile.py Sun Jan 19 22:29:25 2014 +0800 @@ -1090,20 +1090,52 @@ 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') + # File symlink + 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') + f.write('source file content\n') + with open(other_source_file,'w') as f: + f.write('other source file content\n') os.symlink(source_file, target_file) + # Directory symlink + source_dir = os.path.join(tempdir, 'source_dir') + other_source_dir = os.path.join(tempdir, 'other_source_dir') + target_dir = os.path.join(tempdir, 'symlink_dir') + os.mkdir(source_dir) + os.mkdir(other_source_dir) + os.symlink(source_dir, target_dir) tar = tarfile.open(temparchive,'w') - tar.add(source_file) - tar.add(target_file) + # We don't want to add absolute path to tar file because + # we don't want nested directory after extracting the file: + # /home/user/python/symlink/home/user/python/symlink/file + with support.change_cwd(tempdir): + tar.add('source') + tar.add('symlink') + tar.add('source_dir') + tar.add('symlink_dir') tar.close() - # Let's extract it to the location which contains the symlink + # Point target_file to other_source_file and target_dir to + # other_source_dir to exercise overwriting behavior. + os.unlink(target_file) + os.symlink(other_source_file, target_file) + os.unlink(target_dir) + os.symlink(other_source_dir, target_dir) tar = tarfile.open(temparchive,'r') - # this should not raise OSError: [Errno 17] File exists try: + with open(target_file) as f: + self.assertEqual(f.read(), 'other source file content\n') + self.assertEqual(os.readlink(target_dir), other_source_dir) + # Let's extract it to the location which contains the symlink tar.extractall(path=tempdir) + # target_file that symlinked to other_source_file now symlinks + # back to source_file, and target_dir that symlinked to + # other_source_dir now symlinks back to source_dir. + with open(target_file) as f: + self.assertEqual(f.read(), 'source file content\n') + self.assertEqual(os.readlink(target_dir), source_dir) + # This should not raise OSError: [Errno 17] File exists except OSError: self.fail("extractall failed with symlinked files") finally: