/* * Devices support using the MacOS Disk Arbitration library. * * Copyright 2006 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #include #include #include #ifdef HAVE_DISKARBITRATION_DISKARBITRATION_H #include #endif #include "mountmgr.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); #ifdef HAVE_DISKARBITRATION_DISKARBITRATION_H static void appeared_callback( DADiskRef disk, void *context ) { CFDictionaryRef dict = DADiskCopyDescription( disk ); const void *ref; char device[64]; char mount_point[PATH_MAX]; GUID guid, *guid_ptr = NULL; enum device_type type = DEVICE_UNKNOWN; if (!dict) return; if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumeUUID") ))) { CFUUIDBytes bytes = CFUUIDGetUUIDBytes( ref ); memcpy( &guid, &bytes, sizeof(guid) ); guid_ptr = &guid; } /* get device name */ if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done; strcpy( device, "/dev/r" ); CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII ); if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumePath") ))) CFURLGetFileSystemRepresentation( ref, true, (UInt8 *)mount_point, sizeof(mount_point) ); else mount_point[0] = 0; if ((ref = CFDictionaryGetValue( dict, CFSTR("DAMediaKind") ))) { if (!CFStringCompare( ref, CFSTR("IOCDMedia"), 0 )) type = DEVICE_CDROM; if (!CFStringCompare( ref, CFSTR("IODVDMedia"), 0 ) || !CFStringCompare( ref, CFSTR("IOBDMedia"), 0 )) type = DEVICE_DVD; if (!CFStringCompare( ref, CFSTR("IOMedia"), 0 )) type = DEVICE_HARDDISK; } TRACE( "got mount notification for '%s' on '%s' uuid %s\n", device, mount_point, wine_dbgstr_guid(guid_ptr) ); if ((ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )) && CFBooleanGetValue( ref )) add_dos_device( -1, device, device, mount_point, type, guid_ptr ); else if (guid_ptr) add_volume( device, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); done: CFRelease( dict ); } static void changed_callback( DADiskRef disk, CFArrayRef keys, void *context ) { appeared_callback( disk, context ); } static void disappeared_callback( DADiskRef disk, void *context ) { CFDictionaryRef dict = DADiskCopyDescription( disk ); const void *ref; char device[100]; if (!dict) return; /* get device name */ if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done; strcpy( device, "/dev/r" ); CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII ); TRACE( "got unmount notification for '%s'\n", device ); if ((ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )) && CFBooleanGetValue( ref )) remove_dos_device( -1, device ); else remove_volume( device ); done: CFRelease( dict ); } static DWORD WINAPI runloop_thread( void *arg ) { DASessionRef session = DASessionCreate( NULL ); if (!session) return 1; DASessionScheduleWithRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); DARegisterDiskAppearedCallback( session, kDADiskDescriptionMatchVolumeMountable, appeared_callback, NULL ); DARegisterDiskDisappearedCallback( session, kDADiskDescriptionMatchVolumeMountable, disappeared_callback, NULL ); DARegisterDiskDescriptionChangedCallback( session, kDADiskDescriptionMatchVolumeMountable, kDADiskDescriptionWatchVolumePath, changed_callback, NULL ); CFRunLoopRun(); DASessionUnscheduleFromRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); CFRelease( session ); return 0; } void initialize_diskarbitration(void) { HANDLE handle; if (!(handle = CreateThread( NULL, 0, runloop_thread, NULL, 0, NULL ))) return; CloseHandle( handle ); } #else /* HAVE_DISKARBITRATION_DISKARBITRATION_H */ void initialize_diskarbitration(void) { TRACE( "Skipping, Disk Arbitration support not compiled in\n" ); } #endif /* HAVE_DISKARBITRATION_DISKARBITRATION_H */