2 * Copyright (c) 2000-2004, 2006, 2008 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>
42 __SCDynamicStoreSetValue(SCDynamicStoreRef store
, CFStringRef key
, CFDataRef value
, Boolean internal
)
44 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
45 int sc_status
= kSCStatusOK
;
47 CFMutableDictionaryRef newDict
;
48 Boolean newEntry
= FALSE
;
49 CFStringRef sessionKey
;
50 CFStringRef storeSessionKey
;
52 if ((store
== NULL
) || (storePrivate
->server
== MACH_PORT_NULL
)) {
53 return kSCStatusNoStoreSession
; /* you must have an open session to play */
57 SCTrace(TRUE
, _configd_trace
,
58 CFSTR("%s%s : %5d : %@\n"),
59 internal
? "*set " : "set ",
60 storePrivate
->useSessionKeys
? "t " : " ",
66 * 1. Ensure that we hold the lock.
68 sc_status
= __SCDynamicStoreLock(store
, TRUE
);
69 if (sc_status
!= kSCStatusOK
) {
74 * 2. Grab the current (or establish a new) dictionary for this key.
77 dict
= CFDictionaryGetValue(storeData
, key
);
79 newDict
= CFDictionaryCreateMutableCopy(NULL
,
83 newDict
= CFDictionaryCreateMutable(NULL
,
85 &kCFTypeDictionaryKeyCallBacks
,
86 &kCFTypeDictionaryValueCallBacks
);
90 * 3. Update the dictionary entry to be saved to the store.
92 newEntry
= !CFDictionaryContainsKey(newDict
, kSCDData
);
93 CFDictionarySetValue(newDict
, kSCDData
, value
);
95 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), storePrivate
->server
);
98 * 4. Manage per-session keys.
100 if (storePrivate
->useSessionKeys
) {
103 CFMutableDictionaryRef newSession
;
104 CFMutableArrayRef newKeys
;
105 CFDictionaryRef session
;
108 * Add this key to my list of per-session keys
110 session
= CFDictionaryGetValue(sessionData
, sessionKey
);
111 keys
= CFDictionaryGetValue(session
, kSCDSessionKeys
);
112 if ((keys
== NULL
) ||
113 (CFArrayGetFirstIndexOfValue(keys
,
114 CFRangeMake(0, CFArrayGetCount(keys
)),
115 key
) == kCFNotFound
)) {
117 * if no session keys defined "or" keys defined but not
121 /* this is the first session key */
122 newKeys
= CFArrayCreateMutableCopy(NULL
, 0, keys
);
124 /* this is an additional session key */
125 newKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
127 CFArrayAppendValue(newKeys
, key
);
129 /* update session dictionary */
130 newSession
= CFDictionaryCreateMutableCopy(NULL
, 0, session
);
131 CFDictionarySetValue(newSession
, kSCDSessionKeys
, newKeys
);
133 CFDictionarySetValue(sessionData
, sessionKey
, newSession
);
134 CFRelease(newSession
);
138 * Mark the key as a "session" key and track the creator.
140 CFDictionarySetValue(newDict
, kSCDSession
, sessionKey
);
143 * Since we are using per-session keys and this key already
144 * exists, check if it was created by "our" session
146 dict
= CFDictionaryGetValue(storeData
, key
);
147 if (!CFDictionaryGetValueIfPresent(dict
, kSCDSession
, (void *)&storeSessionKey
) ||
148 !CFEqual(sessionKey
, storeSessionKey
)) {
150 * if the key exists and is not a session key or
151 * if the key exists it's not "our" session.
153 sc_status
= kSCStatusKeyExists
;
154 CFRelease(sessionKey
);
161 * Since we are updating this key we need to check and, if
162 * necessary, remove the indication that this key is on
163 * another session's remove-on-close list.
166 CFDictionaryGetValueIfPresent(newDict
, kSCDSession
, (void *)&storeSessionKey
) &&
167 !CFEqual(sessionKey
, storeSessionKey
)) {
168 CFStringRef removedKey
;
170 /* We are no longer a session key! */
171 CFDictionaryRemoveValue(newDict
, kSCDSession
);
173 /* add this session key to the (session) removal list */
174 removedKey
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), storeSessionKey
, key
);
175 CFSetAddValue(removedSessionKeys
, removedKey
);
176 CFRelease(removedKey
);
180 CFRelease(sessionKey
);
183 * 5. Update the dictionary entry in the store.
186 CFDictionarySetValue(storeData
, key
, newDict
);
190 * 6. For "new" entries to the store, check the deferred cleanup
191 * list. If the key is flagged for removal, remove it from the
192 * list since any defined regex's for this key are still defined
193 * and valid. If the key is not flagged then iterate over the
194 * sessionData dictionary looking for regex keys which match the
195 * updated key. If a match is found then we mark those keys as
200 if (CFSetContainsValue(deferredRemovals
, key
)) {
201 CFSetRemoveValue(deferredRemovals
, key
);
208 * 7. Mark this key as "changed". Any "watchers" will be notified
209 * as soon as the lock is released.
211 CFSetAddValue(changedKeys
, key
);
216 * 8. Release our lock.
218 __SCDynamicStoreUnlock(store
, TRUE
);
225 _configset(mach_port_t server
,
226 xmlData_t keyRef
, /* raw XML bytes */
227 mach_msg_type_number_t keyLen
,
228 xmlData_t dataRef
, /* raw XML bytes */
229 mach_msg_type_number_t dataLen
,
235 CFDataRef data
= NULL
; /* data (un-serialized) */
236 CFStringRef key
= NULL
; /* key (un-serialized) */
237 serverSessionRef mySession
;
239 *sc_status
= kSCStatusOK
;
241 /* un-serialize the key */
242 if (!_SCUnserializeString(&key
, NULL
, (void *)keyRef
, keyLen
)) {
243 *sc_status
= kSCStatusFailed
;
246 /* un-serialize the data */
247 if (!_SCUnserializeData(&data
, (void *)dataRef
, dataLen
)) {
248 *sc_status
= kSCStatusFailed
;
251 if (*sc_status
!= kSCStatusOK
) {
255 if (!isA_CFString(key
)) {
256 *sc_status
= kSCStatusInvalidArgument
;
260 mySession
= getSession(server
);
261 if (mySession
== NULL
) {
262 *sc_status
= kSCStatusNoStoreSession
; /* you must have an open session to play */
266 *sc_status
= __SCDynamicStoreSetValue(mySession
->store
, key
, data
, FALSE
);
271 if (key
) CFRelease(key
);
272 if (data
) CFRelease(data
);
277 setSpecificKey(const void *key
, const void *value
, void *context
)
279 CFStringRef k
= (CFStringRef
)key
;
280 CFDataRef v
= (CFDataRef
)value
;
281 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
283 if (!isA_CFString(k
)) {
287 if (!isA_CFData(v
)) {
291 (void) __SCDynamicStoreSetValue(store
, k
, v
, TRUE
);
297 removeSpecificKey(const void *value
, void *context
)
299 CFStringRef k
= (CFStringRef
)value
;
300 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
302 if (!isA_CFString(k
)) {
306 (void) __SCDynamicStoreRemoveValue(store
, k
, TRUE
);
312 notifySpecificKey(const void *value
, void *context
)
314 CFStringRef k
= (CFStringRef
)value
;
315 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
317 if (!isA_CFString(k
)) {
321 (void) __SCDynamicStoreNotifyValue(store
, k
, TRUE
);
328 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store
, CFDictionaryRef keysToSet
, CFArrayRef keysToRemove
, CFArrayRef keysToNotify
)
330 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
331 int sc_status
= kSCStatusOK
;
333 if ((store
== NULL
) || (storePrivate
->server
== MACH_PORT_NULL
)) {
334 return kSCStatusNoStoreSession
; /* you must have an open session to play */
337 if (_configd_trace
) {
338 SCTrace(TRUE
, _configd_trace
,
339 CFSTR("set m : %5d : %d set, %d remove, %d notify\n"),
340 storePrivate
->server
,
341 keysToSet
? CFDictionaryGetCount(keysToSet
) : 0,
342 keysToRemove
? CFArrayGetCount (keysToRemove
) : 0,
343 keysToNotify
? CFArrayGetCount (keysToNotify
) : 0);
347 * Ensure that we hold the lock
349 sc_status
= __SCDynamicStoreLock(store
, TRUE
);
350 if (sc_status
!= kSCStatusOK
) {
355 * Set the new/updated keys
358 CFDictionaryApplyFunction(keysToSet
,
364 * Remove the specified keys
367 CFArrayApplyFunction(keysToRemove
,
368 CFRangeMake(0, CFArrayGetCount(keysToRemove
)),
374 * Notify the specified keys
377 CFArrayApplyFunction(keysToNotify
,
378 CFRangeMake(0, CFArrayGetCount(keysToNotify
)),
383 /* Release our lock */
384 __SCDynamicStoreUnlock(store
, TRUE
);
391 _configset_m(mach_port_t server
,
393 mach_msg_type_number_t dictLen
,
395 mach_msg_type_number_t removeLen
,
397 mach_msg_type_number_t notifyLen
,
400 CFDictionaryRef dict
= NULL
; /* key/value dictionary (un-serialized) */
401 serverSessionRef mySession
;
402 CFArrayRef notify
= NULL
; /* keys to notify (un-serialized) */
403 CFArrayRef remove
= NULL
; /* keys to remove (un-serialized) */
405 *sc_status
= kSCStatusOK
;
407 if ((dictRef
!= NULL
) && (dictLen
> 0)) {
408 /* un-serialize the key/value pairs to set */
409 if (!_SCUnserialize((CFPropertyListRef
*)&dict
, NULL
, (void *)dictRef
, dictLen
)) {
410 *sc_status
= kSCStatusFailed
;
414 if ((removeRef
!= NULL
) && (removeLen
> 0)) {
415 /* un-serialize the keys to remove */
416 if (!_SCUnserialize((CFPropertyListRef
*)&remove
, NULL
, (void *)removeRef
, removeLen
)) {
417 *sc_status
= kSCStatusFailed
;
421 if ((notifyRef
!= NULL
) && (notifyLen
> 0)) {
422 /* un-serialize the keys to notify */
423 if (!_SCUnserialize((CFPropertyListRef
*)¬ify
, NULL
, (void *)notifyRef
, notifyLen
)) {
424 *sc_status
= kSCStatusFailed
;
428 if (*sc_status
!= kSCStatusOK
) {
432 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
433 *sc_status
= kSCStatusInvalidArgument
;
437 if ((remove
!= NULL
) && !isA_CFArray(remove
)) {
438 *sc_status
= kSCStatusInvalidArgument
;
442 if ((notify
!= NULL
) && !isA_CFArray(notify
)) {
443 *sc_status
= kSCStatusInvalidArgument
;
447 mySession
= getSession(server
);
448 if (mySession
== NULL
) {
449 /* you must have an open session to play */
450 *sc_status
= kSCStatusNoStoreSession
;
454 *sc_status
= __SCDynamicStoreSetMultiple(mySession
->store
, dict
, remove
, notify
);
458 if (dict
!= NULL
) CFRelease(dict
);
459 if (remove
!= NULL
) CFRelease(remove
);
460 if (notify
!= NULL
) CFRelease(notify
);