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