#include "configd.h"
#include "configd_server.h"
#include "session.h"
#include "pattern.h"
#define N_QUICK 32
static void
_notifyWatchers()
{
CFIndex keyCnt;
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
keyCnt = CFSetGetCount(changedKeys);
if (keyCnt == 0)
return;
if (keyCnt > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef)))
keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
CFSetGetValues(changedKeys, keys);
while (--keyCnt >= 0) {
CFArrayRef changes;
CFDictionaryRef dict;
CFDictionaryRef info;
CFMutableDictionaryRef newInfo;
CFMutableArrayRef newChanges;
CFArrayRef sessionsWatchingKey;
CFIndex watcherCnt;
const void * watchers_q[N_QUICK];
const void ** watchers = watchers_q;
dict = CFDictionaryGetValue(storeData, (CFStringRef)keys[keyCnt]);
if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) {
continue;
}
sessionsWatchingKey = CFDictionaryGetValue(dict, kSCDWatchers);
watcherCnt = CFArrayGetCount(sessionsWatchingKey);
if (watcherCnt == 0) {
continue;
}
if (watcherCnt > (CFIndex)(sizeof(watchers_q) / sizeof(CFNumberRef)))
watchers = CFAllocatorAllocate(NULL, watcherCnt * sizeof(CFNumberRef), 0);
CFArrayGetValues(sessionsWatchingKey, CFRangeMake(0, watcherCnt), watchers);
while (--watcherCnt >= 0) {
CFStringRef sessionKey;
sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), watchers[watcherCnt]);
info = CFDictionaryGetValue(sessionData, sessionKey);
if (info != NULL) {
newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
} else {
newInfo = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
changes = CFDictionaryGetValue(newInfo, kSCDChangedKeys);
if (changes) {
newChanges = CFArrayCreateMutableCopy(NULL, 0, changes);
} else {
newChanges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
if (!CFArrayContainsValue(newChanges,
CFRangeMake(0, CFArrayGetCount(newChanges)),
(CFStringRef)keys[keyCnt])) {
CFArrayAppendValue(newChanges, (CFStringRef)keys[keyCnt]);
}
CFDictionarySetValue(newInfo, kSCDChangedKeys, newChanges);
CFRelease(newChanges);
CFDictionarySetValue(sessionData, sessionKey, newInfo);
CFRelease(newInfo);
CFRelease(sessionKey);
if (needsNotification == NULL)
needsNotification = CFSetCreateMutable(NULL,
0,
&kCFTypeSetCallBacks);
CFSetAddValue(needsNotification, watchers[watcherCnt]);
}
if (watchers != watchers_q) CFAllocatorDeallocate(NULL, watchers);
}
if (keys != keys_q) CFAllocatorDeallocate(NULL, keys);
CFSetRemoveAllValues(changedKeys);
}
static void
_processDeferredRemovals()
{
CFIndex keyCnt;
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
keyCnt = CFSetGetCount(deferredRemovals);
if (keyCnt == 0)
return;
if (keyCnt > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef)))
keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
CFSetGetValues(deferredRemovals, keys);
while (--keyCnt >= 0) {
patternRemoveKey((CFStringRef)keys[keyCnt]);
}
if (keys != keys_q) CFAllocatorDeallocate(NULL, keys);
CFSetRemoveAllValues(deferredRemovals);
return;
}
static void
_cleanupRemovedSessionKeys(const void *value, void *context)
{
CFStringRef removedKey = (CFStringRef)value;
CFRange dRange;
CFStringRef sessionKey;
CFStringRef key;
CFDictionaryRef sessionDict;
CFArrayRef sessionKeys;
CFIndex i;
CFMutableDictionaryRef newSessionDict;
dRange = CFStringFind(removedKey, CFSTR(":"), 0);
sessionKey = CFStringCreateWithSubstring(NULL,
removedKey,
CFRangeMake(0, dRange.location));
key = CFStringCreateWithSubstring(NULL,
removedKey,
CFRangeMake(dRange.location+dRange.length,
CFStringGetLength(removedKey)-dRange.location-dRange.length));
sessionDict = CFDictionaryGetValue(sessionData, sessionKey);
if (!sessionDict) {
goto done;
}
sessionKeys = CFDictionaryGetValue(sessionDict, kSCDSessionKeys);
if (!sessionKeys) {
goto done;
}
i = CFArrayGetFirstIndexOfValue(sessionKeys,
CFRangeMake(0, CFArrayGetCount(sessionKeys)),
key);
if (i == kCFNotFound) {
goto done;
}
newSessionDict = CFDictionaryCreateMutableCopy(NULL, 0, sessionDict);
if (CFArrayGetCount(sessionKeys) == 1) {
CFDictionaryRemoveValue(newSessionDict, kSCDSessionKeys);
} else {
CFMutableArrayRef newSessionKeys;
newSessionKeys = CFArrayCreateMutableCopy(NULL, 0, sessionKeys);
CFArrayRemoveValueAtIndex(newSessionKeys, i);
CFDictionarySetValue(newSessionDict, kSCDSessionKeys, newSessionKeys);
CFRelease(newSessionKeys);
}
CFDictionarySetValue(sessionData, sessionKey, newSessionDict);
CFRelease(newSessionDict);
done:
CFRelease(sessionKey);
CFRelease(key);
return;
}
__private_extern__
int
__SCDynamicStorePush(void)
{
_notifyWatchers();
_processDeferredRemovals();
CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
CFSetRemoveAllValues(removedSessionKeys);
return kSCStatusOK;
}