For bug #14321, add support for individual files in CONFIG_PROTECT and CONFIG_PROTECT...
authorZac Medico <zmedico@gentoo.org>
Sat, 16 Sep 2006 00:38:46 +0000 (00:38 -0000)
committerZac Medico <zmedico@gentoo.org>
Sat, 16 Sep 2006 00:38:46 +0000 (00:38 -0000)
svn path=/main/trunk/; revision=4458

pym/portage.py
pym/portage_util.py

index cab4fdcae56e3769aa50ad5fb141a838f3d89b73..d07363371d412fffd1457fb470c17e0d94f744b9 100644 (file)
@@ -6112,11 +6112,6 @@ class dblink:
                        #A directory is specified.  Figure out protection paths, listdir() it and process it.
                        mergelist = listdir(join(srcroot, stufftomerge))
                        offset=stufftomerge
-                       # We need mydest defined up here to calc. protection paths.  This is now done once per
-                       # directory rather than once per file merge.  This should really help merge performance.
-                       # Trailing / ensures that protects/masks with trailing /'s match.
-                       mytruncpath = join(destroot, offset).rstrip(sep) + sep
-                       myppath=self.isprotected(mytruncpath)
                else:
                        mergelist=stufftomerge
                        offset=""
@@ -6294,7 +6289,7 @@ class dblink:
                                                # or by a symlink to an existing regular file;
                                                # now, config file management may come into play.
                                                # we only need to tweak mydest if cfg file management is in play.
-                                               if myppath:
+                                               if self.isprotected(mydest):
                                                        # we have a protection path; enable config file management.
                                                        destmd5=portage_checksum.perform_md5(mydest,calc_prelink=1)
                                                        if mymd5==destmd5:
index c44360200006c764c214a32a1860a01d8f1866ac..83cdeda50a0fdcf55acd4653ae5c7169ae66a545 100644 (file)
@@ -7,7 +7,7 @@ from portage_exception import PortageException, FileNotFound, \
 import portage_exception
 from portage_dep import isvalidatom
 
-import sys,string,shlex,os,errno
+import os, errno, shlex, stat, string, sys
 try:
        import cPickle
 except ImportError:
@@ -829,33 +829,65 @@ class ConfigProtect(object):
                self.updateprotect()
 
        def updateprotect(self):
-               #do some config file management prep
+               """Update internal state for isprotected() calls.  Nonexistent paths
+               are ignored."""
                self.protect = []
+               self._dirs = set()
                for x in self.protect_list:
                        ppath = normalize_path(
-                               os.path.join(self.myroot, x.lstrip(os.path.sep))) + os.path.sep
-                       if os.path.isdir(ppath):
+                               os.path.join(self.myroot, x.lstrip(os.path.sep)))
+                       mystat = None
+                       try:
+                               if stat.S_ISDIR(os.lstat(ppath).st_mode):
+                                       self._dirs.add(ppath)
                                self.protect.append(ppath)
+                       except OSError:
+                               # If it doesn't exist, there's no need to protect it.
+                               pass
 
                self.protectmask = []
                for x in self.mask_list:
                        ppath = normalize_path(
-                               os.path.join(self.myroot, x.lstrip(os.path.sep))) + os.path.sep
-                       if os.path.isdir(ppath):
+                               os.path.join(self.myroot, x.lstrip(os.path.sep)))
+                       mystat = None
+                       try:
+                               if stat.S_ISDIR(os.lstat(ppath).st_mode):
+                                       self._dirs.add(ppath)
                                self.protectmask.append(ppath)
-                       #if it doesn't exist, silently skip it
+                       except OSError:
+                               # If it doesn't exist, there's no need to mask it.
+                               pass
 
        def isprotected(self, obj):
-               """Checks if obj is in the current protect/mask directories. Returns
-               0 on unprotected/masked, and 1 on protected."""
+               """Returns True if obj is protected, False otherwise.  The caller must
+               ensure that obj is normalized with a single leading slash.  A trailing
+               slash is optional for directories."""
                masked = 0
                protected = 0
+               sep = os.path.sep
                for ppath in self.protect:
                        if len(ppath) > masked and obj.startswith(ppath):
+                               if ppath in self._dirs:
+                                       if obj != ppath and not obj.startswith(ppath + sep):
+                                               # /etc/foo does not match /etc/foobaz
+                                               continue
+                               elif obj != ppath:
+                                       # force exact match when CONFIG_PROTECT lists a
+                                       # non-directory
+                                       continue
                                protected = len(ppath)
                                #config file management
                                for pmpath in self.protectmask:
                                        if len(pmpath) >= protected and obj.startswith(pmpath):
+                                               if pmpath in self._dirs:
+                                                       if obj != pmpath and \
+                                                               not obj.startswith(pmpath + sep):
+                                                               # /etc/foo does not match /etc/foobaz
+                                                               continue
+                                               elif obj != pmpath:
+                                                       # force exact match when CONFIG_PROTECT_MASK lists
+                                                       # a non-directory
+                                                       continue
                                                #skip, it's in the mask
                                                masked = len(pmpath)
                return protected > masked