2 * Copyright(c) 2000 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@
23 #include <SystemConfiguration/SCD.h>
24 #include <SystemConfiguration/SCP.h>
25 #include "SCPPrivate.h"
26 #include <SystemConfiguration/SCPreferences.h>
27 #include <SystemConfiguration/SCPPath.h>
30 normalizePath(CFStringRef path
)
32 CFArrayRef tmpElements
;
33 CFMutableArrayRef elements
;
37 if (!CFStringHasPrefix(path
, CFSTR("/"))) {
38 /* if no root separator */
42 tmpElements
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
43 elements
= CFArrayCreateMutableCopy(NULL
, 0, tmpElements
);
44 CFRelease(tmpElements
);
46 /* remove empty path components */
47 nElements
= CFArrayGetCount(elements
);
48 for (i
=nElements
; i
>0; i
--) {
49 CFStringRef pathElement
;
51 pathElement
= CFArrayGetValueAtIndex(elements
, i
-1);
52 if (CFStringGetLength(pathElement
) == 0) {
53 CFArrayRemoveValueAtIndex(elements
, i
-1);
68 getPath(SCPSessionRef session
, CFStringRef path
, CFMutableDictionaryRef
*entity
)
74 CFMutableDictionaryRef value
= NULL
;
76 if (session
== NULL
) {
77 return SCP_NOSESSION
; /* you can't do anything with a closed session */
80 elements
= normalizePath(path
);
81 if (elements
== NULL
) {
85 /* get preferences key */
86 status
= SCPGet(session
,
87 CFArrayGetValueAtIndex(elements
, 0),
88 (CFPropertyListRef
*)&value
);
89 if (status
!= SCP_OK
) {
93 if (CFGetTypeID(value
) != CFDictionaryGetTypeID()) {
98 nElements
= CFArrayGetCount(elements
);
99 for (i
=1; i
<nElements
; i
++) {
102 element
= CFArrayGetValueAtIndex(elements
, i
);
103 value
= (CFMutableDictionaryRef
)CFDictionaryGetValue(value
, element
);
105 /* if (parent) path component does not exist */
110 if (CFGetTypeID(value
) != CFDictionaryGetTypeID()) {
128 SCPPathCreateUniqueChild(SCPSessionRef session
,
130 CFStringRef
*newPath
)
133 CFMutableDictionaryRef value
;
134 boolean_t newValue
= FALSE
;
137 CFMutableDictionaryRef newDict
;
139 if (session
== NULL
) {
140 return SCP_NOSESSION
; /* you can't do anything with a closed session */
143 status
= getPath(session
, prefix
, &value
);
148 value
= CFDictionaryCreateMutable(NULL
,
150 &kCFTypeDictionaryKeyCallBacks
,
151 &kCFTypeDictionaryValueCallBacks
);
158 if (CFGetTypeID(value
) != CFDictionaryGetTypeID()) {
159 /* if specified path is not a dictionary */
164 if (CFDictionaryContainsKey(value
, kSCResvLink
)) {
165 /* the path is a link... */
172 CFStringRef pathComponent
;
175 pathComponent
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), i
);
176 found
= CFDictionaryContainsKey(value
, pathComponent
);
177 CFRelease(pathComponent
);
180 /* if we've identified the next unique key */
181 path
= CFStringCreateWithFormat(NULL
,
191 /* save the new dictionary */
192 newDict
= CFDictionaryCreateMutable(NULL
,
194 &kCFTypeDictionaryKeyCallBacks
,
195 &kCFTypeDictionaryValueCallBacks
);
196 status
= SCPPathSetValue(session
, path
, newDict
);
198 if (status
!= SCP_OK
) {
207 if (newValue
) CFRelease(value
);
213 SCPPathGetValue(SCPSessionRef session
,
215 CFDictionaryRef
*value
)
218 CFMutableDictionaryRef entity
;
219 CFStringRef entityLink
;
221 if (session
== NULL
) {
222 return SCP_NOSESSION
; /* you can't do anything with a closed session */
225 status
= getPath(session
, path
, &entity
);
226 if (status
!= SCP_OK
) {
230 /* XXXX Add code here to chase multiple links XXXXX */
232 if ((CFGetTypeID(entity
) == CFDictionaryGetTypeID()) &&
233 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (void **)&entityLink
))) {
234 /* if this is a dictionary AND it is a link */
235 status
= getPath(session
, entityLink
, &entity
);
236 if (status
!= SCP_OK
) {
237 /* if it was a bad link */
248 SCPPathGetLink(SCPSessionRef session
,
253 CFMutableDictionaryRef entity
;
254 CFStringRef entityLink
;
256 if (session
== NULL
) {
257 return SCP_NOSESSION
; /* you can't do anything with a closed session */
260 status
= getPath(session
, path
, &entity
);
261 if (status
!= SCP_OK
) {
265 if ((CFGetTypeID(entity
) == CFDictionaryGetTypeID()) &&
266 (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (void **)&entityLink
))) {
267 /* if this is a dictionary AND it is a link */
277 SCPPathSetValue(SCPSessionRef session
, CFStringRef path
, CFDictionaryRef value
)
279 CFMutableDictionaryRef element
;
280 CFArrayRef elements
= NULL
;
283 boolean_t newRoot
= FALSE
;
284 CFMutableDictionaryRef root
= NULL
;
285 SCPStatus status
= SCP_NOKEY
;
287 if (session
== NULL
) {
288 return SCP_NOSESSION
; /* you can't do anything with a closed session */
291 elements
= normalizePath(path
);
292 if (elements
== NULL
) {
296 /* get preferences key */
297 status
= SCPGet(session
,
298 CFArrayGetValueAtIndex(elements
, 0),
299 (CFPropertyListRef
*)&root
);
300 if (status
!= SCP_OK
) {
301 root
= CFDictionaryCreateMutable(NULL
,
303 &kCFTypeDictionaryKeyCallBacks
,
304 &kCFTypeDictionaryValueCallBacks
);
308 nElements
= CFArrayGetCount(elements
);
309 if (nElements
== 1) {
310 /* if we are only updating the data associated with the preference key */
315 root
= (CFMutableDictionaryRef
)value
;
319 for (i
=1; i
<nElements
-1; i
++) {
320 CFStringRef pathComponent
;
321 CFMutableDictionaryRef tmpElement
;
323 pathComponent
= CFArrayGetValueAtIndex(elements
, i
);
324 tmpElement
= (void *)CFDictionaryGetValue(element
, pathComponent
);
325 if (tmpElement
== NULL
) {
326 /* if (parent) path component does not exist */
327 tmpElement
= CFDictionaryCreateMutable(NULL
,
329 &kCFTypeDictionaryKeyCallBacks
,
330 &kCFTypeDictionaryValueCallBacks
);
331 CFDictionarySetValue(element
, pathComponent
, tmpElement
);
332 CFRelease(tmpElement
);
334 element
= tmpElement
;
338 CFDictionarySetValue(element
,
339 CFArrayGetValueAtIndex(elements
, nElements
-1),
342 status
= SCPSet(session
, CFArrayGetValueAtIndex(elements
, 0), root
);
344 if (newRoot
) CFRelease(root
);
351 SCPPathSetLink(SCPSessionRef session
, CFStringRef path
, CFStringRef link
)
353 CFMutableDictionaryRef dict
;
356 if (session
== NULL
) {
357 return SCP_NOSESSION
; /* you can't do anything with a closed session */
360 dict
= CFDictionaryCreateMutable(NULL
,
362 &kCFTypeDictionaryKeyCallBacks
,
363 &kCFTypeDictionaryValueCallBacks
);
364 CFDictionaryAddValue(dict
, kSCResvLink
, link
);
365 status
= SCPPathSetValue(session
, path
, dict
);
373 SCPPathRemove(SCPSessionRef session
, CFStringRef path
)
375 CFMutableDictionaryRef element
;
376 CFArrayRef elements
= NULL
;
379 CFMutableDictionaryRef root
= NULL
;
380 SCPStatus status
= SCP_NOKEY
;
382 if (session
== NULL
) {
383 return SCP_NOSESSION
; /* you can't do anything with a closed session */
386 elements
= normalizePath(path
);
387 if (elements
== NULL
) {
391 /* get preferences key */
392 status
= SCPGet(session
,
393 CFArrayGetValueAtIndex(elements
, 0),
394 (CFPropertyListRef
*)&root
);
395 if (status
!= SCP_OK
) {
399 nElements
= CFArrayGetCount(elements
);
400 if (nElements
== 1) {
401 /* if we are removing the data associated with the preference key */
402 status
= SCPRemove(session
, CFArrayGetValueAtIndex(elements
, 0));
407 for (i
=1; i
<nElements
-1; i
++) {
408 CFStringRef pathComponent
;
409 CFMutableDictionaryRef tmpElement
;
411 pathComponent
= CFArrayGetValueAtIndex(elements
, i
);
412 tmpElement
= (void *)CFDictionaryGetValue(element
, pathComponent
);
413 if (tmpElement
== NULL
) {
417 element
= tmpElement
;
420 CFDictionaryRemoveValue(element
,
421 CFArrayGetValueAtIndex(elements
, nElements
-1));
422 status
= SCPSet(session
, CFArrayGetValueAtIndex(elements
, 0), root
);