Borrow the eject code for OSX from xine-lib-1.2-macos branch, as contributed

by Matt Messier. This allows to eject disks on Mac OS X without having to
call an external utility.

Incidentally this fixes libcdio eject function on Mac OS X 10.4 and later, as
hditool was moved from /usr/sbin to /usr/bin.
This commit is contained in:
flameeyes
2007-08-09 02:19:40 +00:00
parent e9c92f9c11
commit 48751a50f3
2 changed files with 134 additions and 8 deletions

View File

@@ -19,7 +19,7 @@ define(RELEASE_NUM, 79cvs)
define(CDIO_VERSION_STR, 0.$1)
AC_PREREQ(2.52)
AC_REVISION([$Id: configure.ac,v 1.210 2007/05/16 10:00:50 rocky Exp $])dnl
AC_REVISION([$Id: configure.ac,v 1.211 2007/08/09 02:19:40 flameeyes Exp $])dnl
AC_INIT(libcdio, CDIO_VERSION_STR(RELEASE_NUM))
AC_CONFIG_SRCDIR(src/cd-info.c)
@@ -298,7 +298,7 @@ dnl AM_PROG_LIBTOOL tests whether we have GNU ld
dnl this must come before checking --with-versioned-libs
dnl which requires GNU ld.
AM_PROG_LIBTOOL
dnl system
# FIXME:
@@ -380,6 +380,20 @@ case $host_os in
AC_DEFINE([HAVE_DARWIN_CDROM], [1],
[Define 1 if you have Darwin OS X-type CD-ROM support])
DARWIN_PKG_LIB_HACK="-Wl,-framework,CoreFoundation -Wl,-framework,IOKit"
dnl Prior to Mac OS X 10.4 (Tiger), DiskArbitration was a private framework.
dnl It's now public, and it's needed to do cd/dvd unmount/eject.
AC_MSG_CHECKING([for DiskArbitration framework])
ac_save_LIBS="$LIBS" LIBS="$LIBS -framework CoreFoundation -framework DiskArbitration"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <DiskArbitration/DiskArbitration.h>]], [[]])],
[have_diskarbitration_framework=yes], [have_diskarbitration_framework=no])
LIBS="$ac_save_LIBS"
AC_MSG_RESULT([$have_diskarbitration_framework])
if test x"$have_diskarbitration_framework" = x"yes"; then
AC_DEFINE([HAVE_DISKARBITRATION], 1, [Define to 1 if you have the Apple DiskArbitration framework])
DARWIN_PKG_LIB_HACK="$DARWIN_PKG_LIB_HACK -Wl,-framework,DiskArbitration"
fi
AC_SUBST(DARWIN_PKG_LIB_HACK)
LIBCDIO_LIBS="$LIBCDIO_LIBS $DARWIN_PKG_LIB_HACK"
cd_drivers="${cd_drivers}, Darwin"

View File

