better support of host drives
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2124 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
66c6ef7678
commit
19cb37389f
682
block-raw.c
682
block-raw.c
@ -46,100 +46,42 @@
|
||||
#ifdef __sun__
|
||||
#include <sys/dkio.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
|
||||
//#define DEBUG_FLOPPY
|
||||
|
||||
#define FTYPE_FILE 0
|
||||
#define FTYPE_CD 1
|
||||
#define FTYPE_FD 2
|
||||
|
||||
/* if the FD is not accessed during that time (in ms), we try to
|
||||
reopen it to see if the disk has been changed */
|
||||
#define FD_OPEN_TIMEOUT 1000
|
||||
|
||||
typedef struct BDRVRawState {
|
||||
int fd;
|
||||
int type;
|
||||
#if defined(__linux__)
|
||||
/* linux floppy specific */
|
||||
int fd_open_flags;
|
||||
int64_t fd_open_time;
|
||||
int64_t fd_error_time;
|
||||
int fd_got_error;
|
||||
int fd_media_changed;
|
||||
#endif
|
||||
} BDRVRawState;
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
|
||||
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
|
||||
|
||||
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
|
||||
{
|
||||
kern_return_t kernResult;
|
||||
mach_port_t masterPort;
|
||||
CFMutableDictionaryRef classesToMatch;
|
||||
|
||||
kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
|
||||
if ( KERN_SUCCESS != kernResult ) {
|
||||
printf( "IOMasterPort returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
classesToMatch = IOServiceMatching( kIOCDMediaClass );
|
||||
if ( classesToMatch == NULL ) {
|
||||
printf( "IOServiceMatching returned a NULL dictionary.\n" );
|
||||
} else {
|
||||
CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
|
||||
}
|
||||
kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
|
||||
if ( KERN_SUCCESS != kernResult )
|
||||
{
|
||||
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
|
||||
{
|
||||
io_object_t nextMedia;
|
||||
kern_return_t kernResult = KERN_FAILURE;
|
||||
*bsdPath = '\0';
|
||||
nextMedia = IOIteratorNext( mediaIterator );
|
||||
if ( nextMedia )
|
||||
{
|
||||
CFTypeRef bsdPathAsCFString;
|
||||
bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
|
||||
if ( bsdPathAsCFString ) {
|
||||
size_t devPathLength;
|
||||
strcpy( bsdPath, _PATH_DEV );
|
||||
strcat( bsdPath, "r" );
|
||||
devPathLength = strlen( bsdPath );
|
||||
if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
|
||||
kernResult = KERN_SUCCESS;
|
||||
}
|
||||
CFRelease( bsdPathAsCFString );
|
||||
}
|
||||
IOObjectRelease( nextMedia );
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
static int fd_open(BlockDriverState *bs);
|
||||
|
||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd, open_flags;
|
||||
int fd, open_flags, ret;
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
kern_return_t kernResult;
|
||||
io_iterator_t mediaIterator;
|
||||
char bsdPath[ MAXPATHLEN ];
|
||||
int fd;
|
||||
|
||||
kernResult = FindEjectableCDMedia( &mediaIterator );
|
||||
kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
|
||||
|
||||
if ( bsdPath[ 0 ] != '\0' ) {
|
||||
strcat(bsdPath,"s0");
|
||||
/* some CDs don't have a partition 0 */
|
||||
fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
bsdPath[strlen(bsdPath)-1] = '1';
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
filename = bsdPath;
|
||||
}
|
||||
|
||||
if ( mediaIterator )
|
||||
IOObjectRelease( mediaIterator );
|
||||
}
|
||||
#endif
|
||||
open_flags = O_BINARY;
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
open_flags |= O_RDWR;
|
||||
@ -150,9 +92,15 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
if (flags & BDRV_O_CREAT)
|
||||
open_flags |= O_CREAT | O_TRUNC;
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
|
||||
fd = open(filename, open_flags, 0644);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
if (ret == -EROFS)
|
||||
ret = -EACCES;
|
||||
return ret;
|
||||
}
|
||||
s->fd = fd;
|
||||
return 0;
|
||||
}
|
||||
@ -180,6 +128,10 @@ static int raw_pread(BlockDriverState *bs, int64_t offset,
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
lseek(s->fd, offset, SEEK_SET);
|
||||
ret = read(s->fd, buf, count);
|
||||
return ret;
|
||||
@ -191,13 +143,17 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
lseek(s->fd, offset, SEEK_SET);
|
||||
ret = write(s->fd, buf, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Unix AOP using POSIX AIO */
|
||||
/* Unix AIO using POSIX AIO */
|
||||
|
||||
typedef struct RawAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
@ -236,15 +192,18 @@ void qemu_aio_init(void)
|
||||
act.sa_handler = aio_signal_handler;
|
||||
sigaction(aio_sig_num, &act, NULL);
|
||||
|
||||
#if defined(__GLIBC__) && defined(__linux__)
|
||||
{
|
||||
/* XXX: aio thread exit seems to hang on RH 9 */
|
||||
/* XXX: aio thread exit seems to hang on RedHat 9 and this init
|
||||
seems to fix the problem. */
|
||||
struct aioinit ai;
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
ai.aio_threads = 2;
|
||||
ai.aio_threads = 1;
|
||||
ai.aio_num = 1;
|
||||
ai.aio_idle_time = 365 * 100000;
|
||||
aio_init(&ai);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_aio_poll(void)
|
||||
@ -270,7 +229,7 @@ void qemu_aio_poll(void)
|
||||
if (ret == acb->aiocb.aio_nbytes)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -1;
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = -ret;
|
||||
}
|
||||
@ -329,6 +288,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawAIOCB *acb;
|
||||
|
||||
if (fd_open(bs) < 0)
|
||||
return NULL;
|
||||
|
||||
acb = qemu_aio_get(bs, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
@ -405,12 +367,17 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
close(s->fd);
|
||||
if (s->fd >= 0) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->type != FTYPE_FILE)
|
||||
return -ENOTSUP;
|
||||
if (ftruncate(s->fd, offset) < 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
@ -428,6 +395,11 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||
struct dk_minfo minfo;
|
||||
int rv;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef _BSD
|
||||
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
|
||||
@ -455,12 +427,6 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
/* On Windows hosts it can happen that we're unable to get file size
|
||||
for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
|
||||
if (size == -1)
|
||||
size = LONG_LONG_MAX;
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -509,13 +475,358 @@ BlockDriver bdrv_raw = {
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
/* host device */
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
|
||||
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
|
||||
|
||||
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
|
||||
{
|
||||
kern_return_t kernResult;
|
||||
mach_port_t masterPort;
|
||||
CFMutableDictionaryRef classesToMatch;
|
||||
|
||||
kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
|
||||
if ( KERN_SUCCESS != kernResult ) {
|
||||
printf( "IOMasterPort returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
classesToMatch = IOServiceMatching( kIOCDMediaClass );
|
||||
if ( classesToMatch == NULL ) {
|
||||
printf( "IOServiceMatching returned a NULL dictionary.\n" );
|
||||
} else {
|
||||
CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
|
||||
}
|
||||
kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
|
||||
if ( KERN_SUCCESS != kernResult )
|
||||
{
|
||||
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
|
||||
{
|
||||
io_object_t nextMedia;
|
||||
kern_return_t kernResult = KERN_FAILURE;
|
||||
*bsdPath = '\0';
|
||||
nextMedia = IOIteratorNext( mediaIterator );
|
||||
if ( nextMedia )
|
||||
{
|
||||
CFTypeRef bsdPathAsCFString;
|
||||
bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
|
||||
if ( bsdPathAsCFString ) {
|
||||
size_t devPathLength;
|
||||
strcpy( bsdPath, _PATH_DEV );
|
||||
strcat( bsdPath, "r" );
|
||||
devPathLength = strlen( bsdPath );
|
||||
if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
|
||||
kernResult = KERN_SUCCESS;
|
||||
}
|
||||
CFRelease( bsdPathAsCFString );
|
||||
}
|
||||
IOObjectRelease( nextMedia );
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd, open_flags, ret;
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
kern_return_t kernResult;
|
||||
io_iterator_t mediaIterator;
|
||||
char bsdPath[ MAXPATHLEN ];
|
||||
int fd;
|
||||
|
||||
kernResult = FindEjectableCDMedia( &mediaIterator );
|
||||
kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
|
||||
|
||||
if ( bsdPath[ 0 ] != '\0' ) {
|
||||
strcat(bsdPath,"s0");
|
||||
/* some CDs don't have a partition 0 */
|
||||
fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
bsdPath[strlen(bsdPath)-1] = '1';
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
filename = bsdPath;
|
||||
}
|
||||
|
||||
if ( mediaIterator )
|
||||
IOObjectRelease( mediaIterator );
|
||||
}
|
||||
#endif
|
||||
open_flags = O_BINARY;
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
open_flags |= O_RDWR;
|
||||
} else {
|
||||
open_flags |= O_RDONLY;
|
||||
bs->read_only = 1;
|
||||
}
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
#if defined(__linux__)
|
||||
if (strstart(filename, "/dev/cd", NULL)) {
|
||||
/* open will not fail even if no CD is inserted */
|
||||
open_flags |= O_NONBLOCK;
|
||||
s->type = FTYPE_CD;
|
||||
} else if (strstart(filename, "/dev/fd", NULL)) {
|
||||
s->type = FTYPE_FD;
|
||||
s->fd_open_flags = open_flags;
|
||||
/* open will not fail even if no floppy is inserted */
|
||||
open_flags |= O_NONBLOCK;
|
||||
}
|
||||
#endif
|
||||
fd = open(filename, open_flags, 0644);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
if (ret == -EROFS)
|
||||
ret = -EACCES;
|
||||
return ret;
|
||||
}
|
||||
s->fd = fd;
|
||||
#if defined(__linux__)
|
||||
/* close fd so that we can reopen it as needed */
|
||||
if (s->type == FTYPE_FD) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
s->fd_media_changed = 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__) && !defined(QEMU_TOOL)
|
||||
|
||||
/* Note: we do not have a reliable method to detect if the floppy is
|
||||
present. The current method is to try to open the floppy at every
|
||||
I/O and to keep it opened during a few hundreds of ms. */
|
||||
static int fd_open(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int last_media_present;
|
||||
|
||||
if (s->type != FTYPE_FD)
|
||||
return 0;
|
||||
last_media_present = (s->fd >= 0);
|
||||
if (s->fd >= 0 &&
|
||||
(qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy closed\n");
|
||||
#endif
|
||||
}
|
||||
if (s->fd < 0) {
|
||||
if (s->fd_got_error &&
|
||||
(qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy (open delayed)\n");
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
s->fd = open(bs->filename, s->fd_open_flags);
|
||||
if (s->fd < 0) {
|
||||
s->fd_error_time = qemu_get_clock(rt_clock);
|
||||
s->fd_got_error = 1;
|
||||
if (last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy\n");
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy opened\n");
|
||||
#endif
|
||||
}
|
||||
if (!last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
s->fd_open_time = qemu_get_clock(rt_clock);
|
||||
s->fd_got_error = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int fd_open(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_CD:
|
||||
ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
|
||||
if (ret == CDS_DISC_OK)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
case FTYPE_FD:
|
||||
ret = fd_open(bs);
|
||||
return (ret >= 0);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* currently only used by fdc.c, but a CD version would be good too */
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_FD:
|
||||
{
|
||||
int ret;
|
||||
/* XXX: we do not have a true media changed indication. It
|
||||
does not work if the floppy is changed without trying
|
||||
to read it */
|
||||
fd_open(bs);
|
||||
ret = s->fd_media_changed;
|
||||
s->fd_media_changed = 0;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy changed=%d\n", ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_CD:
|
||||
if (eject_flag) {
|
||||
if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
|
||||
perror("CDROMEJECT");
|
||||
} else {
|
||||
if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
|
||||
perror("CDROMEJECT");
|
||||
}
|
||||
break;
|
||||
case FTYPE_FD:
|
||||
{
|
||||
int fd;
|
||||
if (s->fd >= 0) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
|
||||
if (fd >= 0) {
|
||||
if (ioctl(fd, FDEJECT, 0) < 0)
|
||||
perror("FDEJECT");
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_CD:
|
||||
if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
|
||||
/* Note: an error can happen if the distribution automatically
|
||||
mounts the CD-ROM */
|
||||
// perror("CDROM_LOCKDOOR");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#endif /* !linux */
|
||||
|
||||
BlockDriver bdrv_host_device = {
|
||||
"host_device",
|
||||
sizeof(BDRVRawState),
|
||||
NULL, /* no probe for protocols */
|
||||
hdev_open,
|
||||
NULL,
|
||||
NULL,
|
||||
raw_close,
|
||||
NULL,
|
||||
raw_flush,
|
||||
|
||||
.bdrv_aio_read = raw_aio_read,
|
||||
.bdrv_aio_write = raw_aio_write,
|
||||
.bdrv_aio_cancel = raw_aio_cancel,
|
||||
.aiocb_size = sizeof(RawAIOCB),
|
||||
.bdrv_pread = raw_pread,
|
||||
.bdrv_pwrite = raw_pwrite,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = raw_is_inserted,
|
||||
.bdrv_media_changed = raw_media_changed,
|
||||
.bdrv_eject = raw_eject,
|
||||
.bdrv_set_locked = raw_set_locked,
|
||||
};
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
/* XXX: use another file ? */
|
||||
#include <winioctl.h>
|
||||
|
||||
#define FTYPE_FILE 0
|
||||
#define FTYPE_CD 1
|
||||
|
||||
typedef struct BDRVRawState {
|
||||
HANDLE hfile;
|
||||
int type;
|
||||
char drive_letter[2];
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct RawAIOCB {
|
||||
@ -565,6 +876,23 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags, create_flags;
|
||||
DWORD overlapped;
|
||||
char device_name[64];
|
||||
const char *p;
|
||||
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
if (find_cdrom(device_name, sizeof(device_name)) < 0)
|
||||
return -ENOENT;
|
||||
filename = device_name;
|
||||
} else {
|
||||
/* transform drive letters into device name */
|
||||
if (((filename[0] >= 'a' && filename[0] <= 'z') ||
|
||||
(filename[0] >= 'A' && filename[0] <= 'Z')) &&
|
||||
filename[1] == ':' && filename[2] == '\0') {
|
||||
snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
|
||||
filename = device_name;
|
||||
}
|
||||
}
|
||||
s->type = find_device_type(filename);
|
||||
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||
@ -765,10 +1093,22 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
LARGE_INTEGER l;
|
||||
ULARGE_INTEGER available, total, total_free;
|
||||
|
||||
l.LowPart = GetFileSize(s->hfile, &l.HighPart);
|
||||
if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
|
||||
return -EIO;
|
||||
switch(s->ftype) {
|
||||
case FTYPE_FILE:
|
||||
l.LowPart = GetFileSize(s->hfile, &l.HighPart);
|
||||
if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
|
||||
return -EIO;
|
||||
break;
|
||||
case FTYPE_CD:
|
||||
if (!GetDiskFreeSpaceEx(s->drive_letter, &available, &total, &total_free))
|
||||
return -EIO;
|
||||
l = total;
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
return l.QuadPart;
|
||||
}
|
||||
|
||||
@ -833,4 +1173,146 @@ BlockDriver bdrv_raw = {
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
/* host device */
|
||||
|
||||
static int find_cdrom(char *cdrom_name, int cdrom_name_size)
|
||||
{
|
||||
char drives[256], *pdrv = drives;
|
||||
UINT type;
|
||||
|
||||
memset(drives, 0, sizeof(drivers));
|
||||
GetLogicalDriveStrings(sizeof(drives), drives);
|
||||
while(pdrv[0] != '\0') {
|
||||
type = GetDriveType(pdrv);
|
||||
switch(type) {
|
||||
case DRIVE_CDROM:
|
||||
snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
pdrv += lstrlen(pdrv) + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int find_device_type(const char *filename)
|
||||
{
|
||||
UINT type;
|
||||
const char *p;
|
||||
|
||||
if (strstart(filename, "\\\\.\\", &p) ||
|
||||
strstart(filename, "//./", &p)) {
|
||||
s->drive_letter[0] = p[0];
|
||||
s->drive_letter[1] = '\0';
|
||||
type = GetDriveType(s->drive_letter);
|
||||
if (type == DRIVE_CDROM)
|
||||
return FTYPE_CD;
|
||||
else
|
||||
return FTYPE_FILE;
|
||||
} else {
|
||||
return FTYPE_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags, create_flags;
|
||||
DWORD overlapped;
|
||||
char device_name[64];
|
||||
const char *p;
|
||||
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
if (find_cdrom(device_name, sizeof(device_name)) < 0)
|
||||
return -ENOENT;
|
||||
filename = device_name;
|
||||
} else {
|
||||
/* transform drive letters into device name */
|
||||
if (((filename[0] >= 'a' && filename[0] <= 'z') ||
|
||||
(filename[0] >= 'A' && filename[0] <= 'Z')) &&
|
||||
filename[1] == ':' && filename[2] == '\0') {
|
||||
snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
|
||||
filename = device_name;
|
||||
}
|
||||
}
|
||||
s->type = find_device_type(filename);
|
||||
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||
} else {
|
||||
access_flags = GENERIC_READ;
|
||||
}
|
||||
create_flags = OPEN_EXISTING;
|
||||
|
||||
#ifdef QEMU_TOOL
|
||||
overlapped = 0;
|
||||
#else
|
||||
overlapped = FILE_FLAG_OVERLAPPED;
|
||||
#endif
|
||||
s->hfile = CreateFile(filename, access_flags,
|
||||
FILE_SHARE_READ, NULL,
|
||||
create_flags, overlapped, 0);
|
||||
if (s->hfile == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/***********************************************/
|
||||
/* removable device additionnal commands */
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
DWORD ret_count;
|
||||
|
||||
if (s->type == FTYPE_FILE)
|
||||
return -ENOTSUP;
|
||||
if (eject_flag) {
|
||||
DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
|
||||
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
|
||||
} else {
|
||||
DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
|
||||
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
BlockDriver bdrv_host_device = {
|
||||
"host_device",
|
||||
sizeof(BDRVRawState),
|
||||
NULL, /* no probe for protocols */
|
||||
hdev_open,
|
||||
NULL,
|
||||
NULL,
|
||||
raw_close,
|
||||
NULL,
|
||||
raw_flush,
|
||||
|
||||
#if 0
|
||||
.bdrv_aio_read = raw_aio_read,
|
||||
.bdrv_aio_write = raw_aio_write,
|
||||
.bdrv_aio_cancel = raw_aio_cancel,
|
||||
.aiocb_size = sizeof(RawAIOCB);
|
||||
#endif
|
||||
.bdrv_pread = raw_pread,
|
||||
.bdrv_pwrite = raw_pwrite,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
#endif /* _WIN32 */
|
||||
|
218
block.c
218
block.c
@ -181,24 +181,37 @@ void get_tmp_filename(char *filename, int size)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static int is_windows_drive(const char *filename)
|
||||
{
|
||||
if (((filename[0] >= 'a' && filename[0] <= 'z') ||
|
||||
(filename[0] >= 'A' && filename[0] <= 'Z')) &&
|
||||
filename[1] == ':' && filename[2] == '\0')
|
||||
return 1;
|
||||
if (strstart(filename, "\\\\.\\", NULL) ||
|
||||
strstart(filename, "//./", NULL))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static BlockDriver *find_protocol(const char *filename)
|
||||
{
|
||||
BlockDriver *drv1;
|
||||
char protocol[128];
|
||||
int len;
|
||||
const char *p;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (is_windows_drive(filename))
|
||||
return &bdrv_raw;
|
||||
#endif
|
||||
p = strchr(filename, ':');
|
||||
if (!p)
|
||||
return &bdrv_raw;
|
||||
len = p - filename;
|
||||
if (len > sizeof(protocol) - 1)
|
||||
len = sizeof(protocol) - 1;
|
||||
#ifdef _WIN32
|
||||
if (len == 1) {
|
||||
/* specific win32 case for driver letters */
|
||||
return &bdrv_raw;
|
||||
}
|
||||
#endif
|
||||
memcpy(protocol, filename, len);
|
||||
protocol[len] = '\0';
|
||||
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
|
||||
@ -218,14 +231,28 @@ static BlockDriver *find_image_format(const char *filename)
|
||||
uint8_t buf[2048];
|
||||
BlockDriverState *bs;
|
||||
|
||||
/* detect host devices. By convention, /dev/cdrom[N] is always
|
||||
recognized as a host CDROM */
|
||||
if (strstart(filename, "/dev/cdrom", NULL))
|
||||
return &bdrv_host_device;
|
||||
#ifdef _WIN32
|
||||
if (is_windows_drive(filename))
|
||||
return &bdrv_host_device;
|
||||
#else
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(filename, &st) >= 0 &&
|
||||
(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
|
||||
return &bdrv_host_device;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
drv = find_protocol(filename);
|
||||
/* no need to test disk image formats for vvfat or host specific
|
||||
devices */
|
||||
/* no need to test disk image formats for vvfat */
|
||||
if (drv == &bdrv_vvfat)
|
||||
return drv;
|
||||
if (strstart(filename, "/dev/", NULL))
|
||||
return &bdrv_raw;
|
||||
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
@ -362,9 +389,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs->inserted = 1;
|
||||
|
||||
/* call the change callback */
|
||||
bs->media_changed = 1;
|
||||
if (bs->change_cb)
|
||||
bs->change_cb(bs->change_opaque);
|
||||
|
||||
@ -373,7 +399,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->inserted) {
|
||||
if (bs->drv) {
|
||||
if (bs->backing_hd)
|
||||
bdrv_delete(bs->backing_hd);
|
||||
bs->drv->bdrv_close(bs);
|
||||
@ -385,9 +411,9 @@ void bdrv_close(BlockDriverState *bs)
|
||||
#endif
|
||||
bs->opaque = NULL;
|
||||
bs->drv = NULL;
|
||||
bs->inserted = 0;
|
||||
|
||||
/* call the change callback */
|
||||
bs->media_changed = 1;
|
||||
if (bs->change_cb)
|
||||
bs->change_cb(bs->change_opaque);
|
||||
}
|
||||
@ -403,12 +429,13 @@ void bdrv_delete(BlockDriverState *bs)
|
||||
/* commit COW file into the raw image */
|
||||
int bdrv_commit(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int64_t i, total_sectors;
|
||||
int n, j;
|
||||
unsigned char sector[512];
|
||||
|
||||
if (!bs->inserted)
|
||||
return -ENOENT;
|
||||
if (!drv)
|
||||
return -ENOMEDIUM;
|
||||
|
||||
if (bs->read_only) {
|
||||
return -EACCES;
|
||||
@ -420,7 +447,7 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
|
||||
total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
|
||||
for (i = 0; i < total_sectors;) {
|
||||
if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
|
||||
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
|
||||
for(j = 0; j < n; j++) {
|
||||
if (bdrv_read(bs, i, sector, 1) != 0) {
|
||||
return -EIO;
|
||||
@ -436,20 +463,20 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
if (bs->drv->bdrv_make_empty)
|
||||
return bs->drv->bdrv_make_empty(bs);
|
||||
if (drv->bdrv_make_empty)
|
||||
return drv->bdrv_make_empty(bs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return < 0 if error */
|
||||
/* return < 0 if error. See bdrv_write() for the return codes */
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!bs->inserted)
|
||||
return -1;
|
||||
if (!drv)
|
||||
return -ENOMEDIUM;
|
||||
|
||||
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
|
||||
memcpy(buf, bs->boot_sector_data, 512);
|
||||
@ -466,7 +493,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != len)
|
||||
return -EIO;
|
||||
return -EINVAL;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
@ -474,15 +501,20 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
}
|
||||
|
||||
/* return < 0 if error */
|
||||
/* Return < 0 if error. Important errors are:
|
||||
-EIO generic I/O error (may happen for all errors)
|
||||
-ENOMEDIUM No media inserted.
|
||||
-EINVAL Invalid sector number or nb_sectors
|
||||
-EACCES Trying to write a read-only device
|
||||
*/
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!bs->inserted)
|
||||
return -1;
|
||||
if (!bs->drv)
|
||||
return -ENOMEDIUM;
|
||||
if (bs->read_only)
|
||||
return -1;
|
||||
return -EACCES;
|
||||
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
|
||||
memcpy(bs->boot_sector_data, buf, 512);
|
||||
}
|
||||
@ -501,7 +533,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
}
|
||||
|
||||
/* not necessary now */
|
||||
static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
|
||||
uint8_t *buf, int count1)
|
||||
{
|
||||
@ -603,7 +634,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_pread)
|
||||
return bdrv_pread_em(bs, offset, buf1, count1);
|
||||
return drv->bdrv_pread(bs, offset, buf1, count1);
|
||||
@ -618,7 +649,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_pwrite)
|
||||
return bdrv_pwrite_em(bs, offset, buf1, count1);
|
||||
return drv->bdrv_pwrite(bs, offset, buf1, count1);
|
||||
@ -631,7 +662,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_truncate)
|
||||
return -ENOTSUP;
|
||||
return drv->bdrv_truncate(bs, offset);
|
||||
@ -644,7 +675,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_getlength) {
|
||||
/* legacy mode */
|
||||
return bs->total_sectors * SECTOR_SIZE;
|
||||
@ -652,9 +683,16 @@ int64_t bdrv_getlength(BlockDriverState *bs)
|
||||
return drv->bdrv_getlength(bs);
|
||||
}
|
||||
|
||||
/* return 0 as number of sectors if no device present or error */
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
||||
{
|
||||
*nb_sectors_ptr = bs->total_sectors;
|
||||
int64_t length;
|
||||
length = bdrv_getlength(bs);
|
||||
if (length < 0)
|
||||
length = 0;
|
||||
else
|
||||
length = length >> SECTOR_BITS;
|
||||
*nb_sectors_ptr = length;
|
||||
}
|
||||
|
||||
/* force a given boot sector. */
|
||||
@ -715,21 +753,7 @@ int bdrv_is_read_only(BlockDriverState *bs)
|
||||
return bs->read_only;
|
||||
}
|
||||
|
||||
int bdrv_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return bs->inserted;
|
||||
}
|
||||
|
||||
int bdrv_is_locked(BlockDriverState *bs)
|
||||
{
|
||||
return bs->locked;
|
||||
}
|
||||
|
||||
void bdrv_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
bs->locked = locked;
|
||||
}
|
||||
|
||||
/* XXX: no longer used */
|
||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
||||
void (*change_cb)(void *opaque), void *opaque)
|
||||
{
|
||||
@ -761,7 +785,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
|
||||
|
||||
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
|
||||
{
|
||||
if (!bs->inserted || !bs->drv) {
|
||||
if (!bs->drv) {
|
||||
buf[0] = '\0';
|
||||
} else {
|
||||
pstrcpy(buf, buf_size, bs->drv->format_name);
|
||||
@ -833,7 +857,7 @@ void bdrv_info(void)
|
||||
if (bs->removable) {
|
||||
term_printf(" locked=%d", bs->locked);
|
||||
}
|
||||
if (bs->inserted) {
|
||||
if (bs->drv) {
|
||||
term_printf(" file=%s", bs->filename);
|
||||
if (bs->backing_file[0] != '\0')
|
||||
term_printf(" backing_file=%s", bs->backing_file);
|
||||
@ -863,7 +887,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_write_compressed)
|
||||
return -ENOTSUP;
|
||||
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
|
||||
@ -873,7 +897,7 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_get_info)
|
||||
return -ENOTSUP;
|
||||
memset(bdi, 0, sizeof(*bdi));
|
||||
@ -888,7 +912,7 @@ int bdrv_snapshot_create(BlockDriverState *bs,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_snapshot_create)
|
||||
return -ENOTSUP;
|
||||
return drv->bdrv_snapshot_create(bs, sn_info);
|
||||
@ -899,7 +923,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_snapshot_goto)
|
||||
return -ENOTSUP;
|
||||
return drv->bdrv_snapshot_goto(bs, snapshot_id);
|
||||
@ -909,7 +933,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_snapshot_delete)
|
||||
return -ENOTSUP;
|
||||
return drv->bdrv_snapshot_delete(bs, snapshot_id);
|
||||
@ -920,7 +944,7 @@ int bdrv_snapshot_list(BlockDriverState *bs,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_snapshot_list)
|
||||
return -ENOTSUP;
|
||||
return drv->bdrv_snapshot_list(bs, psn_info);
|
||||
@ -1001,7 +1025,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!bs->inserted)
|
||||
if (!drv)
|
||||
return NULL;
|
||||
|
||||
/* XXX: we assume that nb_sectors == 0 is suppored by the async read */
|
||||
@ -1021,7 +1045,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!bs->inserted)
|
||||
if (!drv)
|
||||
return NULL;
|
||||
if (bs->read_only)
|
||||
return NULL;
|
||||
@ -1170,6 +1194,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
|
||||
void bdrv_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_raw);
|
||||
bdrv_register(&bdrv_host_device);
|
||||
#ifndef _WIN32
|
||||
bdrv_register(&bdrv_cow);
|
||||
#endif
|
||||
@ -1211,3 +1236,78 @@ void qemu_aio_release(void *p)
|
||||
acb->next = drv->free_aiocb;
|
||||
drv->free_aiocb = acb;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* removable device support */
|
||||
|
||||
/**
|
||||
* Return TRUE if the media is present
|
||||
*/
|
||||
int bdrv_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
if (!drv)
|
||||
return 0;
|
||||
if (!drv->bdrv_is_inserted)
|
||||
return 1;
|
||||
ret = drv->bdrv_is_inserted(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if the media changed since the last call to this
|
||||
* function. It is currently only used for floppy disks
|
||||
*/
|
||||
int bdrv_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
if (!drv || !drv->bdrv_media_changed)
|
||||
ret = -ENOTSUP;
|
||||
else
|
||||
ret = drv->bdrv_media_changed(bs);
|
||||
if (ret == -ENOTSUP)
|
||||
ret = bs->media_changed;
|
||||
bs->media_changed = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* If eject_flag is TRUE, eject the media. Otherwise, close the tray
|
||||
*/
|
||||
void bdrv_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
if (!drv || !drv->bdrv_eject) {
|
||||
ret = -ENOTSUP;
|
||||
} else {
|
||||
ret = drv->bdrv_eject(bs, eject_flag);
|
||||
}
|
||||
if (ret == -ENOTSUP) {
|
||||
if (eject_flag)
|
||||
bdrv_close(bs);
|
||||
}
|
||||
}
|
||||
|
||||
int bdrv_is_locked(BlockDriverState *bs)
|
||||
{
|
||||
return bs->locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock or unlock the media (if it is locked, the user won't be able
|
||||
* to eject it manually).
|
||||
*/
|
||||
void bdrv_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
bs->locked = locked;
|
||||
if (drv && drv->bdrv_set_locked) {
|
||||
drv->bdrv_set_locked(bs, locked);
|
||||
}
|
||||
}
|
||||
|
12
block_int.h
12
block_int.h
@ -70,6 +70,12 @@ struct BlockDriver {
|
||||
QEMUSnapshotInfo **psn_info);
|
||||
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||
|
||||
/* removable device specific */
|
||||
int (*bdrv_is_inserted)(BlockDriverState *bs);
|
||||
int (*bdrv_media_changed)(BlockDriverState *bs);
|
||||
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
|
||||
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
|
||||
|
||||
BlockDriverAIOCB *free_aiocb;
|
||||
struct BlockDriver *next;
|
||||
};
|
||||
@ -78,7 +84,6 @@ struct BlockDriverState {
|
||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
||||
size in sectors */
|
||||
int read_only; /* if true, the media is read only */
|
||||
int inserted; /* if true, the media is present */
|
||||
int removable; /* if true, the media can be removed */
|
||||
int locked; /* if true, the media cannot temporarily be ejected */
|
||||
int encrypted; /* if true, the media is encrypted */
|
||||
@ -86,7 +91,7 @@ struct BlockDriverState {
|
||||
void (*change_cb)(void *opaque);
|
||||
void *change_opaque;
|
||||
|
||||
BlockDriver *drv;
|
||||
BlockDriver *drv; /* NULL means no media */
|
||||
void *opaque;
|
||||
|
||||
int boot_sector_enabled;
|
||||
@ -96,7 +101,8 @@ struct BlockDriverState {
|
||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||
this file image */
|
||||
int is_temporary;
|
||||
|
||||
int media_changed;
|
||||
|
||||
BlockDriverState *backing_hd;
|
||||
/* async read/write emulation */
|
||||
|
||||
|
@ -206,7 +206,7 @@ Select the emulated machine (@code{-M ?} for list)
|
||||
@item -fda file
|
||||
@item -fdb file
|
||||
Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
|
||||
use the host floppy by using @file{/dev/fd0} as filename.
|
||||
use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}).
|
||||
|
||||
@item -hda file
|
||||
@item -hdb file
|
||||
@ -217,7 +217,7 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
|
||||
@item -cdrom file
|
||||
Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
|
||||
@option{-cdrom} at the same time). You can use the host CD-ROM by
|
||||
using @file{/dev/cdrom} as filename.
|
||||
using @file{/dev/cdrom} as filename (@pxref{host_drives}).
|
||||
|
||||
@item -boot [a|c|d]
|
||||
Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is
|
||||
@ -916,6 +916,7 @@ snapshots.
|
||||
* disk_images_snapshot_mode:: Snapshot mode
|
||||
* vm_snapshots:: VM snapshots
|
||||
* qemu_img_invocation:: qemu-img Invocation
|
||||
* host_drives:: Using host drives
|
||||
* disk_images_fat_images:: Virtual FAT disk images
|
||||
@end menu
|
||||
|
||||
@ -997,6 +998,57 @@ state is not saved or restored properly (in particular USB).
|
||||
|
||||
@include qemu-img.texi
|
||||
|
||||
@node host_drives
|
||||
@subsection Using host drives
|
||||
|
||||
In addition to disk image files, QEMU can directly access host
|
||||
devices. We describe here the usage for QEMU version >= 0.8.3.
|
||||
|
||||
@subsubsection Linux
|
||||
|
||||
On Linux, you can directly use the host device filename instead of a
|
||||
disk image filename provided you have enough proviledge to access
|
||||
it. For example, use @file{/dev/cdrom} to access to the CDROM or
|
||||
@file{/dev/fd0} for the floppy.
|
||||
|
||||
@table
|
||||
@item CD
|
||||
You can specify a CDROM device even if no CDROM is loaded. QEMU has
|
||||
specific code to detect CDROM insertion or removal. CDROM ejection by
|
||||
the guest OS is supported. Currently only data CDs are supported.
|
||||
@item Floppy
|
||||
You can specify a floppy device even if no floppy is loaded. Floppy
|
||||
removal is currently not detected accurately (if you change floppy
|
||||
without doing floppy access while the floppy is not loaded, the guest
|
||||
OS will think that the same floppy is loaded).
|
||||
@item Hard disks
|
||||
Hard disks can be used. Normally you must specify the whole disk
|
||||
(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can
|
||||
see it as a partitioned disk. WARNING: unless you know what you do, it
|
||||
is better to only make READ-ONLY accesses to the hard disk otherwise
|
||||
you may corrupt your host data (use the @option{-snapshot} command
|
||||
line option or modify the device permissions accordingly).
|
||||
@end table
|
||||
|
||||
@subsubsection Windows
|
||||
|
||||
On Windows you can use any host drives as QEMU drive. The prefered
|
||||
syntax is the driver letter (e.g. @file{d:}). The alternate syntax
|
||||
@file{\\.\d:} is supported. @file{/dev/cdrom} is supported as an alias
|
||||
to the first CDROM drive.
|
||||
|
||||
Currently there is no specific code to handle removable medias, so it
|
||||
is better to use the @code{change} or @code{eject} monitor commands to
|
||||
change or eject media.
|
||||
|
||||
@subsubsection Mac OS X
|
||||
|
||||
@file{/dev/cdrom} is an alias to the first CDROM.
|
||||
|
||||
Currently there is no specific code to handle removable medias, so it
|
||||
is better to use the @code{change} or @code{eject} monitor commands to
|
||||
change or eject media.
|
||||
|
||||
@node disk_images_fat_images
|
||||
@subsection Virtual FAT disk images
|
||||
|
||||
|
4
vl.h
4
vl.h
@ -50,6 +50,7 @@
|
||||
#define fsync _commit
|
||||
#define lseek _lseeki64
|
||||
#define ENOTSUP 4096
|
||||
#define ENOMEDIUM 4097
|
||||
extern int qemu_ftruncate64(int, int64_t);
|
||||
#define ftruncate qemu_ftruncate64
|
||||
|
||||
@ -502,6 +503,7 @@ typedef struct BlockDriverState BlockDriverState;
|
||||
typedef struct BlockDriver BlockDriver;
|
||||
|
||||
extern BlockDriver bdrv_raw;
|
||||
extern BlockDriver bdrv_host_device;
|
||||
extern BlockDriver bdrv_cow;
|
||||
extern BlockDriver bdrv_qcow;
|
||||
extern BlockDriver bdrv_vmdk;
|
||||
@ -604,8 +606,10 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
|
||||
int bdrv_is_removable(BlockDriverState *bs);
|
||||
int bdrv_is_read_only(BlockDriverState *bs);
|
||||
int bdrv_is_inserted(BlockDriverState *bs);
|
||||
int bdrv_media_changed(BlockDriverState *bs);
|
||||
int bdrv_is_locked(BlockDriverState *bs);
|
||||
void bdrv_set_locked(BlockDriverState *bs, int locked);
|
||||
void bdrv_eject(BlockDriverState *bs, int eject_flag);
|
||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
||||
void (*change_cb)(void *opaque), void *opaque);
|
||||
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
|
||||
|
Loading…
Reference in New Issue
Block a user