#include "configd.h"
CFMutableDictionaryRef sessionData = NULL;
CFMutableDictionaryRef cacheData = NULL;
CFMutableDictionaryRef cacheData_s = NULL;
CFMutableSetRef changedKeys = NULL;
CFMutableSetRef changedKeys_s = NULL;
CFMutableSetRef deferredRemovals = NULL;
CFMutableSetRef deferredRemovals_s = NULL;
CFMutableSetRef removedSessionKeys = NULL;
CFMutableSetRef removedSessionKeys_s = NULL;
CFMutableSetRef needsNotification = NULL;
void
_swapLockedCacheData()
{
void *temp;
temp = cacheData;
cacheData = cacheData_s;
cacheData_s = temp;
temp = changedKeys;
changedKeys = changedKeys_s;
changedKeys_s = temp;
temp = deferredRemovals;
deferredRemovals = deferredRemovals_s;
deferredRemovals_s = temp;
temp = removedSessionKeys;
removedSessionKeys = removedSessionKeys_s;
removedSessionKeys_s = temp;
return;
}
void
_addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFArrayRef watchers;
CFMutableArrayRef newWatchers;
CFArrayRef watcherRefs;
CFMutableArrayRef newWatcherRefs;
CFIndex i;
int refCnt;
CFNumberRef refNum;
dict = CFDictionaryGetValue(cacheData, watchedKey);
if (dict) {
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
} else {
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
if (watchers) {
newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
} else {
newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
i = CFArrayGetFirstIndexOfValue(newWatchers,
CFRangeMake(0, CFArrayGetCount(newWatchers)),
sessionNum);
if (i == -1) {
CFArrayAppendValue(newWatchers, sessionNum);
refCnt = 1;
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArrayAppendValue(newWatcherRefs, refNum);
CFRelease(refNum);
} else {
refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
refCnt++;
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
CFRelease(refNum);
}
CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
CFRelease(newWatchers);
CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
CFRelease(newWatcherRefs);
CFDictionarySetValue(cacheData, watchedKey, newDict);
CFRelease(newDict);
SCDLog(LOG_DEBUG, CFSTR(" _addWatcher: %@, %@"), sessionNum, watchedKey);
return;
}
void
_addRegexWatcherByKey(const void *key, void *val, void *context)
{
CFStringRef cacheStr = key;
CFDictionaryRef info = val;
mach_port_t sessionID = ((addContextRef)context)->session->server;
regex_t *preg = ((addContextRef)context)->preg;
int cacheKeyLen;
char *cacheKey;
CFNumberRef sessionNum;
int reError;
char reErrBuf[256];
int reErrStrLen;
if (CFDictionaryContainsKey(info, kSCDData) == FALSE) {
return;
}
cacheKeyLen = CFStringGetLength(cacheStr) + 1;
cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0);
if (!CFStringGetCString(cacheStr, cacheKey, cacheKeyLen, kCFStringEncodingMacRoman)) {
SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert cache key to C string"));
CFAllocatorDeallocate(NULL, cacheKey);
return;
}
reError = regexec(preg, cacheKey, 0, NULL, 0);
switch (reError) {
case 0 :
sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionID);
_addWatcher(sessionNum, cacheStr);
CFRelease(sessionNum);
break;
case REG_NOMATCH :
break;
default :
reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
break;
}
CFAllocatorDeallocate(NULL, cacheKey);
}
void
_addRegexWatchersBySession(const void *key, void *val, void *context)
{
CFStringRef sessionKey = key;
CFDictionaryRef info = val;
CFStringRef addedKey = context;
CFIndex newKeyLen;
char *newKeyStr;
CFArrayRef rKeys;
CFArrayRef rData;
CFIndex i;
if (info == NULL) {
return;
}
rKeys = CFDictionaryGetValue(info, kSCDRegexKeys);
if (rKeys == NULL) {
return;
}
rData = CFDictionaryGetValue(info, kSCDRegexData);
newKeyLen = CFStringGetLength(addedKey) + 1;
newKeyStr = CFAllocatorAllocate(NULL, newKeyLen, 0);
if (!CFStringGetCString(addedKey, newKeyStr, newKeyLen, kCFStringEncodingMacRoman)) {
SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert new key to C string"));
CFAllocatorDeallocate(NULL, newKeyStr);
return;
}
for (i=0; i<CFArrayGetCount(rKeys); i++) {
CFDataRef regexData = CFArrayGetValueAtIndex(rData, i);
regex_t *preg = (regex_t *)CFDataGetBytePtr(regexData);
int reError;
char reErrBuf[256];
int reErrStrLen;
SInt32 sessionInt;
CFNumberRef sessionNum;
reError = regexec(preg, newKeyStr, 0, NULL, 0);
switch (reError) {
case 0 :
sessionInt = CFStringGetIntValue(sessionKey);
sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionInt);
_addWatcher(sessionNum, addedKey);
CFRelease(sessionNum);
break;
case REG_NOMATCH :
break;
default :
reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
break;
}
}
CFAllocatorDeallocate(NULL, newKeyStr);
return;
}
void
_removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFArrayRef watchers;
CFMutableArrayRef newWatchers;
CFArrayRef watcherRefs;
CFMutableArrayRef newWatcherRefs;
CFIndex i;
int refCnt;
CFNumberRef refNum;
dict = CFDictionaryGetValue(cacheData, watchedKey);
if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDWatchers) == FALSE)) {
SCDLog(LOG_DEBUG, CFSTR("_removeWatcher: key not present in dictionary."));
return;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
i = CFArrayGetFirstIndexOfValue(newWatchers,
CFRangeMake(0, CFArrayGetCount(newWatchers)),
sessionNum);
if (i == -1) {
SCDLog(LOG_DEBUG, CFSTR("_removeWatcher: no reference for session %@"), sessionNum);
CFRelease(newDict);
CFRelease(newWatchers);
CFRelease(newWatcherRefs);
return;
}
refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
if (--refCnt > 0) {
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
CFRelease(refNum);
} else {
CFArrayRemoveValueAtIndex(newWatchers, i);
CFArrayRemoveValueAtIndex(newWatcherRefs, i);
}
if (CFArrayGetCount(newWatchers) > 0) {
CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
} else {
CFDictionaryRemoveValue(newDict, kSCDWatchers);
CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
}
CFRelease(newWatchers);
CFRelease(newWatcherRefs);
if (CFDictionaryGetCount(newDict) > 0) {
CFDictionarySetValue(cacheData, watchedKey, newDict);
} else {
CFDictionaryRemoveValue(cacheData, watchedKey);
}
CFRelease(newDict);
SCDLog(LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey);
return;
}
void
_removeRegexWatcherByKey(const void *key, void *val, void *context)
{
CFStringRef cacheStr = key;
CFDictionaryRef info = val;
mach_port_t sessionID = ((removeContextRef)context)->session->server;
regex_t *preg = ((removeContextRef)context)->preg;
CFNumberRef sessionNum;
CFArrayRef watchers;
int cacheKeyLen;
char *cacheKey;
int reError;
char reErrBuf[256];
int reErrStrLen;
if ((info == NULL) || (CFDictionaryContainsKey(info, kSCDWatchers) == FALSE)) {
return;
}
sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionID);
watchers = CFDictionaryGetValue(info, kSCDWatchers);
if (CFArrayContainsValue(watchers,
CFRangeMake(0, CFArrayGetCount(watchers)),
sessionNum) == FALSE) {
CFRelease(sessionNum);
return;
}
cacheKeyLen = CFStringGetLength(cacheStr) + 1;
cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0);
if (!CFStringGetCString(cacheStr, cacheKey, cacheKeyLen, kCFStringEncodingMacRoman)) {
SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert key to C string"));
CFAllocatorDeallocate(NULL, cacheKey);
CFRelease(sessionNum);
return;
}
reError = regexec(preg, cacheKey, 0, NULL, 0);
switch (reError) {
case 0 :
_removeWatcher(sessionNum, cacheStr);
break;
case REG_NOMATCH :
break;
default :
reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
break;
}
CFAllocatorDeallocate(NULL, cacheKey);
CFRelease(sessionNum);
}
void
_removeRegexWatchersBySession(const void *key, void *val, void *context)
{
CFStringRef sessionKey = key;
CFDictionaryRef info = val;
CFStringRef removedKey = context;
CFIndex oldKeyLen;
char *oldKeyStr;
CFArrayRef rKeys;
CFArrayRef rData;
CFIndex i;
if (info == NULL) {
return;
}
rKeys = CFDictionaryGetValue(info, kSCDRegexKeys);
if (rKeys == NULL) {
return;
}
rData = CFDictionaryGetValue(info, kSCDRegexData);
oldKeyLen = CFStringGetLength(removedKey) + 1;
oldKeyStr = CFAllocatorAllocate(NULL, oldKeyLen, 0);
if (!CFStringGetCString(removedKey, oldKeyStr, oldKeyLen, kCFStringEncodingMacRoman)) {
SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert old key to C string"));
CFAllocatorDeallocate(NULL, oldKeyStr);
return;
}
for (i=0; i<CFArrayGetCount(rKeys); i++) {
CFDataRef regexData = CFArrayGetValueAtIndex(rData, i);
regex_t *preg = (regex_t *)CFDataGetBytePtr(regexData);
int reError;
char reErrBuf[256];
int reErrStrLen;
SInt32 sessionInt;
CFNumberRef sessionNum;
reError = regexec(preg, oldKeyStr, 0, NULL, 0);
switch (reError) {
case 0 :
sessionInt = CFStringGetIntValue(sessionKey);
sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionInt);
_removeWatcher(sessionNum, removedKey);
CFRelease(sessionNum);
break;
case REG_NOMATCH :
break;
default :
reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
break;
}
}
CFAllocatorDeallocate(NULL, oldKeyStr);
return;
}