2 * Copyright (c) 2000-2005, 2011, 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 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 #include <sys/types.h>
41 #pragma mark SCDynamicStore "cache"
44 static Boolean use_cache
= FALSE
;
46 static CFMutableDictionaryRef cached_keys
= NULL
;
47 static CFMutableDictionaryRef cached_set
= NULL
;
48 static CFMutableArrayRef cached_removals
= NULL
;
49 static CFMutableArrayRef cached_notifys
= NULL
;
56 // if we are already using the cache
60 cached_keys
= CFDictionaryCreateMutable(NULL
,
62 &kCFTypeDictionaryKeyCallBacks
,
63 &kCFTypeDictionaryValueCallBacks
);
64 cached_set
= CFDictionaryCreateMutable(NULL
,
66 &kCFTypeDictionaryKeyCallBacks
,
67 &kCFTypeDictionaryValueCallBacks
);
68 cached_removals
= CFArrayCreateMutable(NULL
,
70 &kCFTypeArrayCallBacks
);
71 cached_notifys
= CFArrayCreateMutable(NULL
,
73 &kCFTypeArrayCallBacks
);
80 static CFPropertyListRef
81 cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store
, CFStringRef key
)
83 CFPropertyListRef value
;
85 value
= CFDictionaryGetValue(cached_set
, key
);
87 // if we have "set" a new value
88 return (CFRetain(value
));
91 if (CFArrayContainsValue(cached_removals
,
92 CFRangeMake(0, CFArrayGetCount(cached_removals
)),
94 // if we have "removed" the key
95 _SCErrorSet(kSCStatusNoKey
);
99 value
= CFDictionaryGetValue(cached_keys
, key
);
101 // if we have a cached value
102 return (CFRetain(value
));
105 value
= SCDynamicStoreCopyValue(store
, key
);
107 CFDictionarySetValue(cached_keys
, key
, value
);
115 cache_SCDynamicStoreSetValue(SCDynamicStoreRef store
, CFStringRef key
, CFPropertyListRef value
)
117 #pragma unused (store)
120 i
= CFArrayGetFirstIndexOfValue(cached_removals
,
121 CFRangeMake(0, CFArrayGetCount(cached_removals
)),
123 if (i
!= kCFNotFound
) {
124 // if previously "removed"
125 CFArrayRemoveValueAtIndex(cached_removals
, i
);
128 CFDictionarySetValue(cached_set
, key
, value
);
134 cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store
, CFStringRef key
)
136 #pragma unused (store)
137 CFDictionaryRemoveValue(cached_set
, key
);
139 if (!CFArrayContainsValue(cached_removals
,
140 CFRangeMake(0, CFArrayGetCount(cached_removals
)),
142 CFArrayAppendValue(cached_removals
, key
);
150 cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store
, CFStringRef key
)
152 #pragma unused (store)
153 if (!CFArrayContainsValue(cached_notifys
,
154 CFRangeMake(0, CFArrayGetCount(cached_notifys
)),
156 CFArrayAppendValue(cached_notifys
, key
);
164 cache_write(SCDynamicStoreRef store
)
166 if ((CFDictionaryGetCount(cached_set
) > 0) ||
167 (CFArrayGetCount(cached_removals
) > 0) ||
168 (CFArrayGetCount(cached_notifys
) > 0)) {
169 if (!SCDynamicStoreSetMultiple(store
,
173 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
189 CFRelease(cached_keys
);
190 CFRelease(cached_set
);
191 CFRelease(cached_removals
);
192 CFRelease(cached_notifys
);
200 #pragma mark SCDynamicStore operations
205 do_block(int argc
, char **argv
)
207 Boolean enable
= FALSE
;
210 if ((strcasecmp(argv
[0], "begin") == 0) ||
211 (strcasecmp(argv
[0], "start") == 0) ||
212 (strcasecmp(argv
[0], "on" ) == 0) ||
213 (strcasecmp(argv
[0], "1" ) == 0)) {
215 } else if ((strcasecmp(argv
[0], "end" ) == 0) ||
216 (strcasecmp(argv
[0], "stop" ) == 0) ||
217 (strcasecmp(argv
[0], "off" ) == 0) ||
218 (strcasecmp(argv
[0], "0" ) == 0)) {
221 SCPrint(TRUE
, stdout
, CFSTR("invalid value\n"));
225 enable
= !use_cache
; // toggle
229 // begin block of SCDynamicStore operations
231 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusLocked
));
235 SCPrint(TRUE
, stdout
, CFSTR("Begin block of SCDynamicStore operations\n"));
241 // end block of SCDynamicStore operations
243 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusNeedLock
));
247 n
= CFDictionaryGetCount(cached_keys
) +
248 CFArrayGetCount(cached_removals
) +
249 CFArrayGetCount(cached_notifys
);
250 SCPrint(TRUE
, stdout
,
251 CFSTR("End block of SCDynamicStore operations%s\n"),
252 (n
> 0) ? ", posting changes" : "");
263 static CFComparisonResult
264 sort_keys(const void *p1
, const void *p2
, void *context
)
266 #pragma unused(context)
267 CFStringRef key1
= (CFStringRef
)p1
;
268 CFStringRef key2
= (CFStringRef
)p2
;
269 return CFStringCompare(key1
, key2
, 0);
278 do_list(int argc
, char **argv
)
284 CFMutableArrayRef sortedList
;
286 pattern
= CFStringCreateWithCString(NULL
,
287 (argc
>= 1) ? argv
[0] : ".*",
288 kCFStringEncodingUTF8
);
290 list
= SCDynamicStoreCopyKeyList(store
, pattern
);
293 if (SCError() != kSCStatusOK
) {
294 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
298 SCPrint(TRUE
, stdout
, CFSTR(" no keys.\n"));
303 n
= CFDictionaryGetCount(cached_set
);
305 const void * cachedKeys_q
[N_QUICK
];
306 const void ** cachedKeys
= cachedKeys_q
;
308 if (n
> (CFIndex
)(sizeof(cachedKeys_q
) / sizeof(CFStringRef
))) {
309 cachedKeys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
311 CFDictionaryGetKeysAndValues(cached_set
, cachedKeys
, NULL
);
312 list
= CFArrayCreate(NULL
, cachedKeys
, n
, &kCFTypeArrayCallBacks
);
313 if (cachedKeys
!= cachedKeys_q
) {
314 CFAllocatorDeallocate(NULL
, cachedKeys
);
317 SCPrint(TRUE
, stdout
, CFSTR(" no keys.\n"));
322 } else if (use_cache
&&
323 ((CFDictionaryGetCount(cached_set
) > 0) || (CFArrayGetCount(cached_removals
) > 0))) {
324 SCPrint(TRUE
, stdout
,
325 CFSTR(" Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n"));
328 listCnt
= CFArrayGetCount(list
);
329 sortedList
= CFArrayCreateMutableCopy(NULL
, listCnt
, list
);
331 CFArraySortValues(sortedList
,
332 CFRangeMake(0, listCnt
),
337 for (i
= 0; i
< listCnt
; i
++) {
340 CFSTR(" subKey [%d] = %@\n"),
342 CFArrayGetValueAtIndex(sortedList
, i
));
345 SCPrint(TRUE
, stdout
, CFSTR(" no keys.\n"));
347 CFRelease(sortedList
);
355 do_add(int argc
, char **argv
)
359 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
363 if (!SCDynamicStoreAddValue(store
, key
, value
)) {
364 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
369 val
= cache_SCDynamicStoreCopyValue(store
, key
);
372 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists
));
374 cache_SCDynamicStoreSetValue(store
, key
, value
);
379 if (!SCDynamicStoreAddTemporaryValue(store
, key
, value
)) {
380 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
385 val
= cache_SCDynamicStoreCopyValue(store
, key
);
388 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists
));
390 if (!SCDynamicStoreAddTemporaryValue(store
, key
, value
)) {
391 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
393 // and save the temp value in the cache too!
394 cache_SCDynamicStoreSetValue(store
, key
, value
);
407 do_get(int argc
, char **argv
)
411 CFPropertyListRef newValue
;
413 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
415 newValue
= SCDynamicStoreCopyValue(store
, key
);
417 newValue
= cache_SCDynamicStoreCopyValue(store
, key
);
420 if (newValue
== NULL
) {
421 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
426 CFRelease(value
); /* we have new information, release the old */
436 do_set(int argc
, char **argv
)
441 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
443 if (!SCDynamicStoreSetValue(store
, key
, value
)) {
444 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
447 cache_SCDynamicStoreSetValue(store
, key
, value
);
456 do_show(int argc
, char **argv
)
459 CFPropertyListRef newValue
;
461 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
465 newValue
= SCDynamicStoreCopyValue(store
, key
);
467 newValue
= cache_SCDynamicStoreCopyValue(store
, key
);
472 patterns
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
474 newValue
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
477 CFMutableDictionaryRef newDict
;
479 newDict
= CFDictionaryCreateMutable(NULL
,
481 &kCFTypeDictionaryKeyCallBacks
,
482 &kCFTypeDictionaryValueCallBacks
);
483 keys
= SCDynamicStoreCopyKeyList(store
, key
);
488 n
= CFArrayGetCount(keys
);
489 for (i
= 0; i
< n
; i
++) {
490 CFStringRef storeKey
;
493 storeKey
= CFArrayGetValueAtIndex(keys
, i
);
494 storeVal
= cache_SCDynamicStoreCopyValue(store
, storeKey
);
495 if (storeVal
!= NULL
) {
496 CFDictionarySetValue(newDict
, storeKey
, storeVal
);
503 if ((CFDictionaryGetCount(cached_set
) > 0) || (CFArrayGetCount(cached_removals
) > 0)) {
504 SCPrint(TRUE
, stdout
, CFSTR(" Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n"));
513 if (newValue
== NULL
) {
514 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
518 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), newValue
);
526 do_remove(int argc
, char **argv
)
531 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
533 if (!SCDynamicStoreRemoveValue(store
, key
)) {
534 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
537 cache_SCDynamicStoreRemoveValue(store
, key
);
546 do_notify(int argc
, char **argv
)
551 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
553 if (!SCDynamicStoreNotifyValue(store
, key
)) {
554 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
557 cache_SCDynamicStoreNotifyValue(store
, key
);