From 6f1c2dd6c1eebdcc67d01a19def6300c20073dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20A=C5=9F=C4=B1c=C4=B1?= Date: Thu, 31 Mar 2011 11:37:55 +0000 Subject: [PATCH] archive: Fix failure when a directory is changed with a symlink --- pisi/archive.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/pisi/archive.py b/pisi/archive.py index d6912216..25248600 100644 --- a/pisi/archive.py +++ b/pisi/archive.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2005-2010, TUBITAK/UEKAE +# Copyright (C) 2005-2011, TUBITAK/UEKAE # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free @@ -297,6 +297,45 @@ class ArchiveTar(ArchiveBase): if callback: callback(tarinfo, extracted=False) + if tarinfo.issym() and \ + os.path.isdir(tarinfo.name) and \ + not os.path.islink(tarinfo.name): + # Changing a directory with a symlink. tarfile module + # cannot handle this case. + + if os.path.isdir(tarinfo.linkname): + # Symlink target is a directory. Move old directory's + # content to this directory. + for filename in os.listdir(tarinfo.name): + old_path = util.join_path(tarinfo.name, filename) + new_path = util.join_path(tarinfo.linkname, filename) + + if os.path.lexists(new_path): + if not os.path.isdir(new_path): + # A file with the same name exists in the + # target. Remove the one in the old directory. + os.remove(old_path) + continue + + os.renames(old_path, new_path) + + os.rmdir(tarinfo.name) + + elif not os.path.lexists(tarinfo.linkname): + # Symlink target does not exist. Assume the old + # directory is moved to another place in package. + os.renames(tarinfo.name, tarinfo.linkname) + + else: + # This should not happen. Probably a packaging error. + # Try to rename directory + try: + os.rename(tarinfo.name, + "%s.renamed-by-pisi" % tarinfo.name) + except: + # If fails, try to remove it + shutil.rmtree(tarinfo.name) + self.tar.extract(tarinfo) # tarfile.extract does not honor umask. It must be honored