]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPPath.c
configd-130.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPPath.c
1 /*
2 * Copyright(c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * November 16, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCValidation.h>
36 #include <SystemConfiguration/SCPrivate.h>
37 #include "SCPreferencesInternal.h"
38
39 #define MAXLINKS 8
40
41 static CFArrayRef
42 normalizePath(CFStringRef path)
43 {
44 CFArrayRef tmpElements;
45 CFMutableArrayRef elements;
46 CFIndex nElements;
47 CFIndex i;
48
49 if (!CFStringHasPrefix(path, CFSTR("/"))) {
50 /* if no root separator */
51 return NULL;
52 }
53
54 tmpElements = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
55 elements = CFArrayCreateMutableCopy(NULL, 0, tmpElements);
56 CFRelease(tmpElements);
57
58 /* remove empty path components */
59 nElements = CFArrayGetCount(elements);
60 for (i = nElements; i > 0; i--) {
61 CFStringRef pathElement;
62
63 pathElement = CFArrayGetValueAtIndex(elements, i-1);
64 if (CFStringGetLength(pathElement) == 0) {
65 CFArrayRemoveValueAtIndex(elements, i-1);
66 nElements--;
67 }
68 }
69
70 if (nElements < 1) {
71 CFRelease(elements);
72 return NULL;
73 }
74
75 return elements;
76 }
77
78
79 static Boolean
80 getPath(SCPreferencesRef prefs, CFStringRef path, CFDictionaryRef *entity)
81 {
82 CFStringRef element;
83 CFArrayRef elements;
84 CFIndex i;
85 CFStringRef link;
86 CFIndex nElements;
87 CFIndex nLinks = 0;
88 Boolean ok = FALSE;
89 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
90 CFDictionaryRef value = NULL;
91
92 elements = normalizePath(path);
93 if (elements == NULL) {
94 _SCErrorSet(kSCStatusNoKey);
95 return FALSE;
96 }
97
98 __SCPreferencesAccess(prefs);
99
100 restart :
101
102 nElements = CFArrayGetCount(elements);
103 for (i = 0; i < nElements; i++) {
104 element = CFArrayGetValueAtIndex(elements, i);
105 if (i == 0) {
106 value = CFDictionaryGetValue(prefsPrivate->prefs,
107 CFArrayGetValueAtIndex(elements, 0));
108 } else {
109 value = CFDictionaryGetValue(value, element);
110 }
111 if (value == NULL) {
112 /* if path component does not exist */
113 _SCErrorSet(kSCStatusNoKey);
114 goto done;
115 }
116
117 if (!isA_CFDictionary(value)) {
118 /* if path component not a dictionary */
119 _SCErrorSet(kSCStatusNoKey);
120 goto done;
121 }
122
123 if ((i < nElements-1) &&
124 CFDictionaryGetValueIfPresent(value, kSCResvLink, (const void **)&link)) {
125 /*
126 * if not the last path component and this
127 * element is a link
128 */
129 CFArrayRef linkElements;
130 CFMutableArrayRef newElements;
131
132 if (++nLinks > MAXLINKS) {
133 /* if we are chasing our tail */
134 _SCErrorSet(kSCStatusMaxLink);
135 goto done;
136 }
137
138 linkElements = normalizePath(link);
139 if (linkElements == NULL) {
140 /* if the link is bad */
141 _SCErrorSet(kSCStatusNoKey);
142 goto done;
143 }
144
145 newElements = CFArrayCreateMutableCopy(NULL, 0, linkElements);
146 CFArrayAppendArray(newElements,
147 elements,
148 CFRangeMake(i+1, nElements-i-1));
149 CFRelease(elements);
150 elements = newElements;
151
152 goto restart;
153 }
154 }
155
156 *entity = value;
157 ok = TRUE;
158
159 done :
160
161 CFRelease(elements);
162 return ok;
163 }
164
165
166 static Boolean
167 setPath(SCPreferencesRef prefs, CFStringRef path, CFDictionaryRef entity)
168 {
169 CFStringRef element;
170 CFArrayRef elements;
171 CFIndex i;
172 CFStringRef link;
173 CFIndex nElements;
174 CFIndex nLinks = 0;
175 CFDictionaryRef newEntity = NULL;
176 CFDictionaryRef node = NULL;
177 CFMutableArrayRef nodes;
178 Boolean ok = FALSE;
179 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
180
181 elements = normalizePath(path);
182 if (elements == NULL) {
183 _SCErrorSet(kSCStatusNoKey);
184 return FALSE;
185 }
186
187 __SCPreferencesAccess(prefs);
188
189 restart :
190
191 nElements = CFArrayGetCount(elements);
192 nodes = CFArrayCreateMutable(NULL, nElements-1, &kCFTypeArrayCallBacks);
193 for (i = 0; i < nElements - 1; i++) {
194 element = CFArrayGetValueAtIndex(elements, i);
195 if (i == 0) {
196 node = CFDictionaryGetValue(prefsPrivate->prefs, element);
197 } else {
198 node = CFDictionaryGetValue(node, element);
199
200 }
201
202 if (node) {
203 /* if path component exists */
204 CFArrayAppendValue(nodes, node);
205 } else {
206 /* if path component does not exist */
207 node = CFDictionaryCreate(NULL,
208 NULL,
209 NULL,
210 0,
211 &kCFTypeDictionaryKeyCallBacks,
212 &kCFTypeDictionaryValueCallBacks);
213 CFArrayAppendValue(nodes, node);
214 CFRelease(node);
215 }
216
217 if (!isA_CFDictionary(node)) {
218 _SCErrorSet(kSCStatusNoKey);
219 goto done;
220 }
221
222 if ((i < nElements-1) &&
223 CFDictionaryGetValueIfPresent(node, kSCResvLink, (const void **)&link)) {
224 /*
225 * if not the last path component and this
226 * element is a link
227 */
228 CFArrayRef linkElements;
229 CFMutableArrayRef newElements;
230
231 if (++nLinks > MAXLINKS) {
232 /* if we are chasing our tail */
233 _SCErrorSet(kSCStatusMaxLink);
234 goto done;
235 }
236
237 linkElements = normalizePath(link);
238 if (linkElements == NULL) {
239 /* if the link is bad */
240 _SCErrorSet(kSCStatusNoKey);
241 goto done;
242 }
243
244 newElements = CFArrayCreateMutableCopy(NULL, 0, linkElements);
245 CFArrayAppendArray(newElements,
246 elements,
247 CFRangeMake(i+1, nElements-i-1));
248 CFRelease(elements);
249 elements = newElements;
250
251 CFRelease(nodes);
252 goto restart;
253 }
254 }
255
256 if (entity) {
257 newEntity = CFRetain(entity);
258 }
259 for (i = nElements - 1; i >= 0; i--) {
260 element = CFArrayGetValueAtIndex(elements, i);
261 if (i == 0) {
262 if (newEntity) {
263 CFDictionarySetValue(prefsPrivate->prefs, element, newEntity);
264 } else {
265 CFDictionaryRemoveValue(prefsPrivate->prefs, element);
266 }
267 prefsPrivate->changed = TRUE;
268 ok = TRUE;
269 } else {
270 CFMutableDictionaryRef newNode;
271
272 node = CFArrayGetValueAtIndex(nodes, i-1);
273 newNode = CFDictionaryCreateMutableCopy(NULL, 0, node);
274 if (newEntity) {
275 CFDictionarySetValue(newNode, element, newEntity);
276 CFRelease(newEntity);
277 } else {
278 CFDictionaryRemoveValue(newNode, element);
279 }
280 newEntity = newNode;
281 }
282 }
283 if (newEntity) {
284 CFRelease(newEntity);
285 }
286
287 done :
288
289 CFRelease(nodes);
290 CFRelease(elements);
291 return ok;
292 }
293
294
295 CFStringRef
296 SCPreferencesPathCreateUniqueChild(SCPreferencesRef prefs,
297 CFStringRef prefix)
298 {
299 CFStringRef child;
300 CFStringRef newPath = NULL;
301 CFMutableDictionaryRef newDict = NULL;
302 CFUUIDRef uuid;
303 CFDictionaryRef entity;
304
305 if (prefs == NULL) {
306 /* sorry, you must provide a session */
307 _SCErrorSet(kSCStatusNoPrefsSession);
308 return NULL;
309 }
310
311 if (getPath(prefs, prefix, &entity)) {
312 // if prefix path exists
313 if (CFDictionaryContainsKey(entity, kSCResvLink)) {
314 /* the path is a link... */
315 _SCErrorSet(kSCStatusFailed);
316 return NULL;
317 }
318 } else if (SCError() != kSCStatusNoKey) {
319 // if any error except for a missing prefix path component
320 return NULL;
321 }
322
323 uuid = CFUUIDCreate(NULL);
324 child = CFUUIDCreateString(NULL, uuid);
325 newPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), prefix, child);
326 CFRelease(child);
327 CFRelease(uuid);
328
329 /* save the new dictionary */
330 newDict = CFDictionaryCreateMutable(NULL,
331 0,
332 &kCFTypeDictionaryKeyCallBacks,
333 &kCFTypeDictionaryValueCallBacks);
334 if (!setPath(prefs, newPath, newDict)) {
335 CFRelease(newPath);
336 newPath = NULL;
337 }
338 CFRelease(newDict);
339
340 return newPath;
341 }
342
343
344 CFDictionaryRef
345 SCPreferencesPathGetValue(SCPreferencesRef prefs,
346 CFStringRef path)
347 {
348 CFDictionaryRef entity;
349 CFStringRef entityLink;
350
351 if (prefs == NULL) {
352 /* sorry, you must provide a session */
353 _SCErrorSet(kSCStatusNoPrefsSession);
354 return NULL;
355 }
356
357 if (!getPath(prefs, path, &entity)) {
358 return NULL;
359 }
360
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(prefs, entityLink, &entity)) {
365 /* if it was a bad link */
366 return NULL;
367 }
368 }
369
370 return entity;
371 }
372
373
374 CFStringRef
375 SCPreferencesPathGetLink(SCPreferencesRef prefs,
376 CFStringRef path)
377 {
378 CFDictionaryRef entity;
379 CFStringRef entityLink;
380
381 if (prefs == NULL) {
382 /* sorry, you must provide a session */
383 _SCErrorSet(kSCStatusNoPrefsSession);
384 return NULL;
385 }
386
387 if (!getPath(prefs, path, &entity)) {
388 return NULL;
389 }
390
391 if (isA_CFDictionary(entity) &&
392 (CFDictionaryGetValueIfPresent(entity, kSCResvLink, (const void **)&entityLink))) {
393 /* if this is a dictionary AND it is a link */
394 return entityLink;
395 }
396
397 return NULL;
398 }
399
400
401 Boolean
402 SCPreferencesPathSetValue(SCPreferencesRef prefs,
403 CFStringRef path,
404 CFDictionaryRef value)
405 {
406 Boolean ok;
407
408 if (prefs == NULL) {
409 /* sorry, you must provide a session */
410 _SCErrorSet(kSCStatusNoPrefsSession);
411 return FALSE;
412 }
413
414 if (!value) {
415 _SCErrorSet(kSCStatusInvalidArgument);
416 return FALSE;
417 }
418
419 ok = setPath(prefs, path, value);
420 return ok;
421 }
422
423
424 Boolean
425 SCPreferencesPathSetLink(SCPreferencesRef prefs,
426 CFStringRef path,
427 CFStringRef link)
428 {
429 CFMutableDictionaryRef dict;
430 CFDictionaryRef entity;
431 Boolean ok;
432
433 if (prefs == NULL) {
434 /* sorry, you must provide a session */
435 _SCErrorSet(kSCStatusNoPrefsSession);
436 return FALSE;
437 }
438
439 if (!link) {
440 _SCErrorSet(kSCStatusInvalidArgument);
441 return FALSE;
442 }
443
444 if (!getPath(prefs, link, &entity)) {
445 // if bad link
446 return FALSE;
447 }
448
449 dict = CFDictionaryCreateMutable(NULL,
450 0,
451 &kCFTypeDictionaryKeyCallBacks,
452 &kCFTypeDictionaryValueCallBacks);
453 CFDictionaryAddValue(dict, kSCResvLink, link);
454 ok = setPath(prefs, path, dict);
455 CFRelease(dict);
456
457 return ok;
458 }
459
460
461 Boolean
462 SCPreferencesPathRemoveValue(SCPreferencesRef prefs,
463 CFStringRef path)
464 {
465 CFArrayRef elements = NULL;
466 Boolean ok = FALSE;
467 CFDictionaryRef value;
468
469 if (prefs == NULL) {
470 /* sorry, you must provide a session */
471 _SCErrorSet(kSCStatusNoPrefsSession);
472 return FALSE;
473 }
474
475 if (!getPath(prefs, path, &value)) {
476 // if no such path
477 return FALSE;
478 }
479
480 elements = normalizePath(path);
481 if (elements == NULL) {
482 _SCErrorSet(kSCStatusNoKey);
483 return FALSE;
484 }
485
486 ok = setPath(prefs, path, NULL);
487
488 CFRelease(elements);
489 return ok;
490 }