this repo has no description
at fixPythonPipStalling 359 lines 9.2 kB view raw
1/* 2 * Copyright (c) 2000-2008, 2010-2013, 2015-2018 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 9, 2000 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34#include <TargetConditionals.h> 35#include "SCPreferencesInternal.h" 36#include "SCHelper_client.h" 37 38#include <fcntl.h> 39#include <unistd.h> 40#include <sys/errno.h> 41 42static Boolean 43__SCPreferencesCommitChanges_helper(SCPreferencesRef prefs) 44{ 45 CFDataRef data = NULL; 46 Boolean ok; 47 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 48 uint32_t status = kSCStatusOK; 49 CFDataRef reply = NULL; 50 51 if (prefsPrivate->helper_port == MACH_PORT_NULL) { 52 // if no helper 53 status = kSCStatusAccessError; 54 goto fail; 55 } 56 57 if (prefsPrivate->changed) { 58 ok = _SCSerialize(prefsPrivate->prefs, &data, NULL, NULL); 59 if (!ok) { 60 status = kSCStatusFailed; 61 if (_sc_verbose) { 62 SC_log(LOG_NOTICE, "_SCSerialize() failed"); 63 SC_log(LOG_NOTICE, " prefs = %s", 64 prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path); 65 } 66 goto error; 67 } 68 } 69 70 // have the helper "commit" the prefs 71// status = kSCStatusOK; 72// reply = NULL; 73 ok = _SCHelperExec(prefsPrivate->helper_port, 74 SCHELPER_MSG_PREFS_COMMIT, 75 data, 76 &status, 77 &reply); 78 if (data != NULL) CFRelease(data); 79 if (!ok) { 80 goto fail; 81 } 82 83 if (status != kSCStatusOK) { 84 goto error; 85 } 86 87 if (prefsPrivate->changed) { 88 if (prefsPrivate->signature != NULL) CFRelease(prefsPrivate->signature); 89 prefsPrivate->signature = reply; 90 } else { 91 if (reply != NULL) CFRelease(reply); 92 } 93 94 prefsPrivate->changed = FALSE; 95 return TRUE; 96 97 fail : 98 99 // close helper 100 if (prefsPrivate->helper_port != MACH_PORT_NULL) { 101 _SCHelperClose(&prefsPrivate->helper_port); 102 } 103 104 error : 105 106 // return error 107 if (reply != NULL) CFRelease(reply); 108 _SCErrorSet(status); 109 return FALSE; 110} 111 112 113static ssize_t 114writen(int ref, const void *data, size_t len) 115{ 116 size_t left = len; 117 ssize_t n; 118 const void *p = data; 119 120 while (left > 0) { 121 if ((n = write(ref, p, left)) == -1) { 122 if (errno != EINTR) { 123 return -1; 124 } 125 n = 0; 126 } 127 left -= n; 128 p += n; 129 } 130 return len; 131} 132 133 134Boolean 135SCPreferencesCommitChanges(SCPreferencesRef prefs) 136{ 137 Boolean ok = FALSE; 138 char * path; 139 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 140 Boolean save = TRUE; 141 struct stat statBuf; 142 Boolean wasLocked; 143 144 if (prefs == NULL) { 145 /* sorry, you must provide a session */ 146 _SCErrorSet(kSCStatusNoPrefsSession); 147 return FALSE; 148 } 149 150 /* 151 * Determine if the we have exclusive access to the preferences 152 * and acquire the lock if necessary. 153 */ 154 wasLocked = prefsPrivate->locked; 155 if (!wasLocked) { 156 if (!SCPreferencesLock(prefs, TRUE)) { 157 SC_log(LOG_INFO, "SCPreferencesLock() failed"); 158 return FALSE; 159 } 160 } 161 162 if (prefsPrivate->authorizationData != NULL) { 163 ok = __SCPreferencesCommitChanges_helper(prefs); 164 if (ok) { 165 prefsPrivate->changed = FALSE; 166 } 167 goto done; 168 } 169 170 /* 171 * if necessary, apply changes 172 */ 173 if (!prefsPrivate->changed) { 174 goto committed; 175 } 176 177 /* 178 * check if the preferences should be removed 179 */ 180 if (CFDictionaryGetCount(prefsPrivate->prefs) == 0) { 181 CFBooleanRef val; 182 183 /* if empty */ 184 if ((prefsPrivate->options != NULL) && 185 CFDictionaryGetValueIfPresent(prefsPrivate->options, 186 kSCPreferencesOptionRemoveWhenEmpty, 187 (const void **)&val) && 188 isA_CFBoolean(val) && 189 CFBooleanGetValue(val)) { 190 /* if we've been asked to remove empty .plists */ 191 save = FALSE; 192 } 193 } 194 195 path = prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path; 196 if (save) { 197 int fd; 198 CFDataRef newPrefs; 199 CFIndex pathLen; 200 CFStringRef protectionClass; 201 char * thePath; 202 203 if (stat(prefsPrivate->path, &statBuf) == -1) { 204 if (errno == ENOENT) { 205 memset(&statBuf, 0, sizeof(statBuf)); 206 statBuf.st_mode = 0644; 207 statBuf.st_uid = geteuid(); 208 statBuf.st_gid = getegid(); 209 } else { 210 _SCErrorSet(errno); 211 SC_log(LOG_INFO, "stat() failed: %s", strerror(errno)); 212 goto done; 213 } 214 } 215 216 /* create the (new) preferences file */ 217 pathLen = strlen(path) + sizeof("-new"); 218 thePath = CFAllocatorAllocate(NULL, pathLen, 0); 219 snprintf(thePath, pathLen, "%s-new", path); 220 221 if ((prefsPrivate->options != NULL) && 222 CFDictionaryGetValueIfPresent(prefsPrivate->options, 223 kSCPreferencesOptionProtectionClass, 224 (const void **)&protectionClass)) { 225 int pc; 226 const char *str; 227 228 if (!isA_CFString(protectionClass) || 229 (CFStringGetLength(protectionClass) != 1) || 230 ((str = CFStringGetCStringPtr(protectionClass, kCFStringEncodingASCII)) == NULL) || 231 (str[0] < 'A') || (str[0] > 'F') 232 ) { 233 _SCErrorSet(kSCStatusInvalidArgument); 234 goto done; 235 } 236 237 pc = str[0] - 'A' + 1; // PROTECTION_CLASS_[ABCDEF] 238 fd = open_dprotected_np(thePath, O_WRONLY|O_CREAT, pc, 0, statBuf.st_mode); 239 } else { 240 fd = open(thePath, O_WRONLY|O_CREAT, statBuf.st_mode); 241 } 242 243 if (fd == -1) { 244 _SCErrorSet(errno); 245 SC_log(LOG_NOTICE, "open() failed: %s", strerror(errno)); 246 CFAllocatorDeallocate(NULL, thePath); 247 goto done; 248 } 249 250 /* preserve permissions */ 251 (void) fchown(fd, statBuf.st_uid, statBuf.st_gid); 252 (void) fchmod(fd, statBuf.st_mode); 253 254 /* write the new preferences */ 255 newPrefs = CFPropertyListCreateData(NULL, 256 prefsPrivate->prefs, 257#if TARGET_OS_IPHONE 258 kCFPropertyListBinaryFormat_v1_0, 259#else // TARGET_OS_IPHONE 260 kCFPropertyListXMLFormat_v1_0, 261#endif // TARGET_OS_IPHONE 262 0, 263 NULL); 264 if (!newPrefs) { 265 _SCErrorSet(kSCStatusFailed); 266 SC_log(LOG_INFO, "CFPropertyListCreateData() failed"); 267 SC_log(LOG_INFO, " prefs = %s", path); 268 CFAllocatorDeallocate(NULL, thePath); 269 (void) close(fd); 270 goto done; 271 } 272 if (writen(fd, (const void *)CFDataGetBytePtr(newPrefs), CFDataGetLength(newPrefs)) == -1) { 273 _SCErrorSet(errno); 274 SC_log(LOG_INFO, "writen() failed: %s", strerror(errno)); 275 SC_log(LOG_INFO, " path = %s", thePath); 276 (void) unlink(thePath); 277 CFAllocatorDeallocate(NULL, thePath); 278 (void) close(fd); 279 CFRelease(newPrefs); 280 goto done; 281 } 282 283 /* new preferences have been written */ 284 if (close(fd) == -1) { 285 _SCErrorSet(errno); 286 SC_log(LOG_INFO, "close() failed: %s", strerror(errno)); 287 SC_log(LOG_INFO, " path = %s", thePath); 288 (void) unlink(thePath); 289 CFAllocatorDeallocate(NULL, thePath); 290 CFRelease(newPrefs); 291 goto done; 292 } 293 CFRelease(newPrefs); 294 295 /* rename new->old */ 296 if (rename(thePath, path) == -1) { 297 _SCErrorSet(errno); 298 SC_log(LOG_INFO, "rename() failed: %s", strerror(errno)); 299 SC_log(LOG_INFO, " path = %s --> %s", thePath, path); 300 CFAllocatorDeallocate(NULL, thePath); 301 goto done; 302 } 303 CFAllocatorDeallocate(NULL, thePath); 304 305 if (prefsPrivate->newPath) { 306 /* prefs file saved in "new" directory */ 307 (void) unlink(prefsPrivate->path); 308 (void) symlink(prefsPrivate->newPath, prefsPrivate->path); 309 CFAllocatorDeallocate(NULL, prefsPrivate->path); 310 prefsPrivate->path = path; 311 prefsPrivate->newPath = NULL; 312 } 313 314 /* grab the new signature */ 315 if (stat(path, &statBuf) == -1) { 316 _SCErrorSet(errno); 317 SC_log(LOG_INFO, "stat() failed: %s", strerror(errno)); 318 SC_log(LOG_INFO, " path = %s", thePath); 319 goto done; 320 } 321 } else { 322 /* remove the empty .plist */ 323 unlink(path); 324 325 /* init the new signature */ 326 memset(&statBuf, 0, sizeof(statBuf)); 327 } 328 329 /* update signature */ 330 if (prefsPrivate->signature != NULL) CFRelease(prefsPrivate->signature); 331 prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf); 332 333 committed : 334 335 SC_log(LOG_INFO, "SCPreferences() commit: %s, size=%lld", 336 prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path, 337 __SCPreferencesPrefsSize(prefs)); 338 339 /* post notification */ 340 ok = SCDynamicStoreNotifyValue(NULL, prefsPrivate->sessionKeyCommit); 341 if (!ok) { 342 SC_log(LOG_INFO, "SCDynamicStoreNotifyValue() failed"); 343 _SCErrorSet(kSCStatusFailed); 344 goto done; 345 } 346 347 prefsPrivate->changed = FALSE; 348 349 done : 350 351 if (!wasLocked) { 352 uint32_t status; 353 354 status = SCError(); // preserve status across unlock 355 (void) SCPreferencesUnlock(prefs); 356 _SCErrorSet(status); 357 } 358 return ok; 359}