Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
14 kB · 599 lines
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600/* * 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * 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@ */
/* * Modification History * * April 23, 2003 Allan Nathanson <ajn@apple.com> * - initial revision */
#include "configd.h"#include "pattern.h"
/* * Notes: * * - pattern matching information is maintained in a dictionary (patternData). * - the dictionary "key" is the regular expression being matched * - the dictionary "value" is a CFArray with the following contents * [0] = CFData consisting of the pre-compiled regular expression * [1] = CFArray[CFNumber] consisting of the sessions watching this pattern * [2-n] = dynamic store keys which match this pattern */
typedef struct { CFMutableArrayRef pInfo; CFDataRef pRegex;} addContext, *addContextRef;
static __inline__ voidmy_CFDictionaryApplyFunction(CFDictionaryRef theDict, CFDictionaryApplierFunction applier, void *context){ CFAllocatorRef myAllocator; CFDictionaryRef myDict;
myAllocator = CFGetAllocator(theDict); myDict = CFDictionaryCreateCopy(myAllocator, theDict); CFDictionaryApplyFunction(myDict, applier, context); CFRelease(myDict); return;}
static BooleankeyMatchesPattern(CFStringRef key, CFDataRef pRegex){ CFIndex len; Boolean match = FALSE; regex_t *preg; int reError; char str_q[256]; char * str = str_q;
/* convert store key to C string */ len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), kCFStringEncodingASCII) + 1; if (len > (CFIndex)sizeof(str_q)) str = CFAllocatorAllocate(NULL, len, 0); if (_SC_cfstring_to_cstring(key, str, len, kCFStringEncodingASCII) == NULL) { SC_log(LOG_INFO, "could not convert store key to C string"); goto done; }
/* 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 : match = TRUE; break; case REG_NOMATCH : /* no match */ break; default : { char reErrBuf[256];
(void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf)); SC_log(LOG_INFO, "regexec() failed: %s", reErrBuf); break; } }
done :
if (str != str_q) CFAllocatorDeallocate(NULL, str); return match;}
static voididentifyKeyForPattern(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;}
static BooleanpatternCompile(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; }
if (!CFStringHasSuffix(pattern, CFSTR("$")) || CFStringHasSuffix(pattern, CFSTR("\\$"))) { append = TRUE; }
/* if regex pattern is not bounded at both ends */ if (insert || append) { pattern = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s%@%s"), insert ? "^" : "", pattern, append ? "$" : ""); }
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); } ok = (_SC_cfstring_to_cstring(pattern, str, len, kCFStringEncodingASCII) != NULL); if (insert || append) { 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);#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"));#ifdef DEBUG SC_log(LOG_DEBUG, "%@", *error);#endif /* DEBUG */ }
if (str != str_q) CFAllocatorDeallocate(NULL, str); return ok;}
static voidpatternRelease(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 CFMutableArrayRefpatternCopy(CFStringRef pattern){ CFArrayRef pInfo;
pInfo = CFDictionaryGetValue(patternData, pattern); return (pInfo != NULL) ? CFArrayCreateMutableCopy(NULL, 0, pInfo) : NULL;}
static CF_RETURNS_RETAINED CFMutableArrayRefpatternNew(CFStringRef pattern){ addContext context; CFStringRef err = NULL; CFMutableArrayRef pInfo; CFMutableDataRef pRegex; CFArrayRef pSessions;
/* create the pattern info */ pInfo = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
/* compile the regular expression from the pattern string. */ pRegex = CFDataCreateMutable(NULL, sizeof(regex_t)); CFDataSetLength(pRegex, sizeof(regex_t)); if (!patternCompile(pattern, pRegex, &err)) { CFRelease(err); CFRelease(pRegex); CFRelease(pInfo); return NULL; }
/* add the compiled regular expression to the pattern info */ CFArrayAppendValue(pInfo, pRegex);
/* add the initial (empty) list of sessions watching this pattern */ pSessions = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(pInfo, pSessions); CFRelease(pSessions);
/* identify/add all existing keys that match the specified pattern */ context.pInfo = pInfo; context.pRegex = pRegex; my_CFDictionaryApplyFunction(storeData, (CFDictionaryApplierFunction)identifyKeyForPattern, &context);
CFRelease(pRegex); return pInfo;}
__private_extern__CFArrayRefpatternCopyMatches(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__BooleanpatternKeyMatches(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__BooleanpatternAddSession(CFStringRef pattern, CFNumberRef sessionNum){ CFIndex i; CFIndex n; CFMutableArrayRef pInfo; CFMutableArrayRef pSessions;
/* find (or create new instance of) this pattern */ pInfo = patternCopy(pattern); if (pInfo == NULL) { /* if new pattern */ pInfo = patternNew(pattern); if (pInfo == NULL) { return FALSE; } }
/* add this session as a pattern watcher */ pSessions = (CFMutableArrayRef)CFArrayGetValueAtIndex(pInfo, 1); pSessions = CFArrayCreateMutableCopy(NULL, 0, pSessions); CFArrayAppendValue(pSessions, sessionNum); CFArraySetValueAtIndex(pInfo, 1, pSessions); CFRelease(pSessions);
/* update pattern watcher info */ CFDictionarySetValue(patternData, pattern, pInfo);
/* add this session as a watcher of any existing keys */ n = CFArrayGetCount(pInfo); for (i = 2; i < n; i++) { CFStringRef matchingKey;
matchingKey = CFArrayGetValueAtIndex(pInfo, i); _addWatcher(sessionNum, matchingKey); }
CFRelease(pInfo); return TRUE;}
__private_extern__voidpatternRemoveSession(CFStringRef pattern, CFNumberRef sessionNum){ CFIndex i; CFIndex n; CFMutableArrayRef pInfo; CFDataRef pRegex; CFMutableArrayRef pSessions;
/* find instance of this pattern */ pInfo = patternCopy(pattern); assert(pInfo != NULL);
/* remove this session as a watcher from all matching keys */ n = CFArrayGetCount(pInfo); for (i = 2; i < n; i++) { CFStringRef matchingKey;
matchingKey = CFArrayGetValueAtIndex(pInfo, i); _removeWatcher(sessionNum, matchingKey); }
/* remove session from watchers */ pSessions = (CFMutableArrayRef)CFArrayGetValueAtIndex(pInfo, 1); n = CFArrayGetCount(pSessions); if (n > 1) { /* if other sessions are watching this pattern */
pSessions = CFArrayCreateMutableCopy(NULL, 0, pSessions); i = CFArrayGetFirstIndexOfValue(pSessions, CFRangeMake(0, n), sessionNum); CFArrayRemoveValueAtIndex(pSessions, i); CFArraySetValueAtIndex(pInfo, 1, pSessions); CFRelease(pSessions);
CFDictionarySetValue(patternData, pattern, pInfo); } else { /* if no other sessions are watching this pattern */
pRegex = CFArrayGetValueAtIndex(pInfo, 0); patternRelease(pRegex); CFDictionaryRemoveValue(patternData, pattern); }
CFRelease(pInfo); return;}
static voidaddKeyForPattern(const void *key, void *val, void *context){ CFStringRef pattern = (CFStringRef)key; CFArrayRef pInfo = (CFArrayRef)val; CFStringRef storeKey = (CFStringRef)context;
CFIndex len; regex_t *preg; int reError; char str_q[256]; char * str = str_q;
/* convert store key to C string */ 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) { SC_log(LOG_INFO, "could not convert store key to C string"); goto done; }
/* compare new store key to regular expression pattern */ /* 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 : { /* * we've got a match */ CFIndex i; CFIndex n; CFMutableArrayRef pInfo_new; CFArrayRef pSessions;
/* add watchers */ pSessions = CFArrayGetValueAtIndex(pInfo, 1); n = CFArrayGetCount(pSessions); for (i = 0; i < n; i++) { CFNumberRef sessionNum = CFArrayGetValueAtIndex(pSessions, i);
_addWatcher(sessionNum, storeKey); }
/* add key, update pattern watcher info */ pInfo_new = CFArrayCreateMutableCopy(NULL, 0, pInfo); CFArrayAppendValue(pInfo_new, storeKey); CFDictionarySetValue(patternData, pattern, pInfo_new); CFRelease(pInfo_new); break; } case REG_NOMATCH : /* no match */ break; default : { char reErrBuf[256];
(void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf)); SC_log(LOG_INFO, "%s", reErrBuf); break; } }
done :
if (str != str_q) CFAllocatorDeallocate(NULL, str); return;}
__private_extern__voidpatternAddKey(CFStringRef key){ void *context = (void *)key;
my_CFDictionaryApplyFunction(patternData, (CFDictionaryApplierFunction)addKeyForPattern, context);
return;}
static voidremoveKeyFromPattern(const void *key, void *val, void *context){ CFStringRef pattern = (CFStringRef)key; CFArrayRef pInfo = (CFArrayRef)val; CFStringRef storeKey = (CFStringRef)context;
CFIndex i; CFIndex n; CFMutableArrayRef pInfo_new; CFArrayRef pSessions;
n = CFArrayGetCount(pInfo); if (n <= 2) { /* if no keys match this pattern */ return; }
i = CFArrayGetFirstIndexOfValue(pInfo, CFRangeMake(2, n-2), storeKey); if (i == kCFNotFound) { /* if this key wasn't matched by this pattern */ return; }
/* remove key from pattern info */ pInfo_new = CFArrayCreateMutableCopy(NULL, 0, pInfo); CFArrayRemoveValueAtIndex(pInfo_new, i);
/* remove watchers */ pSessions = CFArrayGetValueAtIndex(pInfo_new, 1); n = CFArrayGetCount(pSessions); for (i = 0; i < n; i++) { CFNumberRef sessionNum = CFArrayGetValueAtIndex(pSessions, i);
_removeWatcher(sessionNum, storeKey); }
CFDictionarySetValue(patternData, pattern, pInfo_new); CFRelease(pInfo_new); return;}
__private_extern__voidpatternRemoveKey(CFStringRef key){ void *context = (void *)key;
my_CFDictionaryApplyFunction(patternData, (CFDictionaryApplierFunction)removeKeyFromPattern, context);
return;}