Alexandre Julliard : ntdll: Added support for physically ejecting devices on Mac OS.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Dec 21 10:36:39 CST 2006


Module: wine
Branch: master
Commit: 9ff161860c51d62f7f05989116cd73908f5611e9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=9ff161860c51d62f7f05989116cd73908f5611e9

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Dec 21 14:14:20 2006 +0100

ntdll: Added support for physically ejecting devices on Mac OS.

---

 dlls/ntdll/cdrom.c |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 98 insertions(+), 1 deletions(-)

diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
index 65712a7..45a2b47 100644
--- a/dlls/ntdll/cdrom.c
+++ b/dlls/ntdll/cdrom.c
@@ -77,7 +77,9 @@
 
 #ifdef HAVE_IOKIT_IOKITLIB_H
 # ifndef SENSEBUFLEN
+#  include <sys/disk.h>
 #  include <IOKit/IOKitLib.h>
+#  include <IOKit/storage/IOMedia.h>
 #  include <IOKit/scsi/SCSICmds_REQUEST_SENSE_Defs.h>
 #  define SENSEBUFLEN kSenseDefaultSize
 # endif
@@ -302,6 +304,82 @@ static int CDROM_MediaChanged(int dev)
 }
 #endif
 
+
+/******************************************************************
+ *		open_parent_device
+ *
+ * On Mac OS, open the device for the whole disk from a fd that points to a partition.
+ * This is ugly and inefficient, but we have no choice since the partition fd doesn't
+ * support the eject ioctl.
+ */
+#ifdef __APPLE__
+static int open_parent_device( int fd )
+{
+    struct stat st;
+    int i, parent_fd = -1;
+    io_service_t service;
+    CFMutableDictionaryRef dict;
+    CFTypeRef val;
+
+    if (fstat( fd, &st ) == -1) return -1;
+    if (!S_ISCHR( st.st_mode )) return -1;
+
+    /* create a dictionary with the right major/minor numbers */
+
+    if (!(dict = IOServiceMatching( kIOMediaClass ))) return -1;
+
+    i = major( st.st_rdev );
+    val = CFNumberCreate( NULL, kCFNumberIntType, &i );
+    CFDictionaryAddValue( dict, CFSTR( "BSD Major" ), val );
+    CFRelease( val );
+
+    i = minor( st.st_rdev );
+    val = CFNumberCreate( NULL, kCFNumberIntType, &i );
+    CFDictionaryAddValue( dict, CFSTR( "BSD Minor" ), val );
+    CFRelease( val );
+
+    CFDictionaryAddValue( dict, CFSTR("Removable"), kCFBooleanTrue );
+
+    service = IOServiceGetMatchingService( kIOMasterPortDefault, dict );
+
+    /* now look for the parent that has the "Whole" attribute set to TRUE */
+
+    while (service)
+    {
+        io_service_t parent = 0;
+        CFBooleanRef whole;
+        CFStringRef str;
+        int ok;
+
+        if (!IOObjectConformsTo( service, kIOMediaClass ))
+            goto next;
+        if (!(whole = IORegistryEntryCreateCFProperty( service, CFSTR("Whole"), NULL, 0 )))
+            goto next;
+        ok = (whole == kCFBooleanTrue);
+        CFRelease( whole );
+        if (!ok) goto next;
+
+        if ((str = IORegistryEntryCreateCFProperty( service, CFSTR("BSD Name"), NULL, 0 )))
+        {
+            char name[100];
+            strcpy( name, "/dev/r" );
+            CFStringGetCString( str, name + 6, sizeof(name) - 6, kCFStringEncodingUTF8 );
+            CFRelease( str );
+            parent_fd = open( name, O_RDONLY );
+        }
+        IOObjectRelease( service );
+        break;
+
+next:
+        IORegistryEntryGetParentEntry( service, kIOServicePlane, &parent );
+        IOObjectRelease( service );
+        service = parent;
+    }
+    return parent_fd;
+}
+#endif
+
+
 /******************************************************************
  *		CDROM_SyncCache                          [internal]
  *
@@ -628,6 +706,9 @@ static NTSTATUS CDROM_SetTray(int fd, BO
     return CDROM_GetStatusCode((ioctl(fd, CDIOCALLOW, NULL)) ||
                                (ioctl(fd, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
                                (ioctl(fd, CDIOCPREVENT, NULL)));
+#elif defined(__APPLE__)
+    if (doEject) return CDROM_GetStatusCode( ioctl( fd, DKIOCEJECT, NULL ) );
+    else return STATUS_NOT_SUPPORTED;
 #else
     return STATUS_NOT_SUPPORTED;
 #endif
@@ -2059,7 +2140,23 @@ NTSTATUS CDROM_DeviceIoControl(HANDLE hD
 	CDROM_ClearCacheEntry(dev);
         if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
             status = STATUS_INVALID_PARAMETER;
-        else status = CDROM_SetTray(fd, TRUE);
+        else
+        {
+#ifdef __APPLE__
+            int parent_fd = open_parent_device( fd );
+            if (parent_fd != -1)
+            {
+                /* This is ugly as hell, but Mac OS is unable to eject from the device fd,
+                 * it wants an fd for the whole device, and it also requires the device fd
+                 * to be closed first, so we have to close the handle that the caller gave us */
+                NtClose( hDevice );
+                if (needs_close) close( fd );
+                fd = parent_fd;
+                needs_close = 1;
+            }
+#endif
+            status = CDROM_SetTray(fd, TRUE);
+        }
         break;
 
     case IOCTL_CDROM_MEDIA_REMOVAL:




More information about the wine-cvs mailing list