#include <errno.h>
#include <libkern/OSByteOrder.h>
#include <stdio.h>
#include <unistd.h>
#include <paths.h>
#include <sys/disk.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <fsproperties.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/CoreStorage/CoreStorageUserLib.h>
#include <IOKit/IOKitLib.h>
#include "FSFormatName.h"
static CFMutableDictionaryRef __FSLocalizedNameTable = NULL;
static OSSpinLock __FSLocalizedNameTableLock = 0;
static bool IsEncrypted(const char *bsdname);
CFStringRef FSCopyFormatNameForFSType(CFStringRef fsType, int16_t fsSubtype, bool localized, bool encrypted)
{
CFTypeRef formatName;
CFStringRef formatNameTableKey;
CFIndex indx;
if (NULL == fsType) return NULL;
formatNameTableKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d%@%d"), (localized ? 1 : 0), fsType, fsSubtype);
OSSpinLockLock(&__FSLocalizedNameTableLock);
formatName = (void*)((NULL == __FSLocalizedNameTable) ? NULL : CFDictionaryGetValue(__FSLocalizedNameTable, (const void *)formatNameTableKey));
OSSpinLockUnlock(&__FSLocalizedNameTableLock);
if (NULL == formatName) { CFBundleRef bundle = NULL;
CFURLRef bundleURL;
CFStringRef fsTypeName;
static CFArrayRef searchPaths = NULL;
if (NULL == searchPaths) {
CFArrayRef tmpPaths = CFCopySearchPathForDirectoriesInDomains(kCFLibraryDirectory, kCFSystemDomainMask | kCFNetworkDomainMask | kCFLocalDomainMask, true);
CFMutableArrayRef tmpStrings;
CFIndex i;
if (NULL == tmpPaths)
return NULL;
tmpStrings = CFArrayCreateMutable(NULL, CFArrayGetCount(tmpPaths), NULL);
if (tmpStrings == NULL)
goto done;
for (i = 0; i < CFArrayGetCount(tmpPaths); i++) {
CFStringRef tStr;
CFURLRef tURL;
char path[PATH_MAX + 1];
CFTypeRef tobject = CFArrayGetValueAtIndex(tmpPaths, i);
if (CFGetTypeID(tobject) == CFURLGetTypeID()) {
if (false ==
CFURLGetFileSystemRepresentation(
tobject,
false,
(UInt8*)path,
sizeof(path))) {
goto done;
}
} else if (CFGetTypeID(tobject) == CFStringGetTypeID()) {
CFStringGetCString(tobject, path, sizeof(path), kCFStringEncodingUTF8);
} else {
goto done;
}
strlcat(path, "/Filesystems", sizeof(path));
tStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
if (tStr == NULL)
goto done;
tURL = CFURLCreateWithFileSystemPath(NULL, tStr, kCFURLPOSIXPathStyle, true);
if (tURL) {
CFArrayAppendValue(tmpStrings, tURL);
}
CFRelease(tStr);
}
searchPaths = CFArrayCreateCopy(NULL, tmpStrings);
done:
CFRelease(tmpStrings);
CFRelease(tmpPaths);
if (searchPaths == NULL)
return NULL;
}
for (indx = 0; indx < CFArrayGetCount(searchPaths); indx++) {
CFURLRef libRef = CFArrayGetValueAtIndex(searchPaths, indx);
fsTypeName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.fs"), fsType);
bundleURL = CFURLCreateWithFileSystemPathRelativeToBase(NULL, fsTypeName, kCFURLPOSIXPathStyle, true, libRef);
bundle = CFBundleCreate(NULL, bundleURL);
CFRelease(fsTypeName);
CFRelease(bundleURL);
if (NULL != bundle) {
break;
}
}
if (NULL != bundle) { CFDictionaryRef localPersonalities = NULL;
CFDictionaryRef bundleDict = CFBundleGetInfoDictionary(bundle);
if (localized == true) {
localPersonalities = CFBundleGetValueForInfoDictionaryKey(bundle, KEY_FS_PERSONALITIES);
}
CFDictionaryRef globalPersonalities = CFDictionaryGetValue(bundleDict, (const void *) KEY_FS_PERSONALITIES);
CFIndex numPersonalities;
if (((NULL != localPersonalities) || (localized == false)) && (NULL != globalPersonalities) &&
((numPersonalities = CFDictionaryGetCount(globalPersonalities)) > 0)) {
CFDictionaryRef valuesBuffer[MAX_FS_SUBTYPES];
CFStringRef keysBuffer[MAX_FS_SUBTYPES];
CFDictionaryRef *values = ((numPersonalities > MAX_FS_SUBTYPES) ? (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * numPersonalities) : valuesBuffer);
CFStringRef *keys = ((numPersonalities > MAX_FS_SUBTYPES) ? (CFStringRef *)malloc(sizeof(CFStringRef) * numPersonalities) : keysBuffer);
CFDictionaryGetKeysAndValues(globalPersonalities, (const void **)keys, (const void **)values);
CFNumberRef subTypeID = CFNumberCreate(NULL, kCFNumberSInt16Type, (const void *)&fsSubtype);
CFStringRef FSNameKey = NULL;
CFIndex index;
CFNumberRef readSubTypeID;
for (index = 0; index < numPersonalities; index++) {
if ((true == CFDictionaryGetValueIfPresent(values[index], (const void *)KEY_FS_SUBTYPE, (const void **)&readSubTypeID)) &&
(CFNumberCompare(subTypeID, readSubTypeID, NULL) == 0)) {
FSNameKey = keys[index];
break;
}
}
CFRelease(subTypeID);
if (NULL == FSNameKey) {
FSNameKey = keys[numPersonalities - 1]; }
CFDictionaryRef FSNameDict;
if (localized == true) {
FSNameDict = CFDictionaryGetValue(localPersonalities, FSNameKey);
} else {
FSNameDict = CFDictionaryGetValue(globalPersonalities, FSNameKey);
}
if (NULL != FSNameDict) {
CFStringRef tempName = CFDictionaryGetValue(FSNameDict, (const void *)KEY_FS_NAME);
CFStringRef encrName = CFDictionaryGetValue(FSNameDict, CFSTR(kFSEncryptNameKey));
if (tempName) {
if (encrName) {
formatName = (void*)CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (formatName != NULL) {
(void)CFDictionarySetValue((void*)formatName, tempName, encrName);
}
} else {
formatName = tempName;
}
}
}
if (values != valuesBuffer) free(values);
if (keys != keysBuffer) free(keys);
}
}
if (NULL == formatName) {
static CFStringRef unknownTypeString = NULL;
CFStringRef unknownFSNameString = NULL;
if (NULL == unknownTypeString) unknownTypeString = CFCopyLocalizedString(UNKNOWN_FS_NAME, "This string is displayed when localized file system name cannot be determined.");
unknownFSNameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ (%@)"), unknownTypeString, fsType);
formatName = (void*)unknownFSNameString;
}
OSSpinLockLock(&__FSLocalizedNameTableLock);
if (NULL == __FSLocalizedNameTable) __FSLocalizedNameTable = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(__FSLocalizedNameTable, (const void *)formatNameTableKey, (const void *)formatName);
OSSpinLockUnlock(&__FSLocalizedNameTableLock);
if (NULL != bundle) CFRelease(bundle); }
CFRelease(formatNameTableKey);
if (CFGetTypeID(formatName) == CFStringGetTypeID()) {
return CFRetain(formatName);
} else if (CFGetTypeID(formatName) == CFDictionaryGetTypeID()) {
size_t numEntries = CFDictionaryGetCount((void*)formatName);
void *keyNames[numEntries];
void *values[numEntries];
CFDictionaryGetKeysAndValues((void*)formatName, (const void**)&keyNames, (const void**)&values);
if (encrypted)
return CFRetain(values[0]);
else
return CFRetain(keyNames[0]);
}
return CFRetain(formatName);
}
CFStringRef _FSCopyLocalizedNameForVolumeFormatAtURL(CFURLRef url)
{
CFStringRef formatName = NULL;
uint8_t buffer[MAXPATHLEN + 1];
if ((NULL != url) && CFURLGetFileSystemRepresentation(url, true, buffer, MAXPATHLEN)) {
struct statfs fsInfo;
bool encrypted = false;
if (statfs((char *)buffer, &fsInfo) == 0) {
CFStringRef fsType = CFStringCreateWithCString(NULL, fsInfo.f_fstypename, kCFStringEncodingASCII);
encrypted = IsEncrypted(fsInfo.f_mntfromname);
#ifdef _DARWIN_FEATURE_64_BIT_INODE
formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_fssubtype, true, encrypted);
#else
formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_reserved1, true, encrypted);
#endif
CFRelease(fsType);
}
}
return formatName;
}
CFStringRef _FSCopyNameForVolumeFormatAtURL(CFURLRef url)
{
CFStringRef formatName = NULL;
uint8_t buffer[MAXPATHLEN + 1];
if ((NULL != url) && CFURLGetFileSystemRepresentation(url, true, buffer, MAXPATHLEN)) {
struct statfs fsInfo;
if (statfs((char *)buffer, &fsInfo) == 0) {
CFStringRef fsType = CFStringCreateWithCString(NULL, fsInfo.f_fstypename, kCFStringEncodingASCII);
bool encrypted = false;
encrypted = IsEncrypted(fsInfo.f_mntfromname);
#ifdef _DARWIN_FEATURE_64_BIT_INODE
formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_fssubtype, false, encrypted);
#else
formatName = FSCopyFormatNameForFSType(fsType, fsInfo.f_reserved1, false, encrypted);
#endif
CFRelease(fsType);
}
}
return formatName;
}
CFStringRef _FSCopyLocalizedNameForVolumeFormatAtNode(CFStringRef devnode)
{
CFStringRef formatName = NULL;
char devnodename[MAXPATHLEN + 1];
char fsname[MAX_FSNAME];
int fssubtype = 0;
if (true == CFStringGetCString(devnode, devnodename, MAXPATHLEN + 1, kCFStringEncodingUTF8)) {
bool encrypted = false;
encrypted = IsEncrypted(devnodename);
memset(fsname, 0, MAX_FSNAME);
if (getfstype(devnodename, fsname, &fssubtype) == true) {
CFStringRef fsType = CFStringCreateWithCString(NULL, fsname, kCFStringEncodingASCII);
formatName = FSCopyFormatNameForFSType(fsType, fssubtype, true, encrypted);
CFRelease(fsType);
}
}
return formatName;
}
CFStringRef _FSCopyNameForVolumeFormatAtNode(CFStringRef devnode)
{
CFStringRef formatName = NULL;
char devnodename[MAXPATHLEN + 1];
char fsname[MAX_FSNAME];
int fssubtype = 0;
if (true == CFStringGetCString(devnode, devnodename, MAXPATHLEN + 1, kCFStringEncodingUTF8)) {
bool encrypted;
encrypted = IsEncrypted(devnodename);
memset(fsname, 0, MAX_FSNAME);
if (getfstype(devnodename, fsname, &fssubtype) == true) {
CFStringRef fsType = CFStringCreateWithCString(NULL, fsname, kCFStringEncodingASCII);
formatName = FSCopyFormatNameForFSType(fsType, fssubtype, false, encrypted);
CFRelease(fsType);
}
}
return formatName;
}
bool getfstype(char *devnode, char *fsname, int *fssubtype)
{
if (is_apfs(devnode, fssubtype) == true) {
strcpy(fsname, APFS_NAME);
return true;
}
if (is_hfs(devnode, fssubtype) == true) {
strcpy(fsname, HFS_NAME);
return true;
}
if (is_msdos(devnode, fssubtype) == true) {
strcpy(fsname, MSDOS_NAME);
return true;
}
return false;
}
bool is_apfs(char *devnode, int *fssubtype)
{
bool result = false;
io_object_t ioObj = IO_OBJECT_NULL;
char * bsdName = NULL;
if (!strncmp(devnode, "/dev/r", 6)) {
bsdName = &devnode[6];
} else if (!strncmp(devnode, "/dev/", 5)) {
bsdName = &devnode[5];
} else {
bsdName = devnode;
}
ioObj = IOServiceGetMatchingService (
kIOMasterPortDefault,
IOBSDNameMatching ( kIOMasterPortDefault, 0, bsdName ) );
if (ioObj != IO_OBJECT_NULL) {
if (IOObjectConformsTo(ioObj, "AppleAPFSVolume")) {
if (NULL != fssubtype)
*fssubtype = kAPFSSubType;
result = true;
CFBooleanRef sensitivity = ( CFBooleanRef ) IORegistryEntrySearchCFProperty (
ioObj,
kIOServicePlane,
CASE_SENSITIVE,
kCFAllocatorDefault,
0 );
if (sensitivity) {
if (CFEqual(sensitivity, kCFBooleanTrue) && (NULL != fssubtype)) {
*fssubtype = kAPFSXSubType;
}
CFRelease(sensitivity);
}
}
IOObjectRelease(ioObj);
}
return result;
}
#define SW16(x) OSSwapBigToHostInt16(x)
#define SW32(x) OSSwapBigToHostInt32(x)
bool is_hfs(char *devnode, int *fssubtype)
{
HFSPlusVolumeHeader *vhp;
off_t hfs_plus_data_offset = 0;
char *buffer = NULL;
int fd = 0;
bool retval = false;
size_t block_size = 0;
*fssubtype = -1;
fd = open(devnode, O_RDONLY | O_NDELAY, 0);
if (fd <= 0) {
goto out;
}
if (ioctl(fd, DKIOCGETBLOCKSIZE, &block_size) == -1) {
block_size = DEV_BSIZE; }
if (block_size > MAX_HFS_BLOCKSIZE) {
goto out;
}
buffer = (char *)malloc(block_size);
if (!buffer) {
goto out;
}
if (readdisk(fd, 1024, sizeof(HFSPlusVolumeHeader), block_size, buffer)
< sizeof(HFSPlusVolumeHeader)) {
goto out;
}
if (getwrapper((HFSMasterDirectoryBlock *)buffer, &hfs_plus_data_offset)) {
off_t volume_header_offset = 1024 + hfs_plus_data_offset;
if (readdisk(fd, volume_header_offset, sizeof(HFSPlusVolumeHeader), block_size, buffer)
< sizeof(HFSPlusVolumeHeader)) {
goto out;
}
}
vhp = (HFSPlusVolumeHeader *)buffer;
switch (SW16(vhp->signature)) {
case kHFSPlusSigWord: {
if (SW16(vhp->version) != kHFSPlusVersion) {
goto out;
}
break;
}
case kHFSXSigWord: {
if (SW16(vhp->version) != kHFSXVersion) {
goto out;
}
break;
}
case kHFSSigWord: {
*fssubtype = kHFSSubType;
retval = true;
goto out;
}
default: {
goto out;
}
};
if ((vhp->journalInfoBlock != 0) && (SW32(vhp->attributes) & kHFSVolumeJournaledMask)) {
*fssubtype = kHFSJSubType;
}
if (SW16(vhp->signature) == kHFSXSigWord) {
BTHeaderRec * bthp;
off_t foffset;
foffset = (off_t)SW32(vhp->catalogFile.extents[0].startBlock) * (off_t)SW32(vhp->blockSize);
if (readdisk(fd, hfs_plus_data_offset + foffset, sizeof(BTHeaderRec) + sizeof(BTNodeDescriptor), block_size, buffer)
< sizeof(BTHeaderRec) + sizeof(BTNodeDescriptor)) {
goto out;
}
bthp = (BTHeaderRec *)&buffer[sizeof(BTNodeDescriptor)];
if ((SW16(bthp->maxKeyLength) == kHFSPlusCatalogKeyMaximumLength) &&
(bthp->keyCompareType == kHFSBinaryCompare)) {
if (*fssubtype == kHFSJSubType) {
*fssubtype = kHFSXJSubType;
} else {
*fssubtype = kHFSXSubType;
}
}
}
if (*fssubtype < 0) {
*fssubtype = kHFSPlusSubType;
}
retval = true;
out:
if (buffer) {
free(buffer);
}
if (fd > 0) {
close(fd);
}
return retval;
}
bool is_msdos(char *devnode, int *fssubtype)
{
union bootsector *bsp;
struct byte_bpb710 *b710;
u_int32_t FATSectors;
u_int32_t TotalSectors;
u_int32_t countOfClusters;
u_int32_t DataSectors;
u_int32_t RootDirSectors;
u_int16_t BytesPerSector;
u_int8_t SectorsPerCluster;
size_t block_size = 0;
char *buffer = NULL;
int fd = 0;
bool retval = false;
*fssubtype = -1;
buffer = (char *)malloc(MAX_DOS_BLOCKSIZE);
if (!buffer) {
goto out;
}
fd = open(devnode, O_RDONLY | O_NDELAY, 0);
if (fd <= 0) {
goto out;
}
if (ioctl(fd, DKIOCGETBLOCKSIZE, &block_size) == -1) {
block_size = DEV_BSIZE; }
if (block_size > MAX_DOS_BLOCKSIZE) {
goto out;
}
if (readdisk(fd, 0, sizeof(union bootsector), block_size, buffer) < sizeof(union bootsector)) {
goto out;
}
bsp = (union bootsector *)buffer;
b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
if (bsp->bs50.bsJump[0] != 0xE9
&& (bsp->bs50.bsJump[0] != 0xEB || bsp->bs50.bsJump[2] != 0x90)) {
goto out;
}
BytesPerSector = getushort(b710->bpbBytesPerSec);
if ((BytesPerSector < 0x200) || (BytesPerSector & (BytesPerSector - 1)) || (BytesPerSector > 0x800)) {
goto out;
}
SectorsPerCluster = b710->bpbSecPerClust;
if ((SectorsPerCluster == 0 ) || (SectorsPerCluster & (SectorsPerCluster - 1))) {
goto out;
}
RootDirSectors = ((getushort(b710->bpbRootDirEnts) * 32) + (BytesPerSector - 1)) / BytesPerSector;
if (getushort(b710->bpbFATsecs)) {
FATSectors = getushort(b710->bpbFATsecs);
} else {
FATSectors = getulong(b710->bpbBigFATsecs);
}
if (getushort(b710->bpbSectors)) {
TotalSectors = getushort(b710->bpbSectors);
} else {
TotalSectors = getulong(b710->bpbHugeSectors);
}
DataSectors = TotalSectors - (getushort(b710->bpbResSectors) + (b710->bpbFATs * FATSectors) + RootDirSectors);
countOfClusters = DataSectors/(b710->bpbSecPerClust);
if (countOfClusters < 4085) {
*fssubtype = 0;
} else if (countOfClusters < 65525) {
*fssubtype = 1;
} else {
*fssubtype = 2;
}
retval = true;
out:
if (buffer) {
free(buffer);
}
if (fd > 0) {
close(fd);
}
return retval;
}
static int getblk(int fd, unsigned long blknum, int blksize, char* buf)
{
off_t offset;
int bytes_read;
offset = (off_t)blknum * (off_t)blksize;
if ((bytes_read = pread(fd, buf, blksize, offset)) != blksize) {
return (-1);
}
return (bytes_read);
}
ssize_t readdisk(int fd, off_t startaddr, size_t length, size_t blocksize, char* buf)
{
ssize_t bytes_read = 0;
size_t start_block = startaddr / blocksize;
size_t num_blocks_to_read = ((startaddr + length) / blocksize) - start_block + 1;
void* tmpbuf = malloc(num_blocks_to_read * blocksize);
void* bufaddr = tmpbuf;
ssize_t block_bytes_read;
for (size_t i = 0; i < num_blocks_to_read; i++, bufaddr += blocksize) {
block_bytes_read = getblk(fd, i + start_block, blocksize, bufaddr);
if (block_bytes_read != blocksize) {
goto cleanup;
}
bytes_read += block_bytes_read;
}
size_t tmpbuf_offset = startaddr - ((startaddr / blocksize) * blocksize);
memcpy(buf, tmpbuf + tmpbuf_offset, length);
cleanup:
free(tmpbuf);
return bytes_read;
}
static int getwrapper(const HFSMasterDirectoryBlock *mdbp, off_t *offset)
{
if ((SW16(mdbp->drSigWord) != kHFSSigWord) ||
(SW16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
return(0);
}
*offset = SW16(mdbp->drAlBlSt) * 512;
*offset += (u_int64_t)SW16(mdbp->drEmbedExtent.startBlock) * (u_int64_t)SW32(mdbp->drAlBlkSiz);
return (1);
}
static uint32_t
fsindex_parse(const char *device)
{
const char *cp = &device[strlen(device)];
int scale = 1, fsindex = 0;
while (--cp >= device && *cp >= '0' && *cp <= '9') {
fsindex += (*cp - '0') * scale;
scale *= 10;
}
return (cp > device && cp[0] == 's' && cp[-1] != '/') ? --fsindex : -1;
}
static bool
IsVEKStateEncrypted(io_object_t apfs_obj, const uint32_t fsindex)
{
OSStatus status;
io_connect_t port;
volume_vek_state_input io_input = {0};
volume_vek_state_output io_output = {0};
size_t o_size = sizeof(volume_vek_state_output);
status = IOServiceOpen(apfs_obj, mach_task_self(), 0, &port);
if (status != kIOReturnSuccess) {
return true;
}
io_input.index = fsindex;
status = IOConnectCallStructMethod(port, APFS_IOUC_VOLUME_GET_VEK_STATE, &io_input, sizeof(volume_vek_state_input),
&io_output, &o_size);
IOServiceClose(port);
if (status == kIOReturnSuccess) {
if (!(io_output.user_protected && !io_output.sys_protected)) {
return false;
}
}
return true;
}
static errno_t
get_lookup_io_obj(const char *bsdname, io_object_t *lookup_obj)
{
const char *diskname = bsdname;
CFMutableDictionaryRef ioMatch;
if (!bsdname || !lookup_obj)
return EINVAL;
*lookup_obj = IO_OBJECT_NULL;
if (strncmp(bsdname, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
diskname = bsdname + strlen(_PATH_DEV);
}
if (diskname == NULL)
return EINVAL;
if (strncmp(diskname, "rdisk", 5) == 0)
diskname++;
ioMatch = IOBSDNameMatching(kIOMasterPortDefault, 0, diskname);
if (!ioMatch)
return ENOENT;
CFDictionarySetValue(ioMatch, CFSTR(kIOProviderClassKey), CFSTR(kIOMediaClass));
*lookup_obj = IOServiceGetMatchingService(kIOMasterPortDefault, ioMatch);
return 0;
}
errno_t
GetFSEncryptionStatus(const char *bsdname, bool *encryption_status, bool require_FDE, fs_media_encryption_details_t *encryption_details)
{
bool fs_encrypted = false;
io_object_t lookup_obj = IO_OBJECT_NULL, parent_obj = IO_OBJECT_NULL;
CFBooleanRef lvfIsEncr = NULL, rolling;
errno_t error;
if (!encryption_status) {
return EINVAL;
}
error = get_lookup_io_obj(bsdname, &lookup_obj);
if (error) {
goto finish;
}
if (encryption_details)
*encryption_details = 0;
if (is_apfs((char*)bsdname, NULL)) {
lvfIsEncr = IORegistryEntryCreateCFProperty(lookup_obj, CFSTR(kAPFSEncryptedKey), kCFAllocatorDefault, 0);
if (lvfIsEncr != NULL && CFBooleanGetValue(lvfIsEncr) == true) {
const uint32_t fsindex = fsindex_parse(bsdname);
if (IORegistryEntryGetParentEntry(lookup_obj, kIOServicePlane, &parent_obj) == 0) {
if (IOObjectConformsTo(parent_obj, APFS_CONTAINER_CLASS)) {
if (IsVEKStateEncrypted(parent_obj, fsindex)) {
fs_encrypted = true;
if (encryption_details)
*encryption_details |= FS_MEDIA_FDE_ENCRYPTED;
} else if (!require_FDE) {
fs_encrypted = true;
}
}
IOObjectRelease(parent_obj);
}
if (encryption_details) {
rolling = IORegistryEntryCreateCFProperty(lookup_obj, CFSTR(kAPFSEncryptionRolling), kCFAllocatorDefault, 0);
if (rolling && CFBooleanGetValue(rolling) == true) {
*encryption_details |= FS_MEDIA_ENCRYPTION_CONVERTING;
CFRelease(rolling);
}
}
}
} else {
lvfIsEncr = IORegistryEntryCreateCFProperty(lookup_obj, CFSTR(kCoreStorageIsEncryptedKey), nil, 0);
if (lvfIsEncr != NULL) {
fs_encrypted = CFBooleanGetValue(lvfIsEncr);
}
}
*encryption_status = fs_encrypted;
finish:
if (lvfIsEncr)
CFRelease(lvfIsEncr);
if (lookup_obj != IO_OBJECT_NULL) {
IOObjectRelease(lookup_obj);
}
return error;
}
static bool
IsEncrypted(const char *bsdname)
{
bool fs_encrypted = false;
(void)GetFSEncryptionStatus(bsdname, &fs_encrypted, true, NULL);
return fs_encrypted;
}
errno_t
GetDiskImageEncryptionStatus(const char *bsdname, bool *encryption_status)
{
io_object_t lookup_obj = IO_OBJECT_NULL;
CFBooleanRef encrypted_property;
errno_t error;
if (!bsdname || !encryption_status) {
return EINVAL;
}
error = get_lookup_io_obj(bsdname, &lookup_obj);
if (error) {
goto finish;
}
encrypted_property = IORegistryEntrySearchCFProperty(lookup_obj,
kIOServicePlane,
CFSTR(kIOHDIXImageEncryptedProperty),
kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents);
if (encrypted_property) {
*encryption_status = (encrypted_property == kCFBooleanTrue);
CFRelease(encrypted_property);
} else {
*encryption_status = false;
}
finish:
if (lookup_obj != IO_OBJECT_NULL)
IOObjectRelease(lookup_obj);
return error;
}
errno_t
_FSGetMediaEncryptionStatusAtPath(const char *path, bool *encryption_status, fs_media_encryption_details_t *encryption_details)
{
bool fs_encrypted = false, di_encrypted = false;
errno_t error;
if (!path || !encryption_status) {
return EINVAL;
}
error = GetFSEncryptionStatus(path, &fs_encrypted, false, encryption_details);
if (error) {
return error;
}
if (!fs_encrypted || encryption_details) {
if (GetDiskImageEncryptionStatus(path, &di_encrypted) == 0) {
if (di_encrypted && encryption_details) {
*encryption_details |= FS_MEDIA_DEV_ENCRYPTED;
}
}
}
*encryption_status = (fs_encrypted || di_encrypted);
return 0;
}
errno_t
_FSGetMediaEncryptionStatus(CFStringRef devnode, bool *encryption_status, fs_media_encryption_details_t *encryption_details)
{
char bsdname[MAXPATHLEN + 1];
if (!CFStringGetCString(devnode, bsdname, MAXPATHLEN + 1, kCFStringEncodingUTF8)) {
return EINVAL;
}
return _FSGetMediaEncryptionStatusAtPath(bsdname, encryption_status, encryption_details);
}