--- /dev/null
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach_types.h>
+#include <sys/mount.h>
+#include <libkern/libkern.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/IOPlatformExpert.h>
+
+#include "hfs_iokit.h"
+#include "hfs.h"
+#include "hfs_dbg.h"
+
+#ifndef panic_on_assert
+bool panic_on_assert;
+#endif
+
+#if DEBUG
+bool hfs_corruption_panics = true;
+#endif
+
+class com_apple_filesystems_hfs : public IOService {
+ OSDeclareDefaultStructors(com_apple_filesystems_hfs)
+
+public:
+
+ bool start(IOService *provider) override;
+ void stop(IOService *provider) override;
+
+protected:
+ vfstable_t vfs_handle;
+};
+
+#define super IOService
+OSDefineMetaClassAndStructors(com_apple_filesystems_hfs, IOService)
+
+extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
+#if CONFIG_HFS_STD
+extern struct vnodeopv_desc hfs_std_vnodeop_opv_desc;
+#endif
+extern struct vnodeopv_desc hfs_specop_opv_desc;
+extern struct vnodeopv_desc hfs_fifoop_opv_desc;
+extern struct vfsops hfs_vfsops;
+
+bool com_apple_filesystems_hfs::start(IOService *provider)
+{
+ if (!super::start(provider))
+ return false;
+
+#ifndef panic_on_assert
+ panic_on_assert = PE_i_can_has_kernel_configuration() & kPEICanHasAssertions;
+#endif
+
+#if DEBUG
+ PE_parse_boot_argn("hfs_corruption_panics", &hfs_corruption_panics, sizeof(hfs_corruption_panics));
+#endif
+
+ struct vnodeopv_desc *op_descs[] = {
+ &hfs_vnodeop_opv_desc,
+#if CONFIG_HFS_STD
+ &hfs_std_vnodeop_opv_desc,
+#endif
+ &hfs_specop_opv_desc,
+#if FIFO
+ &hfs_fifoop_opv_desc,
+#endif
+ };
+
+#define lengthof(x) (sizeof(x)/sizeof(*x))
+
+#ifndef VFS_TBLVNOP_SECLUDE_RENAME
+#define VFS_TBLVNOP_SECLUDE_RENAME 0
+#endif
+
+ struct vfs_fsentry vfe = {
+ .vfe_vfsops = &hfs_vfsops,
+ .vfe_vopcnt = lengthof(op_descs),
+ .vfe_opvdescs = op_descs,
+ .vfe_fsname = "hfs",
+ .vfe_flags = (VFS_TBLNOTYPENUM | VFS_TBLLOCALVOL | VFS_TBLREADDIR_EXTENDED
+ | VFS_TBL64BITREADY | VFS_TBLVNOP_PAGEOUTV2 | VFS_TBLVNOP_PAGEINV2
+ | VFS_TBLTHREADSAFE | VFS_TBLCANMOUNTROOT | VFS_TBLVNOP_SECLUDE_RENAME
+ | VFS_TBLNATIVEXATTR)
+ };
+
+ int ret = vfs_fsadd(&vfe, &vfs_handle);
+
+ if (ret) {
+ printf("hfs: vfs_fsadd failed: %d!\n", ret);
+ vfs_handle = NULL;
+ return false;
+ }
+
+ hfs_sysctl_register();
+
+ return true;
+}
+
+void com_apple_filesystems_hfs::stop(IOService *provider)
+{
+ if (vfs_handle) {
+ vfs_fsremove(vfs_handle);
+ hfs_sysctl_unregister();
+ vfs_handle = NULL;
+ }
+
+ super::stop(provider);
+}
+
+int hfs_is_ejectable(const char *cdev_name)
+{
+ int ret = 0;
+ OSDictionary *dictionary;
+ OSString *dev_name;
+
+ if (strncmp(cdev_name, "/dev/", 5) == 0) {
+ cdev_name += 5;
+ }
+
+ dictionary = IOService::serviceMatching("IOMedia");
+ if( dictionary ) {
+ dev_name = OSString::withCString( cdev_name );
+ if( dev_name ) {
+ IOService *service;
+ mach_timespec_t tv = { 5, 0 }; // wait up to "timeout" seconds for the device
+
+ dictionary->setObject(kIOBSDNameKey, dev_name);
+ dictionary->retain();
+ service = IOService::waitForService(dictionary, &tv);
+ if( service ) {
+ OSBoolean *ejectable = (OSBoolean *)service->getProperty("Ejectable");
+
+ if( ejectable ) {
+ ret = (int)ejectable->getValue();
+ }
+
+ }
+ dev_name->release();
+ }
+ dictionary->release();
+ }
+
+ return ret;
+}
+
+void hfs_iterate_media_with_content(const char *content_uuid_cstring,
+ int (*func)(const char *device,
+ const char *uuid_str,
+ void *arg),
+ void *arg)
+{
+ OSDictionary *dictionary;
+ OSString *content_uuid_string;
+
+ dictionary = IOService::serviceMatching("IOMedia");
+ if (dictionary) {
+ content_uuid_string = OSString::withCString(content_uuid_cstring);
+ if (content_uuid_string) {
+ IOService *service;
+ OSIterator *iter;
+
+ dictionary->setObject("Content", content_uuid_string);
+ dictionary->retain();
+
+ iter = IOService::getMatchingServices(dictionary);
+ while (iter && (service = (IOService *)iter->getNextObject())) {
+ if (service) {
+ OSString *iostr = (OSString *) service->getProperty(kIOBSDNameKey);
+ OSString *uuidstr = (OSString *)service->getProperty("UUID");
+ const char *uuid;
+
+ if (iostr) {
+ if (uuidstr) {
+ uuid = uuidstr->getCStringNoCopy();
+ } else {
+ uuid = "00000000-0000-0000-0000-000000000000";
+ }
+
+ if (!func(iostr->getCStringNoCopy(), uuid, arg))
+ break;
+ }
+ }
+ }
+ if (iter)
+ iter->release();
+
+ content_uuid_string->release();
+ }
+ dictionary->release();
+ }
+}
+
+kern_return_t hfs_get_platform_serial_number(char *serial_number_str,
+ uint32_t len)
+{
+ OSDictionary * platform_dict;
+ IOService *platform;
+ OSString * string;
+
+ if (len < 1) {
+ return 0;
+ }
+ serial_number_str[0] = '\0';
+
+ platform_dict = IOService::serviceMatching( "IOPlatformExpertDevice" );
+ if (platform_dict == NULL) {
+ return KERN_NOT_SUPPORTED;
+ }
+
+ platform = IOService::waitForService( platform_dict );
+ if (platform) {
+ string = (OSString *)platform->getProperty(kIOPlatformSerialNumberKey);
+ if (string == 0) {
+ return KERN_NOT_SUPPORTED;
+ } else {
+ strlcpy( serial_number_str, string->getCStringNoCopy(), len);
+ }
+ }
+
+ return KERN_SUCCESS;
+}
+
+// Interface with AKS
+
+static aks_file_system_key_services_t *
+key_services(void)
+{
+ static aks_file_system_key_services_t *g_key_services;
+
+ if (!g_key_services) {
+ IOService *platform = IOService::getPlatform();
+ if (platform) {
+ IOReturn ret = platform->callPlatformFunction
+ (kAKSFileSystemKeyServices, true, &g_key_services, NULL, NULL, NULL);
+ if (ret)
+ printf("hfs: unable to get " kAKSFileSystemKeyServices " (0x%x)\n", ret);
+ }
+ }
+
+ return g_key_services;
+}
+
+int hfs_unwrap_key(aks_cred_t access, const aks_wrapped_key_t wrapped_key_in,
+ aks_raw_key_t key_out)
+{
+ aks_file_system_key_services_t *ks = key_services();
+ if (!ks || !ks->unwrap_key)
+ return ENXIO;
+ return ks->unwrap_key(access, wrapped_key_in, key_out);
+}
+
+int hfs_rewrap_key(aks_cred_t access, cp_key_class_t dp_class,
+ const aks_wrapped_key_t wrapped_key_in,
+ aks_wrapped_key_t wrapped_key_out)
+{
+ aks_file_system_key_services_t *ks = key_services();
+ if (!ks || !ks->rewrap_key)
+ return ENXIO;
+ return ks->rewrap_key(access, dp_class, wrapped_key_in, wrapped_key_out);
+}
+
+int hfs_new_key(aks_cred_t access, cp_key_class_t dp_class,
+ aks_raw_key_t key_out, aks_wrapped_key_t wrapped_key_out)
+{
+ aks_file_system_key_services_t *ks = key_services();
+ if (!ks || !ks->new_key)
+ return ENXIO;
+ return ks->new_key(access, dp_class, key_out, wrapped_key_out);
+}
+
+int hfs_backup_key(aks_cred_t access, const aks_wrapped_key_t wrapped_key_in,
+ aks_wrapped_key_t wrapped_key_out)
+{
+ aks_file_system_key_services_t *ks = key_services();
+ if (!ks || !ks->backup_key)
+ return ENXIO;
+ return ks->backup_key(access, wrapped_key_in, wrapped_key_out);
+}