2 * Copyright(c) 2000-2003 Apple Computer, 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 16, 2000 Allan Nathanson <ajn@apple.com>
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCValidation.h>
36 #include <SystemConfiguration/SCPrivate.h>
37 #include "SCPreferencesInternal.h"
42 normalizePath(CFStringRef path
)
44 CFArrayRef tmpElements
;
45 CFMutableArrayRef elements
;
49 if (!CFStringHasPrefix(path
, CFSTR("/"))) {
50 /* if no root separator */
54 tmpElements
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
55 elements
= CFArrayCreateMutableCopy(NULL
, 0, tmpElements
);
56 CFRelease(tmpElements
);
58 /* remove empty path components */
59 nElements
= CFArrayGetCount(elements
);
60 for (i
= nElements
; i
> 0; i
--) {
61 CFStringRef pathElement
;
63 pathElement
= CFArrayGetValueAtIndex(elements
, i
-1);
64 if (CFStringGetLength(pathElement
) == 0) {
65 CFArrayRemoveValueAtIndex(elements
, i
-1);
80 getPath(SCPreferencesRef session
, CFStringRef path
, CFDictionaryRef
*entity
)
89 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
90 CFDictionaryRef value
= NULL
;
92 elements
= normalizePath(path
);
93 if (elements
== NULL
) {
94 _SCErrorSet(kSCStatusNoKey
);
100 nElements
= CFArrayGetCount(elements
);
101 for (i
= 0; i
< nElements
; i
++) {
102 element
= CFArrayGetValueAtIndex(elements
, i
);
104 sessionPrivate
->accessed
= TRUE
;
105 value
= CFDictionaryGetValue(sessionPrivate
->prefs
,
106 CFArrayGetValueAtIndex(elements
, 0));
108 value
= CFDictionaryGetValue(value
, element
);
111 /* if path component does not exist */
112 _SCErrorSet(kSCStatusNoKey
);
116 if (!isA_CFDictionary(value
)) {
117 /* if path component not a dictionary */
118 _SCErrorSet(kSCStatusNoKey
);
122 if ((i
< nElements
-1) &&
123 CFDictionaryGetValueIfPresent(value
, kSCResvLink
, (const void **)&link
)) {
125 * if not the last path component and this
128 CFArrayRef linkElements
;
129 CFMutableArrayRef newElements
;
131 if (++nLinks
> MAXLINKS
) {
132 /* if we are chasing our tail */
133 _SCErrorSet(kSCStatusMaxLink
);
137 linkElements
= normalizePath(link
);
138 if (linkElements
== NULL
) {
139 /* if the link is bad */
140 _SCErrorSet(kSCStatusNoKey
);
144 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
145 CFArrayAppendArray(newElements
,
147 CFRangeMake(i
+1, nElements
-i
-1));
149 elements
= newElements
;
166 setPath(SCPreferencesRef session
, CFStringRef path
, CFDictionaryRef entity
)
174 CFDictionaryRef newEntity
= NULL
;
175 CFDictionaryRef node
= NULL
;
176 CFMutableArrayRef nodes
;
178 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
180 elements
= normalizePath(path
);
181 if (elements
== NULL
) {
182 _SCErrorSet(kSCStatusNoKey
);
188 nElements
= CFArrayGetCount(elements
);
189 nodes
= CFArrayCreateMutable(NULL
, nElements
-1, &kCFTypeArrayCallBacks
);
190 for (i
= 0; i
< nElements
- 1; i
++) {
191 element
= CFArrayGetValueAtIndex(elements
, i
);
193 sessionPrivate
->accessed
= TRUE
;
194 node
= CFDictionaryGetValue(sessionPrivate
->prefs
, element
);
196 node
= CFDictionaryGetValue(node
, element
);
201 /* if path component exists */
202 CFArrayAppendValue(nodes
, node
);
204 /* if path component does not exist */
205 node
= CFDictionaryCreate(NULL
,
209 &kCFTypeDictionaryKeyCallBacks
,
210 &kCFTypeDictionaryValueCallBacks
);
211 CFArrayAppendValue(nodes
, node
);
215 if (!isA_CFDictionary(node
)) {
216 _SCErrorSet(kSCStatusNoKey
);
220 if ((i
< nElements
-1) &&
221 CFDictionaryGetValueIfPresent(node
, kSCResvLink
, (const void **)&link
)) {
223 * if not the last path component and this
226 CFArrayRef linkElements
;
227 CFMutableArrayRef newElements
;
229 if (++nLinks
> MAXLINKS
) {
230 /* if we are chasing our tail */
231 _SCErrorSet(kSCStatusMaxLink
);
235 linkElements
= normalizePath(link
);
236 if (linkElements
== NULL
) {
237 /* if the link is bad */
238 _SCErrorSet(kSCStatusNoKey
);
242 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
243 CFArrayAppendArray(newElements
,
245 CFRangeMake(i
+1, nElements
-i
-1));
247 elements
= newElements
;
255 newEntity
= CFRetain(entity
);
257 for (i
= nElements
- 1; i
>= 0; i
--) {
258 element
= CFArrayGetValueAtIndex(elements
, i
);
261 CFDictionarySetValue(sessionPrivate
->prefs
, element
, newEntity
);
263 CFDictionaryRemoveValue(sessionPrivate
->prefs
, element
);
265 sessionPrivate
->changed
= TRUE
;
268 CFMutableDictionaryRef newNode
;
270 node
= CFArrayGetValueAtIndex(nodes
, i
-1);
271 newNode
= CFDictionaryCreateMutableCopy(NULL
, 0, node
);
273 CFDictionarySetValue(newNode
, element
, newEntity
);
274 CFRelease(newEntity
);
276 CFDictionaryRemoveValue(newNode
, element
);
282 CFRelease(newEntity
);
294 SCPreferencesPathCreateUniqueChild(SCPreferencesRef session
,
298 CFStringRef newPath
= NULL
;
299 CFMutableDictionaryRef newDict
= NULL
;
301 CFDictionaryRef entity
;
304 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathCreateUniqueChild:"));
305 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" prefix = %@"), prefix
);
308 if (getPath(session
, prefix
, &entity
)) {
309 // if prefix path exists
310 if (CFDictionaryContainsKey(entity
, kSCResvLink
)) {
311 /* the path is a link... */
312 _SCErrorSet(kSCStatusFailed
);
315 } else if (SCError() != kSCStatusNoKey
) {
316 // if any error except for a missing prefix path component
320 uuid
= CFUUIDCreate(NULL
);
321 child
= CFUUIDCreateString(NULL
, uuid
);
322 newPath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, child
);
326 /* save the new dictionary */
327 newDict
= CFDictionaryCreateMutable(NULL
,
329 &kCFTypeDictionaryKeyCallBacks
,
330 &kCFTypeDictionaryValueCallBacks
);
331 if (setPath(session
, newPath
, newDict
)) {
332 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" child = %@"), newPath
);
344 SCPreferencesPathGetValue(SCPreferencesRef session
,
347 CFDictionaryRef entity
;
348 CFStringRef entityLink
;
351 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathGetValue:"));
352 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
355 if (!getPath(session
, path
, &entity
)) {
359 if (isA_CFDictionary(entity
) &&
360 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
361 /* if this is a dictionary AND it is a link */
362 if (!getPath(session
, entityLink
, &entity
)) {
363 /* if it was a bad link */
368 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" value = %@"), entity
);
374 SCPreferencesPathGetLink(SCPreferencesRef session
,
377 CFDictionaryRef entity
;
378 CFStringRef entityLink
;
381 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathGetLink:"));
382 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
385 if (!getPath(session
, path
, &entity
)) {
389 if (isA_CFDictionary(entity
) &&
390 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
391 /* if this is a dictionary AND it is a link */
392 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" link = %@"), entityLink
);
401 SCPreferencesPathSetValue(SCPreferencesRef session
,
403 CFDictionaryRef value
)
408 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathSetValue:"));
409 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
410 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" value = %@"), value
);
414 _SCErrorSet(kSCStatusInvalidArgument
);
418 ok
= setPath(session
, path
, value
);
424 SCPreferencesPathSetLink(SCPreferencesRef session
,
428 CFMutableDictionaryRef dict
;
429 CFDictionaryRef entity
;
433 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathSetLink:"));
434 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
435 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" link = %@"), link
);
439 _SCErrorSet(kSCStatusInvalidArgument
);
443 if (!getPath(session
, link
, &entity
)) {
448 dict
= CFDictionaryCreateMutable(NULL
,
450 &kCFTypeDictionaryKeyCallBacks
,
451 &kCFTypeDictionaryValueCallBacks
);
452 CFDictionaryAddValue(dict
, kSCResvLink
, link
);
453 ok
= setPath(session
, path
, dict
);
461 SCPreferencesPathRemoveValue(SCPreferencesRef session
,
464 CFArrayRef elements
= NULL
;
466 CFDictionaryRef value
;
469 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathRemoveValue:"));
470 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
473 if (!getPath(session
, path
, &value
)) {
478 elements
= normalizePath(path
);
479 if (elements
== NULL
) {
480 _SCErrorSet(kSCStatusNoKey
);
484 ok
= setPath(session
, path
, NULL
);