@@ -1,5 +1,5 @@
/*
$Id: osx.c,v 1.9 2006/03/26 02:34:41 rocky Exp $
$Id: osx.c,v 1.10 2007/08/09 02:19:40 flameeyes Exp $
Copyright (C) 2003, 2004, 2005, 2006 Rocky Bernstein
<rockyb@users.sourceforge.net>
@@ -35,7 +35,7 @@
#include "config.h"
#endif
static const char _rcsid[] = "$Id: osx.c,v 1.9 2006/03/26 02:34:41 rocky Exp $";
static const char _rcsid[] = "$Id: osx.c,v 1.10 2007/08/09 02:19:40 flameeyes Exp $";
#include <cdio/logging.h>
#include <cdio/sector.h>
@@ -87,6 +87,10 @@ static const char _rcsid[] = "$Id: osx.c,v 1.9 2006/03/26 02:34:41 rocky Exp $";
#include <IOKit/storage/IODVDMediaBSDClient.h>
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
#ifdef HAVE_DISKARBITRATION
#include <DiskArbitration/DiskArbitration.h>
#endif
/* FIXME */
#define MAX_BIG_BUFF_SIZE 65535
@@ -1316,13 +1320,17 @@ get_track_lba_osx(void *p_user_data, track_t i_track)
/*!
Eject media . Return DRIVER_OP_SUCCESS if successful.
The only way to cleanly unmount the disc under MacOS X is to use the
'disktool' command line utility. It uses the non-public Disk
Arbitration API, which can not be used by Cocoa or Carbon
applications.
The only way to cleanly unmount the disc under MacOS X (before
Tiger) is to use the 'disktool' command line utility. It uses the
non-public DiskArbitration API, which can not be used by Cocoa or
Carbon applications.
Since Tiger (MacOS X 10.4), DiskArbitration is a public framework
and we can use it as needed.
*/
#ifndef HAVE_DISKARBITRATION
static driver_return_code_t
_eject_media_osx (void *user_data) {
@@ -1363,6 +1371,110 @@ _eject_media_osx (void *user_data) {
return DRIVER_OP_ERROR;
}
#else /* HAVE_DISKARBITRATION */
typedef struct dacontext_s {
int result;
Boolean completed;
DASessionRef session;
CFRunLoopRef runloop;
CFRunLoopSourceRef cancel;
} dacontext_t;
static void cancel_runloop(void *info) { /* do nothing */ }
static CFRunLoopSourceContext cancelRunLoopSourceContext = {
.perform = cancel_runloop
};
static void media_eject_callback(DADiskRef disk, DADissenterRef dissenter, void *context)
{
dacontext_t *dacontext = (dacontext_t *)context;
dacontext->result = (dissenter ? DRIVER_OP_ERROR : DRIVER_OP_SUCCESS);
dacontext->completed = TRUE;
CFRunLoopSourceSignal(dacontext->cancel);
CFRunLoopWakeUp(dacontext->runloop);
}
static void media_unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *context)
{
dacontext_t *dacontext = (dacontext_t *)context;
if (!dissenter) {
DADiskEject(disk, kDADiskEjectOptionDefault, media_eject_callback, context);
}
else {
dacontext->result = DRIVER_OP_ERROR;
dacontext->completed = TRUE;
CFRunLoopSourceSignal(dacontext->cancel);
CFRunLoopWakeUp(dacontext->runloop);
}
}
static driver_return_code_t
_eject_media_osx (void *user_data) {
_img_private_t *p_env = user_data;
char *psz_drive;
DADiskRef disk;
dacontext_t dacontext;
CFDictionaryRef description;
if( ( psz_drive = (char *)strstr( p_env->gen.source_name, "disk" ) ) == NULL ||
strlen( psz_drive ) <= 4 )
{
return DRIVER_OP_ERROR;
}
dacontext.result = DRIVER_OP_SUCCESS;
dacontext.completed = FALSE;
dacontext.runloop = CFRunLoopGetCurrent();
dacontext.cancel = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &cancelRunLoopSourceContext);
if (!dacontext.cancel)
{
return DRIVER_OP_ERROR;
}
if (!(dacontext.session = DASessionCreate(kCFAllocatorDefault)))
{
CFRelease(dacontext.cancel);
return DRIVER_OP_ERROR;
}
if ((disk = DADiskCreateFromBSDName(kCFAllocatorDefault, dacontext.session, psz_drive)) != NULL)
{
if ((description = DADiskCopyDescription(disk)) != NULL)
{
/* Does the device need to be unmounted first? */
DASessionScheduleWithRunLoop(dacontext.session, dacontext.runloop, kCFRunLoopDefaultMode);
if (CFDictionaryGetValueIfPresent(description, kDADiskDescriptionVolumePathKey, NULL))
{
DADiskUnmount(disk, kDADiskUnmountOptionDefault, media_unmount_callback, &dacontext);
}
else
{
DADiskEject(disk, kDADiskEjectOptionDefault, media_eject_callback, &dacontext);
}
CFRunLoopAddSource(dacontext.runloop, dacontext.cancel, kCFRunLoopDefaultMode);
if (!dacontext.completed)
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 30.0, TRUE); /* timeout after 30 seconds */
}
CFRunLoopRemoveSource(dacontext.runloop, dacontext.cancel, kCFRunLoopDefaultMode);
DASessionUnscheduleFromRunLoop(dacontext.session, dacontext.runloop, kCFRunLoopDefaultMode);
CFRelease(description);
}
CFRelease(disk);
}
CFRunLoopSourceInvalidate(dacontext.cancel);
CFRelease(dacontext.cancel);
CFRelease(dacontext.session);
return dacontext.result;
}
#endif
/*!
Return the size of the CD in logical block address (LBA) units.