Bugs #168772 and #193695 - During unmerge, only ignore specific
authorZac Medico <zmedico@gentoo.org>
Wed, 26 Sep 2007 04:46:33 +0000 (04:46 -0000)
committerZac Medico <zmedico@gentoo.org>
Wed, 26 Sep 2007 04:46:33 +0000 (04:46 -0000)
exceptions raised from unlink() and rmdir() calls.

Bug #193695 - Add support for FreeBSD chflags during unmerge. This
code is adapted from the code that already exists in movefile()
for the merge phase.

In movefile() FreeBSD chflags handling, use chflags instead of
lchflags when temporarily adjusting the flags on the parent
directory since we want to follow any symlinks to the real
parent directory.

(trunk r7803:7807)

svn path=/main/branches/2.1.2/; revision=7832

pym/portage.py

index 47d204b6350a4ce675f37e8b958c03672edade2f..39ecb0dab8420cc15a23c59d8bb3acba710746ba 100644 (file)
@@ -4148,9 +4148,11 @@ def movefile(src,dest,newmtime=None,sstat=None,mysettings=None):
        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]):
@@ -4257,7 +4259,7 @@ def movefile(src,dest,newmtime=None,sstat=None,mysettings=None):
        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
 
@@ -7446,7 +7448,30 @@ class dblink:
 
                        #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))
@@ -7496,13 +7521,11 @@ class dblink:
                                        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
 
@@ -7528,9 +7551,12 @@ class dblink:
                                        # 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):
@@ -7550,13 +7576,11 @@ class dblink:
                                                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]):
@@ -7571,10 +7595,31 @@ class dblink:
 
                        for obj in mydirs:
                                try:
-                                       os.rmdir(obj)
+                                       if bsd_chflags:
+                                               lstatobj = os.lstat(obj)
+                                               if lstatobj.st_flags != 0:
+                                                       bsd_chflags.lchflags(obj, 0)
+                                               parent_name = os.path.dirname(obj)
+                                               # 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:
+                                               os.rmdir(obj)
+                                       finally:
+                                               if bsd_chflags and pflags != 0:
+                                                       # Restore the parent flags we saved before unlinking
+                                                       bsd_chflags.chflags(parent_name, pflags)
                                        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)