2 * Copyright(c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
32 * November 16, 2000 Allan Nathanson <ajn@apple.com>
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCValidation.h>
38 #include <SystemConfiguration/SCPrivate.h>
39 #include "SCPreferencesInternal.h"
44 normalizePath(CFStringRef path
)
46 CFArrayRef tmpElements
;
47 CFMutableArrayRef elements
;
51 if (!CFStringHasPrefix(path
, CFSTR("/"))) {
52 /* if no root separator */
56 tmpElements
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
57 elements
= CFArrayCreateMutableCopy(NULL
, 0, tmpElements
);
58 CFRelease(tmpElements
);
60 /* remove empty path components */
61 nElements
= CFArrayGetCount(elements
);
62 for (i
= nElements
; i
> 0; i
--) {
63 CFStringRef pathElement
;
65 pathElement
= CFArrayGetValueAtIndex(elements
, i
-1);
66 if (CFStringGetLength(pathElement
) == 0) {
67 CFArrayRemoveValueAtIndex(elements
, i
-1);
82 getPath(SCPreferencesRef session
, CFStringRef path
, CFDictionaryRef
*entity
)
91 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
92 CFDictionaryRef value
= NULL
;
94 elements
= normalizePath(path
);
95 if (elements
== NULL
) {
96 _SCErrorSet(kSCStatusNoKey
);
102 nElements
= CFArrayGetCount(elements
);
103 for (i
= 0; i
< nElements
; i
++) {
104 element
= CFArrayGetValueAtIndex(elements
, i
);
106 sessionPrivate
->accessed
= TRUE
;
107 value
= CFDictionaryGetValue(sessionPrivate
->prefs
,
108 CFArrayGetValueAtIndex(elements
, 0));
110 value
= CFDictionaryGetValue(value
, element
);
113 /* if path component does not exist */
114 _SCErrorSet(kSCStatusNoKey
);
118 if (!isA_CFDictionary(value
)) {
119 /* if path component not a dictionary */
120 _SCErrorSet(kSCStatusNoKey
);
124 if ((i
< nElements
-1) &&
125 CFDictionaryGetValueIfPresent(value
, kSCResvLink
, (const void **)&link
)) {
127 * if not the last path component and this
130 CFArrayRef linkElements
;
131 CFMutableArrayRef newElements
;
133 if (++nLinks
> MAXLINKS
) {
134 /* if we are chasing our tail */
135 _SCErrorSet(kSCStatusMaxLink
);
139 linkElements
= normalizePath(link
);
140 if (linkElements
== NULL
) {
141 /* if the link is bad */
142 _SCErrorSet(kSCStatusNoKey
);
146 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
147 CFArrayAppendArray(newElements
,
149 CFRangeMake(i
+1, nElements
-i
-1));
151 elements
= newElements
;
168 setPath(SCPreferencesRef session
, CFStringRef path
, CFDictionaryRef entity
)
176 CFDictionaryRef newEntity
= NULL
;
177 CFDictionaryRef node
= NULL
;
178 CFMutableArrayRef nodes
;
180 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
182 elements
= normalizePath(path
);
183 if (elements
== NULL
) {
184 _SCErrorSet(kSCStatusNoKey
);
190 nElements
= CFArrayGetCount(elements
);
191 nodes
= CFArrayCreateMutable(NULL
, nElements
-1, &kCFTypeArrayCallBacks
);
192 for (i
= 0; i
< nElements
- 1; i
++) {
193 element
= CFArrayGetValueAtIndex(elements
, i
);
195 sessionPrivate
->accessed
= TRUE
;
196 node
= CFDictionaryGetValue(sessionPrivate
->prefs
, element
);
198 node
= CFDictionaryGetValue(node
, element
);
203 /* if path component exists */
204 CFArrayAppendValue(nodes
, node
);
206 /* if path component does not exist */
207 node
= CFDictionaryCreate(NULL
,
211 &kCFTypeDictionaryKeyCallBacks
,
212 &kCFTypeDictionaryValueCallBacks
);
213 CFArrayAppendValue(nodes
, node
);
217 if (!isA_CFDictionary(node
)) {
218 _SCErrorSet(kSCStatusNoKey
);
222 if ((i
< nElements
-1) &&
223 CFDictionaryGetValueIfPresent(node
, kSCResvLink
, (const void **)&link
)) {
225 * if not the last path component and this
228 CFArrayRef linkElements
;
229 CFMutableArrayRef newElements
;
231 if (++nLinks
> MAXLINKS
) {
232 /* if we are chasing our tail */
233 _SCErrorSet(kSCStatusMaxLink
);
237 linkElements
= normalizePath(link
);
238 if (linkElements
== NULL
) {
239 /* if the link is bad */
240 _SCErrorSet(kSCStatusNoKey
);
244 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
245 CFArrayAppendArray(newElements
,
247 CFRangeMake(i
+1, nElements
-i
-1));
249 elements
= newElements
;
257 newEntity
= CFRetain(entity
);
259 for (i
= nElements
- 1; i
>= 0; i
--) {
260 element
= CFArrayGetValueAtIndex(elements
, i
);
263 CFDictionarySetValue(sessionPrivate
->prefs
, element
, newEntity
);
265 CFDictionaryRemoveValue(sessionPrivate
->prefs
, element
);
267 sessionPrivate
->changed
= TRUE
;
270 CFMutableDictionaryRef newNode
;
272 node
= CFArrayGetValueAtIndex(nodes
, i
-1);
273 newNode
= CFDictionaryCreateMutableCopy(NULL
, 0, node
);
275 CFDictionarySetValue(newNode
, element
, newEntity
);
276 CFRelease(newEntity
);
278 CFDictionaryRemoveValue(newNode
, element
);
284 CFRelease(newEntity
);
296 SCPreferencesPathCreateUniqueChild(SCPreferencesRef session
,
300 CFStringRef newPath
= NULL
;
301 CFMutableDictionaryRef newDict
= NULL
;
303 CFDictionaryRef entity
;
306 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathCreateUniqueChild:"));
307 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" prefix = %@"), prefix
);
310 if (getPath(session
, prefix
, &entity
)) {
311 // if prefix path exists
312 if (CFDictionaryContainsKey(entity
, kSCResvLink
)) {
313 /* the path is a link... */
314 _SCErrorSet(kSCStatusFailed
);
317 } else if (SCError() != kSCStatusNoKey
) {
318 // if any error except for a missing prefix path component
322 uuid
= CFUUIDCreate(NULL
);
323 child
= CFUUIDCreateString(NULL
, uuid
);
324 newPath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, child
);
328 /* save the new dictionary */
329 newDict
= CFDictionaryCreateMutable(NULL
,
331 &kCFTypeDictionaryKeyCallBacks
,
332 &kCFTypeDictionaryValueCallBacks
);
333 if (setPath(session
, newPath
, newDict
)) {
334 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" child = %@"), newPath
);
346 SCPreferencesPathGetValue(SCPreferencesRef session
,
349 CFDictionaryRef entity
;
350 CFStringRef entityLink
;
353 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathGetValue:"));
354 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
357 if (!getPath(session
, path
, &entity
)) {
361 if (isA_CFDictionary(entity
) &&
362 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
363 /* if this is a dictionary AND it is a link */
364 if (!getPath(session
, entityLink
, &entity
)) {
365 /* if it was a bad link */
370 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" value = %@"), entity
);
376 SCPreferencesPathGetLink(SCPreferencesRef session
,
379 CFDictionaryRef entity
;
380 CFStringRef entityLink
;
383 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathGetLink:"));
384 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
387 if (!getPath(session
, path
, &entity
)) {
391 if (isA_CFDictionary(entity
) &&
392 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
393 /* if this is a dictionary AND it is a link */
394 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" link = %@"), entityLink
);
403 SCPreferencesPathSetValue(SCPreferencesRef session
,
405 CFDictionaryRef value
)
410 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathSetValue:"));
411 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
412 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" value = %@"), value
);
416 _SCErrorSet(kSCStatusInvalidArgument
);
420 ok
= setPath(session
, path
, value
);
426 SCPreferencesPathSetLink(SCPreferencesRef session
,
430 CFMutableDictionaryRef dict
;
431 CFDictionaryRef entity
;
435 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathSetLink:"));
436 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
437 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" link = %@"), link
);
441 _SCErrorSet(kSCStatusInvalidArgument
);
445 if (!getPath(session
, link
, &entity
)) {
450 dict
= CFDictionaryCreateMutable(NULL
,
452 &kCFTypeDictionaryKeyCallBacks
,
453 &kCFTypeDictionaryValueCallBacks
);
454 CFDictionaryAddValue(dict
, kSCResvLink
, link
);
455 ok
= setPath(session
, path
, dict
);
463 SCPreferencesPathRemoveValue(SCPreferencesRef session
,
466 CFArrayRef elements
= NULL
;
468 CFDictionaryRef value
;
471 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCPreferencesPathRemoveValue:"));
472 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" path = %@"), path
);
475 if (!getPath(session
, path
, &value
)) {
480 elements
= normalizePath(path
);
481 if (elements
== NULL
) {
482 _SCErrorSet(kSCStatusNoKey
);
486 ok
= setPath(session
, path
, NULL
);