mirror of https://github.com/xemu-project/xemu.git
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__
|
#ifdef __sun__
|
||||||
#include <sys/dkio.h>
|
#include <sys/dkio.h>
|
||||||
#endif
|
#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 {
|
typedef struct BDRVRawState {
|
||||||
int fd;
|
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;
|
} BDRVRawState;
|
||||||
|
|
||||||
#ifdef CONFIG_COCOA
|
static int fd_open(BlockDriverState *bs);
|
||||||
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 raw_open(BlockDriverState *bs, const char *filename, int flags)
|
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
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;
|
open_flags = O_BINARY;
|
||||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||||
open_flags |= 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)
|
if (flags & BDRV_O_CREAT)
|
||||||
open_flags |= O_CREAT | O_TRUNC;
|
open_flags |= O_CREAT | O_TRUNC;
|
||||||
|
|
||||||
|
s->type = FTYPE_FILE;
|
||||||
|
|
||||||
fd = open(filename, open_flags, 0644);
|
fd = open(filename, open_flags, 0644);
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
return -errno;
|
ret = -errno;
|
||||||
|
if (ret == -EROFS)
|
||||||
|
ret = -EACCES;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -180,6 +128,10 @@ static int raw_pread(BlockDriverState *bs, int64_t offset,
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = fd_open(bs);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
lseek(s->fd, offset, SEEK_SET);
|
lseek(s->fd, offset, SEEK_SET);
|
||||||
ret = read(s->fd, buf, count);
|
ret = read(s->fd, buf, count);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -191,13 +143,17 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = fd_open(bs);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
lseek(s->fd, offset, SEEK_SET);
|
lseek(s->fd, offset, SEEK_SET);
|
||||||
ret = write(s->fd, buf, count);
|
ret = write(s->fd, buf, count);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* Unix AOP using POSIX AIO */
|
/* Unix AIO using POSIX AIO */
|
||||||
|
|
||||||
typedef struct RawAIOCB {
|
typedef struct RawAIOCB {
|
||||||
BlockDriverAIOCB common;
|
BlockDriverAIOCB common;
|
||||||
|
@ -236,15 +192,18 @@ void qemu_aio_init(void)
|
||||||
act.sa_handler = aio_signal_handler;
|
act.sa_handler = aio_signal_handler;
|
||||||
sigaction(aio_sig_num, &act, NULL);
|
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;
|
struct aioinit ai;
|
||||||
memset(&ai, 0, sizeof(ai));
|
memset(&ai, 0, sizeof(ai));
|
||||||
ai.aio_threads = 2;
|
ai.aio_threads = 1;
|
||||||
ai.aio_num = 1;
|
ai.aio_num = 1;
|
||||||
ai.aio_idle_time = 365 * 100000;
|
ai.aio_idle_time = 365 * 100000;
|
||||||
aio_init(&ai);
|
aio_init(&ai);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_aio_poll(void)
|
void qemu_aio_poll(void)
|
||||||
|
@ -270,7 +229,7 @@ void qemu_aio_poll(void)
|
||||||
if (ret == acb->aiocb.aio_nbytes)
|
if (ret == acb->aiocb.aio_nbytes)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
else
|
else
|
||||||
ret = -1;
|
ret = -EINVAL;
|
||||||
} else {
|
} else {
|
||||||
ret = -ret;
|
ret = -ret;
|
||||||
}
|
}
|
||||||
|
@ -329,6 +288,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
RawAIOCB *acb;
|
RawAIOCB *acb;
|
||||||
|
|
||||||
|
if (fd_open(bs) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
acb = qemu_aio_get(bs, cb, opaque);
|
acb = qemu_aio_get(bs, cb, opaque);
|
||||||
if (!acb)
|
if (!acb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -405,12 +367,17 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||||
static void raw_close(BlockDriverState *bs)
|
static void raw_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
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)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
|
if (s->type != FTYPE_FILE)
|
||||||
|
return -ENOTSUP;
|
||||||
if (ftruncate(s->fd, offset) < 0)
|
if (ftruncate(s->fd, offset) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -428,6 +395,11 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||||
struct dk_minfo minfo;
|
struct dk_minfo minfo;
|
||||||
int rv;
|
int rv;
|
||||||
#endif
|
#endif
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = fd_open(bs);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
#ifdef _BSD
|
#ifdef _BSD
|
||||||
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
|
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);
|
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;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,13 +475,358 @@ BlockDriver bdrv_raw = {
|
||||||
.bdrv_getlength = raw_getlength,
|
.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 */
|
#else /* _WIN32 */
|
||||||
|
|
||||||
/* XXX: use another file ? */
|
/* XXX: use another file ? */
|
||||||
#include <winioctl.h>
|
#include <winioctl.h>
|
||||||
|
|
||||||
|
#define FTYPE_FILE 0
|
||||||
|
#define FTYPE_CD 1
|
||||||
|
|
||||||
typedef struct BDRVRawState {
|
typedef struct BDRVRawState {
|
||||||
HANDLE hfile;
|
HANDLE hfile;
|
||||||
|
int type;
|
||||||
|
char drive_letter[2];
|
||||||
} BDRVRawState;
|
} BDRVRawState;
|
||||||
|
|
||||||
typedef struct RawAIOCB {
|
typedef struct RawAIOCB {
|
||||||
|
@ -565,6 +876,23 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
int access_flags, create_flags;
|
int access_flags, create_flags;
|
||||||
DWORD overlapped;
|
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) {
|
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||||
|
@ -765,10 +1093,22 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
LARGE_INTEGER l;
|
LARGE_INTEGER l;
|
||||||
|
ULARGE_INTEGER available, total, total_free;
|
||||||
|
|
||||||
l.LowPart = GetFileSize(s->hfile, &l.HighPart);
|
switch(s->ftype) {
|
||||||
if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
|
case FTYPE_FILE:
|
||||||
return -EIO;
|
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;
|
return l.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,4 +1173,146 @@ BlockDriver bdrv_raw = {
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.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 */
|
#endif /* _WIN32 */
|
||||||
|
|
218
block.c
218
block.c
|
@ -181,24 +181,37 @@ void get_tmp_filename(char *filename, int size)
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
static BlockDriver *find_protocol(const char *filename)
|
||||||
{
|
{
|
||||||
BlockDriver *drv1;
|
BlockDriver *drv1;
|
||||||
char protocol[128];
|
char protocol[128];
|
||||||
int len;
|
int len;
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (is_windows_drive(filename))
|
||||||
|
return &bdrv_raw;
|
||||||
|
#endif
|
||||||
p = strchr(filename, ':');
|
p = strchr(filename, ':');
|
||||||
if (!p)
|
if (!p)
|
||||||
return &bdrv_raw;
|
return &bdrv_raw;
|
||||||
len = p - filename;
|
len = p - filename;
|
||||||
if (len > sizeof(protocol) - 1)
|
if (len > sizeof(protocol) - 1)
|
||||||
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);
|
memcpy(protocol, filename, len);
|
||||||
protocol[len] = '\0';
|
protocol[len] = '\0';
|
||||||
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
|
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];
|
uint8_t buf[2048];
|
||||||
BlockDriverState *bs;
|
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);
|
drv = find_protocol(filename);
|
||||||
/* no need to test disk image formats for vvfat or host specific
|
/* no need to test disk image formats for vvfat */
|
||||||
devices */
|
|
||||||
if (drv == &bdrv_vvfat)
|
if (drv == &bdrv_vvfat)
|
||||||
return drv;
|
return drv;
|
||||||
if (strstart(filename, "/dev/", NULL))
|
|
||||||
return &bdrv_raw;
|
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
|
ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -362,9 +389,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->inserted = 1;
|
|
||||||
|
|
||||||
/* call the change callback */
|
/* call the change callback */
|
||||||
|
bs->media_changed = 1;
|
||||||
if (bs->change_cb)
|
if (bs->change_cb)
|
||||||
bs->change_cb(bs->change_opaque);
|
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)
|
void bdrv_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
if (bs->inserted) {
|
if (bs->drv) {
|
||||||
if (bs->backing_hd)
|
if (bs->backing_hd)
|
||||||
bdrv_delete(bs->backing_hd);
|
bdrv_delete(bs->backing_hd);
|
||||||
bs->drv->bdrv_close(bs);
|
bs->drv->bdrv_close(bs);
|
||||||
|
@ -385,9 +411,9 @@ void bdrv_close(BlockDriverState *bs)
|
||||||
#endif
|
#endif
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
bs->inserted = 0;
|
|
||||||
|
|
||||||
/* call the change callback */
|
/* call the change callback */
|
||||||
|
bs->media_changed = 1;
|
||||||
if (bs->change_cb)
|
if (bs->change_cb)
|
||||||
bs->change_cb(bs->change_opaque);
|
bs->change_cb(bs->change_opaque);
|
||||||
}
|
}
|
||||||
|
@ -403,12 +429,13 @@ void bdrv_delete(BlockDriverState *bs)
|
||||||
/* commit COW file into the raw image */
|
/* commit COW file into the raw image */
|
||||||
int bdrv_commit(BlockDriverState *bs)
|
int bdrv_commit(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
|
BlockDriver *drv = bs->drv;
|
||||||
int64_t i, total_sectors;
|
int64_t i, total_sectors;
|
||||||
int n, j;
|
int n, j;
|
||||||
unsigned char sector[512];
|
unsigned char sector[512];
|
||||||
|
|
||||||
if (!bs->inserted)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
if (bs->read_only) {
|
if (bs->read_only) {
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
@ -420,7 +447,7 @@ int bdrv_commit(BlockDriverState *bs)
|
||||||
|
|
||||||
total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
|
total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
|
||||||
for (i = 0; i < total_sectors;) {
|
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++) {
|
for(j = 0; j < n; j++) {
|
||||||
if (bdrv_read(bs, i, sector, 1) != 0) {
|
if (bdrv_read(bs, i, sector, 1) != 0) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -436,20 +463,20 @@ int bdrv_commit(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->drv->bdrv_make_empty)
|
if (drv->bdrv_make_empty)
|
||||||
return bs->drv->bdrv_make_empty(bs);
|
return drv->bdrv_make_empty(bs);
|
||||||
|
|
||||||
return 0;
|
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,
|
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
if (!bs->inserted)
|
if (!drv)
|
||||||
return -1;
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
|
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
|
||||||
memcpy(buf, bs->boot_sector_data, 512);
|
memcpy(buf, bs->boot_sector_data, 512);
|
||||||
|
@ -466,7 +493,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
else if (ret != len)
|
else if (ret != len)
|
||||||
return -EIO;
|
return -EINVAL;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} 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,
|
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
const uint8_t *buf, int nb_sectors)
|
const uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!bs->inserted)
|
if (!bs->drv)
|
||||||
return -1;
|
return -ENOMEDIUM;
|
||||||
if (bs->read_only)
|
if (bs->read_only)
|
||||||
return -1;
|
return -EACCES;
|
||||||
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
|
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
|
||||||
memcpy(bs->boot_sector_data, buf, 512);
|
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,
|
static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
|
||||||
uint8_t *buf, int count1)
|
uint8_t *buf, int count1)
|
||||||
{
|
{
|
||||||
|
@ -603,7 +634,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_pread)
|
if (!drv->bdrv_pread)
|
||||||
return bdrv_pread_em(bs, offset, buf1, count1);
|
return bdrv_pread_em(bs, offset, buf1, count1);
|
||||||
return drv->bdrv_pread(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;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_pwrite)
|
if (!drv->bdrv_pwrite)
|
||||||
return bdrv_pwrite_em(bs, offset, buf1, count1);
|
return bdrv_pwrite_em(bs, offset, buf1, count1);
|
||||||
return drv->bdrv_pwrite(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;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_truncate)
|
if (!drv->bdrv_truncate)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
return drv->bdrv_truncate(bs, offset);
|
return drv->bdrv_truncate(bs, offset);
|
||||||
|
@ -644,7 +675,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_getlength) {
|
if (!drv->bdrv_getlength) {
|
||||||
/* legacy mode */
|
/* legacy mode */
|
||||||
return bs->total_sectors * SECTOR_SIZE;
|
return bs->total_sectors * SECTOR_SIZE;
|
||||||
|
@ -652,9 +683,16 @@ int64_t bdrv_getlength(BlockDriverState *bs)
|
||||||
return drv->bdrv_getlength(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)
|
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. */
|
/* force a given boot sector. */
|
||||||
|
@ -715,21 +753,7 @@ int bdrv_is_read_only(BlockDriverState *bs)
|
||||||
return bs->read_only;
|
return bs->read_only;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_is_inserted(BlockDriverState *bs)
|
/* XXX: no longer used */
|
||||||
{
|
|
||||||
return bs->inserted;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bdrv_is_locked(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
return bs->locked;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bdrv_set_locked(BlockDriverState *bs, int locked)
|
|
||||||
{
|
|
||||||
bs->locked = locked;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
void bdrv_set_change_cb(BlockDriverState *bs,
|
||||||
void (*change_cb)(void *opaque), void *opaque)
|
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)
|
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
|
||||||
{
|
{
|
||||||
if (!bs->inserted || !bs->drv) {
|
if (!bs->drv) {
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
} else {
|
} else {
|
||||||
pstrcpy(buf, buf_size, bs->drv->format_name);
|
pstrcpy(buf, buf_size, bs->drv->format_name);
|
||||||
|
@ -833,7 +857,7 @@ void bdrv_info(void)
|
||||||
if (bs->removable) {
|
if (bs->removable) {
|
||||||
term_printf(" locked=%d", bs->locked);
|
term_printf(" locked=%d", bs->locked);
|
||||||
}
|
}
|
||||||
if (bs->inserted) {
|
if (bs->drv) {
|
||||||
term_printf(" file=%s", bs->filename);
|
term_printf(" file=%s", bs->filename);
|
||||||
if (bs->backing_file[0] != '\0')
|
if (bs->backing_file[0] != '\0')
|
||||||
term_printf(" backing_file=%s", bs->backing_file);
|
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;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_write_compressed)
|
if (!drv->bdrv_write_compressed)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
|
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;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_get_info)
|
if (!drv->bdrv_get_info)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
memset(bdi, 0, sizeof(*bdi));
|
memset(bdi, 0, sizeof(*bdi));
|
||||||
|
@ -888,7 +912,7 @@ int bdrv_snapshot_create(BlockDriverState *bs,
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_snapshot_create)
|
if (!drv->bdrv_snapshot_create)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
return drv->bdrv_snapshot_create(bs, sn_info);
|
return drv->bdrv_snapshot_create(bs, sn_info);
|
||||||
|
@ -899,7 +923,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_snapshot_goto)
|
if (!drv->bdrv_snapshot_goto)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
return drv->bdrv_snapshot_goto(bs, snapshot_id);
|
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;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_snapshot_delete)
|
if (!drv->bdrv_snapshot_delete)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
return drv->bdrv_snapshot_delete(bs, snapshot_id);
|
return drv->bdrv_snapshot_delete(bs, snapshot_id);
|
||||||
|
@ -920,7 +944,7 @@ int bdrv_snapshot_list(BlockDriverState *bs,
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOENT;
|
return -ENOMEDIUM;
|
||||||
if (!drv->bdrv_snapshot_list)
|
if (!drv->bdrv_snapshot_list)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
return drv->bdrv_snapshot_list(bs, psn_info);
|
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;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
if (!bs->inserted)
|
if (!drv)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* XXX: we assume that nb_sectors == 0 is suppored by the async read */
|
/* 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;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
if (!bs->inserted)
|
if (!drv)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (bs->read_only)
|
if (bs->read_only)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1170,6 +1194,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
|
||||||
void bdrv_init(void)
|
void bdrv_init(void)
|
||||||
{
|
{
|
||||||
bdrv_register(&bdrv_raw);
|
bdrv_register(&bdrv_raw);
|
||||||
|
bdrv_register(&bdrv_host_device);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
bdrv_register(&bdrv_cow);
|
bdrv_register(&bdrv_cow);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1211,3 +1236,78 @@ void qemu_aio_release(void *p)
|
||||||
acb->next = drv->free_aiocb;
|
acb->next = drv->free_aiocb;
|
||||||
drv->free_aiocb = acb;
|
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);
|
QEMUSnapshotInfo **psn_info);
|
||||||
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
|
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;
|
BlockDriverAIOCB *free_aiocb;
|
||||||
struct BlockDriver *next;
|
struct BlockDriver *next;
|
||||||
};
|
};
|
||||||
|
@ -78,7 +84,6 @@ struct BlockDriverState {
|
||||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
int64_t total_sectors; /* if we are reading a disk image, give its
|
||||||
size in sectors */
|
size in sectors */
|
||||||
int read_only; /* if true, the media is read only */
|
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 removable; /* if true, the media can be removed */
|
||||||
int locked; /* if true, the media cannot temporarily be ejected */
|
int locked; /* if true, the media cannot temporarily be ejected */
|
||||||
int encrypted; /* if true, the media is encrypted */
|
int encrypted; /* if true, the media is encrypted */
|
||||||
|
@ -86,7 +91,7 @@ struct BlockDriverState {
|
||||||
void (*change_cb)(void *opaque);
|
void (*change_cb)(void *opaque);
|
||||||
void *change_opaque;
|
void *change_opaque;
|
||||||
|
|
||||||
BlockDriver *drv;
|
BlockDriver *drv; /* NULL means no media */
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
int boot_sector_enabled;
|
int boot_sector_enabled;
|
||||||
|
@ -96,7 +101,8 @@ struct BlockDriverState {
|
||||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||||
this file image */
|
this file image */
|
||||||
int is_temporary;
|
int is_temporary;
|
||||||
|
int media_changed;
|
||||||
|
|
||||||
BlockDriverState *backing_hd;
|
BlockDriverState *backing_hd;
|
||||||
/* async read/write emulation */
|
/* async read/write emulation */
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ Select the emulated machine (@code{-M ?} for list)
|
||||||
@item -fda file
|
@item -fda file
|
||||||
@item -fdb file
|
@item -fdb file
|
||||||
Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
|
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 -hda file
|
||||||
@item -hdb 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
|
@item -cdrom file
|
||||||
Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
|
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
|
@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]
|
@item -boot [a|c|d]
|
||||||
Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is
|
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
|
* disk_images_snapshot_mode:: Snapshot mode
|
||||||
* vm_snapshots:: VM snapshots
|
* vm_snapshots:: VM snapshots
|
||||||
* qemu_img_invocation:: qemu-img Invocation
|
* qemu_img_invocation:: qemu-img Invocation
|
||||||
|
* host_drives:: Using host drives
|
||||||
* disk_images_fat_images:: Virtual FAT disk images
|
* disk_images_fat_images:: Virtual FAT disk images
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
@ -997,6 +998,57 @@ state is not saved or restored properly (in particular USB).
|
||||||
|
|
||||||
@include qemu-img.texi
|
@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
|
@node disk_images_fat_images
|
||||||
@subsection Virtual FAT disk images
|
@subsection Virtual FAT disk images
|
||||||
|
|
||||||
|
|
4
vl.h
4
vl.h
|
@ -50,6 +50,7 @@
|
||||||
#define fsync _commit
|
#define fsync _commit
|
||||||
#define lseek _lseeki64
|
#define lseek _lseeki64
|
||||||
#define ENOTSUP 4096
|
#define ENOTSUP 4096
|
||||||
|
#define ENOMEDIUM 4097
|
||||||
extern int qemu_ftruncate64(int, int64_t);
|
extern int qemu_ftruncate64(int, int64_t);
|
||||||
#define ftruncate qemu_ftruncate64
|
#define ftruncate qemu_ftruncate64
|
||||||
|
|
||||||
|
@ -502,6 +503,7 @@ typedef struct BlockDriverState BlockDriverState;
|
||||||
typedef struct BlockDriver BlockDriver;
|
typedef struct BlockDriver BlockDriver;
|
||||||
|
|
||||||
extern BlockDriver bdrv_raw;
|
extern BlockDriver bdrv_raw;
|
||||||
|
extern BlockDriver bdrv_host_device;
|
||||||
extern BlockDriver bdrv_cow;
|
extern BlockDriver bdrv_cow;
|
||||||
extern BlockDriver bdrv_qcow;
|
extern BlockDriver bdrv_qcow;
|
||||||
extern BlockDriver bdrv_vmdk;
|
extern BlockDriver bdrv_vmdk;
|
||||||
|
@ -604,8 +606,10 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
|
||||||
int bdrv_is_removable(BlockDriverState *bs);
|
int bdrv_is_removable(BlockDriverState *bs);
|
||||||
int bdrv_is_read_only(BlockDriverState *bs);
|
int bdrv_is_read_only(BlockDriverState *bs);
|
||||||
int bdrv_is_inserted(BlockDriverState *bs);
|
int bdrv_is_inserted(BlockDriverState *bs);
|
||||||
|
int bdrv_media_changed(BlockDriverState *bs);
|
||||||
int bdrv_is_locked(BlockDriverState *bs);
|
int bdrv_is_locked(BlockDriverState *bs);
|
||||||
void bdrv_set_locked(BlockDriverState *bs, int locked);
|
void bdrv_set_locked(BlockDriverState *bs, int locked);
|
||||||
|
void bdrv_eject(BlockDriverState *bs, int eject_flag);
|
||||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
void bdrv_set_change_cb(BlockDriverState *bs,
|
||||||
void (*change_cb)(void *opaque), void *opaque);
|
void (*change_cb)(void *opaque), void *opaque);
|
||||||
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
|
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
|
||||||
|
|
Loading…
Reference in New Issue