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); 
  75 getPath(SCPreferencesRef prefs
, CFStringRef path
, CFDictionaryRef 
*entity
) 
  84         CFDictionaryRef         value           
= NULL
; 
  86         elements 
= normalizePath(path
); 
  87         if (elements 
== NULL
) { 
  88                 _SCErrorSet(kSCStatusNoKey
); 
  94         nElements 
= CFArrayGetCount(elements
); 
  97                 SCPreferencesPrivateRef prefsPrivate    
= (SCPreferencesPrivateRef
)prefs
; 
  99                 __SCPreferencesAccess(prefs
); 
 100                 value 
= prefsPrivate
->prefs
; 
 103         for (i 
= 0; i 
< nElements
; i
++) { 
 104                 element 
= CFArrayGetValueAtIndex(elements
, i
); 
 106                         value 
= SCPreferencesGetValue(prefs
, CFArrayGetValueAtIndex(elements
, 0)); 
 108                         value 
= CFDictionaryGetValue(value
, element
); 
 111                         /* if path component does not exist */ 
 112                         _SCErrorSet(kSCStatusNoKey
); 
 116                 if (!isA_CFDictionary(value
)) { 
 117                         /* if path component not a dictionary */ 
 118                         _SCErrorSet(kSCStatusNoKey
); 
 122                 if ((i 
< nElements 
- 1) && 
 123                     CFDictionaryGetValueIfPresent(value
, kSCResvLink
, (const void **)&link
)) { 
 125                          * if not the last path component and this 
 128                         CFArrayRef              linkElements
; 
 129                         CFMutableArrayRef       newElements
; 
 131                         if (++nLinks 
> MAXLINKS
) { 
 132                                 /* if we are chasing our tail */ 
 133                                 _SCErrorSet(kSCStatusMaxLink
); 
 137                         linkElements 
= normalizePath(link
); 
 138                         if (linkElements 
== NULL
) { 
 139                                 /* if the link is bad */ 
 140                                 _SCErrorSet(kSCStatusNoKey
); 
 144                         newElements 
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
); 
 145                         CFArrayAppendArray(newElements
, 
 147                                            CFRangeMake(i 
+ 1, nElements
-i 
- 1)); 
 149                         elements 
= newElements
; 
 166 setPath(SCPreferencesRef prefs
, CFStringRef path
, CFDictionaryRef entity
) 
 174         CFDictionaryRef         newEntity       
= NULL
; 
 175         CFDictionaryRef         node            
= NULL
; 
 176         CFMutableArrayRef       nodes           
= NULL
; 
 179         if ((entity 
!= NULL
) && !isA_CFDictionary(entity
)) { 
 180                 _SCErrorSet(kSCStatusInvalidArgument
); 
 184         elements 
= normalizePath(path
); 
 185         if (elements 
== NULL
) { 
 186                 _SCErrorSet(kSCStatusNoKey
); 
 192         nElements 
= CFArrayGetCount(elements
); 
 195                 SCPreferencesPrivateRef prefsPrivate    
= (SCPreferencesPrivateRef
)prefs
; 
 197                 __SCPreferencesAccess(prefs
); 
 199                 if (prefsPrivate
->prefs 
!= NULL
) { 
 200                         CFRelease(prefsPrivate
->prefs
); 
 203                 if (entity 
== NULL
) { 
 204                         prefsPrivate
->prefs 
= CFDictionaryCreateMutable(NULL
, 
 206                                                                         &kCFTypeDictionaryKeyCallBacks
, 
 207                                                                         &kCFTypeDictionaryValueCallBacks
); 
 209                         prefsPrivate
->prefs 
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
); 
 212                 prefsPrivate
->changed 
= TRUE
; 
 217         nodes 
= CFArrayCreateMutable(NULL
, nElements 
- 1, &kCFTypeArrayCallBacks
); 
 218         for (i 
= 0; i 
< nElements 
- 1; i
++) { 
 219                 element 
= CFArrayGetValueAtIndex(elements
, i
); 
 221                         node 
= SCPreferencesGetValue(prefs
, element
); 
 223                         node 
= CFDictionaryGetValue(node
, element
); 
 228                         /* if path component exists */ 
 229                         CFArrayAppendValue(nodes
, node
); 
 231                         /* if path component does not exist */ 
 232                         node 
= CFDictionaryCreate(NULL
, 
 236                                                   &kCFTypeDictionaryKeyCallBacks
, 
 237                                                   &kCFTypeDictionaryValueCallBacks
); 
 238                         CFArrayAppendValue(nodes
, node
); 
 242                 if (!isA_CFDictionary(node
)) { 
 243                         _SCErrorSet(kSCStatusNoKey
); 
 247                 if ((i 
< nElements 
- 1) && 
 248                     CFDictionaryGetValueIfPresent(node
, kSCResvLink
, (const void **)&link
)) { 
 250                          * if not the last path component and this 
 253                         CFArrayRef              linkElements
; 
 254                         CFMutableArrayRef       newElements
; 
 256                         if (++nLinks 
> MAXLINKS
) { 
 257                                 /* if we are chasing our tail */ 
 258                                 _SCErrorSet(kSCStatusMaxLink
); 
 262                         linkElements 
= normalizePath(link
); 
 263                         if (linkElements 
== NULL
) { 
 264                                 /* if the link is bad */ 
 265                                 _SCErrorSet(kSCStatusNoKey
); 
 269                         newElements 
= CFArrayCreateMutableCopy(NULL
, 0, linkElements
); 
 270                         CFArrayAppendArray(newElements
, 
 272                                            CFRangeMake(i 
+ 1, nElements
-i 
- 1)); 
 274                         elements 
= newElements
; 
 282          * make sure that the last component doesn't step on top 
 283          * of a non-dictionary component. 
 285         element 
= CFArrayGetValueAtIndex(elements
, nElements 
- 1); 
 287                 node 
= CFArrayGetValueAtIndex(nodes
, nElements 
- 2); 
 288                 node 
= CFDictionaryGetValue(node
, element
); 
 290                 node 
= SCPreferencesGetValue(prefs
, element
); 
 292         if ((node 
!= NULL
) && !isA_CFDictionary(node
)) { 
 293                 // we won't step on a non-dictionary component 
 294                 _SCErrorSet(kSCStatusInvalidArgument
); 
 298         if (entity 
!= NULL
) { 
 299                 newEntity 
= CFRetain(entity
); 
 301         for (i 
= nElements 
- 1; i 
>= 0; i
--) { 
 302                 element 
= CFArrayGetValueAtIndex(elements
, i
); 
 304                         if (newEntity 
!= NULL
) { 
 305                                 ok 
= SCPreferencesSetValue(prefs
, element
, newEntity
); 
 307                                 ok 
= SCPreferencesRemoveValue(prefs
, element
); 
 310                         CFMutableDictionaryRef  newNode
; 
 312                         node    
= CFArrayGetValueAtIndex(nodes
, i 
- 1); 
 313                         newNode 
= CFDictionaryCreateMutableCopy(NULL
, 0, node
); 
 314                         if (newEntity 
!= NULL
) { 
 315                                 CFDictionarySetValue(newNode
, element
, newEntity
); 
 316                                 CFRelease(newEntity
); 
 318                                 CFDictionaryRemoveValue(newNode
, element
); 
 319                                 if (CFDictionaryGetCount(newNode
) == 0) { 
 320                                         // prune the (now empty) parent 
 328         if (newEntity 
!= NULL
) { 
 329                 CFRelease(newEntity
); 
 334         if (nodes 
!= NULL
)      CFRelease(nodes
); 
 341 SCPreferencesPathCreateUniqueChild(SCPreferencesRef     prefs
, 
 345         CFStringRef             newPath         
= NULL
; 
 346         CFMutableDictionaryRef  newDict         
= NULL
; 
 348         CFDictionaryRef         entity
; 
 351                 /* sorry, you must provide a session */ 
 352                 _SCErrorSet(kSCStatusNoPrefsSession
); 
 356         if (getPath(prefs
, prefix
, &entity
)) { 
 357                 // if prefix path exists 
 358                 if (CFDictionaryContainsKey(entity
, kSCResvLink
)) { 
 359                         /* the path is a link... */ 
 360                         _SCErrorSet(kSCStatusFailed
); 
 363         } else if (SCError() != kSCStatusNoKey
) { 
 364                 // if any error except for a missing prefix path component 
 368         uuid    
= CFUUIDCreate(NULL
); 
 369         child   
= CFUUIDCreateString(NULL
, uuid
); 
 370         newPath 
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, child
); 
 374         /* save the new dictionary */ 
 375         newDict 
= CFDictionaryCreateMutable(NULL
, 
 377                                             &kCFTypeDictionaryKeyCallBacks
, 
 378                                             &kCFTypeDictionaryValueCallBacks
); 
 379         if (!setPath(prefs
, newPath
, newDict
)) { 
 390 SCPreferencesPathGetValue(SCPreferencesRef      prefs
, 
 393         CFDictionaryRef entity
; 
 394         CFStringRef     entityLink
; 
 397                 /* sorry, you must provide a session */ 
 398                 _SCErrorSet(kSCStatusNoPrefsSession
); 
 402         if (!getPath(prefs
, path
, &entity
)) { 
 406         if (isA_CFDictionary(entity
) && 
 407             (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) { 
 408                 /* if this is a dictionary AND it is a link */ 
 409                 if (!getPath(prefs
, entityLink
, &entity
)) { 
 410                         /* if it was a bad link */ 
 420 SCPreferencesPathGetLink(SCPreferencesRef       prefs
, 
 423         CFDictionaryRef entity
; 
 424         CFStringRef     entityLink
; 
 427                 /* sorry, you must provide a session */ 
 428                 _SCErrorSet(kSCStatusNoPrefsSession
); 
 432         if (!getPath(prefs
, path
, &entity
)) { 
 436         if (isA_CFDictionary(entity
) && 
 437             (CFDictionaryGetValueIfPresent(entity
, kSCResvLink
, (const void **)&entityLink
))) { 
 438                 /* if this is a dictionary AND it is a link */ 
 447 SCPreferencesPathSetValue(SCPreferencesRef      prefs
, 
 449                           CFDictionaryRef       value
) 
 454                 /* sorry, you must provide a session */ 
 455                 _SCErrorSet(kSCStatusNoPrefsSession
); 
 459 #define NETPREF_NEEDS_REPAIR 
 460 #ifdef  NETPREF_NEEDS_REPAIR 
 461         if (CFEqual(path
, CFSTR("/CurrentSet")) && isA_CFString(value
)) { 
 462 //              static Boolean  warned  = FALSE; 
 464 //                      SCPrint(TRUE, stderr, CFSTR("SCPreferencesPathSetValue(, %@, ) called with non-dictionary value\n"), path); 
 467                 return SCPreferencesSetValue(prefs
, CFSTR("CurrentSet"), value
); 
 469 #endif  // NETPREF_NEEDS_REPAIR 
 471         if (!isA_CFDictionary(value
)) { 
 472 #ifdef  NETPREF_NEEDS_REPAIR 
 473 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesPathSetValue(, %@, ) called with non-dictionary value\n"), path
); 
 474 #endif  // NETPREF_NEEDS_REPAIR 
 475                 _SCErrorSet(kSCStatusInvalidArgument
); 
 479         ok 
= setPath(prefs
, path
, value
); 
 485 SCPreferencesPathSetLink(SCPreferencesRef       prefs
, 
 489         CFMutableDictionaryRef  dict
; 
 490         CFDictionaryRef         entity
; 
 494                 /* sorry, you must provide a session */ 
 495                 _SCErrorSet(kSCStatusNoPrefsSession
); 
 499         if (!isA_CFString(link
)) { 
 500                 _SCErrorSet(kSCStatusInvalidArgument
); 
 504         if (!getPath(prefs
, link
, &entity
)) { 
 509         dict 
= CFDictionaryCreateMutable(NULL
, 
 511                                          &kCFTypeDictionaryKeyCallBacks
, 
 512                                          &kCFTypeDictionaryValueCallBacks
); 
 513         CFDictionaryAddValue(dict
, kSCResvLink
, link
); 
 514         ok 
= setPath(prefs
, path
, dict
); 
 522 SCPreferencesPathRemoveValue(SCPreferencesRef   prefs
, 
 525         CFArrayRef              elements        
= NULL
; 
 527         CFDictionaryRef         value
; 
 530                 /* sorry, you must provide a session */ 
 531                 _SCErrorSet(kSCStatusNoPrefsSession
); 
 535         if (!getPath(prefs
, path
, &value
)) { 
 540         elements 
= normalizePath(path
); 
 541         if (elements 
== NULL
) { 
 542                 _SCErrorSet(kSCStatusNoKey
); 
 546         ok 
= setPath(prefs
, path
, NULL
);