this repo has no description
at fixPythonPipStalling 552 lines 13 kB view raw
1/* 2 * Copyright (c) 2000-2006, 2008, 2011, 2012, 2016 Apple 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 "SCPreferencesInternal.h" 35 36#define MAXLINKS 8 37 38static CF_RETURNS_RETAINED CFMutableArrayRef 39normalizePath(CFStringRef path) 40{ 41 CFMutableArrayRef elements; 42 CFIndex n; 43 CFArrayRef tmpElements; 44 45 if (!isA_CFString(path)) { 46 _SCErrorSet(kSCStatusInvalidArgument); 47 return NULL; 48 } 49 50 if (!CFStringHasPrefix(path, CFSTR("/"))) { 51 /* if no root separator */ 52 return NULL; 53 } 54 55 tmpElements = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); 56 elements = CFArrayCreateMutableCopy(NULL, 0, tmpElements); 57 CFRelease(tmpElements); 58 59 /* remove empty path components */ 60 n = CFArrayGetCount(elements); 61 while (n-- > 0) { 62 CFStringRef pathElement; 63 64 pathElement = CFArrayGetValueAtIndex(elements, n); 65 if (CFStringGetLength(pathElement) == 0) { 66 CFArrayRemoveValueAtIndex(elements, n); 67 } 68 } 69 70 return elements; 71} 72 73 74static Boolean 75getPath(SCPreferencesRef prefs, CFStringRef path, CFDictionaryRef *entity) 76{ 77 CFStringRef element; 78 CFMutableArrayRef elements; 79 CFIndex i; 80 CFStringRef link; 81 CFIndex nElements; 82 CFIndex nLinks = 0; 83 Boolean ok = FALSE; 84 CFDictionaryRef value = NULL; 85 86 elements = normalizePath(path); 87 if (elements == NULL) { 88 _SCErrorSet(kSCStatusNoKey); 89 return FALSE; 90 } 91 92 restart : 93 94 nElements = CFArrayGetCount(elements); 95 96 if (nElements < 1) { 97 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 98 99 __SCPreferencesAccess(prefs); 100 101 *entity = prefsPrivate->prefs; 102 ok = TRUE; 103 goto done; 104 } 105 106 for (i = 0; i < nElements; i++) { 107 element = CFArrayGetValueAtIndex(elements, i); 108 if (i == 0) { 109 value = SCPreferencesGetValue(prefs, CFArrayGetValueAtIndex(elements, 0)); 110 } else { 111 value = CFDictionaryGetValue(value, element); 112 } 113 if (value == NULL) { 114 /* if path component does not exist */ 115 _SCErrorSet(kSCStatusNoKey); 116 goto done; 117 } 118 119 if (!isA_CFDictionary(value)) { 120 /* if path component not a dictionary */ 121 _SCErrorSet(kSCStatusNoKey); 122 goto done; 123 } 124 125 if ((i < nElements - 1) && 126 CFDictionaryGetValueIfPresent(value, kSCResvLink, (const void **)&link)) { 127 /* 128 * if not the last path component and this 129 * element is a link 130 */ 131 CFMutableArrayRef linkElements; 132 133 if (++nLinks > MAXLINKS) { 134 /* if we are chasing our tail */ 135 _SCErrorSet(kSCStatusMaxLink); 136 goto done; 137 } 138 139 linkElements = normalizePath(link); 140 if (linkElements == NULL) { 141 /* if the link is bad */ 142 _SCErrorSet(kSCStatusNoKey); 143 goto done; 144 } 145 146 CFArrayAppendArray(linkElements, 147 elements, 148 CFRangeMake(i + 1, nElements-i - 1)); 149 CFRelease(elements); 150 elements = linkElements; 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 166static Boolean 167setPath(SCPreferencesRef prefs, CFStringRef path, CFDictionaryRef entity) 168{ 169 CFStringRef element; 170 CFMutableArrayRef 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 = NULL; 178 Boolean ok = FALSE; 179 180 if ((entity != NULL) && !isA_CFDictionary(entity)) { 181 _SCErrorSet(kSCStatusInvalidArgument); 182 return FALSE; 183 } 184 185 elements = normalizePath(path); 186 if (elements == NULL) { 187 _SCErrorSet(kSCStatusNoKey); 188 return FALSE; 189 } 190 191 restart : 192 193 nElements = CFArrayGetCount(elements); 194 195 if (nElements < 1) { 196 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 197 198 __SCPreferencesAccess(prefs); 199 200 if (prefsPrivate->prefs != NULL) { 201 CFRelease(prefsPrivate->prefs); 202 } 203 204 if (entity == NULL) { 205 prefsPrivate->prefs = CFDictionaryCreateMutable(NULL, 206 0, 207 &kCFTypeDictionaryKeyCallBacks, 208 &kCFTypeDictionaryValueCallBacks); 209 } else { 210 prefsPrivate->prefs = CFDictionaryCreateMutableCopy(NULL, 0, entity); 211 } 212 213 prefsPrivate->changed = TRUE; 214 ok = TRUE; 215 goto done; 216 } 217 218 nodes = CFArrayCreateMutable(NULL, nElements - 1, &kCFTypeArrayCallBacks); 219 for (i = 0; i < nElements - 1; i++) { 220 element = CFArrayGetValueAtIndex(elements, i); 221 if (i == 0) { 222 node = SCPreferencesGetValue(prefs, element); 223 } else { 224 node = CFDictionaryGetValue(node, element); 225 226 } 227 228 if (node) { 229 /* if path component exists */ 230 CFArrayAppendValue(nodes, node); 231 } else { 232 /* if path component does not exist */ 233 node = CFDictionaryCreate(NULL, 234 NULL, 235 NULL, 236 0, 237 &kCFTypeDictionaryKeyCallBacks, 238 &kCFTypeDictionaryValueCallBacks); 239 CFArrayAppendValue(nodes, node); 240 CFRelease(node); 241 } 242 243 if (!isA_CFDictionary(node)) { 244 _SCErrorSet(kSCStatusNoKey); 245 goto done; 246 } 247 248 if ((i < nElements - 1) && 249 CFDictionaryGetValueIfPresent(node, kSCResvLink, (const void **)&link)) { 250 /* 251 * if not the last path component and this 252 * element is a link 253 */ 254 CFMutableArrayRef linkElements; 255 256 if (++nLinks > MAXLINKS) { 257 /* if we are chasing our tail */ 258 _SCErrorSet(kSCStatusMaxLink); 259 goto done; 260 } 261 262 linkElements = normalizePath(link); 263 if (linkElements == NULL) { 264 /* if the link is bad */ 265 _SCErrorSet(kSCStatusNoKey); 266 goto done; 267 } 268 269 CFArrayAppendArray(linkElements, 270 elements, 271 CFRangeMake(i + 1, nElements-i - 1)); 272 CFRelease(elements); 273 elements = linkElements; 274 275 CFRelease(nodes); 276 nodes = NULL; 277 goto restart; 278 } 279 } 280 281 /* 282 * make sure that the last component doesn't step on top 283 * of a non-dictionary component. 284 */ 285 element = CFArrayGetValueAtIndex(elements, nElements - 1); 286 if (nElements > 1) { 287 node = CFArrayGetValueAtIndex(nodes, nElements - 2); 288 node = CFDictionaryGetValue(node, element); 289 } else { 290 node = SCPreferencesGetValue(prefs, element); 291 } 292 if ((node != NULL) && !isA_CFDictionary(node)) { 293 // we won't step on a non-dictionary component 294 _SCErrorSet(kSCStatusInvalidArgument); 295 goto done; 296 } 297 298 if (entity != NULL) { 299 newEntity = CFRetain(entity); 300 } 301 for (i = nElements - 1; i >= 0; i--) { 302 element = CFArrayGetValueAtIndex(elements, i); 303 if (i == 0) { 304 if (newEntity != NULL) { 305 ok = SCPreferencesSetValue(prefs, element, newEntity); 306 } else { 307 ok = SCPreferencesRemoveValue(prefs, element); 308 } 309 } else { 310 CFMutableDictionaryRef newNode; 311 312 node = CFArrayGetValueAtIndex(nodes, i - 1); 313 newNode = CFDictionaryCreateMutableCopy(NULL, 0, node); 314 if (newEntity != NULL) { 315 CFDictionarySetValue(newNode, element, newEntity); 316 CFRelease(newEntity); 317 } else { 318 CFDictionaryRemoveValue(newNode, element); 319 if (CFDictionaryGetCount(newNode) == 0) { 320 // prune the (now empty) parent 321 CFRelease(newNode); 322 newNode = NULL; 323 } 324 } 325 newEntity = newNode; 326 } 327 } 328 if (newEntity != NULL) { 329 CFRelease(newEntity); 330 } 331 332 done : 333 334 if (nodes != NULL) CFRelease(nodes); 335 CFRelease(elements); 336 return ok; 337} 338 339 340CFStringRef 341SCPreferencesPathCreateUniqueChild(SCPreferencesRef prefs, 342 CFStringRef prefix) 343{ 344 CFStringRef child; 345 CFStringRef newPath = NULL; 346 CFDictionaryRef newDict; 347 CFUUIDRef uuid; 348 CFDictionaryRef entity; 349 350 if (prefs == NULL) { 351 /* sorry, you must provide a session */ 352 _SCErrorSet(kSCStatusNoPrefsSession); 353 return NULL; 354 } 355 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); 361 return NULL; 362 } 363 } else if (SCError() != kSCStatusNoKey) { 364 // if any error except for a missing prefix path component 365 return NULL; 366 } 367 368 uuid = CFUUIDCreate(NULL); 369 child = CFUUIDCreateString(NULL, uuid); 370 newPath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), prefix, child); 371 CFRelease(child); 372 CFRelease(uuid); 373 374 /* save a new/empty dictionary */ 375 newDict = CFDictionaryCreate(NULL, 376 NULL, NULL, 0, 377 &kCFTypeDictionaryKeyCallBacks, 378 &kCFTypeDictionaryValueCallBacks); 379 assert(newDict != NULL); 380 381 if (!setPath(prefs, newPath, newDict)) { 382 CFRelease(newPath); 383 newPath = NULL; 384 } 385 CFRelease(newDict); 386 387 return newPath; 388} 389 390 391CFDictionaryRef 392SCPreferencesPathGetValue(SCPreferencesRef prefs, 393 CFStringRef path) 394{ 395 CFDictionaryRef entity; 396 CFStringRef entityLink; 397 398 if (prefs == NULL) { 399 /* sorry, you must provide a session */ 400 _SCErrorSet(kSCStatusNoPrefsSession); 401 return NULL; 402 } 403 404 if (!getPath(prefs, path, &entity)) { 405 return NULL; 406 } 407 408 if (isA_CFDictionary(entity) && 409 (CFDictionaryGetValueIfPresent(entity, kSCResvLink, (const void **)&entityLink))) { 410 /* if this is a dictionary AND it is a link */ 411 if (!getPath(prefs, entityLink, &entity)) { 412 /* if it was a bad link */ 413 return NULL; 414 } 415 } 416 417 return entity; 418} 419 420 421CFStringRef 422SCPreferencesPathGetLink(SCPreferencesRef prefs, 423 CFStringRef path) 424{ 425 CFDictionaryRef entity; 426 CFStringRef entityLink; 427 428 if (prefs == NULL) { 429 /* sorry, you must provide a session */ 430 _SCErrorSet(kSCStatusNoPrefsSession); 431 return NULL; 432 } 433 434 if (!getPath(prefs, path, &entity)) { 435 return NULL; 436 } 437 438 if (isA_CFDictionary(entity) && 439 (CFDictionaryGetValueIfPresent(entity, kSCResvLink, (const void **)&entityLink))) { 440 /* if this is a dictionary AND it is a link */ 441 return entityLink; 442 } 443 444 return NULL; 445} 446 447 448Boolean 449SCPreferencesPathSetValue(SCPreferencesRef prefs, 450 CFStringRef path, 451 CFDictionaryRef value) 452{ 453 Boolean ok; 454 455 if (prefs == NULL) { 456 /* sorry, you must provide a session */ 457 _SCErrorSet(kSCStatusNoPrefsSession); 458 return FALSE; 459 } 460 461#define NETPREF_NEEDS_REPAIR 462#ifdef NETPREF_NEEDS_REPAIR 463 if (CFEqual(path, CFSTR("/CurrentSet")) && isA_CFString(value)) { 464 static Boolean warned = FALSE; 465 if (!warned) { 466 SCPrint(TRUE, stderr, CFSTR("SCPreferencesPathSetValue(, %@, ) called with non-dictionary value\n"), path); 467 warned = TRUE; 468 } 469 return SCPreferencesSetValue(prefs, CFSTR("CurrentSet"), value); 470 } 471#endif // NETPREF_NEEDS_REPAIR 472 473 if (!isA_CFDictionary(value)) { 474#ifdef NETPREF_NEEDS_REPAIR 475SCPrint(TRUE, stderr, CFSTR("SCPreferencesPathSetValue(, %@, ) called with non-dictionary value\n"), path); 476#endif // NETPREF_NEEDS_REPAIR 477 _SCErrorSet(kSCStatusInvalidArgument); 478 return FALSE; 479 } 480 481 ok = setPath(prefs, path, value); 482 return ok; 483} 484 485 486Boolean 487SCPreferencesPathSetLink(SCPreferencesRef prefs, 488 CFStringRef path, 489 CFStringRef link) 490{ 491 CFMutableDictionaryRef dict; 492 CFDictionaryRef entity; 493 Boolean ok; 494 495 if (prefs == NULL) { 496 /* sorry, you must provide a session */ 497 _SCErrorSet(kSCStatusNoPrefsSession); 498 return FALSE; 499 } 500 501 if (!isA_CFString(link)) { 502 _SCErrorSet(kSCStatusInvalidArgument); 503 return FALSE; 504 } 505 506 if (!getPath(prefs, link, &entity)) { 507 // if bad link 508 return FALSE; 509 } 510 511 dict = CFDictionaryCreateMutable(NULL, 512 0, 513 &kCFTypeDictionaryKeyCallBacks, 514 &kCFTypeDictionaryValueCallBacks); 515 CFDictionarySetValue(dict, kSCResvLink, link); 516 ok = setPath(prefs, path, dict); 517 CFRelease(dict); 518 519 return ok; 520} 521 522 523Boolean 524SCPreferencesPathRemoveValue(SCPreferencesRef prefs, 525 CFStringRef path) 526{ 527 CFMutableArrayRef elements = NULL; 528 Boolean ok = FALSE; 529 CFDictionaryRef value; 530 531 if (prefs == NULL) { 532 /* sorry, you must provide a session */ 533 _SCErrorSet(kSCStatusNoPrefsSession); 534 return FALSE; 535 } 536 537 if (!getPath(prefs, path, &value)) { 538 // if no such path 539 return FALSE; 540 } 541 542 elements = normalizePath(path); 543 if (elements == NULL) { 544 _SCErrorSet(kSCStatusNoKey); 545 return FALSE; 546 } 547 548 ok = setPath(prefs, path, NULL); 549 550 CFRelease(elements); 551 return ok; 552}