1/* 2 * Copyright (c) 2008 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#include <IOKit/IOCFURLAccess.h> 24 25#include <unistd.h> 26#include <dirent.h> 27#include <sys/stat.h> 28#include <sys/types.h> 29#include <pwd.h> 30#include <fcntl.h> 31 32#include "IOKitInternal.h" 33 34/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 35/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 36 37#ifdef HAVE_CFURLACCESS 38 39CFTypeRef IOURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) 40{ 41 return (CFURLCreatePropertyFromResource(alloc, url, property, errorCode)); 42} 43 44Boolean IOURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *resourceData, CFDictionaryRef *properties, CFArrayRef desiredProperties, SInt32 *errorCode) 45{ 46 return (CFURLCreateDataAndPropertiesFromResource(alloc, url, resourceData, properties, desiredProperties, errorCode)); 47} 48 49Boolean IOCFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef dataToWrite, CFDictionaryRef propertiesToWrite, SInt32 *errorCode) 50{ 51 return (CFURLWriteDataAndPropertiesToResource(url, dataToWrite, propertiesToWrite, errorCode)); 52} 53 54/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 55/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 56 57#else /* !HAVE_CFURLACCESS */ 58 59/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 60/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 61 62#define kIOFileURLExists CFSTR("kIOFileURLExists") 63#define kIOFileURLPOSIXMode CFSTR("kIOFileURLPOSIXMode") 64#define kIOFileURLSize CFSTR("kIOFileURLSize") 65 66static Boolean _IOFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode); 67static CFDictionaryRef _IOFileURLCreatePropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFArrayRef desiredProperties, SInt32 *errorCode); 68static Boolean _IOFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef propertyDict, SInt32 *errorCode); 69 70static CFMutableArrayRef _IOContentsOfDirectory(CFAllocatorRef alloc, char path[CFMaxPathLength], CFURLRef base, CFStringRef matchingAbstractType); 71extern Boolean _IOReadBytesFromFile(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength); 72extern Boolean _IOWriteBytesToFile(const char *path, const void *bytes, CFIndex length); 73 74CFTypeRef IOURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) { 75 CFArrayRef array = CFArrayCreate(alloc, (const void **)&property, 1, &kCFTypeArrayCallBacks); 76 CFDictionaryRef dict; 77 78 if (IOURLCreateDataAndPropertiesFromResource(alloc, url, NULL, &dict, array, errorCode)) { 79 CFTypeRef result = CFDictionaryGetValue(dict, property); 80 if (result) CFRetain(result); 81 CFRelease(array); 82 CFRelease(dict); 83 return result; 84 } else { 85 if (dict) CFRelease(dict); 86 CFRelease(array); 87 return NULL; 88 } 89} 90 91Boolean IOURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFDictionaryRef *fetchedProperties, CFArrayRef desiredProperties, SInt32 *errorCode) { 92 93 CFStringRef scheme = CFURLCopyScheme(url); 94 95 if (!scheme) { 96 if (errorCode) *errorCode = kIOURLImproperArgumentsError; 97 if (fetchedData) *fetchedData = NULL; 98 if (fetchedProperties) *fetchedProperties = NULL; 99 return FALSE; 100 } else { 101 Boolean result; 102 if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) { 103 result = _IOFileURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode); 104 } else { 105 if (fetchedData) *fetchedData = NULL; 106 if (fetchedProperties) *fetchedProperties = NULL; 107 if (errorCode) *errorCode = kIOURLUnknownSchemeError; 108 result = FALSE; 109 } 110 CFRelease(scheme); 111 return result; 112 } 113} 114 115static Boolean _IOFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) { 116 char buffer[CFMaxPathSize]; 117 Boolean success = TRUE; 118 119 if (!CFURLGetFileSystemRepresentation(url, TRUE, buffer, CFMaxPathSize)) { 120 if (fetchedData) *fetchedData = NULL; 121 if (fetchedProperties) *fetchedProperties = NULL; 122 if (errorCode) *errorCode = kIOURLImproperArgumentsError; 123 return FALSE; 124 } 125 126 if (errorCode) *errorCode = 0; 127 if (fetchedData) { 128 void *bytes; 129 CFIndex length; 130 Boolean releaseAlloc = FALSE; 131 132 if (alloc == NULL) { 133 // We need a real allocator to pass to _IOReadBytesFromFile 134 alloc = CFRetain(CFAllocatorGetDefault()); 135 releaseAlloc = TRUE; 136 } 137 if (!_IOReadBytesFromFile(alloc, buffer, &bytes, &length, 0)) { 138 if (errorCode) *errorCode = kIOURLUnknownError; 139 *fetchedData = NULL; 140 success = FALSE; 141 } else { 142 *fetchedData = CFDataCreateWithBytesNoCopy(alloc, bytes, length, alloc); 143 } 144 if (releaseAlloc) { 145 // Now the CFData should be hanging on to it. 146 CFRelease(alloc); 147 } 148 } 149 150 if (fetchedProperties) { 151 *fetchedProperties = _IOFileURLCreatePropertiesFromResource(alloc, url, desiredProperties, errorCode); 152 if (!*fetchedProperties) success = FALSE; 153 } 154 155 return success; 156} 157 158Boolean IOURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDictionaryRef propertyDict, SInt32 *errorCode) { 159 CFStringRef scheme = CFURLCopyScheme(url); 160 if (!scheme) { 161 if (errorCode) *errorCode = kIOURLImproperArgumentsError; 162 return FALSE; 163 } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) { 164 Boolean success = TRUE; 165 CFRelease(scheme); 166 if (errorCode) *errorCode = 0; 167 if (data) { 168 char cPath[CFMaxPathSize]; 169 if (!CFURLGetFileSystemRepresentation(url, TRUE, cPath, CFMaxPathSize)) { 170 if (errorCode) *errorCode = kIOURLImproperArgumentsError; 171 success = FALSE; 172 } else if (CFURLHasDirectoryPath(url)) { 173 // Create a directory 174 success = !mkdir(cPath, 0777); 175 if (!success && errorCode) *errorCode = kIOURLUnknownError; 176 } else { 177 // Write data 178 SInt32 length = CFDataGetLength(data); 179 const void *bytes = (0 == length) ? (const void *)"" : CFDataGetBytePtr(data); 180 success = _IOWriteBytesToFile(cPath, bytes, length); 181 if (!success && errorCode) *errorCode = kIOURLUnknownError; 182 } 183 } 184 if (propertyDict) { 185 if (!_IOFileURLWritePropertiesToResource(url, propertyDict, errorCode)) 186 success = FALSE; 187 } 188 return success; 189 } else { 190 if (errorCode) *errorCode = kIOURLUnknownSchemeError; 191 return FALSE; 192 } 193} 194 195static Boolean _IOFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef propertyDict, SInt32 *errorCode) { 196 CFTypeRef buffer[16]; 197 void **keys; 198 void **values; 199 Boolean result = TRUE; 200 SInt32 index, count; 201 char cPath[CFMaxPathSize]; 202 203 if (!CFURLGetFileSystemRepresentation(url, TRUE, cPath, CFMaxPathSize)) { 204 if (errorCode) *errorCode = kIOURLImproperArgumentsError; 205 return FALSE; 206 } 207 208 count = CFDictionaryGetCount(propertyDict); 209 if (count < 8) { 210 keys = buffer; 211 values = buffer+8; 212 } else { 213 keys = CFAllocatorAllocate(CFGetAllocator(url), sizeof(void *) * count * 2, 0); 214 values = keys + count; 215 } 216 CFDictionaryGetKeysAndValues(propertyDict, keys, values); 217 218 for (index = 0; index < count; index ++) { 219 CFStringRef key = keys[index]; 220 CFTypeRef value = values[index]; 221 if (CFEqual(key, kIOFileURLPOSIXMode) || CFEqual(key, kIOURLFilePOSIXMode)) { 222 SInt32 mode; 223 int err; 224 if (CFEqual(key, kIOURLFilePOSIXMode)) { 225 CFNumberRef modeNum = (CFNumberRef)value; 226 CFNumberGetValue(modeNum, kCFNumberSInt32Type, &mode); 227 } else { 228 const mode_t *modePtr = (const mode_t *)CFDataGetBytePtr((CFDataRef)value); 229 mode = *modePtr; 230 } 231 err = chmod(cPath, mode); 232 if (err != 0) result = FALSE; 233 } else { 234 result = FALSE; 235 } 236 } 237 238 if (keys != &buffer[0]) CFAllocatorDeallocate(CFGetAllocator(url), keys); 239 240 if (errorCode) *errorCode = result ? 0 : kIOURLUnknownError; 241 return result; 242} 243 244static CFDictionaryRef _IOFileURLCreatePropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFArrayRef desiredProperties, SInt32 *errorCode) { 245 static CFArrayRef _allProps = NULL; 246 char cPath[CFMaxPathSize]; 247 SInt32 index, count, statResult = 0; 248 CFMutableDictionaryRef propertyDict = NULL; 249 struct stat statBuf; 250 Boolean statCompleted = FALSE; 251 252 if (!CFURLGetFileSystemRepresentation(url, TRUE, cPath, CFMaxPathSize)) { 253 if (errorCode) *errorCode = kIOURLImproperArgumentsError; 254 return NULL; 255 } 256 if (errorCode) *errorCode = 0; 257 if (!desiredProperties) { 258 // Cheap and dirty hack to make this work for the moment; ultimately we need to do something more sophisticated. This will result in an error return whenever a property key is defined which isn't applicable to all file URLs. REW, 3/2/99 259 if (!_allProps) { 260 const void *values[9]; 261 values[0] = kIOURLFileExists; 262 values[1] = kIOURLFilePOSIXMode; 263 values[2] = kIOURLFileDirectoryContents; 264 values[3] = kIOURLFileLength; 265 values[4] = kIOURLFileLastModificationTime; 266 values[5] = kIOURLFileOwnerID; 267 values[6] = kIOFileURLExists; 268 values[7] = kIOFileURLPOSIXMode; 269 values[8] = kIOFileURLSize; 270 _allProps = CFArrayCreate(NULL, values, 8, &kCFTypeArrayCallBacks); 271 } 272 desiredProperties = _allProps; 273 } 274 275 count = CFArrayGetCount(desiredProperties); 276 propertyDict = CFDictionaryCreateMutable(alloc, 0, & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); 277 if (count == 0) return propertyDict; 278 for (index = 0; index < count; index ++) { 279 CFStringRef key = (CFMutableStringRef )CFArrayGetValueAtIndex(desiredProperties, index); 280 if (!statCompleted && (CFEqual(key, kIOURLFilePOSIXMode) || CFEqual(key, kIOURLFileDirectoryContents) || CFEqual(key, kIOURLFileLength) || CFEqual(key, kIOURLFileLastModificationTime) || CFEqual(key, kIOURLFileExists) || CFEqual(key, kIOFileURLExists) || CFEqual(key, kIOFileURLPOSIXMode) || CFEqual(key, kIOFileURLSize) || CFEqual(key, kIOURLFileOwnerID))) { 281 statResult = stat(cPath, &statBuf); 282 if (statResult != 0) statResult = thread_errno(); 283 statCompleted = TRUE; 284 } else if (errorCode) { 285 *errorCode = kIOURLUnknownError; 286 } 287 if (CFEqual(key, kIOFileURLPOSIXMode)) { 288 if (statResult == 0) { 289 CFDataRef modeData = CFDataCreate(alloc, (void *)(&(statBuf.st_mode)), sizeof(statBuf.st_mode)); 290 CFDictionarySetValue(propertyDict, kIOFileURLPOSIXMode, modeData); 291 CFRelease(modeData); 292 } else if (errorCode) { 293 *errorCode = kIOURLUnknownError; 294 } 295 } else if (CFEqual(key, kIOURLFilePOSIXMode)) { 296 if (statResult == 0) { 297 SInt32 value = statBuf.st_mode; 298 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &value); 299 CFDictionarySetValue(propertyDict, kIOURLFilePOSIXMode, num); 300 CFRelease(num); 301 } else if (errorCode) { 302 *errorCode = kIOURLUnknownError; 303 } 304 } else if (CFEqual(key, kIOURLFileDirectoryContents)) { 305 if (statResult == 0 && (statBuf.st_mode & S_IFMT) == S_IFDIR) { 306 CFMutableArrayRef contents = _IOContentsOfDirectory(alloc, cPath, url, NULL); 307 if (contents) { 308 CFDictionarySetValue(propertyDict, kIOURLFileDirectoryContents, contents); 309 CFRelease(contents); 310 } else if (errorCode) { 311 *errorCode = kIOURLUnknownError; 312 } 313 } else if (errorCode) { 314 *errorCode = kIOURLUnknownError; 315 } 316 } else if (CFEqual(key, kIOFileURLSize)) { 317 if (statResult == 0) { 318 UInt64 length = statBuf.st_size; 319 CFDataRef tmpData = CFDataCreate(alloc, (void *)(&length), sizeof(UInt64)); 320 CFDictionarySetValue(propertyDict, kIOFileURLSize, tmpData); 321 CFRelease(tmpData); 322 } else if (errorCode) { 323 *errorCode = kIOURLUnknownError; 324 } 325 } else if (CFEqual(key, kIOURLFileLength)) { 326 if (statResult == 0) { 327 SInt64 length = statBuf.st_size; 328 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt64Type, &length); 329 CFDictionarySetValue(propertyDict, kIOURLFileLength, num); 330 CFRelease(num); 331 } else if (errorCode) { 332 *errorCode = kIOURLUnknownError; 333 } 334 } else if (CFEqual(key, kIOURLFileLastModificationTime)) { 335 if (statResult == 0) { 336 CFDateRef date = CFDateCreate(alloc, statBuf.st_mtime - kCFAbsoluteTimeIntervalSince1970); 337 CFDictionarySetValue(propertyDict, kIOURLFileLastModificationTime, date); 338 CFRelease(date); 339 } else if (errorCode) { 340 *errorCode = kIOURLUnknownError; 341 } 342 } else if (CFEqual(key, kIOURLFileExists)) { 343 if (statResult == 0) { 344 CFDictionarySetValue(propertyDict, kIOURLFileExists, kCFBooleanTrue); 345 } else if (statResult == ENOENT) { 346 CFDictionarySetValue(propertyDict, kIOURLFileExists, kCFBooleanFalse); 347 } else if (errorCode) { 348 *errorCode = kIOURLUnknownError; 349 } 350 } else if (CFEqual(key, kIOFileURLExists)) { 351 if (statResult == 0) { 352 CFDictionarySetValue(propertyDict, kIOFileURLExists, kIOFileURLExists); 353 } else if (statResult == ENOENT) { 354 CFDictionarySetValue(propertyDict, kIOFileURLExists, kCFBooleanFalse); // Choose any value other than kIOFileURLExists to designate non-existance. Note that we cannot use NULL, since the dictionary has value callbacks kCFTypeDictionaryValueCallBacks, which is not tolerant of NULL values. 355 } else if (errorCode) { 356 *errorCode = kIOURLUnknownError; 357 } 358 } else if (CFEqual(key, kIOURLFileOwnerID)) { 359 if (statResult == 0) { 360 SInt32 uid = statBuf.st_uid; 361 CFNumberRef num = CFNumberCreate(alloc, kCFNumberSInt32Type, &uid); 362 CFDictionarySetValue(propertyDict, kIOURLFileOwnerID, num); 363 CFRelease(num); 364 } else if (errorCode) { 365 *errorCode = kIOURLUnknownError; 366 } 367 // Add more properties here 368 } else if (errorCode) { 369 *errorCode = kIOURLUnknownPropertyKeyError; 370 } 371 } 372 return propertyDict; 373} 374 375 376// File Utilities 377 378// Note: as of November 2006, the matchingAbstractType isn't used at this function's only call site 379static CFMutableArrayRef _IOContentsOfDirectory(CFAllocatorRef alloc, char path[CFMaxPathLength], CFURLRef base, CFStringRef matchingAbstractType) { 380 CFMutableArrayRef files; 381 Boolean releaseBase = FALSE; 382 CFIndex pathLength = strlen(path); 383 // MF:!!! Need to use four-letter type codes where appropriate. 384 CFStringRef extension = (matchingAbstractType ? CFRetain(matchingAbstractType) : NULL); 385 CFIndex extLen = (extension ? CFStringGetLength(extension) : 0); 386 char extBuff[CFMaxPathSize]; 387 388 int fd, numread; 389 long basep; 390 char dirge[8192]; 391 392 if (extLen > 0) { 393 // not sure what extension might contain ... currently unused 394 CFStringGetBytes(extension, CFRangeMake(0, extLen), kCFStringEncodingMacRoman, 0, FALSE, extBuff, CFMaxPathSize, &extLen); 395 extBuff[extLen] = '\0'; // CFStringGetBytes set extLen to number of bytes in converted string 396 } 397 398 fd = open(path, O_RDONLY, 0777); 399 if (fd < 0) { 400 if (extension) { 401 CFRelease(extension); 402 } 403 return NULL; 404 } 405 files = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); 406 407 while ((numread = getdirentries(fd, dirge, sizeof(dirge), &basep)) > 0) { 408 struct dirent *dent; 409 for (dent = (struct dirent *)dirge; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) { 410 CFURLRef fileURL; 411 CFIndex nameLen; 412 413 nameLen = dent->d_namlen; 414 // skip . & ..; they cause descenders to go berserk 415 if (0 == dent->d_ino /*d_fileno*/ || (dent->d_name[0] == '.' && (nameLen == 1 || (nameLen == 2 && dent->d_name[1] == '.')))) { 416 continue; 417 } 418 if (extLen > 0) { 419 // Check to see if it matches the extension we're looking for. 420 if (strncmp(&(dent->d_name[nameLen - extLen]), extBuff, extLen) != 0) { 421 continue; 422 } 423 } 424 if (base == NULL) { 425 base = CFURLCreateFromFileSystemRepresentation(alloc, path, pathLength, TRUE); 426 releaseBase = TRUE; 427 } 428 429 if (dent->d_type == DT_DIR || dent->d_type == DT_UNKNOWN) { 430 Boolean isDir = (dent->d_type == DT_DIR); 431 if (!isDir) { 432 // Ugh; must stat. 433 char subdirPath[CFMaxPathLength]; 434 struct stat statBuf; 435 strncpy(subdirPath, path, pathLength); 436 subdirPath[pathLength] = '/'; 437 strncpy(subdirPath + pathLength + 1, dent->d_name, nameLen); 438 subdirPath[pathLength + nameLen + 1] = '\0'; 439 if (stat(subdirPath, &statBuf) == 0) { 440 isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR); 441 } 442 } 443 fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, dent->d_name, nameLen, isDir, base); 444 } else { 445 fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, dent->d_name, nameLen, FALSE, base); 446 } 447 CFArrayAppendValue(files, fileURL); 448 CFRelease(fileURL); 449 } 450 } 451 close(fd); 452 if (-1 == numread) { 453 CFRelease(files); 454 if (releaseBase) { 455 CFRelease(base); 456 } 457 if (extension) { 458 CFRelease(extension); 459 } 460 return NULL; 461 } 462 463 if (extension) { 464 CFRelease(extension); 465 } 466 if (releaseBase) { 467 CFRelease(base); 468 } 469 return files; 470} 471 472#endif /* !HAVE_CFURLACCESS */ 473/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 474/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 475 476#define CF_OPENFLGS (0) 477#define thread_set_errno(V) do {errno = (V);} while (0) 478 479/* Note: _IOReadBytesFromFile is called from PowerManagament project daemon powerd 480 * e.g. it has references outside of this file. 481 */ 482Boolean _IOReadBytesFromFile(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength) { 483 // alloc must be a valid allocator. 484 // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length. 485 struct stat statBuf; 486 int fd = -1; 487 488 if (!alloc) { 489 // MF:!!! This is no good. This function needs to require a non-NULL allocator. We should probably log or assert or something. 490 return FALSE; 491 } 492 493 *bytes = NULL; 494 fd = open(path, O_RDONLY|CF_OPENFLGS, 0666); 495 if (fd < 0) { 496 return FALSE; 497 } 498 if (fstat(fd, &statBuf) < 0) { 499 int saveerr = thread_errno(); 500 close(fd); 501 thread_set_errno(saveerr); 502 return FALSE; 503 } 504 if ((statBuf.st_mode & S_IFMT) != S_IFREG) { 505 close(fd); 506 thread_set_errno(EACCES); 507 return FALSE; 508 } 509 if (statBuf.st_size == 0) { 510 *bytes = CFAllocatorAllocate(alloc, 4, 0); // don't return constant string -- it's freed! 511 *length = 0; 512 } else { 513 CFIndex desiredLength; 514 if ((maxLength >= statBuf.st_size) || (maxLength == 0)) { 515 desiredLength = statBuf.st_size; 516 } else { 517 desiredLength = maxLength; 518 } 519 *bytes = CFAllocatorAllocate(alloc, desiredLength, 0); 520 if (read(fd, *bytes, desiredLength) < 0) { 521 CFAllocatorDeallocate(alloc, *bytes); 522 *bytes = NULL; 523 close(fd); 524 return FALSE; 525 } 526 *length = desiredLength; 527 } 528 close(fd); 529 return TRUE; 530} 531 532Boolean _IOWriteBytesToFile(const char *path, const void *bytes, CFIndex length) { 533 struct stat statBuf; 534 int fd = -1; 535 int mode, mask; 536 537 mask = umask(0); 538 umask(mask); 539 mode = 0666 & ~mask; 540 if (0 == stat(path, &statBuf)) { 541 mode = statBuf.st_mode; 542 } else if (thread_errno() != ENOENT) { 543 return FALSE; 544 } 545 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|CF_OPENFLGS, 0666); 546 if (fd < 0) { 547 return FALSE; 548 } 549 if (length && write(fd, bytes, length) != length) { 550 int saveerr = thread_errno(); 551 close(fd); 552 thread_set_errno(saveerr); 553 return FALSE; 554 } 555 fsync(fd); 556 close(fd); 557 return TRUE; 558} 559