ntdll: On Mac OS, close the CDROM device before opening the parent.

This is needed to allow ejecting DVD disks.
oldstable
Alexandre Julliard 2007-08-29 16:44:16 +02:00
parent a76ef05c90
commit 572771ebfa
1 changed files with 26 additions and 20 deletions

View File

@ -305,27 +305,28 @@ static int CDROM_MediaChanged(int dev)
/****************************************************************** /******************************************************************
* open_parent_device * get_parent_device
* *
* On Mac OS, open the device for the whole disk from a fd that points to a partition. * On Mac OS, get 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 * This is ugly and inefficient, but we have no choice since the partition fd doesn't
* support the eject ioctl. * support the eject ioctl.
*/ */
#ifdef __APPLE__ #ifdef __APPLE__
static int open_parent_device( int fd ) static NTSTATUS get_parent_device( int fd, char *name, size_t len )
{ {
NTSTATUS status = STATUS_NO_SUCH_FILE;
struct stat st; struct stat st;
int i, parent_fd = -1; int i;
io_service_t service; io_service_t service;
CFMutableDictionaryRef dict; CFMutableDictionaryRef dict;
CFTypeRef val; CFTypeRef val;
if (fstat( fd, &st ) == -1) return -1; if (fstat( fd, &st ) == -1) return FILE_GetNtStatus();
if (!S_ISCHR( st.st_mode )) return -1; if (!S_ISCHR( st.st_mode )) return STATUS_OBJECT_TYPE_MISMATCH;
/* create a dictionary with the right major/minor numbers */ /* create a dictionary with the right major/minor numbers */
if (!(dict = IOServiceMatching( kIOMediaClass ))) return -1; if (!(dict = IOServiceMatching( kIOMediaClass ))) return STATUS_NO_MEMORY;
i = major( st.st_rdev ); i = major( st.st_rdev );
val = CFNumberCreate( NULL, kCFNumberIntType, &i ); val = CFNumberCreate( NULL, kCFNumberIntType, &i );
@ -360,11 +361,10 @@ static int open_parent_device( int fd )
if ((str = IORegistryEntryCreateCFProperty( service, CFSTR("BSD Name"), NULL, 0 ))) if ((str = IORegistryEntryCreateCFProperty( service, CFSTR("BSD Name"), NULL, 0 )))
{ {
char name[100];
strcpy( name, "/dev/r" ); strcpy( name, "/dev/r" );
CFStringGetCString( str, name + 6, sizeof(name) - 6, kCFStringEncodingUTF8 ); CFStringGetCString( str, name + 6, len - 6, kCFStringEncodingUTF8 );
CFRelease( str ); CFRelease( str );
parent_fd = open( name, O_RDONLY ); status = STATUS_SUCCESS;
} }
IOObjectRelease( service ); IOObjectRelease( service );
break; break;
@ -374,7 +374,7 @@ next:
IOObjectRelease( service ); IOObjectRelease( service );
service = parent; service = parent;
} }
return parent_fd; return status;
} }
#endif #endif
@ -2181,17 +2181,23 @@ NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice,
else else
{ {
#ifdef __APPLE__ #ifdef __APPLE__
int parent_fd = open_parent_device( fd ); char name[100];
if (parent_fd != -1)
{
/* This is ugly as hell, but Mac OS is unable to eject from the device fd, /* 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 * 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 */ * to be closed first, so we have to close the handle that the caller gave us.
* Also for some reason it wants the fd to be closed before we even open the parent.
*/
if ((status = get_parent_device( fd, name, sizeof(name) ))) break;
NtClose( hDevice ); NtClose( hDevice );
if (needs_close) close( fd ); if (needs_close) close( fd );
fd = parent_fd; TRACE("opening parent %s\n", name );
needs_close = 1; if ((fd = open( name, O_RDONLY )) == -1)
{
status = FILE_GetNtStatus();
break;
} }
needs_close = 1;
#endif #endif
status = CDROM_SetTray(fd, TRUE); status = CDROM_SetTray(fd, TRUE);
} }