]> git.saurik.com Git - apple/configd.git/blobdiff - configd.tproj/pattern.c
configd-1109.101.1.tar.gz
[apple/configd.git] / configd.tproj / pattern.c
index fa3bf864fa0f276ba0bb1af9e4c53d8eb9cdf24b..909075762ab948bf38f24ecc4e367d657c28e4d7 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003, 2004, 2006-2008, 2011, 2012, 2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -47,7 +47,7 @@
 
 typedef struct {
        CFMutableArrayRef       pInfo;
-       regex_t                 *preg;
+       CFDataRef               pRegex;
 } addContext, *addContextRef;
 
 
@@ -67,39 +67,33 @@ my_CFDictionaryApplyFunction(CFDictionaryRef                        theDict,
 }
 
 
-static void
-identifyKeyForPattern(const void *key, void *val, void *context)
+static Boolean
+keyMatchesPattern(CFStringRef key, CFDataRef pRegex)
 {
-       CFStringRef             storeKey        = (CFStringRef)key;
-       CFDictionaryRef         storeValue      = (CFDictionaryRef)val;
-       CFMutableArrayRef       pInfo           = ((addContextRef)context)->pInfo;
-       regex_t *               preg            = ((addContextRef)context)->preg;
-
        CFIndex                 len;
+       Boolean                 match           = FALSE;
+       regex_t                 *preg;
        int                     reError;
        char                    str_q[256];
        char *                  str             = str_q;
 
-       if (!CFDictionaryContainsKey(storeValue, kSCDData)) {
-               /* if no data (yet) */
-               return;
-       }
-
        /* convert store key to C string */
-       len = CFStringGetLength(storeKey) + 1;
+       len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), kCFStringEncodingASCII) + 1;
        if (len > (CFIndex)sizeof(str_q))
                str = CFAllocatorAllocate(NULL, len, 0);
-       if (_SC_cfstring_to_cstring(storeKey, str, len, kCFStringEncodingASCII) == NULL) {
-               SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not convert store key to C string"));
+       if (_SC_cfstring_to_cstring(key, str, len, kCFStringEncodingASCII) == NULL) {
+               SC_log(LOG_INFO, "could not convert store key to C string");
                goto done;
        }
 
-       /* compare store key to new notification keys regular expression pattern */
+       /* ALIGN: CF aligns to >8 byte boundries */
+       preg = (regex_t *)(void *)CFDataGetBytePtr(pRegex);
+
+       /* compare key to regular expression pattern */
        reError = regexec(preg, str, 0, NULL, 0);
        switch (reError) {
                case 0 :
-                       /* we've got a match */
-                       CFArrayAppendValue(pInfo, storeKey);
+                       match = TRUE;
                        break;
                case REG_NOMATCH :
                        /* no match */
@@ -108,7 +102,7 @@ identifyKeyForPattern(const void *key, void *val, void *context)
                        char    reErrBuf[256];
 
                        (void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
-                       SCLog(_configd_verbose, LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+                       SC_log(LOG_INFO, "regexec() failed: %s", reErrBuf);
                        break;
                }
        }
@@ -116,20 +110,47 @@ identifyKeyForPattern(const void *key, void *val, void *context)
     done :
 
        if (str != str_q) CFAllocatorDeallocate(NULL, str);
+       return match;
+}
+
+
+static void
+identifyKeyForPattern(const void *key, void *val, void *context)
+{
+       CFStringRef             storeKey        = (CFStringRef)key;
+       CFDictionaryRef         storeValue      = (CFDictionaryRef)val;
+       CFMutableArrayRef       pInfo           = ((addContextRef)context)->pInfo;
+       CFDataRef               pRegex          = ((addContextRef)context)->pRegex;
+
+       if (!CFDictionaryContainsKey(storeValue, kSCDData)) {
+               /* if no data (yet) */
+               return;
+       }
+
+       if (keyMatchesPattern(storeKey, pRegex)) {
+               /* if we've got a match */
+               CFArrayAppendValue(pInfo, storeKey);
+       }
+
        return;
 }
 
 
-__private_extern__ Boolean
-patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error)
+static Boolean
+patternCompile(CFStringRef pattern, CFDataRef pRegex, CFStringRef *error)
 {
        Boolean         append          = FALSE;
        Boolean         insert          = FALSE;
        CFIndex         len             = 0;
+       CFIndex         len_c;
        Boolean         ok;
        char            str_q[256];
        char *          str             = str_q;
 
+       if (CFStringGetLength(pattern) == 0) {
+               SC_log(LOG_NOTICE, "empty regex pattern");
+       }
+
        if (!CFStringHasPrefix(pattern, CFSTR("^"))) {
                insert = TRUE;
        }
@@ -149,14 +170,18 @@ patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error)
                                                 append ? "$" : "");
        }
 
