2 * Copyright (c) 2000-2004, 2006, 2011, 2015, 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
36 #include "configd_server.h"
48 const void * keys_q
[N_QUICK
];
49 const void ** keys
= keys_q
;
51 keyCnt
= CFSetGetCount(changedKeys
);
53 return; /* if nothing to do */
55 if (keyCnt
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
)))
56 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
58 CFSetGetValues(changedKeys
, keys
);
60 while (--keyCnt
>= 0) {
64 CFMutableDictionaryRef newInfo
;
65 CFMutableArrayRef newChanges
;
66 CFArrayRef sessionsWatchingKey
;
68 const void * watchers_q
[N_QUICK
];
69 const void ** watchers
= watchers_q
;
71 dict
= CFDictionaryGetValue(storeData
, (CFStringRef
)keys
[keyCnt
]);
72 if ((dict
== NULL
) || !CFDictionaryContainsKey(dict
, kSCDWatchers
)) {
73 /* key doesn't exist or nobody cares if it changed */
78 * Add this key to the list of changes for each of the
79 * sessions which is "watching".
81 sessionsWatchingKey
= CFDictionaryGetValue(dict
, kSCDWatchers
);
82 watcherCnt
= CFArrayGetCount(sessionsWatchingKey
);
83 if (watcherCnt
== 0) {
88 if (watcherCnt
> (CFIndex
)(sizeof(watchers_q
) / sizeof(CFNumberRef
)))
89 watchers
= CFAllocatorAllocate(NULL
, watcherCnt
* sizeof(CFNumberRef
), 0);
91 CFArrayGetValues(sessionsWatchingKey
, CFRangeMake(0, watcherCnt
), watchers
);
93 while (--watcherCnt
>= 0) {
94 CFStringRef sessionKey
;
96 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@"), watchers
[watcherCnt
]);
97 info
= CFDictionaryGetValue(sessionData
, sessionKey
);
99 newInfo
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
101 newInfo
= CFDictionaryCreateMutable(NULL
,
103 &kCFTypeDictionaryKeyCallBacks
,
104 &kCFTypeDictionaryValueCallBacks
);
107 changes
= CFDictionaryGetValue(newInfo
, kSCDChangedKeys
);
109 newChanges
= CFArrayCreateMutableCopy(NULL
, 0, changes
);
111 newChanges
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
114 if (!CFArrayContainsValue(newChanges
,
115 CFRangeMake(0, CFArrayGetCount(newChanges
)),
116 (CFStringRef
)keys
[keyCnt
])) {
117 CFArrayAppendValue(newChanges
, (CFStringRef
)keys
[keyCnt
]);
119 CFDictionarySetValue(newInfo
, kSCDChangedKeys
, newChanges
);
120 CFRelease(newChanges
);
121 CFDictionarySetValue(sessionData
, sessionKey
, newInfo
);
123 CFRelease(sessionKey
);
126 * flag this session as needing a kick
128 if (needsNotification
== NULL
)
129 needsNotification
= CFSetCreateMutable(NULL
,
131 &kCFTypeSetCallBacks
);
132 CFSetAddValue(needsNotification
, watchers
[watcherCnt
]);
135 if (watchers
!= watchers_q
) CFAllocatorDeallocate(NULL
, watchers
);
138 if (keys
!= keys_q
) CFAllocatorDeallocate(NULL
, keys
);
141 * The list of changed keys have been updated for any sessions
142 * monitoring changes to the "store". The next step, handled by
143 * the "configd" server, is to push out any needed notifications.
145 CFSetRemoveAllValues(changedKeys
);
151 _processDeferredRemovals()
154 const void * keys_q
[N_QUICK
];
155 const void ** keys
= keys_q
;
157 keyCnt
= CFSetGetCount(deferredRemovals
);
159 return; /* if nothing to do */
161 if (keyCnt
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
)))
162 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
164 CFSetGetValues(deferredRemovals
, keys
);
166 while (--keyCnt
>= 0) {
167 patternRemoveKey((CFStringRef
)keys
[keyCnt
]);
170 if (keys
!= keys_q
) CFAllocatorDeallocate(NULL
, keys
);
173 * All regex keys associated with removed store dictionary keys have
174 * been removed. Start the list fresh again.
176 CFSetRemoveAllValues(deferredRemovals
);
183 _cleanupRemovedSessionKeys(const void *value
, void *context
)
185 #pragma unused(context)
186 CFStringRef removedKey
= (CFStringRef
)value
;
188 CFStringRef sessionKey
;
190 CFDictionaryRef sessionDict
;
191 CFArrayRef sessionKeys
;
193 CFMutableDictionaryRef newSessionDict
;
195 dRange
= CFStringFind(removedKey
, CFSTR(":"), 0);
196 sessionKey
= CFStringCreateWithSubstring(NULL
,
198 CFRangeMake(0, dRange
.location
));
199 key
= CFStringCreateWithSubstring(NULL
,
201 CFRangeMake(dRange
.location
+dRange
.length
,
202 CFStringGetLength(removedKey
)-dRange
.location
-dRange
.length
));
205 * remove the key from the session key list
207 sessionDict
= CFDictionaryGetValue(sessionData
, sessionKey
);
213 sessionKeys
= CFDictionaryGetValue(sessionDict
, kSCDSessionKeys
);
215 /* if no session keys */
219 i
= CFArrayGetFirstIndexOfValue(sessionKeys
,
220 CFRangeMake(0, CFArrayGetCount(sessionKeys
)),
222 if (i
== kCFNotFound
) {
223 /* if this session key has already been removed */
227 newSessionDict
= CFDictionaryCreateMutableCopy(NULL
, 0, sessionDict
);
228 if (CFArrayGetCount(sessionKeys
) == 1) {
229 /* remove the last (session) key */
230 CFDictionaryRemoveValue(newSessionDict
, kSCDSessionKeys
);
232 CFMutableArrayRef newSessionKeys
;
234 /* remove the (session) key */
235 newSessionKeys
= CFArrayCreateMutableCopy(NULL
, 0, sessionKeys
);
236 CFArrayRemoveValueAtIndex(newSessionKeys
, i
);
237 CFDictionarySetValue(newSessionDict
, kSCDSessionKeys
, newSessionKeys
);
238 CFRelease(newSessionKeys
);
240 CFDictionarySetValue(sessionData
, sessionKey
, newSessionDict
);
241 CFRelease(newSessionDict
);
245 CFRelease(sessionKey
);
254 __SCDynamicStorePush(void)
257 * push notifications to any session watching those keys which
258 * were recently changed.
263 * process any deferred key deletions.
265 _processDeferredRemovals();
268 * clean up any removed session keys
270 CFSetApplyFunction(removedSessionKeys
, _cleanupRemovedSessionKeys
, NULL
);
271 CFSetRemoveAllValues(removedSessionKeys
);