1/*
2 * Copyright (c) 2003, 2004, 2006, 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * May 1, 2003	Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32#include <CoreFoundation/CoreFoundation.h>
33#include <SystemConfiguration/SystemConfiguration.h>
34#include <SystemConfiguration/SCPrivate.h>	// for SCLog()
35
36#include "cache.h"
37
38
39static	CFMutableDictionaryRef	cached_keys	= NULL;
40static	CFMutableDictionaryRef	cached_set	= NULL;
41static	CFMutableArrayRef	cached_removals	= NULL;
42static	CFMutableArrayRef	cached_notifys	= NULL;
43
44
45__private_extern__
46void
47cache_open(void)
48{
49	cached_keys     = CFDictionaryCreateMutable(NULL,
50						    0,
51						    &kCFTypeDictionaryKeyCallBacks,
52						    &kCFTypeDictionaryValueCallBacks);
53	cached_set      = CFDictionaryCreateMutable(NULL,
54						    0,
55						    &kCFTypeDictionaryKeyCallBacks,
56						    &kCFTypeDictionaryValueCallBacks);
57	cached_removals = CFArrayCreateMutable(NULL,
58					       0,
59					       &kCFTypeArrayCallBacks);
60	cached_notifys  = CFArrayCreateMutable(NULL,
61					       0,
62					       &kCFTypeArrayCallBacks);
63
64	return;
65}
66
67
68__private_extern__
69CFPropertyListRef
70cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
71{
72	CFPropertyListRef	value;
73
74	value = CFDictionaryGetValue(cached_set, key);
75	if (value) {
76		// if we have "set" a new value
77		return (CFRetain(value));
78	}
79
80	if (CFArrayContainsValue(cached_removals,
81				 CFRangeMake(0, CFArrayGetCount(cached_removals)),
82				 key)) {
83		// if we have "removed" the key
84		_SCErrorSet(kSCStatusNoKey);
85		return NULL;
86	}
87
88	value = CFDictionaryGetValue(cached_keys, key);
89	if (value) {
90		// if we have a cached value
91		return (CFRetain(value));
92	}
93
94	value = SCDynamicStoreCopyValue(store, key);
95	if (value) {
96		CFDictionarySetValue(cached_keys, key, value);
97	}
98
99	return value;
100}
101
102
103__private_extern__
104void
105cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
106{
107	CFIndex	i;
108
109	i = CFArrayGetFirstIndexOfValue(cached_removals,
110					CFRangeMake(0, CFArrayGetCount(cached_removals)),
111					key);
112	if (i != kCFNotFound) {
113		// if previously "removed"
114		CFArrayRemoveValueAtIndex(cached_removals, i);
115	}
116
117	CFDictionarySetValue(cached_set, key, value);
118
119	return;
120}
121
122__private_extern__
123void
124cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
125{
126	CFDictionaryRemoveValue(cached_set, key);
127
128	if (!CFArrayContainsValue(cached_removals,
129				  CFRangeMake(0, CFArrayGetCount(cached_removals)),
130				  key)) {
131		CFArrayAppendValue(cached_removals, key);
132	}
133
134	return;
135}
136
137
138__private_extern__
139void
140cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key)
141{
142	if (!CFArrayContainsValue(cached_notifys,
143				  CFRangeMake(0, CFArrayGetCount(cached_notifys)),
144				  key)) {
145		CFArrayAppendValue(cached_notifys, key);
146	}
147
148	return;
149}
150
151
152__private_extern__
153void
154cache_write(SCDynamicStoreRef store)
155{
156	if ((CFDictionaryGetCount(cached_set) > 0) ||
157	    (CFArrayGetCount(cached_removals) > 0) ||
158	    (CFArrayGetCount(cached_notifys)  > 0)) {
159		if (!SCDynamicStoreSetMultiple(store,
160				 cached_set,
161				 cached_removals,
162				 cached_notifys)) {
163			SCLog(TRUE,
164			      LOG_ERR,
165			      CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
166			      SCErrorString(SCError()));
167		}
168	}
169
170	return;
171}
172
173
174__private_extern__
175void
176cache_close(void)
177{
178	CFRelease(cached_keys);
179	CFRelease(cached_set);
180	CFRelease(cached_removals);
181	CFRelease(cached_notifys);
182
183	return;
184}
185