]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPPath.c
configd-24.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPPath.c
1 /*
2 * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <SystemConfiguration/SCD.h>
24 #include <SystemConfiguration/SCP.h>
25 #include "SCPPrivate.h"
26 #include <SystemConfiguration/SCPreferences.h>
27 #include <SystemConfiguration/SCPPath.h>
28
29 static CFArrayRef
30 normalizePath(CFStringRef path)
31 {
32 CFArrayRef tmpElements;
33 CFMutableArrayRef elements;
34 CFIndex nElements;
35 CFIndex i;
36
37 if (!CFStringHasPrefix(path, CFSTR("/"))) {
38 /* if no root separator */
39 return NULL;
40 }
41
42 tmpElements = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
43 elements = CFArrayCreateMutableCopy(NULL, 0, tmpElements);
44 CFRelease(tmpElements);
45
46 /* remove empty path components */
47 nElements = CFArrayGetCount(elements);
48 for (i=nElements; i>0; i--) {
49 CFStringRef pathElement;
50
51 pathElement = CFArrayGetValueAtIndex(elements, i-1);
52 if (CFStringGetLength(pathElement) == 0) {
53 CFArrayRemoveValueAtIndex(elements, i-1);
54 nElements--;
55 }
56 }
57
58 if (nElements < 1) {
59 CFRelease(elements);
60 return NULL;
61 }
62
63 return elements;
64 }
65
66
67 static SCPStatus
68 getPath(SCPSessionRef session, CFStringRef path, CFMutableDictionaryRef *entity)
69 {
70 CFArrayRef elements;
71 CFIndex i;
72 CFIndex nElements;
73 SCPStatus status;
74 CFMutableDictionaryRef value = NULL;
75
76 if (session == NULL) {
77 return SCP_NOSESSION; /* you can't do anything with a closed session */
78 }
79
80 elements = normalizePath(path);
81 if (elements == NULL) {
82 return SCP_NOKEY;
83 }
84
85 /* get preferences key */
86 status = SCPGet(session,
87 CFArrayGetValueAtIndex(elements, 0),
88 (CFPropertyListRef *)&value);
89 if (status != SCP_OK) {
90 goto done;
91 }
92
93 if (CFGetTypeID(value) != CFDictionaryGetTypeID()) {
94 status = SCP_NOKEY;
95 goto done;
96 }
97
98 nElements = CFArrayGetCount(elements);
99 for (i=1; i<nElements; i++) {
100 CFStringRef element;
101
102 element = CFArrayGetValueAtIndex(elements, i);
103 value = (CFMutableDictionaryRef)CFDictionaryGetValue(value, element);
104 if (value == NULL) {
105 /* if (parent) path component does not exist */
106 status = SCP_NOKEY;
107 goto done;
108 }
109
110 if (CFGetTypeID(value) != CFDictionaryGetTypeID()) {
111 status = SCP_NOKEY;
112 goto done;
113 }
114
115 }
116
117 *entity = value;
118 status = SCP_OK;
119
120 done :
121
122 CFRelease(elements);
123 return status;
124 }
125
126
127 SCPStatus
128 SCPPathCreateUniqueChild(SCPSessionRef session,
129 CFStringRef prefix,
130 CFStringRef *newPath)
131 {
132 SCPStatus status;
133 CFMutableDictionaryRef value;
134 boolean_t newValue = FALSE;
135 CFIndex i;
136 CFStringRef path;
137 CFMutableDictionaryRef newDict;
138
139 if (session == NULL) {
140 return SCP_NOSESSION; /* you can't do anything with a closed session */
141 }
142
143 status = getPath(session, prefix, &value);
144 switch (status) {
145 case SCP_OK :
146 break;
147 case SCP_NOKEY :
148 value = CFDictionaryCreateMutable(NULL,
149 0,
150 &kCFTypeDictionaryKeyCallBacks,
151 &kCFTypeDictionaryValueCallBacks);
152 newValue = TRUE;
153 break;
154 default :
155 return status;
156 }
157
158 if (CFGetTypeID(value) != CFDictionaryGetTypeID()) {
159 /* if specified path is not a dictionary */
160 status = SCP_NOKEY;
161 goto done;
162 }
163
164 if (CFDictionaryContainsKey(value, kSCResvLink)) {
165 /* the path is a link... */
166 status = SCP_FAILED;
167 goto done;
168 }
169
170 i = 0;
171 while (TRUE) {
172 CFStringRef pathComponent;
173 Boolean found;
174
175 pathComponent = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), i);
176 found = CFDictionaryContainsKey(value, pathComponent);
177 CFRelease(pathComponent);
178
179 if (!found) {
180 /* if we've identified the next unique key */
181 path = CFStringCreateWithFormat(NULL,
182 NULL,
183 CFSTR("%@/%i"),
184 prefix,
185 i);
186 break;
187 }
188 i++;
189 }
190
191 /* save the new dictionary */
192 newDict = CFDictionaryCreateMutable(NULL,
193 0,
194 &kCFTypeDictionaryKeyCallBacks,
195 &kCFTypeDictionaryValueCallBacks);
196 status = SCPPathSetValue(session, path, newDict);
197 CFRelease(newDict);
198 if (status != SCP_OK) {
199 CFRelease(path);
200 goto done;
201 }
202
203 *newPath = path;
204
205 done :
206
207 if (newValue) CFRelease(value);
208 return status;
209 }
210
211
212 SCPStatus
213 SCPPathGetValue(SCPSessionRef session,
214 CFStringRef path,
215 CFDictionaryRef *value)
216 {
217 SCPStatus status;
218 CFMutableDictionaryRef entity;
219 CFStringRef entityLink;
220
221 if (session == NULL) {
222 return SCP_NOSESSION; /* you can't do anything with a closed session */
223 }
224
225 status = getPath(session, path, &entity);
226 if (status != SCP_OK) {
227 return status;
228 }
229
230 /* XXXX Add code here to chase multiple links XXXXX */
231
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 */
238 return status;
239 }
240 }
241
242 *value = entity;
243 return status;
244 }
245
246
247 SCPStatus
248 SCPPathGetLink(SCPSessionRef session,
249 CFStringRef path,
250 CFStringRef *link)
251 {
252 SCPStatus status;
253 CFMutableDictionaryRef entity;
254 CFStringRef entityLink;
255
256 if (session == NULL) {
257 return SCP_NOSESSION; /* you can't do anything with a closed session */
258 }
259
260 status = getPath(session, path, &entity);
261 if (status != SCP_OK) {
262 return status;
263 }
264
265 if ((CFGetTypeID(entity) == CFDictionaryGetTypeID()) &&
266 (CFDictionaryGetValueIfPresent(entity, kSCResvLink, (void **)&entityLink))) {
267 /* if this is a dictionary AND it is a link */
268 *link = entityLink;
269 return status;
270 }
271
272 return SCP_NOKEY;
273 }
274
275
276 SCPStatus
277 SCPPathSetValue(SCPSessionRef session, CFStringRef path, CFDictionaryRef value)
278 {
279 CFMutableDictionaryRef element;
280 CFArrayRef elements = NULL;
281 CFIndex i;
282 CFIndex nElements;
283 boolean_t newRoot = FALSE;
284 CFMutableDictionaryRef root = NULL;
285 SCPStatus status = SCP_NOKEY;
286
287 if (session == NULL) {
288 return SCP_NOSESSION; /* you can't do anything with a closed session */
289 }
290
291 elements = normalizePath(path);
292 if (elements == NULL) {
293 return SCP_NOKEY;
294 }
295
296 /* get preferences key */
297 status = SCPGet(session,
298 CFArrayGetValueAtIndex(elements, 0),
299 (CFPropertyListRef *)&root);
300 if (status != SCP_OK) {
301 root = CFDictionaryCreateMutable(NULL,
302 0,
303 &kCFTypeDictionaryKeyCallBacks,
304 &kCFTypeDictionaryValueCallBacks);
305 newRoot = TRUE;
306 }
307
308 nElements = CFArrayGetCount(elements);
309 if (nElements == 1) {
310 /* if we are only updating the data associated with the preference key */
311 if (newRoot) {
312 CFRelease(root);
313 newRoot = FALSE;
314 }
315 root = (CFMutableDictionaryRef)value;
316 }
317
318 element = root;
319 for (i=1; i<nElements-1; i++) {
320 CFStringRef pathComponent;
321 CFMutableDictionaryRef tmpElement;
322
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,
328 0,
329 &kCFTypeDictionaryKeyCallBacks,
330 &kCFTypeDictionaryValueCallBacks);
331 CFDictionarySetValue(element, pathComponent, tmpElement);
332 CFRelease(tmpElement);
333 }
334 element = tmpElement;
335 }
336
337 if (nElements > 1) {
338 CFDictionarySetValue(element,
339 CFArrayGetValueAtIndex(elements, nElements-1),
340 value);
341 }
342 status = SCPSet(session, CFArrayGetValueAtIndex(elements, 0), root);
343
344 if (newRoot) CFRelease(root);
345 CFRelease(elements);
346 return status;
347 }
348
349
350 SCPStatus
351 SCPPathSetLink(SCPSessionRef session, CFStringRef path, CFStringRef link)
352 {
353 CFMutableDictionaryRef dict;
354 SCPStatus status;
355
356 if (session == NULL) {
357 return SCP_NOSESSION; /* you can't do anything with a closed session */
358 }
359
360 dict = CFDictionaryCreateMutable(NULL,
361 0,
362 &kCFTypeDictionaryKeyCallBacks,
363 &kCFTypeDictionaryValueCallBacks);
364 CFDictionaryAddValue(dict, kSCResvLink, link);
365 status = SCPPathSetValue(session, path, dict);
366 CFRelease(dict);
367
368 return status;
369 }
370
371
372 SCPStatus
373 SCPPathRemove(SCPSessionRef session, CFStringRef path)
374 {
375 CFMutableDictionaryRef element;
376 CFArrayRef elements = NULL;
377 CFIndex i;
378 CFIndex nElements;
379 CFMutableDictionaryRef root = NULL;
380 SCPStatus status = SCP_NOKEY;
381
382 if (session == NULL) {
383 return SCP_NOSESSION; /* you can't do anything with a closed session */
384 }
385
386 elements = normalizePath(path);
387 if (elements == NULL) {
388 return SCP_NOKEY;
389 }
390
391 /* get preferences key */
392 status = SCPGet(session,
393 CFArrayGetValueAtIndex(elements, 0),
394 (CFPropertyListRef *)&root);
395 if (status != SCP_OK) {
396 goto done;
397 }
398
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));
403 goto done;
404 }
405
406 element = root;
407 for (i=1; i<nElements-1; i++) {
408 CFStringRef pathComponent;
409 CFMutableDictionaryRef tmpElement;
410
411 pathComponent = CFArrayGetValueAtIndex(elements, i);
412 tmpElement = (void *)CFDictionaryGetValue(element, pathComponent);
413 if (tmpElement == NULL) {
414 status = SCP_NOKEY;
415 goto done;
416 }
417 element = tmpElement;
418 }
419
420 CFDictionaryRemoveValue(element,
421 CFArrayGetValueAtIndex(elements, nElements-1));
422 status = SCPSet(session, CFArrayGetValueAtIndex(elements, 0), root);
423
424 done :
425
426 CFRelease(elements);
427 return status;
428 }