-       (void)CFStringGetBytes(pattern,
-                              CFRangeMake(0, CFStringGetLength(pattern)),
-                              kCFStringEncodingASCII,
-                              0,
-                              FALSE,
-                              NULL,
-                              0,
-                              &len);
+       len_c = CFStringGetBytes(pattern,
+                                CFRangeMake(0, CFStringGetLength(pattern)),
+                                kCFStringEncodingASCII,
+                                0,
+                                FALSE,
+                                NULL,
+                                0,
+                                &len);
+       if (len_c <= 0) {
+               SC_log(LOG_NOTICE, "could not get buffer length for \"%@\"", pattern);
+               len = sizeof(str_q) - 1;
+       }
        if (++len > (CFIndex)sizeof(str_q)) {
                str = CFAllocatorAllocate(NULL, len, 0);
        }
@@ -165,20 +190,28 @@ patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error)
                CFRelease(pattern);
        }
        if (ok) {
+               regex_t *preg;
                int     reError;
 
+               /* ALIGN: CF aligns to >8 byte boundries */
+               preg = (regex_t *)(void *)CFDataGetBytePtr(pRegex);
+
                reError = regcomp(preg, str, REG_EXTENDED);
                if (reError != 0) {
                        char    reErrBuf[256];
 
                        (void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
                        *error = CFStringCreateWithCString(NULL, reErrBuf, kCFStringEncodingASCII);
-                       SCLog(_configd_verbose, LOG_DEBUG, CFSTR("regcomp(%s) failed: %s"), str, reErrBuf);
+#ifdef DEBUG
+                       SC_log(LOG_DEBUG, "regcomp(%s) failed: %s", str, reErrBuf);
+#endif /* DEBUG */
                        ok = FALSE;
                }
        } else {
                *error = CFRetain(CFSTR("could not convert pattern to regex string"));
-               SCLog(_configd_verbose, LOG_DEBUG, CFSTR("%@"), *error);
+#ifdef DEBUG
+               SC_log(LOG_DEBUG, "%@", *error);
+#endif /* DEBUG */
        }
 
        if (str != str_q)       CFAllocatorDeallocate(NULL, str);
@@ -186,23 +219,34 @@ patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error)
 }
 
 
-__private_extern__
-CFMutableArrayRef
+static void
+patternRelease(CFDataRef pRegex)
+{
+       regex_t         *preg;
+
+       /* ALIGN: CF aligns to >8 byte boundries */
+       preg = (regex_t *)(void *)CFDataGetBytePtr(pRegex);
+       regfree(preg);
+
+       return;
+}
+
+
+static CF_RETURNS_RETAINED CFMutableArrayRef
 patternCopy(CFStringRef        pattern)
 {
        CFArrayRef      pInfo;
 
        pInfo = CFDictionaryGetValue(patternData, pattern);
-       return pInfo ? CFArrayCreateMutableCopy(NULL, 0, pInfo) : NULL;
+       return (pInfo != NULL) ? CFArrayCreateMutableCopy(NULL, 0, pInfo) : NULL;
 }
 
 
