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