提交 19cb3738 编写于 作者: B bellard

better support of host drives


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2124 c046a42c-6fe2-441c-8c8c-71466251a162
上级 66c6ef76
此差异已折叠。
......@@ -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);
}
}
......@@ -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
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册