-__private_extern__
-CFMutableArrayRef
+static CF_RETURNS_RETAINED CFMutableArrayRef
 patternNew(CFStringRef pattern)
 {
        addContext              context;
-       CFStringRef             err;
+       CFStringRef             err     = NULL;
        CFMutableArrayRef       pInfo;
        CFMutableDataRef        pRegex;
        CFArrayRef              pSessions;
@@ -213,7 +257,7 @@ patternNew(CFStringRef pattern)
        /* compile the regular expression from the pattern string. */
        pRegex = CFDataCreateMutable(NULL, sizeof(regex_t));
        CFDataSetLength(pRegex, sizeof(regex_t));
-       if (!patternCompile(pattern, (regex_t *)CFDataGetBytePtr(pRegex), &err)) {
+       if (!patternCompile(pattern, pRegex, &err)) {
                CFRelease(err);
                CFRelease(pRegex);
                CFRelease(pInfo);
@@ -229,8 +273,8 @@ patternNew(CFStringRef pattern)
        CFRelease(pSessions);
 
        /* identify/add all existing keys that match the specified pattern */
-       context.pInfo = pInfo;
-       context.preg  = (regex_t *)CFDataGetBytePtr(pRegex);
+       context.pInfo  = pInfo;
+       context.pRegex = pRegex;
        my_CFDictionaryApplyFunction(storeData,
                                     (CFDictionaryApplierFunction)identifyKeyForPattern,
                                     &context);
@@ -240,6 +284,87 @@ patternNew(CFStringRef pattern)
 }
 
 
+__private_extern__
+CFArrayRef
+patternCopyMatches(CFStringRef pattern)
+{
+       Boolean                 isNew   = FALSE;
+       CFArrayRef              keys;
+       CFMutableArrayRef       pInfo;
+
+       /* find (or create new instance of) this pattern */
+       pInfo = patternCopy(pattern);
+       if (pInfo == NULL) {
+               /* if new pattern */
+               pInfo = patternNew(pattern);
+               if (pInfo == NULL) {
+                       return NULL;
+               }
+
+               isNew = TRUE;
+       }
+
+       if (isNew) {
+               CFDataRef       pRegex;
+
+               pRegex = CFArrayGetValueAtIndex(pInfo, 0);
+               patternRelease(pRegex);
+       }
+
+       CFArrayReplaceValues(pInfo, CFRangeMake(0, 2), NULL, 0);
+       keys = CFArrayCreateCopy(NULL, pInfo);
+       CFRelease(pInfo);
+
+       return keys;
+}
+
+
+__private_extern__
+Boolean
+patternKeyMatches(CFStringRef pattern, CFStringRef key)
+{
+       Boolean                 isNew   = FALSE;
+       Boolean                 match   = FALSE;
+       CFMutableArrayRef       pInfo;
+       CFDataRef               pRegex;
+
+       /* find (or create new instance of) this pattern */
+       pInfo = patternCopy(pattern);
+       if (pInfo != NULL) {
+               CFIndex         n;
+
+               /* if existing pattern, check if known key */
+               n = CFArrayGetCount(pInfo);
+               match = (n > 2) &&
+                       CFArrayContainsValue(pInfo, CFRangeMake(2, n - 2), key);
+               if (match) {
+                       goto done;
+               }
+       } else {
+               /* if new pattern */
+               pInfo = patternNew(pattern);
+               if (pInfo == NULL) {
+                       return FALSE;
+               }
+
+               isNew = TRUE;
+       }
+
+       pRegex = CFArrayGetValueAtIndex(pInfo, 0);
+       match = keyMatchesPattern(key, pRegex);
+
+       if (isNew) {
+               patternRelease(pRegex);
+       }
+
+    done :
+
+       CFRelease(pInfo);
+
+       return match;
+}
+
+
 __private_extern__
 Boolean
 patternAddSession(CFStringRef pattern, CFNumberRef sessionNum)
@@ -251,10 +376,10 @@ patternAddSession(CFStringRef pattern, CFNumberRef sessionNum)
 
        /* find (or create new instance of) this pattern */
        pInfo = patternCopy(pattern);
-       if (!pInfo) {
+       if (pInfo == NULL) {
                /* if new pattern */
                pInfo = patternNew(pattern);
-               if (!pInfo) {
+               if (pInfo == NULL) {
                        return FALSE;
                }
        }
@@ -295,6 +420,7 @@ patternRemoveSession(CFStringRef pattern, CFNumberRef sessionNum)
 
        /* find instance of this pattern */
        pInfo = patternCopy(pattern);
+       assert(pInfo != NULL);
 
        /* remove this session as a watcher from all matching keys */
        n = CFArrayGetCount(pInfo);
@@ -322,7 +448,7 @@ patternRemoveSession(CFStringRef pattern, CFNumberRef sessionNum)
                /* if no other sessions are watching this pattern */
 
                pRegex = CFArrayGetValueAtIndex(pInfo, 0);
-               regfree((regex_t *)CFDataGetBytePtr(pRegex));
+               patternRelease(pRegex);
                CFDictionaryRemoveValue(patternData, pattern);
        }
 
@@ -345,16 +471,17 @@ addKeyForPattern(const void *key, void *val, void *context)
        char *                  str             = str_q;
 
        /* convert store key to C string */
-       len = CFStringGetLength(storeKey) + 1;
+       len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(storeKey), kCFStringEncodingASCII) + 1;
        if (len > (CFIndex)sizeof(str_q))
                str = CFAllocatorAllocate(NULL, len, 0);
        if (_SC_cfstring_to_cstring(storeKey, str, len, kCFStringEncodingASCII) == NULL) {
-               SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not convert store key to C string"));
+               SC_log(LOG_INFO, "could not convert store key to C string");
                goto done;
        }
 
        /* compare new store key to regular expression pattern */
-       preg = (regex_t *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0));
+       /* ALIGN: CF aligns to >8 byte boundries */
+       preg = (regex_t *)(void *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0));
        reError = regexec(preg, str, 0, NULL, 0);
        switch (reError) {
                case 0 : {
@@ -389,7 +516,7 @@ addKeyForPattern(const void *key, void *val, void *context)
                        char    reErrBuf[256];
 
                        (void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
-                       SCLog(_configd_verbose, LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+                       SC_log(LOG_INFO, "%s", reErrBuf);
                        break;
                }
        }
@@ -405,9 +532,11 @@ __private_extern__
 void
 patternAddKey(CFStringRef key)
 {
+       void    *context        = (void *)key;
+
        my_CFDictionaryApplyFunction(patternData,
                                     (CFDictionaryApplierFunction)addKeyForPattern,
-                                    (void *)key);
+                                    context);
 
        return;
 }
@@ -432,7 +561,7 @@ removeKeyFromPattern(const void *key, void *val, void *context)
        }
 
        i = CFArrayGetFirstIndexOfValue(pInfo, CFRangeMake(2, n-2), storeKey);
-       if (i == -1) {
+       if (i == kCFNotFound) {
                /* if this key wasn't matched by this pattern */
                return;
        }
@@ -460,9 +589,11 @@ __private_extern__
 void
 patternRemoveKey(CFStringRef key)
 {
+       void    *context        = (void *)key;
+
        my_CFDictionaryApplyFunction(patternData,
                                     (CFDictionaryApplierFunction)removeKeyFromPattern,
-                                    (void *)key);
+                                    context);
 
        return;
 }