1/* 2 * Copyright (c) 1999-2004 Apple Computer, 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#include <libkern/OSByteOrder.h> 25#include <stdio.h> 26#include <unistd.h> 27#include <paths.h> 28#include <fsproperties.h> 29 30#include <IOKit/storage/IOMedia.h> 31#include <IOKit/storage/CoreStorage/CoreStorageUserLib.h> 32 33#include "FSFormatName.h" 34 35static CFMutableDictionaryRef __FSLocalizedNameTable = NULL; 36static OSSpinLock __FSLocalizedNameTableLock = 0; 37static bool IsEncrypted(const char *bsdname); 38 39CFStringRef FSCopyFormatNameForFSType(CFStringRef fsType, int16_t fsSubtype, bool localized, bool encrypted) 40{ 41 CFTypeRef formatName; 42 CFStringRef formatNameTableKey; 43 CFIndex indx; 44 45 if (NULL == fsType) return NULL; 46 47 // Create a key for cache localized name table (i.e. "0hfs0") 48 formatNameTableKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d%@%d"), (localized ? 1 : 0), fsType, fsSubtype); 49 50 // Use OSSpinLock to protect the table accessed from multiple threads 51 OSSpinLockLock(&__FSLocalizedNameTableLock); 52 formatName = (void*)((NULL == __FSLocalizedNameTable) ? NULL : CFDictionaryGetValue(__FSLocalizedNameTable, (const void *)formatNameTableKey)); 53 OSSpinLockUnlock(&__FSLocalizedNameTableLock); 54 55 if (NULL == formatName) { // not in the cache 56 CFBundleRef bundle = NULL; 57 CFURLRef bundleURL; 58 CFStringRef fsTypeName; 59 static CFArrayRef searchPaths = NULL; 60 61 /* Construct a bundle path URL from the fsType argument and create a CFBundle. We search (using CFCopySearchPathForDirectoriesInDomains) /Network/Library/Filesystems, /Library/Filesystems, and /System/Library/Filesystems. */ 62 63 // Create CFURL for /System/Library/Filesystems and cache it 64 if (NULL == searchPaths) { 65 CFArrayRef tmpPaths = CFCopySearchPathForDirectoriesInDomains(kCFLibraryDirectory, kCFSystemDomainMask | kCFNetworkDomainMask | kCFLocalDomainMask, true); 66 CFMutableArrayRef tmpStrings; 67 CFIndex i; 68 69 if (NULL == tmpPaths) 70 return NULL; // No directories to search?!?! 71 72 tmpStrings = CFArrayCreateMutable(NULL, CFArrayGetCount(tmpPaths), NULL); 73 if (tmpStrings == NULL) 74 goto done; 75 for (i = 0; i < CFArrayGetCount(tmpPaths); i++) { 76 CFStringRef tStr; 77 CFURLRef tURL; 78 char path[PATH_MAX + 1]; 79 CFTypeRef tobject = CFArrayGetValueAtIndex(tmpPaths, i); 80 81 if (CFGetTypeID(tobject) == CFURLGetTypeID()) { 82 if (false == 83 CFURLGetFileSystemRepresentation( 84 tobject, 85 false, 86 (UInt8*)path, 87 sizeof(path))) { 88 goto done; 89 } 90 } else if (CFGetTypeID(tobject) == CFStringGetTypeID()) { 91 CFStringGetCString(tobject, path, sizeof(path), kCFStringEncodingUTF8); 92 } else { 93 goto done; 94 } 95 strlcat(path, "/Filesystems", sizeof(path)); 96 tStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8); 97 if (tStr == NULL) 98 goto done; 99 tURL = CFURLCreateWithFileSystemPath(NULL, tStr, kCFURLPOSIXPathStyle, true); 100 if (tURL) { 101 CFArrayAppendValue(tmpStrings, tURL); 102 } 103 CFRelease(tStr); 104 } 105 searchPaths = CFArrayCreateCopy(NULL, tmpStrings); 106done: 107 CFRelease(tmpStrings); 108 CFRelease(tmpPaths); 109 if (searchPaths == NULL) 110 return NULL; 111 } 112 113 for (indx = 0; indx < CFArrayGetCount(searchPaths); indx++) { 114 CFURLRef libRef = CFArrayGetValueAtIndex(searchPaths, indx); 115 116 fsTypeName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.fs"), fsType); 117 bundleURL = CFURLCreateWithFileSystemPathRelativeToBase(NULL, fsTypeName, kCFURLPOSIXPathStyle, true, libRef); 118 bundle = CFBundleCreate(NULL, bundleURL); 119 120 CFRelease(fsTypeName); 121 CFRelease(bundleURL); 122 if (NULL != bundle) { 123 break; 124 } 125 } 126 127 if (NULL != bundle) { // the bundle exists at path 128 CFDictionaryRef localPersonalities = NULL; 129 130 // Access the Info dictionary in the bundle 131 CFDictionaryRef bundleDict = CFBundleGetInfoDictionary(bundle); 132 133 // Get localized FSPersonalities only if we want localized name 134 if (localized == true) { 135 localPersonalities = CFBundleGetValueForInfoDictionaryKey(bundle, KEY_FS_PERSONALITIES); 136//NSLog(CFSTR("localPersonalities = %@\n"), localPersonalities); 137 } 138 139 /* Get global FSPersonalities. We need to access this since FSSubType exists only 140 * in global FSPersonalities 141 */ 142 CFDictionaryRef globalPersonalities = CFDictionaryGetValue(bundleDict, (const void *) KEY_FS_PERSONALITIES); 143//NSLog(CFSTR("globalPersonalities = %@\n"), globalPersonalities); 144 CFIndex numPersonalities; 145 if (((NULL != localPersonalities) || (localized == false)) && // localPersonalities or we don't want localizations 146 (NULL != globalPersonalities) && 147 ((numPersonalities = CFDictionaryGetCount(globalPersonalities)) > 0)) { 148 149 // read all FSPersonalities keys and values 150 CFDictionaryRef valuesBuffer[MAX_FS_SUBTYPES]; 151 CFStringRef keysBuffer[MAX_FS_SUBTYPES]; 152 CFDictionaryRef *values = ((numPersonalities > MAX_FS_SUBTYPES) ? (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * numPersonalities) : valuesBuffer); 153 CFStringRef *keys = ((numPersonalities > MAX_FS_SUBTYPES) ? (CFStringRef *)malloc(sizeof(CFStringRef) * numPersonalities) : keysBuffer); 154 CFDictionaryGetKeysAndValues(globalPersonalities, (const void **)keys, (const void **)values); 155 156 // create CFNumberRef for the FSSubType 157 CFNumberRef subTypeID = CFNumberCreate(NULL, kCFNumberSInt16Type, (const void *)&fsSubtype); 158 CFStringRef FSNameKey = NULL; 159 160 // search for valid FSSubType - we will use its key from global FSPersonalties to 161 // access FSName from localized FSPersonalities 162 CFIndex index; 163 CFNumberRef readSubTypeID; 164 for (index = 0; index < numPersonalities; index++) { 165 if ((true == CFDictionaryGetValueIfPresent(values[index], (const void *)KEY_FS_SUBTYPE, (const void **)&readSubTypeID)) && 166 (CFNumberCompare(subTypeID, readSubTypeID, NULL) == 0)) { 167 FSNameKey = keys[index]; 168 break; 169 } 170 } 171 172 CFRelease(subTypeID); 173 174 /* If a personality hasn't been found, use the last value in the dictionary (note the content of CFDictionary is unordered so choosing the last doesn't produce consistent result) */ 175 if (NULL == FSNameKey) { 176 FSNameKey = keys[numPersonalities - 1]; // is selecting the last entry right ? 177 } 178 179 // Get FSName from the FSPersonalities entry 180 CFDictionaryRef FSNameDict; 181 if (localized == true) { 182 FSNameDict = CFDictionaryGetValue(localPersonalities, FSNameKey); 183 } else { 184 FSNameDict = CFDictionaryGetValue(globalPersonalities, FSNameKey); 185 } 186 if (NULL != FSNameDict) { 187 CFStringRef tempName = CFDictionaryGetValue(FSNameDict, (const void *)KEY_FS_NAME); 188 CFStringRef encrName = CFDictionaryGetValue(FSNameDict, CFSTR(kFSCoreStorageEncryptNameKey)); 189 if (tempName) { 190 if (encrName) { 191 formatName = (void*)CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 192 if (formatName != NULL) { 193 (void)CFDictionarySetValue((void*)formatName, tempName, encrName); 194 } 195 } else { 196 formatName = tempName; 197 } 198 } 199 } 200 201 if (values != valuesBuffer) free(values); 202 if (keys != keysBuffer) free(keys); 203 } 204 } 205 206 // If all failed, return "Unknown format (f_fstypename)" as the last resort 207 if (NULL == formatName) { 208 static CFStringRef unknownTypeString = NULL; 209 CFStringRef unknownFSNameString = NULL; 210 211 // This should use the framework bundle this code resides. CarbonCore ??? */ 212 if (NULL == unknownTypeString) unknownTypeString = CFCopyLocalizedString(UNKNOWN_FS_NAME, "This string is displayed when localized file system name cannot be determined."); 213 214 unknownFSNameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (%@)"), unknownTypeString, fsType); 215 formatName = (void*)unknownFSNameString; 216 } 217 218 // Cache the result 219 OSSpinLockLock(&__FSLocalizedNameTableLock); 220 if (NULL == __FSLocalizedNameTable) __FSLocalizedNameTable = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 221// NSLog(CFSTR("Setting value %@ for key %@\n"), formatName, formatNameTableKey); 222 CFDictionarySetValue(__FSLocalizedNameTable, (const void *)formatNameTableKey, (const void *)formatName); 223 OSSpinLockUnlock(&__FSLocalizedNameTableLock); 224// NSLog(CFSTR("Localized Name Table = %@\n"), __FSLocalizedNameTable); 225 226 if (NULL != bundle) CFRelease(bundle); // it has to be released here since formatName might be owned by the bundle 227 } 228 229 CFRelease(formatNameTableKey); 230 231 if (CFGetTypeID(formatName) == CFStringGetTypeID()) { 232 return CFRetain(formatName); 233 } else if (CFGetTypeID(formatName) == CFDictionaryGetTypeID()) { 234 // Dictionary with the (possibly localized) name as the key, and the encrypted name as the value 235 // If we want the encrypted name, we return the value, else we return the key 236 size_t numEntries = CFDictionaryGetCount((void*)formatName); 237 void *keyNames[numEntries]; 238 void *values[numEntries]; 239 CFDictionaryGetKeysAndValues((void*)formatName, (const void**)&keyNames, (const void**)&values); 240 if (encrypted) 241 return CFRetain(values[0]); 242 else 243 return CFRetain(keyNames[0]); 244 } 245 246 return CFRetain(formatName); 247} 248 249CFStringRef _FSCopyLocalizedNameForVolumeFormatAtURL(CFURLRef url) 250{ 251 CFStringRef formatName = NULL; 252 uint8_t buffer[MAXPATHLEN + 1]; 253 254 if ((NULL != url) && CFURLGetFileSystemRepresentation(url, true, buffer, MAXPATHLEN)) { 255 struct statfs fsInfo; 256 bool encrypted = false; 257 258 if (statfs((char *)buffer, &fsInfo) == 0) { 259 CFStringRef fsType = CFStringCreateWithCString(NULL, fsInfo.f_fstypename, kCFStringEncodingASCII); 260 261 encrypted = IsEncrypted(fsInfo.f_mntfromname); 262#ifdef _DARWIN_FEATURE_64_BIT_INODE 263 formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_fssubtype, true, encrypted); 264#else 265 formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_reserved1, true, encrypted); 266#endif 267 268 CFRelease(fsType); 269 } 270 } 271 272 return formatName; 273} 274 275CFStringRef _FSCopyNameForVolumeFormatAtURL(CFURLRef url) 276{ 277 CFStringRef formatName = NULL; 278 uint8_t buffer[MAXPATHLEN + 1]; 279 280 if ((NULL != url) && CFURLGetFileSystemRepresentation(url, true, buffer, MAXPATHLEN)) { 281 struct statfs fsInfo; 282 283 if (statfs((char *)buffer, &fsInfo) == 0) { 284 CFStringRef fsType = CFStringCreateWithCString(NULL, fsInfo.f_fstypename, kCFStringEncodingASCII); 285 bool encrypted = false; 286 287 encrypted = IsEncrypted(fsInfo.f_mntfromname); 288 289#ifdef _DARWIN_FEATURE_64_BIT_INODE 290 formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_fssubtype, false, encrypted); 291#else 292 formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_reserved1, false, encrypted); 293#endif 294 295 CFRelease(fsType); 296 } 297 } 298 299 return formatName; 300} 301 302CFStringRef _FSCopyLocalizedNameForVolumeFormatAtNode(CFStringRef devnode) 303{ 304 CFStringRef formatName = NULL; 305 char devnodename[MAXPATHLEN + 1]; 306 char fsname[MAX_FSNAME]; 307 int fssubtype = 0; 308 309 /* convert CFStringRef devnode to CSTR */ 310 if (true == CFStringGetCString(devnode, devnodename, MAXPATHLEN + 1, kCFStringEncodingUTF8)) { 311 bool encrypted = false; 312 313 encrypted = IsEncrypted(devnodename); 314 315 /* get fsname and fssubtype */ 316 memset(fsname, MAX_FSNAME, 0); 317 if (getfstype(devnodename, fsname, &fssubtype) == true) { 318 319 /* get unlocalized string */ 320 CFStringRef fsType = CFStringCreateWithCString(NULL, fsname, kCFStringEncodingASCII); 321 formatName = FSCopyFormatNameForFSType(fsType, fssubtype, true, encrypted); 322 CFRelease(fsType); 323 } 324 } 325 return formatName; 326} 327 328CFStringRef _FSCopyNameForVolumeFormatAtNode(CFStringRef devnode) 329{ 330 CFStringRef formatName = NULL; 331 char devnodename[MAXPATHLEN + 1]; 332 char fsname[MAX_FSNAME]; 333 int fssubtype = 0; 334 335 /* convert CFStringRef devnode to CSTR */ 336 if (true == CFStringGetCString(devnode, devnodename, MAXPATHLEN + 1, kCFStringEncodingUTF8)) { 337 bool encrypted; 338 339 encrypted = IsEncrypted(devnodename); 340 /* get fsname and fssubtype */ 341 memset(fsname, MAX_FSNAME, 0); 342 if (getfstype(devnodename, fsname, &fssubtype) == true) { 343 344 /* get unlocalized string */ 345 CFStringRef fsType = CFStringCreateWithCString(NULL, fsname, kCFStringEncodingASCII); 346 formatName = FSCopyFormatNameForFSType(fsType, fssubtype, false, encrypted); 347 CFRelease(fsType); 348 } 349 } 350 return formatName; 351} 352 353/* Return the fsname and subtype number for devnode */ 354bool getfstype(char *devnode, char *fsname, int *fssubtype) 355{ 356 /* Check if HFS */ 357 if (is_hfs(devnode, fssubtype) == true) { 358 strcpy(fsname, HFS_NAME); 359 return true; 360 } 361 362 /* Check if MSDOS */ 363 if (is_msdos(devnode, fssubtype) == true) { 364 strcpy(fsname, MSDOS_NAME); 365 return true; 366 } 367 368 return false; 369} 370 371#define SW16(x) OSSwapBigToHostInt16(x) 372#define SW32(x) OSSwapBigToHostInt32(x) 373 374/* Check if the disk is HFS disk and return its subtypes */ 375bool is_hfs(char *devnode, int *fssubtype) 376{ 377 HFSPlusVolumeHeader *vhp; 378 off_t offset = 0; 379 char *buffer = NULL; 380 int fd = 0; 381 bool retval = false; 382 383 /* default fssubtype to non-existing value */ 384 *fssubtype = -1; 385 386 buffer = (char *)malloc(MAX_HFS_BLOCK_READ); 387 if (!buffer) { 388 goto out; 389 } 390 391 /* open the device */ 392 fd = open(devnode, O_RDONLY | O_NDELAY, 0); 393 if (fd <= 0) { 394 goto out; 395 } 396 397 /* read volume header (512 bytes, block 2) from the device */ 398 if (getblk(fd, 2, MAX_HFS_BLOCK_READ, buffer) < MAX_HFS_BLOCK_READ) { 399 goto out; 400 } 401 402 /* Check if it is a HFS volume */ 403 if (getwrapper((HFSMasterDirectoryBlock *)buffer, &offset)) { 404 if (getblk(fd, 2 + (offset/MAX_HFS_BLOCK_READ), MAX_HFS_BLOCK_READ, buffer) < MAX_HFS_BLOCK_READ) { 405 goto out; 406 } 407 } 408 409 vhp = (HFSPlusVolumeHeader *)buffer; 410 411 /* Validate signature */ 412 switch (SW16(vhp->signature)) { 413 case kHFSPlusSigWord: { 414 if (SW16(vhp->version) != kHFSPlusVersion) { 415 goto out; 416 } 417 break; 418 } 419 420 case kHFSXSigWord: { 421 if (SW16(vhp->version) != kHFSXVersion) { 422 goto out; 423 } 424 break; 425 } 426 427 case kHFSSigWord: { 428 /* HFS */ 429 *fssubtype = kHFSSubType; 430 retval = true; 431 goto out; 432 } 433 434 default: { 435 goto out; 436 } 437 }; 438 439 if ((vhp->journalInfoBlock != 0) && (SW32(vhp->attributes) & kHFSVolumeJournaledMask)) { 440 /* Journaled */ 441 *fssubtype = kHFSJSubType; 442 } 443 444 if (SW16(vhp->signature) == kHFSXSigWord) { 445 BTHeaderRec * bthp; 446 off_t foffset; 447 448 foffset = (off_t)SW32(vhp->catalogFile.extents[0].startBlock) * (off_t)SW32(vhp->blockSize); 449 if (getblk(fd, (offset/MAX_HFS_BLOCK_READ) + (foffset/MAX_HFS_BLOCK_READ) , MAX_HFS_BLOCK_READ, buffer) < MAX_HFS_BLOCK_READ) { 450 goto out; 451 } 452 453 bthp = (BTHeaderRec *)&buffer[sizeof(BTNodeDescriptor)]; 454 455 if ((SW16(bthp->maxKeyLength) == kHFSPlusCatalogKeyMaximumLength) && 456 (bthp->keyCompareType == kHFSBinaryCompare)) { 457 /* HFSX */ 458 if (*fssubtype == kHFSJSubType) { 459 /* Journaled HFSX */ 460 *fssubtype = kHFSXJSubType; 461 } else { 462 /* HFSX */ 463 *fssubtype = kHFSXSubType; 464 } 465 } 466 } 467 468 if (*fssubtype < 0) { 469 /* default HFS Plus */ 470 *fssubtype = kHFSPlusSubType; 471 } 472 473 retval = true; 474 475out: 476 if (buffer) { 477 free(buffer); 478 } 479 if (fd > 0) { 480 close(fd); 481 } 482 return retval; 483} 484 485/* Check if the disk is MSDOS disk and return its subtypes */ 486bool is_msdos(char *devnode, int *fssubtype) 487{ 488 union bootsector *bsp; 489 struct byte_bpb710 *b710; 490 u_int32_t FATSectors; 491 u_int32_t TotalSectors; 492 u_int32_t countOfClusters; 493 u_int32_t DataSectors; 494 u_int32_t RootDirSectors; 495 u_int16_t BytesPerSector; 496 u_int8_t SectorsPerCluster; 497 char *buffer = NULL; 498 int fd = 0; 499 bool retval = false; 500 501 /* default fssubtype to non-existing value */ 502 *fssubtype = -1; 503 504 buffer = (char *)malloc(MAX_DOS_BLOCKSIZE); 505 if (!buffer) { 506 goto out; 507 } 508 509 /* open the device */ 510 fd = open(devnode, O_RDONLY | O_NDELAY, 0); 511 if (fd <= 0) { 512 goto out; 513 } 514 515 /* read the block */ 516 if (getblk(fd, 0, MAX_DOS_BLOCKSIZE, buffer) < MAX_DOS_BLOCKSIZE) { 517 goto out; 518 } 519 520 bsp = (union bootsector *)buffer; 521 b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 522 523 /* The first three bytes are an Intel x86 jump instruction. It should be one 524 * of the following forms: 525 * 0xE9 0x?? 0x?? 526 * 0xEC 0x?? 0x90 527 * where 0x?? means any byte value is OK. 528 */ 529 if (bsp->bs50.bsJump[0] != 0xE9 530 && (bsp->bs50.bsJump[0] != 0xEB || bsp->bs50.bsJump[2] != 0x90)) { 531 goto out; 532 } 533 534 /* We only work with 512, 1024, and 2048 byte sectors */ 535 BytesPerSector = getushort(b710->bpbBytesPerSec); 536 if ((BytesPerSector < 0x200) || (BytesPerSector & (BytesPerSector - 1)) || (BytesPerSector > 0x800)) { 537 goto out; 538 } 539 540 /* Check to make sure valid sectors per cluster */ 541 SectorsPerCluster = b710->bpbSecPerClust; 542 if ((SectorsPerCluster == 0 ) || (SectorsPerCluster & (SectorsPerCluster - 1))) { 543 goto out; 544 } 545 546 RootDirSectors = ((getushort(b710->bpbRootDirEnts) * 32) + (BytesPerSector - 1)) / BytesPerSector; 547 548 if (getushort(b710->bpbFATsecs)) { 549 FATSectors = getushort(b710->bpbFATsecs); 550 } else { 551 FATSectors = getulong(b710->bpbBigFATsecs); 552 } 553 554 if (getushort(b710->bpbSectors)) { 555 TotalSectors = getushort(b710->bpbSectors); 556 } else { 557 TotalSectors = getulong(b710->bpbHugeSectors); 558 } 559 560 DataSectors = TotalSectors - (getushort(b710->bpbResSectors) + (b710->bpbFATs * FATSectors) + RootDirSectors); 561 562 countOfClusters = DataSectors/(b710->bpbSecPerClust); 563 564 if (countOfClusters < 4085) { 565 /* FAT12 */ 566 *fssubtype = 0; 567 } else if (countOfClusters < 65525) { 568 /* FAT16 */ 569 *fssubtype = 1; 570 } else { 571 /* FAT32 */ 572 *fssubtype = 2; 573 } 574 575 retval = true; 576 577out: 578 if (buffer) { 579 free(buffer); 580 } 581 if (fd > 0) { 582 close(fd); 583 } 584 return retval; 585} 586 587/* read raw block from disk */ 588static int getblk(int fd, unsigned long blknum, int blksize, char* buf) 589{ 590 off_t offset; 591 int bytes_read; 592 593 offset = (off_t)blknum * (off_t)blksize; 594 595 if ((bytes_read = pread(fd, buf, blksize, offset)) != blksize) { 596 return (-1); 597 } 598 599 return (bytes_read); 600} 601 602/* get HFS wrapper information */ 603static int getwrapper(const HFSMasterDirectoryBlock *mdbp, off_t *offset) 604{ 605 if ((SW16(mdbp->drSigWord) != kHFSSigWord) || 606 (SW16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) { 607 return(0); 608 } 609 *offset = SW16(mdbp->drAlBlSt) * 512; 610 *offset += (u_int64_t)SW16(mdbp->drEmbedExtent.startBlock) * (u_int64_t)SW32(mdbp->drAlBlkSiz); 611 612 return (1); 613} 614 615static bool 616IsEncrypted(const char *bsdname) 617{ 618 bool retval = false; 619 const char *diskname = NULL; 620 CFMutableDictionaryRef ioMatch; //IOServiceGetMatchingService() releases:! 621 io_object_t ioObj = IO_OBJECT_NULL; 622 CFBooleanRef lvfIsEncr = NULL; 623 624 if (strncmp(bsdname, _PATH_DEV, strlen(_PATH_DEV)) == 0) { 625 diskname = bsdname + strlen(_PATH_DEV); 626 } 627 628 if (diskname == NULL) 629 goto finish; 630 631 if (strncmp(diskname, "rdisk", 5) == 0) 632 diskname++; 633 634 //look up the IOMedia object 635 ioMatch = IOBSDNameMatching(kIOMasterPortDefault, 0, diskname); 636 if (!ioMatch) 637 goto finish; 638 639 // Setting this allows a fast-path lookup to happen 640 // see 10248763 641 CFDictionarySetValue(ioMatch, CFSTR(kIOProviderClassKey), CFSTR(kIOMediaClass)); 642 643 ioObj = IOServiceGetMatchingService(kIOMasterPortDefault, ioMatch); 644 ioMatch = NULL; 645 //IOServiceGetMatching() released ioMatch 646 if (ioObj == IO_OBJECT_NULL) { 647 goto finish; 648 } 649 lvfIsEncr = IORegistryEntryCreateCFProperty(ioObj, CFSTR(kCoreStorageIsEncryptedKey), nil, 0); 650 if (lvfIsEncr == NULL) 651 retval = false; 652 else 653 retval = CFBooleanGetValue(lvfIsEncr); 654 655finish: 656 if (lvfIsEncr) 657 CFRelease(lvfIsEncr); 658 if (ioObj != IO_OBJECT_NULL) { 659 IOObjectRelease(ioObj); 660 } 661 return retval; 662} 663