+
+#ifdef __APPLE_CC__
+/****************************************************************************
+ * bsd_name_for_path
+ *
+ * Returns the BSD device name for the block device that contains the
+ * passed-in path. Returns NULL on failure.
+ ****************************************************************************/
+static char* bsd_name_for_path(char *path)
+{
+ OSStatus err;
+ FSRef ref;
+ err = FSPathMakeRef( (const UInt8 *) input, &ref, NULL );
+ if( err != noErr )
+ {
+ return NULL;
+ }
+
+ // Get the volume reference number.
+ FSCatalogInfo catalogInfo;
+ err = FSGetCatalogInfo( &ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL,
+ NULL);
+ if( err != noErr )
+ {
+ return NULL;
+ }
+ FSVolumeRefNum volRefNum = catalogInfo.volume;
+
+ // Now let's get the device name
+ GetVolParmsInfoBuffer volumeParms;
+ err = FSGetVolumeParms( volRefNum, &volumeParms, sizeof( volumeParms ) );
+ if( err != noErr )
+ {
+ return NULL;
+ }
+
+ // A version 4 GetVolParmsInfoBuffer contains the BSD node name in the vMDeviceID field.
+ // It is actually a char * value. This is mentioned in the header CoreServices/CarbonCore/Files.h.
+ if( volumeParms.vMVersion < 4 )
+ {
+ return NULL;
+ }
+
+ // vMDeviceID might be zero as is reported with experimental ZFS (zfs-119) support in Leopard.
+ if( !volumeParms.vMDeviceID )
+ {
+ return NULL;
+ }
+
+ return strdup( volumeParms.vMDeviceID );
+}
+
+/****************************************************************************
+ * device_is_dvd
+ *
+ * Returns whether or not the passed in BSD device represents a DVD, or other
+ * optical media.
+ ****************************************************************************/
+static int device_is_dvd(char *device)
+{
+ io_service_t service = get_iokit_service(device);
+ if( service == IO_OBJECT_NULL )
+ {
+ return 0;
+ }
+ int result = is_dvd_service(service);
+ IOObjectRelease(service);
+ return result;
+}
+
+/****************************************************************************
+ * get_iokit_service
+ *
+ * Returns the IOKit service object for the passed in BSD device name.
+ ****************************************************************************/
+static io_service_t get_iokit_service( char *device )
+{
+ CFMutableDictionaryRef matchingDict;
+ matchingDict = IOBSDNameMatching( kIOMasterPortDefault, 0, device );
+ if( matchingDict == NULL )
+ {
+ return IO_OBJECT_NULL;
+ }
+ // Fetch the object with the matching BSD node name. There should only be
+ // one match, so IOServiceGetMatchingService is used instead of
+ // IOServiceGetMatchingServices to simplify the code.
+ return IOServiceGetMatchingService( kIOMasterPortDefault, matchingDict );
+}
+
+/****************************************************************************
+ * is_dvd_service
+ *
+ * Returns whether or not the service passed in is a DVD.
+ *
+ * Searches for an IOMedia object that represents the entire (whole) media that
+ * the volume is on. If the volume is on partitioned media, the whole media
+ * object will be a parent of the volume's media object. If the media is not
+ * partitioned, the volume's media object will be the whole media object.
+ ****************************************************************************/
+static int is_dvd_service( io_service_t service )
+{
+ kern_return_t kernResult;
+ io_iterator_t iter;
+
+ // Create an iterator across all parents of the service object passed in.
+ kernResult = IORegistryEntryCreateIterator( service,
+ kIOServicePlane,
+ kIORegistryIterateRecursively | kIORegistryIterateParents,
+ &iter );
+ if( kernResult != KERN_SUCCESS )
+ {
+ return 0;
+ }
+ if( iter == IO_OBJECT_NULL )
+ {
+ return 0;
+ }
+
+ // A reference on the initial service object is released in the do-while
+ // loop below, so add a reference to balance.
+ IOObjectRetain( service );
+
+ int result = 0;
+ do
+ {
+ if( is_whole_media_service( service ) &&
+ IOObjectConformsTo( service, kIODVDMediaClass) )
+ {
+ result = 1;
+ }
+ IOObjectRelease( service );
+ } while( !result && (service = IOIteratorNext( iter )) );
+ IOObjectRelease( iter );
+
+ return result;
+}
+
+/****************************************************************************
+ * is_whole_media_service
+ *
+ * Returns whether or not the service passed in is an IOMedia service and
+ * represents the "whole" media instead of just a partition.
+ *
+ * The whole media object is indicated in the IORegistry by the presence of a
+ * property with the key "Whole" and value "Yes".
+ ****************************************************************************/
+static is_whole_media_service( io_service_t service )
+{
+ int result = 0;
+
+ if( IOObjectConformsTo( service, kIOMediaClass ) )
+ {
+ CFTypeRef wholeMedia = IORegistryEntryCreateCFProperty( service,
+ CFSTR( kIOMediaWholeKey ),
+ kCFAllocatorDefault,
+ 0 );
+ if ( !wholeMedia )
+ {
+ return 0;
+ }
+ result = CFBooleanGetValue( (CFBooleanRef)wholeMedia );
+ CFRelease( wholeMedia );
+ }
+
+ return result;
+}
+#endif // __APPLE_CC__