Index: pym/portage.py =================================================================== --- pym/portage.py (revision 7806) +++ pym/portage.py (working copy) @@ -4139,9 +4139,11 @@ if bsd_chflags: if destexists and dstat.st_flags != 0: bsd_chflags.lchflags(dest, 0) + # Use normal stat/chflags for the parent since we want to + # follow any symlinks to the real parent directory. pflags = os.stat(os.path.dirname(dest)).st_flags if pflags != 0: - bsd_chflags.lchflags(os.path.dirname(dest), 0) + bsd_chflags.chflags(os.path.dirname(dest), 0) if destexists: if stat.S_ISLNK(dstat[stat.ST_MODE]): @@ -4248,7 +4250,7 @@ if bsd_chflags: # Restore the flags we saved before moving if pflags: - bsd_chflags.lchflags(os.path.dirname(dest), pflags) + bsd_chflags.chflags(os.path.dirname(dest), pflags) return newmtime @@ -7437,7 +7439,30 @@ #process symlinks second-to-last, directories last. mydirs = [] + ignored_unlink_errnos = (errno.ENOENT, errno.EISDIR) modprotect = os.path.join(self.vartree.root, "lib/modules/") + + def unlink(file_name, lstatobj): + if bsd_chflags: + if lstatobj.st_flags != 0: + bsd_chflags.lchflags(file_name, 0) + parent_name = os.path.dirname(file_name) + # Use normal stat/chflags for the parent since we want to + # follow any symlinks to the real parent directory. + pflags = os.stat(parent_name).st_flags + if pflags != 0: + bsd_chflags.chflags(parent_name, 0) + try: + if not stat.S_ISLNK(lstatobj.st_mode): + # Remove permissions to ensure that any hardlinks to + # suid/sgid files are rendered harmless. + os.chmod(file_name, 0) + os.unlink(file_name) + finally: + if bsd_chflags and pflags != 0: + # Restore the parent flags we saved before unlinking + bsd_chflags.chflags(parent_name, pflags) + def show_unmerge(zing, desc, file_type, file_name): writemsg_stdout("%s %s %s %s\n" % \ (zing, desc.ljust(8), file_type, file_name)) @@ -7487,13 +7512,11 @@ not (islink and statobj and stat.S_ISDIR(statobj.st_mode)) and \ not self.isprotected(obj): try: - # Remove permissions to ensure that any hardlinks to - # suid/sgid files are rendered harmless. - if statobj and not islink: - os.chmod(obj, 0) - os.unlink(obj) + unlink(obj, lstatobj) except EnvironmentError, e: - pass + if e.errno not in ignored_unlink_errnos: + raise + del e show_unmerge("<<<", "", file_type, obj) continue @@ -7519,9 +7542,12 @@ # contents as a directory even if it happens to correspond # to a symlink when it's merged to the live filesystem. try: - os.unlink(obj) + unlink(obj, lstatobj) show_unmerge("<<<", "", file_type, obj) - except (OSError,IOError),e: + except (OSError, IOError),e: + if e.errno not in ignored_unlink_errnos: + raise + del e show_unmerge("!!!", "", file_type, obj) elif pkgfiles[objkey][0] == "obj": if statobj is None or not stat.S_ISREG(statobj.st_mode): @@ -7541,13 +7567,11 @@ show_unmerge("---", "!md5", file_type, obj) continue try: - # Remove permissions to ensure that any hardlinks to - # suid/sgid files are rendered harmless. - if not islink: - os.chmod(obj, 0) - os.unlink(obj) + unlink(obj, lstatobj) except (OSError,IOError),e: - pass + if e.errno not in ignored_unlink_errnos: + raise + del e show_unmerge("<<<", "", file_type, obj) elif pkgfiles[objkey][0] == "fif": if not stat.S_ISFIFO(lstatobj[stat.ST_MODE]): @@ -7564,8 +7588,14 @@ try: os.rmdir(obj) show_unmerge("<<<", "", "dir", obj) - except (OSError, IOError): - show_unmerge("---", "!empty", "dir", obj) + except EnvironmentError, e: + if e.errno not in (errno.ENOENT, + errno.EEXIST, errno.ENOTEMPTY, + errno.ENOTDIR): + raise + if e.errno != errno.ENOENT: + show_unmerge("---", "!empty", "dir", obj) + del e #remove self from vartree database so that our own virtual gets zapped if we're the last node self.vartree.zap(self.mycpv)