2 * Copyright (c) 2000-2005 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 prefs
, CFStringRef path
, CFDictionaryRef
*entity
)
89 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
90 CFDictionaryRef value
= NULL
;
92 elements
= normalizePath(path
);
93 if (elements
== NULL
) {
94 _SCErrorSet(kSCStatusNoKey
);
98 __SCPreferencesAccess(prefs
);
102 nElements
= CFArrayGetCount(elements
);
103 for (i
= 0; i
< nElements
; i
++) {
104 element
= CFArrayGetValueAtIndex(elements
, i
);
106 value
= CFDictionaryGetValue(prefsPrivate
->prefs
,
107 CFArrayGetValueAtIndex(elements
, 0));
109 value
= CFDictionaryGetValue(value
, element
);
112 /* if path component does not exist */
113 _SCErrorSet(kSCStatusNoKey
);
117 if (!isA_CFDictionary(value
)) {
118 /* if path component not a dictionary */
119 _SCErrorSet(kSCStatusNoKey
);
123 if ((i
< nElements
-1) &&
124 CFDictionaryGetValueIfPresent(value
, kSCResvLink
, (const void **)&link
)) {
126 * if not the last path component and this
129 CFArrayRef linkElements
;
130 CFMutableArrayRef newElements
;
132 if (++nLinks
> MAXLINKS
) {
133 /* if we are chasing our tail */
134 _SCErrorSet(kSCStatusMaxLink
);
138 linkElements
= normalizePath(link
);
139 if (linkElements
== NULL
) {
140 /* if the link is bad */
141 _SCErrorSet(kSCStatusNoKey
);
145 newElements
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
);
146 CFArrayAppendArray(newElements
,
148 CFRangeMake(i
+1, nElements
-i
-1));
150 elements
= newElements
;
167 setPath(SCPreferencesRef prefs
, CFStringRef path
, CFDictionaryRef entity
)
175 CFDictionaryRef newEntity
= NULL
;
176 CFDictionaryRef node
= NULL
;
177 CFMutableArrayRef nodes
;
179 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
181 elements
= normalizePath(path
);
182 if (elements
== NULL
) {
183 _SCErrorSet(kSCStatusNoKey
);
187 __SCPreferencesAccess(prefs
);
191 nElements
= CFArrayGetCount(elements
);
192 nodes
= CFArrayCreateMutable(NULL
, nElements
-1, &kCFTypeArrayCallBacks
);
193 for (i
= 0; i
< nElements
- 1; i
++) {
194 element
= CFArrayGetValueAtIndex(elements
, i
);
196 node
= CFDictionaryGetValue(prefsPrivate
->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(prefsPrivate
->prefs
, element
, newEntity
);
265 CFDictionaryRemoveValue(prefsPrivate
->prefs
, element
);
267 prefsPrivate
->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
);
279 if (CFDictionaryGetCount(newNode
) == 0) {
280 // prune the (now empty) parent
289 CFRelease(newEntity
);
301 SCPreferencesPathCreateUniqueChild(SCPreferencesRef prefs
,
305 CFStringRef newPath
= NULL
;
306 CFMutableDictionaryRef newDict
= NULL
;
308 CFDictionaryRef entity
;
311 /* sorry, you must provide a session */
312 _SCErrorSet(kSCStatusNoPrefsSession
);
316 if (getPath(prefs
, prefix
, &entity
)) {
317 // if prefix path exists
318 if (CFDictionaryContainsKey(entity
, kSCResvLink
)) {
319 /* the path is a link... */
320 _SCErrorSet(kSCStatusFailed
);
323 } else if (SCError() != kSCStatusNoKey
) {
324 // if any error except for a missing prefix path component
328 uuid
= CFUUIDCreate(NULL
);
329 child
= CFUUIDCreateString(NULL
, uuid
);
330 newPath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, child
);
334 /* save the new dictionary */
335 newDict
= CFDictionaryCreateMutable(NULL
,
337 &kCFTypeDictionaryKeyCallBacks
,
338 &kCFTypeDictionaryValueCallBacks
);
339 if (!setPath(prefs
, newPath
, newDict
)) {
350 SCPreferencesPathGetValue(SCPreferencesRef prefs
,
353 CFDictionaryRef entity
;
354 CFStringRef entityLink
;
357 /* sorry, you must provide a session */
358 _SCErrorSet(kSCStatusNoPrefsSession
);
362 if (!getPath(prefs
, path
, &entity
)) {
366 if (isA_CFDictionary(entity
) &&
367 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
368 /* if this is a dictionary AND it is a link */
369 if (!getPath(prefs
, entityLink
, &entity
)) {
370 /* if it was a bad link */
380 SCPreferencesPathGetLink(SCPreferencesRef prefs
,
383 CFDictionaryRef entity
;
384 CFStringRef entityLink
;
387 /* sorry, you must provide a session */
388 _SCErrorSet(kSCStatusNoPrefsSession
);
392 if (!getPath(prefs
, path
, &entity
)) {
396 if (isA_CFDictionary(entity
) &&
397 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) {
398 /* if this is a dictionary AND it is a link */
407 SCPreferencesPathSetValue(SCPreferencesRef prefs
,
409 CFDictionaryRef value
)
414 /* sorry, you must provide a session */
415 _SCErrorSet(kSCStatusNoPrefsSession
);
420 _SCErrorSet(kSCStatusInvalidArgument
);
424 ok
= setPath(prefs
, path
, value
);
430 SCPreferencesPathSetLink(SCPreferencesRef prefs
,
434 CFMutableDictionaryRef dict
;
435 CFDictionaryRef entity
;
439 /* sorry, you must provide a session */
440 _SCErrorSet(kSCStatusNoPrefsSession
);
445 _SCErrorSet(kSCStatusInvalidArgument
);
449 if (!getPath(prefs
, link
, &entity
)) {
454 dict
= CFDictionaryCreateMutable(NULL
,
456 &kCFTypeDictionaryKeyCallBacks
,
457 &kCFTypeDictionaryValueCallBacks
);
458 CFDictionaryAddValue(dict
, kSCResvLink
, link
);
459 ok
= setPath(prefs
, path
, dict
);
467 SCPreferencesPathRemoveValue(SCPreferencesRef prefs
,
470 CFArrayRef elements
= NULL
;
472 CFDictionaryRef value
;
475 /* sorry, you must provide a session */
476 _SCErrorSet(kSCStatusNoPrefsSession
);
480 if (!getPath(prefs
, path
, &value
)) {
485 elements
= normalizePath(path
);
486 if (elements
== NULL
) {
487 _SCErrorSet(kSCStatusNoKey
);
491 ok
= setPath(prefs
, path
, NULL
);