2 * Copyright(c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1(the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * November 16, 2000 Allan Nathanson <ajn@apple.com>
33 #include <SystemConfiguration/SystemConfiguration.h>
34 #include <SystemConfiguration/SCValidation.h>
35 #include <SystemConfiguration/SCPrivate.h>
36 #include "SCPreferencesInternal.h"
41 normalizePath(CFStringRef path
)
43 CFArrayRef tmpElements
;
44 CFMutableArrayRef elements
;
48 if (!CFStringHasPrefix(path
, CFSTR("/"))) {
49 /* if no root separator */
53 tmpElements
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
54 elements
= CFArrayCreateMutableCopy(NULL
, 0, tmpElements
);
55 CFRelease(tmpElements
);
57 /* remove empty path components */
58 nElements
= CFArrayGetCount(elements
);
59 for (i
=nElements
; i
>0; i
--) {
60 CFStringRef pathElement
;
62 pathElement
= CFArrayGetValueAtIndex(elements
, i
-1);
63 if (CFStringGetLength(pathElement
) == 0) {
64 CFArrayRemoveValueAtIndex(elements
, i
-1);
79 getPath(SCPreferencesRef session
, CFStringRef path
, CFDictionaryRef
*entity
)
88 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
89 CFDictionaryRef value
= NULL
;
91 elements
= normalizePath(path
);
92 if (elements
== NULL
) {
93 _SCErrorSet(kSCStatusNoKey
);
99 nElements
= CFArrayGetCount(elements
);
100 for (i
=0; i
<nElements
; i
++) {
101 element
= CFArrayGetValueAtIndex(elements
, i
);
103 sessionPrivate
->accessed
= TRUE
;
104 value
= CFDictionaryGetValue(sessionPrivate
->prefs
,
105 CFArrayGetValueAtIndex(elements
, 0));
107 value
= CFDictionaryGetValue(value
, element
);
110 /* if path component does not exist */
111 _SCErrorSet(kSCStatusNoKey
);
115 if (!isA_CFDictionary(value
)) {
116 /* if path component not a dictionary */
117 _SCErrorSet(kSCStatusNoKey
);
121 if ((i
< nElements
-1) &&
122 CFDictionaryGetValueIfPresent(value
, kSCResvLink
, (const void **)&link
)) {
124 * if not the last path component and this
127 CFArrayRef linkElements
;
128 CFMutableArrayRef newElements
;
130 if (++nLinks
> MAXLINKS
) {
131 /* if we are chasing our tail */
132 _SCErrorSet(kSCStatusMaxLink
);
136 linkElements
= normalizePath(link
);
137 if (linkElements
== NULL
) {
138 /* if the link is bad */
139 _SCErrorSet(kSCStatusNoKey
);
143 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
144 CFArrayAppendArray(newElements
,
146 CFRangeMake(i
+1, nElements
-i
-1));
148 elements
= newElements
;
165 setPath(SCPreferencesRef session
, CFStringRef path
, CFDictionaryRef entity
)
173 CFDictionaryRef newEntity
= NULL
;
174 CFDictionaryRef node
= NULL
;
175 CFMutableArrayRef nodes
;
177 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
179 elements
= normalizePath(path
);
180 if (elements
== NULL
) {
181 _SCErrorSet(kSCStatusNoKey
);
187 nElements
= CFArrayGetCount(elements
);
188 nodes
= CFArrayCreateMutable(NULL
, nElements
-1, &kCFTypeArrayCallBacks
);
189 for (i
=0; i
<nElements
-1; i
++) {
190 element
= CFArrayGetValueAtIndex(elements
, i
);
192 sessionPrivate
->accessed
= TRUE
;
193 node
= CFDictionaryGetValue(sessionPrivate
->prefs
, element
);
195 node
= CFDictionaryGetValue(node
, element
);
200 /* if path component exists */
201 CFArrayAppendValue(nodes
, node
);
203 /* if path component does not exist */
204 node
= CFDictionaryCreate(NULL
,
208 &kCFTypeDictionaryKeyCallBacks
,
209 &kCFTypeDictionaryValueCallBacks
);
210 CFArrayAppendValue(nodes
, node
);
214 if (!isA_CFDictionary(node
)) {
215 _SCErrorSet(kSCStatusNoKey
);
219 if ((i
< nElements
-1) &&
220 CFDictionaryGetValueIfPresent(node
, kSCResvLink
, (const void **)&link
)) {
222 * if not the last path component and this
225 CFArrayRef linkElements
;
226 CFMutableArrayRef newElements
;
228 if (++nLinks
> MAXLINKS
) {
229 /* if we are chasing our tail */
230 _SCErrorSet(kSCStatusMaxLink
);
234 linkElements
= normalizePath(link
);
235 if (linkElements
== NULL
) {
236 /* if the link is bad */
237 _SCErrorSet(kSCStatusNoKey
);
241 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
242 CFArrayAppendArray(newElements
,
244 CFRangeMake(i
+1, nElements
-i
-1));
246 elements
= newElements
;
254 newEntity
= CFRetain(entity
);
256 for (i
=nElements
-1; i
>=0; i
--) {
257 element
= CFArrayGetValueAtIndex(elements
, i
);
260 CFDictionarySetValue(sessionPrivate
->prefs
, element
, newEntity
);
262 CFDictionaryRemoveValue(sessionPrivate
->prefs
, element
);
264 sessionPrivate
->changed
= TRUE
;
267 CFMutableDictionaryRef newNode
;
269 node
= CFArrayGetValueAtIndex(nodes
, i
-1);
270 newNode
= CFDictionaryCreateMutableCopy(NULL
, 0, node
);
272 CFDictionarySetValue(newNode
, element
, newEntity
);
273 CFRelease(newEntity
);
275 CFDictionaryRemoveValue(newNode
, element
);
281 CFRelease(newEntity
);
293 SCPreferencesPathCreateUniqueChild(SCPreferencesRef session
,
297 CFStringRef newPath
= NULL
;
298 CFMutableDictionaryRef newDict
= NULL
;
300 CFDictionaryRef entity
;
302 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesPathCreateUniqueChild:"));
303 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" prefix = %@"), prefix
);
305 if (getPath(session
, prefix
, &entity
)) {
306 // if prefix path exists
307 if (CFDictionaryContainsKey(entity
, kSCResvLink
)) {
308 /* the path is a link... */
309 _SCErrorSet(kSCStatusFailed
);
312 } else if (SCError() != kSCStatusNoKey
) {
313 // if any error except for a missing prefix path component
317 uuid
= CFUUIDCreate(NULL
);
318 child
= CFUUIDCreateString(NULL
, uuid
);
319 newPath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, child
);
323 /* save the new dictionary */
324 newDict
= CFDictionaryCreateMutable(NULL
,
326 &kCFTypeDictionaryKeyCallBacks
,
327 &kCFTypeDictionaryValueCallBacks
);
328 if (setPath(session
, newPath
, newDict
)) {
329 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" child = %@"), newPath
);
341 SCPreferencesPathGetValue(SCPreferencesRef session
,
344 CFDictionaryRef entity
;
345 CFStringRef entityLink
;
347 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesPathGetValue:"));
348 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
350 if (!getPath(session
, path
, &entity
)) {
354 if (isA_CFDictionary(entity
) &&
355 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
356 /* if this is a dictionary AND it is a link */
357 if (!getPath(session
, entityLink
, &entity
)) {
358 /* if it was a bad link */
363 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" value = %@"), entity
);
369 SCPreferencesPathGetLink(SCPreferencesRef session
,
372 CFDictionaryRef entity
;
373 CFStringRef entityLink
;
375 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesPathGetLink:"));
376 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
378 if (!getPath(session
, path
, &entity
)) {
382 if (isA_CFDictionary(entity
) &&
383 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
384 /* if this is a dictionary AND it is a link */
385 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" link = %@"), entityLink
);
394 SCPreferencesPathSetValue(SCPreferencesRef session
,
396 CFDictionaryRef value
)
400 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesPathSetValue:"));
401 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
402 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" value = %@"), value
);
405 _SCErrorSet(kSCStatusInvalidArgument
);
409 ok
= setPath(session
, path
, value
);
415 SCPreferencesPathSetLink(SCPreferencesRef session
,
419 CFMutableDictionaryRef dict
;
420 CFDictionaryRef entity
;
423 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesPathSetLink:"));
424 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
425 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" link = %@"), link
);
428 _SCErrorSet(kSCStatusInvalidArgument
);
432 if (!getPath(session
, link
, &entity
)) {
437 dict
= CFDictionaryCreateMutable(NULL
,
439 &kCFTypeDictionaryKeyCallBacks
,
440 &kCFTypeDictionaryValueCallBacks
);
441 CFDictionaryAddValue(dict
, kSCResvLink
, link
);
442 ok
= setPath(session
, path
, dict
);
450 SCPreferencesPathRemoveValue(SCPreferencesRef session
,
453 CFArrayRef elements
= NULL
;
455 CFDictionaryRef value
;
457 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesPathRemoveValue:"));
458 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
460 if (!getPath(session
, path
, &value
)) {
465 elements
= normalizePath(path
);
466 if (elements
== NULL
) {
467 _SCErrorSet(kSCStatusNoKey
);
471 ok
= setPath(session
, path
, NULL
);