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