Commit 19cb37389f4641d48803f0c5d72708749cbcf318

Authored by bellard
1 parent 66c6ef76

better support of host drives


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2124 c046a42c-6fe2-441c-8c8c-71466251a162
block-raw.c
@@ -46,100 +46,42 @@ @@ -46,100 +46,42 @@
46 #ifdef __sun__ 46 #ifdef __sun__
47 #include <sys/dkio.h> 47 #include <sys/dkio.h>
48 #endif 48 #endif
  49 +#ifdef __linux__
  50 +#include <sys/ioctl.h>
  51 +#include <linux/cdrom.h>
  52 +#include <linux/fd.h>
  53 +#endif
49 54
50 -typedef struct BDRVRawState {  
51 - int fd;  
52 -} BDRVRawState; 55 +//#define DEBUG_FLOPPY
53 56
54 -#ifdef CONFIG_COCOA  
55 -static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );  
56 -static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );  
57 -  
58 -kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )  
59 -{  
60 - kern_return_t kernResult;  
61 - mach_port_t masterPort;  
62 - CFMutableDictionaryRef classesToMatch;  
63 -  
64 - kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );  
65 - if ( KERN_SUCCESS != kernResult ) {  
66 - printf( "IOMasterPort returned %d\n", kernResult );  
67 - }  
68 -  
69 - classesToMatch = IOServiceMatching( kIOCDMediaClass );  
70 - if ( classesToMatch == NULL ) {  
71 - printf( "IOServiceMatching returned a NULL dictionary.\n" );  
72 - } else {  
73 - CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );  
74 - }  
75 - kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );  
76 - if ( KERN_SUCCESS != kernResult )  
77 - {  
78 - printf( "IOServiceGetMatchingServices returned %d\n", kernResult );  
79 - }  
80 -  
81 - return kernResult;  
82 -} 57 +#define FTYPE_FILE 0
  58 +#define FTYPE_CD 1
  59 +#define FTYPE_FD 2
83 60
84 -kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )  
85 -{  
86 - io_object_t nextMedia;  
87 - kern_return_t kernResult = KERN_FAILURE;  
88 - *bsdPath = '\0';  
89 - nextMedia = IOIteratorNext( mediaIterator );  
90 - if ( nextMedia )  
91 - {  
92 - CFTypeRef bsdPathAsCFString;  
93 - bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );  
94 - if ( bsdPathAsCFString ) {  
95 - size_t devPathLength;  
96 - strcpy( bsdPath, _PATH_DEV );  
97 - strcat( bsdPath, "r" );  
98 - devPathLength = strlen( bsdPath );  
99 - if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {  
100 - kernResult = KERN_SUCCESS;  
101 - }  
102 - CFRelease( bsdPathAsCFString );  
103 - }  
104 - IOObjectRelease( nextMedia );  
105 - }  
106 -  
107 - return kernResult;  
108 -} 61 +/* if the FD is not accessed during that time (in ms), we try to
  62 + reopen it to see if the disk has been changed */
  63 +#define FD_OPEN_TIMEOUT 1000
109 64
  65 +typedef struct BDRVRawState {
  66 + int fd;
  67 + int type;
  68 +#if defined(__linux__)
  69 + /* linux floppy specific */
  70 + int fd_open_flags;
  71 + int64_t fd_open_time;
  72 + int64_t fd_error_time;
  73 + int fd_got_error;
  74 + int fd_media_changed;
110 #endif 75 #endif
  76 +} BDRVRawState;
  77 +
  78 +static int fd_open(BlockDriverState *bs);
111 79
112 static int raw_open(BlockDriverState *bs, const char *filename, int flags) 80 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
113 { 81 {
114 BDRVRawState *s = bs->opaque; 82 BDRVRawState *s = bs->opaque;
115 - int fd, open_flags; 83 + int fd, open_flags, ret;
116 84
117 -#ifdef CONFIG_COCOA  
118 - if (strstart(filename, "/dev/cdrom", NULL)) {  
119 - kern_return_t kernResult;  
120 - io_iterator_t mediaIterator;  
121 - char bsdPath[ MAXPATHLEN ];  
122 - int fd;  
123 -  
124 - kernResult = FindEjectableCDMedia( &mediaIterator );  
125 - kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );  
126 -  
127 - if ( bsdPath[ 0 ] != '\0' ) {  
128 - strcat(bsdPath,"s0");  
129 - /* some CDs don't have a partition 0 */  
130 - fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);  
131 - if (fd < 0) {  
132 - bsdPath[strlen(bsdPath)-1] = '1';  
133 - } else {  
134 - close(fd);  
135 - }  
136 - filename = bsdPath;  
137 - }  
138 -  
139 - if ( mediaIterator )  
140 - IOObjectRelease( mediaIterator );  
141 - }  
142 -#endif  
143 open_flags = O_BINARY; 85 open_flags = O_BINARY;
144 if ((flags & BDRV_O_ACCESS) == O_RDWR) { 86 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
145 open_flags |= O_RDWR; 87 open_flags |= O_RDWR;
@@ -150,9 +92,15 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) @@ -150,9 +92,15 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
150 if (flags & BDRV_O_CREAT) 92 if (flags & BDRV_O_CREAT)
151 open_flags |= O_CREAT | O_TRUNC; 93 open_flags |= O_CREAT | O_TRUNC;
152 94
  95 + s->type = FTYPE_FILE;
  96 +
153 fd = open(filename, open_flags, 0644); 97 fd = open(filename, open_flags, 0644);
154 - if (fd < 0)  
155 - return -errno; 98 + if (fd < 0) {
  99 + ret = -errno;
  100 + if (ret == -EROFS)
  101 + ret = -EACCES;
  102 + return ret;
  103 + }
156 s->fd = fd; 104 s->fd = fd;
157 return 0; 105 return 0;
158 } 106 }
@@ -180,6 +128,10 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, @@ -180,6 +128,10 @@ static int raw_pread(BlockDriverState *bs, int64_t offset,
180 BDRVRawState *s = bs->opaque; 128 BDRVRawState *s = bs->opaque;
181 int ret; 129 int ret;
182 130
  131 + ret = fd_open(bs);
  132 + if (ret < 0)
  133 + return ret;
  134 +
183 lseek(s->fd, offset, SEEK_SET); 135 lseek(s->fd, offset, SEEK_SET);
184 ret = read(s->fd, buf, count); 136 ret = read(s->fd, buf, count);
185 return ret; 137 return ret;
@@ -191,13 +143,17 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, @@ -191,13 +143,17 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
191 BDRVRawState *s = bs->opaque; 143 BDRVRawState *s = bs->opaque;
192 int ret; 144 int ret;
193 145
  146 + ret = fd_open(bs);
  147 + if (ret < 0)
  148 + return ret;
  149 +
194 lseek(s->fd, offset, SEEK_SET); 150 lseek(s->fd, offset, SEEK_SET);
195 ret = write(s->fd, buf, count); 151 ret = write(s->fd, buf, count);
196 return ret; 152 return ret;
197 } 153 }
198 154
199 /***********************************************************/ 155 /***********************************************************/
200 -/* Unix AOP using POSIX AIO */ 156 +/* Unix AIO using POSIX AIO */
201 157
202 typedef struct RawAIOCB { 158 typedef struct RawAIOCB {
203 BlockDriverAIOCB common; 159 BlockDriverAIOCB common;
@@ -236,15 +192,18 @@ void qemu_aio_init(void) @@ -236,15 +192,18 @@ void qemu_aio_init(void)
236 act.sa_handler = aio_signal_handler; 192 act.sa_handler = aio_signal_handler;
237 sigaction(aio_sig_num, &act, NULL); 193 sigaction(aio_sig_num, &act, NULL);
238 194
  195 +#if defined(__GLIBC__) && defined(__linux__)
239 { 196 {
240 - /* XXX: aio thread exit seems to hang on RH 9 */ 197 + /* XXX: aio thread exit seems to hang on RedHat 9 and this init
  198 + seems to fix the problem. */
241 struct aioinit ai; 199 struct aioinit ai;
242 memset(&ai, 0, sizeof(ai)); 200 memset(&ai, 0, sizeof(ai));
243 - ai.aio_threads = 2; 201 + ai.aio_threads = 1;
244 ai.aio_num = 1; 202 ai.aio_num = 1;
245 ai.aio_idle_time = 365 * 100000; 203 ai.aio_idle_time = 365 * 100000;
246 aio_init(&ai); 204 aio_init(&ai);
247 } 205 }
  206 +#endif
248 } 207 }
249 208
250 void qemu_aio_poll(void) 209 void qemu_aio_poll(void)
@@ -270,7 +229,7 @@ void qemu_aio_poll(void) @@ -270,7 +229,7 @@ void qemu_aio_poll(void)
270 if (ret == acb->aiocb.aio_nbytes) 229 if (ret == acb->aiocb.aio_nbytes)
271 ret = 0; 230 ret = 0;
272 else 231 else
273 - ret = -1; 232 + ret = -EINVAL;
274 } else { 233 } else {
275 ret = -ret; 234 ret = -ret;
276 } 235 }
@@ -329,6 +288,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs, @@ -329,6 +288,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
329 BDRVRawState *s = bs->opaque; 288 BDRVRawState *s = bs->opaque;
330 RawAIOCB *acb; 289 RawAIOCB *acb;
331 290
  291 + if (fd_open(bs) < 0)
  292 + return NULL;
  293 +
332 acb = qemu_aio_get(bs, cb, opaque); 294 acb = qemu_aio_get(bs, cb, opaque);
333 if (!acb) 295 if (!acb)
334 return NULL; 296 return NULL;
@@ -405,12 +367,17 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb) @@ -405,12 +367,17 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
405 static void raw_close(BlockDriverState *bs) 367 static void raw_close(BlockDriverState *bs)
406 { 368 {
407 BDRVRawState *s = bs->opaque; 369 BDRVRawState *s = bs->opaque;
408 - close(s->fd); 370 + if (s->fd >= 0) {
  371 + close(s->fd);
  372 + s->fd = -1;
  373 + }
409 } 374 }
410 375
411 static int raw_truncate(BlockDriverState *bs, int64_t offset) 376 static int raw_truncate(BlockDriverState *bs, int64_t offset)
412 { 377 {
413 BDRVRawState *s = bs->opaque; 378 BDRVRawState *s = bs->opaque;
  379 + if (s->type != FTYPE_FILE)
  380 + return -ENOTSUP;
414 if (ftruncate(s->fd, offset) < 0) 381 if (ftruncate(s->fd, offset) < 0)
415 return -errno; 382 return -errno;
416 return 0; 383 return 0;
@@ -428,6 +395,11 @@ static int64_t raw_getlength(BlockDriverState *bs) @@ -428,6 +395,11 @@ static int64_t raw_getlength(BlockDriverState *bs)
428 struct dk_minfo minfo; 395 struct dk_minfo minfo;
429 int rv; 396 int rv;
430 #endif 397 #endif
  398 + int ret;
  399 +
  400 + ret = fd_open(bs);
  401 + if (ret < 0)
  402 + return ret;
431 403
432 #ifdef _BSD 404 #ifdef _BSD
433 if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { 405 if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
@@ -455,12 +427,6 @@ static int64_t raw_getlength(BlockDriverState *bs) @@ -455,12 +427,6 @@ static int64_t raw_getlength(BlockDriverState *bs)
455 { 427 {
456 size = lseek(fd, 0, SEEK_END); 428 size = lseek(fd, 0, SEEK_END);
457 } 429 }
458 -#ifdef _WIN32  
459 - /* On Windows hosts it can happen that we're unable to get file size  
460 - for CD-ROM raw device (it's inherent limitation of the CDFS driver). */  
461 - if (size == -1)  
462 - size = LONG_LONG_MAX;  
463 -#endif  
464 return size; 430 return size;
465 } 431 }
466 432
@@ -509,13 +475,358 @@ BlockDriver bdrv_raw = { @@ -509,13 +475,358 @@ BlockDriver bdrv_raw = {
509 .bdrv_getlength = raw_getlength, 475 .bdrv_getlength = raw_getlength,
510 }; 476 };
511 477
  478 +/***********************************************/
  479 +/* host device */
  480 +
  481 +#ifdef CONFIG_COCOA
  482 +static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
  483 +static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
  484 +
  485 +kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
  486 +{
  487 + kern_return_t kernResult;
  488 + mach_port_t masterPort;
  489 + CFMutableDictionaryRef classesToMatch;
  490 +
  491 + kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
  492 + if ( KERN_SUCCESS != kernResult ) {
  493 + printf( "IOMasterPort returned %d\n", kernResult );
  494 + }
  495 +
  496 + classesToMatch = IOServiceMatching( kIOCDMediaClass );
  497 + if ( classesToMatch == NULL ) {
  498 + printf( "IOServiceMatching returned a NULL dictionary.\n" );
  499 + } else {
  500 + CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
  501 + }
  502 + kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
  503 + if ( KERN_SUCCESS != kernResult )
  504 + {
  505 + printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
  506 + }
  507 +
  508 + return kernResult;
  509 +}
  510 +
  511 +kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
  512 +{
  513 + io_object_t nextMedia;
  514 + kern_return_t kernResult = KERN_FAILURE;
  515 + *bsdPath = '\0';
  516 + nextMedia = IOIteratorNext( mediaIterator );
  517 + if ( nextMedia )
  518 + {
  519 + CFTypeRef bsdPathAsCFString;
  520 + bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
  521 + if ( bsdPathAsCFString ) {
  522 + size_t devPathLength;
  523 + strcpy( bsdPath, _PATH_DEV );
  524 + strcat( bsdPath, "r" );
  525 + devPathLength = strlen( bsdPath );
  526 + if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
  527 + kernResult = KERN_SUCCESS;
  528 + }
  529 + CFRelease( bsdPathAsCFString );
  530 + }
  531 + IOObjectRelease( nextMedia );
  532 + }
  533 +
  534 + return kernResult;
  535 +}
  536 +
  537 +#endif
  538 +
  539 +static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
  540 +{
  541 + BDRVRawState *s = bs->opaque;
  542 + int fd, open_flags, ret;
  543 +
  544 +#ifdef CONFIG_COCOA
  545 + if (strstart(filename, "/dev/cdrom", NULL)) {
  546 + kern_return_t kernResult;
  547 + io_iterator_t mediaIterator;
  548 + char bsdPath[ MAXPATHLEN ];
  549 + int fd;
  550 +
  551 + kernResult = FindEjectableCDMedia( &mediaIterator );
  552 + kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
  553 +
  554 + if ( bsdPath[ 0 ] != '\0' ) {
  555 + strcat(bsdPath,"s0");
  556 + /* some CDs don't have a partition 0 */
  557 + fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
  558 + if (fd < 0) {
  559 + bsdPath[strlen(bsdPath)-1] = '1';
  560 + } else {
  561 + close(fd);
  562 + }
  563 + filename = bsdPath;
  564 + }
  565 +
  566 + if ( mediaIterator )
  567 + IOObjectRelease( mediaIterator );
  568 + }
  569 +#endif
  570 + open_flags = O_BINARY;
  571 + if ((flags & BDRV_O_ACCESS) == O_RDWR) {
  572 + open_flags |= O_RDWR;
  573 + } else {
  574 + open_flags |= O_RDONLY;
  575 + bs->read_only = 1;
  576 + }
  577 +
  578 + s->type = FTYPE_FILE;
  579 +#if defined(__linux__)
  580 + if (strstart(filename, "/dev/cd", NULL)) {
  581 + /* open will not fail even if no CD is inserted */
  582 + open_flags |= O_NONBLOCK;
  583 + s->type = FTYPE_CD;
  584 + } else if (strstart(filename, "/dev/fd", NULL)) {
  585 + s->type = FTYPE_FD;
  586 + s->fd_open_flags = open_flags;
  587 + /* open will not fail even if no floppy is inserted */
  588 + open_flags |= O_NONBLOCK;
  589 + }
  590 +#endif
  591 + fd = open(filename, open_flags, 0644);
  592 + if (fd < 0) {
  593 + ret = -errno;
  594 + if (ret == -EROFS)
  595 + ret = -EACCES;
  596 + return ret;
  597 + }
  598 + s->fd = fd;
  599 +#if defined(__linux__)
  600 + /* close fd so that we can reopen it as needed */
  601 + if (s->type == FTYPE_FD) {
  602 + close(s->fd);
  603 + s->fd = -1;
  604 + s->fd_media_changed = 1;
  605 + }
  606 +#endif
  607 + return 0;
  608 +}
  609 +
  610 +#if defined(__linux__) && !defined(QEMU_TOOL)
  611 +
  612 +/* Note: we do not have a reliable method to detect if the floppy is
  613 + present. The current method is to try to open the floppy at every
  614 + I/O and to keep it opened during a few hundreds of ms. */
  615 +static int fd_open(BlockDriverState *bs)
  616 +{
  617 + BDRVRawState *s = bs->opaque;
  618 + int last_media_present;
  619 +
  620 + if (s->type != FTYPE_FD)
  621 + return 0;
  622 + last_media_present = (s->fd >= 0);
  623 + if (s->fd >= 0 &&
  624 + (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
  625 + close(s->fd);
  626 + s->fd = -1;
  627 +#ifdef DEBUG_FLOPPY
  628 + printf("Floppy closed\n");
  629 +#endif
  630 + }
  631 + if (s->fd < 0) {
  632 + if (s->fd_got_error &&
  633 + (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
  634 +#ifdef DEBUG_FLOPPY
  635 + printf("No floppy (open delayed)\n");
  636 +#endif
  637 + return -EIO;
  638 + }
  639 + s->fd = open(bs->filename, s->fd_open_flags);
  640 + if (s->fd < 0) {
  641 + s->fd_error_time = qemu_get_clock(rt_clock);
  642 + s->fd_got_error = 1;
  643 + if (last_media_present)
  644 + s->fd_media_changed = 1;
  645 +#ifdef DEBUG_FLOPPY
  646 + printf("No floppy\n");
  647 +#endif
  648 + return -EIO;
  649 + }
  650 +#ifdef DEBUG_FLOPPY
  651 + printf("Floppy opened\n");
  652 +#endif
  653 + }
  654 + if (!last_media_present)
  655 + s->fd_media_changed = 1;
  656 + s->fd_open_time = qemu_get_clock(rt_clock);
  657 + s->fd_got_error = 0;
  658 + return 0;
  659 +}
  660 +#else
  661 +static int fd_open(BlockDriverState *bs)
  662 +{
  663 + return 0;
  664 +}
  665 +#endif
  666 +
  667 +#if defined(__linux__)
  668 +
  669 +static int raw_is_inserted(BlockDriverState *bs)
  670 +{
  671 + BDRVRawState *s = bs->opaque;
  672 + int ret;
  673 +
  674 + switch(s->type) {
  675 + case FTYPE_CD:
  676 + ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
  677 + if (ret == CDS_DISC_OK)
  678 + return 1;
  679 + else
  680 + return 0;
  681 + break;
  682 + case FTYPE_FD:
  683 + ret = fd_open(bs);
  684 + return (ret >= 0);
  685 + default:
  686 + return 1;
  687 + }
  688 +}
  689 +
  690 +/* currently only used by fdc.c, but a CD version would be good too */
  691 +static int raw_media_changed(BlockDriverState *bs)
  692 +{
  693 + BDRVRawState *s = bs->opaque;
  694 +
  695 + switch(s->type) {
  696 + case FTYPE_FD:
  697 + {
  698 + int ret;
  699 + /* XXX: we do not have a true media changed indication. It
  700 + does not work if the floppy is changed without trying
  701 + to read it */
  702 + fd_open(bs);
  703 + ret = s->fd_media_changed;
  704 + s->fd_media_changed = 0;
  705 +#ifdef DEBUG_FLOPPY
  706 + printf("Floppy changed=%d\n", ret);
  707 +#endif
  708 + return ret;
  709 + }
  710 + default:
  711 + return -ENOTSUP;
  712 + }
  713 +}
  714 +
  715 +static int raw_eject(BlockDriverState *bs, int eject_flag)
  716 +{
  717 + BDRVRawState *s = bs->opaque;
  718 +
  719 + switch(s->type) {
  720 + case FTYPE_CD:
  721 + if (eject_flag) {
  722 + if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
  723 + perror("CDROMEJECT");
  724 + } else {
  725 + if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
  726 + perror("CDROMEJECT");
  727 + }
  728 + break;
  729 + case FTYPE_FD:
  730 + {
  731 + int fd;
  732 + if (s->fd >= 0) {
  733 + close(s->fd);
  734 + s->fd = -1;
  735 + }
  736 + fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
  737 + if (fd >= 0) {
  738 + if (ioctl(fd, FDEJECT, 0) < 0)
  739 + perror("FDEJECT");
  740 + close(fd);
  741 + }
  742 + }
  743 + break;
  744 + default:
  745 + return -ENOTSUP;
  746 + }
  747 + return 0;
  748 +}
  749 +
  750 +static int raw_set_locked(BlockDriverState *bs, int locked)
  751 +{
  752 + BDRVRawState *s = bs->opaque;
  753 +
  754 + switch(s->type) {
  755 + case FTYPE_CD:
  756 + if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
  757 + /* Note: an error can happen if the distribution automatically
  758 + mounts the CD-ROM */
  759 + // perror("CDROM_LOCKDOOR");
  760 + }
  761 + break;
  762 + default:
  763 + return -ENOTSUP;
  764 + }
  765 + return 0;
  766 +}
  767 +
  768 +#else
  769 +
  770 +static int raw_is_inserted(BlockDriverState *bs)
  771 +{
  772 + return 1;
  773 +}
  774 +
  775 +static int raw_media_changed(BlockDriverState *bs)
  776 +{
  777 + return -ENOTSUP;
  778 +}
  779 +
  780 +static int raw_eject(BlockDriverState *bs, int eject_flag)
  781 +{
  782 + return -ENOTSUP;
  783 +}
  784 +
  785 +static int raw_set_locked(BlockDriverState *bs, int locked)
  786 +{
  787 + return -ENOTSUP;
  788 +}
  789 +
  790 +#endif /* !linux */
  791 +
  792 +BlockDriver bdrv_host_device = {
  793 + "host_device",
  794 + sizeof(BDRVRawState),
  795 + NULL, /* no probe for protocols */
  796 + hdev_open,
  797 + NULL,
  798 + NULL,
  799 + raw_close,
  800 + NULL,
  801 + raw_flush,
  802 +
  803 + .bdrv_aio_read = raw_aio_read,
  804 + .bdrv_aio_write = raw_aio_write,
  805 + .bdrv_aio_cancel = raw_aio_cancel,
  806 + .aiocb_size = sizeof(RawAIOCB),
  807 + .bdrv_pread = raw_pread,
  808 + .bdrv_pwrite = raw_pwrite,
  809 + .bdrv_getlength = raw_getlength,
  810 +
  811 + /* removable device support */
  812 + .bdrv_is_inserted = raw_is_inserted,
  813 + .bdrv_media_changed = raw_media_changed,
  814 + .bdrv_eject = raw_eject,
  815 + .bdrv_set_locked = raw_set_locked,
  816 +};
  817 +
512 #else /* _WIN32 */ 818 #else /* _WIN32 */
513 819
514 /* XXX: use another file ? */ 820 /* XXX: use another file ? */
515 #include <winioctl.h> 821 #include <winioctl.h>
516 822
  823 +#define FTYPE_FILE 0
  824 +#define FTYPE_CD 1
  825 +
517 typedef struct BDRVRawState { 826 typedef struct BDRVRawState {
518 HANDLE hfile; 827 HANDLE hfile;
  828 + int type;
  829 + char drive_letter[2];
519 } BDRVRawState; 830 } BDRVRawState;
520 831
521 typedef struct RawAIOCB { 832 typedef struct RawAIOCB {
@@ -565,6 +876,23 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) @@ -565,6 +876,23 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
565 BDRVRawState *s = bs->opaque; 876 BDRVRawState *s = bs->opaque;
566 int access_flags, create_flags; 877 int access_flags, create_flags;
567 DWORD overlapped; 878 DWORD overlapped;
  879 + char device_name[64];
  880 + const char *p;
  881 +
  882 + if (strstart(filename, "/dev/cdrom", NULL)) {
  883 + if (find_cdrom(device_name, sizeof(device_name)) < 0)
  884 + return -ENOENT;
  885 + filename = device_name;
  886 + } else {
  887 + /* transform drive letters into device name */
  888 + if (((filename[0] >= 'a' && filename[0] <= 'z') ||
  889 + (filename[0] >= 'A' && filename[0] <= 'Z')) &&
  890 + filename[1] == ':' && filename[2] == '\0') {
  891 + snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
  892 + filename = device_name;
  893 + }
  894 + }
  895 + s->type = find_device_type(filename);
568 896
569 if ((flags & BDRV_O_ACCESS) == O_RDWR) { 897 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
570 access_flags = GENERIC_READ | GENERIC_WRITE; 898 access_flags = GENERIC_READ | GENERIC_WRITE;
@@ -765,10 +1093,22 @@ static int64_t raw_getlength(BlockDriverState *bs) @@ -765,10 +1093,22 @@ static int64_t raw_getlength(BlockDriverState *bs)
765 { 1093 {
766 BDRVRawState *s = bs->opaque; 1094 BDRVRawState *s = bs->opaque;
767 LARGE_INTEGER l; 1095 LARGE_INTEGER l;
  1096 + ULARGE_INTEGER available, total, total_free;
768 1097
769 - l.LowPart = GetFileSize(s->hfile, &l.HighPart);  
770 - if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)  
771 - return -EIO; 1098 + switch(s->ftype) {
  1099 + case FTYPE_FILE:
  1100 + l.LowPart = GetFileSize(s->hfile, &l.HighPart);
  1101 + if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
  1102 + return -EIO;
  1103 + break;
  1104 + case FTYPE_CD:
  1105 + if (!GetDiskFreeSpaceEx(s->drive_letter, &available, &total, &total_free))
  1106 + return -EIO;
  1107 + l = total;
  1108 + break;
  1109 + default:
  1110 + return -EIO;
  1111 + }
772 return l.QuadPart; 1112 return l.QuadPart;
773 } 1113 }
774 1114
@@ -833,4 +1173,146 @@ BlockDriver bdrv_raw = { @@ -833,4 +1173,146 @@ BlockDriver bdrv_raw = {
833 .bdrv_truncate = raw_truncate, 1173 .bdrv_truncate = raw_truncate,
834 .bdrv_getlength = raw_getlength, 1174 .bdrv_getlength = raw_getlength,
835 }; 1175 };
  1176 +
  1177 +/***********************************************/
  1178 +/* host device */
  1179 +
  1180 +static int find_cdrom(char *cdrom_name, int cdrom_name_size)
  1181 +{
  1182 + char drives[256], *pdrv = drives;
  1183 + UINT type;
  1184 +
  1185 + memset(drives, 0, sizeof(drivers));
  1186 + GetLogicalDriveStrings(sizeof(drives), drives);
  1187 + while(pdrv[0] != '\0') {
  1188 + type = GetDriveType(pdrv);
  1189 + switch(type) {
  1190 + case DRIVE_CDROM:
  1191 + snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
  1192 + return 0;
  1193 + break;
  1194 + }
  1195 + pdrv += lstrlen(pdrv) + 1;
  1196 + }
  1197 + return -1;
  1198 +}
  1199 +
  1200 +static int find_device_type(const char *filename)
  1201 +{
  1202 + UINT type;
  1203 + const char *p;
  1204 +
  1205 + if (strstart(filename, "\\\\.\\", &p) ||
  1206 + strstart(filename, "//./", &p)) {
  1207 + s->drive_letter[0] = p[0];
  1208 + s->drive_letter[1] = '\0';
  1209 + type = GetDriveType(s->drive_letter);
  1210 + if (type == DRIVE_CDROM)
  1211 + return FTYPE_CD;
  1212 + else
  1213 + return FTYPE_FILE;
  1214 + } else {
  1215 + return FTYPE_FILE;
  1216 + }
  1217 +}
  1218 +
  1219 +static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
  1220 +{
  1221 + BDRVRawState *s = bs->opaque;
  1222 + int access_flags, create_flags;
  1223 + DWORD overlapped;
  1224 + char device_name[64];
  1225 + const char *p;
  1226 +
  1227 + if (strstart(filename, "/dev/cdrom", NULL)) {
  1228 + if (find_cdrom(device_name, sizeof(device_name)) < 0)
  1229 + return -ENOENT;
  1230 + filename = device_name;
  1231 + } else {
  1232 + /* transform drive letters into device name */
  1233 + if (((filename[0] >= 'a' && filename[0] <= 'z') ||
  1234 + (filename[0] >= 'A' && filename[0] <= 'Z')) &&
  1235 + filename[1] == ':' && filename[2] == '\0') {
  1236 + snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
  1237 + filename = device_name;
  1238 + }
  1239 + }
  1240 + s->type = find_device_type(filename);
  1241 +
  1242 + if ((flags & BDRV_O_ACCESS) == O_RDWR) {
  1243 + access_flags = GENERIC_READ | GENERIC_WRITE;
  1244 + } else {
  1245 + access_flags = GENERIC_READ;
  1246 + }
  1247 + create_flags = OPEN_EXISTING;
  1248 +
  1249 +#ifdef QEMU_TOOL
  1250 + overlapped = 0;
  1251 +#else
  1252 + overlapped = FILE_FLAG_OVERLAPPED;
  1253 +#endif
  1254 + s->hfile = CreateFile(filename, access_flags,
  1255 + FILE_SHARE_READ, NULL,
  1256 + create_flags, overlapped, 0);
  1257 + if (s->hfile == INVALID_HANDLE_VALUE)
  1258 + return -1;
  1259 + return 0;
  1260 +}
  1261 +
  1262 +#if 0
  1263 +/***********************************************/
  1264 +/* removable device additionnal commands */
  1265 +
  1266 +static int raw_is_inserted(BlockDriverState *bs)
  1267 +{
  1268 + return 1;
  1269 +}
  1270 +
  1271 +static int raw_media_changed(BlockDriverState *bs)
  1272 +{
  1273 + return -ENOTSUP;
  1274 +}
  1275 +
  1276 +static int raw_eject(BlockDriverState *bs, int eject_flag)
  1277 +{
  1278 + DWORD ret_count;
  1279 +
  1280 + if (s->type == FTYPE_FILE)
  1281 + return -ENOTSUP;
  1282 + if (eject_flag) {
  1283 + DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
  1284 + NULL, 0, NULL, 0, &lpBytesReturned, NULL);
  1285 + } else {
  1286 + DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
  1287 + NULL, 0, NULL, 0, &lpBytesReturned, NULL);
  1288 + }
  1289 +}
  1290 +
  1291 +static int raw_set_locked(BlockDriverState *bs, int locked)
  1292 +{
  1293 + return -ENOTSUP;
  1294 +}
  1295 +#endif
  1296 +
  1297 +BlockDriver bdrv_host_device = {
  1298 + "host_device",
  1299 + sizeof(BDRVRawState),
  1300 + NULL, /* no probe for protocols */
  1301 + hdev_open,
  1302 + NULL,
  1303 + NULL,
  1304 + raw_close,
  1305 + NULL,
  1306 + raw_flush,
  1307 +
  1308 +#if 0
  1309 + .bdrv_aio_read = raw_aio_read,
  1310 + .bdrv_aio_write = raw_aio_write,
  1311 + .bdrv_aio_cancel = raw_aio_cancel,
  1312 + .aiocb_size = sizeof(RawAIOCB);
  1313 +#endif
  1314 + .bdrv_pread = raw_pread,
  1315 + .bdrv_pwrite = raw_pwrite,
  1316 + .bdrv_getlength = raw_getlength,
  1317 +};
836 #endif /* _WIN32 */ 1318 #endif /* _WIN32 */
@@ -181,24 +181,37 @@ void get_tmp_filename(char *filename, int size) @@ -181,24 +181,37 @@ void get_tmp_filename(char *filename, int size)
181 } 181 }
182 #endif 182 #endif
183 183
  184 +#ifdef _WIN32
  185 +static int is_windows_drive(const char *filename)
  186 +{
  187 + if (((filename[0] >= 'a' && filename[0] <= 'z') ||
  188 + (filename[0] >= 'A' && filename[0] <= 'Z')) &&
  189 + filename[1] == ':' && filename[2] == '\0')
  190 + return 1;
  191 + if (strstart(filename, "\\\\.\\", NULL) ||
  192 + strstart(filename, "//./", NULL))
  193 + return 1;
  194 + return 0;
  195 +}
  196 +#endif
  197 +
184 static BlockDriver *find_protocol(const char *filename) 198 static BlockDriver *find_protocol(const char *filename)
185 { 199 {
186 BlockDriver *drv1; 200 BlockDriver *drv1;
187 char protocol[128]; 201 char protocol[128];
188 int len; 202 int len;
189 const char *p; 203 const char *p;
  204 +
  205 +#ifdef _WIN32
  206 + if (is_windows_drive(filename))
  207 + return &bdrv_raw;
  208 +#endif
190 p = strchr(filename, ':'); 209 p = strchr(filename, ':');
191 if (!p) 210 if (!p)
192 return &bdrv_raw; 211 return &bdrv_raw;
193 len = p - filename; 212 len = p - filename;
194 if (len > sizeof(protocol) - 1) 213 if (len > sizeof(protocol) - 1)
195 len = sizeof(protocol) - 1; 214 len = sizeof(protocol) - 1;
196 -#ifdef _WIN32  
197 - if (len == 1) {  
198 - /* specific win32 case for driver letters */  
199 - return &bdrv_raw;  
200 - }  
201 -#endif  
202 memcpy(protocol, filename, len); 215 memcpy(protocol, filename, len);
203 protocol[len] = '\0'; 216 protocol[len] = '\0';
204 for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 217 for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
@@ -218,14 +231,28 @@ static BlockDriver *find_image_format(const char *filename) @@ -218,14 +231,28 @@ static BlockDriver *find_image_format(const char *filename)
218 uint8_t buf[2048]; 231 uint8_t buf[2048];
219 BlockDriverState *bs; 232 BlockDriverState *bs;
220 233
  234 + /* detect host devices. By convention, /dev/cdrom[N] is always
  235 + recognized as a host CDROM */
  236 + if (strstart(filename, "/dev/cdrom", NULL))
  237 + return &bdrv_host_device;
  238 +#ifdef _WIN32
  239 + if (is_windows_drive(filename))
  240 + return &bdrv_host_device;
  241 +#else
  242 + {
  243 + struct stat st;
  244 + if (stat(filename, &st) >= 0 &&
  245 + (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
  246 + return &bdrv_host_device;
  247 + }
  248 + }
  249 +#endif
  250 +
221 drv = find_protocol(filename); 251 drv = find_protocol(filename);
222 - /* no need to test disk image formats for vvfat or host specific  
223 - devices */ 252 + /* no need to test disk image formats for vvfat */
224 if (drv == &bdrv_vvfat) 253 if (drv == &bdrv_vvfat)
225 return drv; 254 return drv;
226 - if (strstart(filename, "/dev/", NULL))  
227 - return &bdrv_raw;  
228 - 255 +
229 ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY); 256 ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
230 if (ret < 0) 257 if (ret < 0)
231 return NULL; 258 return NULL;
@@ -362,9 +389,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, @@ -362,9 +389,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
362 goto fail; 389 goto fail;
363 } 390 }
364 391
365 - bs->inserted = 1;  
366 -  
367 /* call the change callback */ 392 /* call the change callback */
  393 + bs->media_changed = 1;
368 if (bs->change_cb) 394 if (bs->change_cb)
369 bs->change_cb(bs->change_opaque); 395 bs->change_cb(bs->change_opaque);
370 396
@@ -373,7 +399,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, @@ -373,7 +399,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
373 399
374 void bdrv_close(BlockDriverState *bs) 400 void bdrv_close(BlockDriverState *bs)
375 { 401 {
376 - if (bs->inserted) { 402 + if (bs->drv) {
377 if (bs->backing_hd) 403 if (bs->backing_hd)
378 bdrv_delete(bs->backing_hd); 404 bdrv_delete(bs->backing_hd);
379 bs->drv->bdrv_close(bs); 405 bs->drv->bdrv_close(bs);
@@ -385,9 +411,9 @@ void bdrv_close(BlockDriverState *bs) @@ -385,9 +411,9 @@ void bdrv_close(BlockDriverState *bs)
385 #endif 411 #endif
386 bs->opaque = NULL; 412 bs->opaque = NULL;
387 bs->drv = NULL; 413 bs->drv = NULL;
388 - bs->inserted = 0;  
389 414
390 /* call the change callback */ 415 /* call the change callback */
  416 + bs->media_changed = 1;
391 if (bs->change_cb) 417 if (bs->change_cb)
392 bs->change_cb(bs->change_opaque); 418 bs->change_cb(bs->change_opaque);
393 } 419 }
@@ -403,12 +429,13 @@ void bdrv_delete(BlockDriverState *bs) @@ -403,12 +429,13 @@ void bdrv_delete(BlockDriverState *bs)
403 /* commit COW file into the raw image */ 429 /* commit COW file into the raw image */
404 int bdrv_commit(BlockDriverState *bs) 430 int bdrv_commit(BlockDriverState *bs)
405 { 431 {
  432 + BlockDriver *drv = bs->drv;
406 int64_t i, total_sectors; 433 int64_t i, total_sectors;
407 int n, j; 434 int n, j;
408 unsigned char sector[512]; 435 unsigned char sector[512];
409 436
410 - if (!bs->inserted)  
411 - return -ENOENT; 437 + if (!drv)
  438 + return -ENOMEDIUM;
412 439
413 if (bs->read_only) { 440 if (bs->read_only) {
414 return -EACCES; 441 return -EACCES;
@@ -420,7 +447,7 @@ int bdrv_commit(BlockDriverState *bs) @@ -420,7 +447,7 @@ int bdrv_commit(BlockDriverState *bs)
420 447
421 total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; 448 total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
422 for (i = 0; i < total_sectors;) { 449 for (i = 0; i < total_sectors;) {
423 - if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 450 + if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
424 for(j = 0; j < n; j++) { 451 for(j = 0; j < n; j++) {
425 if (bdrv_read(bs, i, sector, 1) != 0) { 452 if (bdrv_read(bs, i, sector, 1) != 0) {
426 return -EIO; 453 return -EIO;
@@ -436,20 +463,20 @@ int bdrv_commit(BlockDriverState *bs) @@ -436,20 +463,20 @@ int bdrv_commit(BlockDriverState *bs)
436 } 463 }
437 } 464 }
438 465
439 - if (bs->drv->bdrv_make_empty)  
440 - return bs->drv->bdrv_make_empty(bs); 466 + if (drv->bdrv_make_empty)
  467 + return drv->bdrv_make_empty(bs);
441 468
442 return 0; 469 return 0;
443 } 470 }
444 471
445 -/* return < 0 if error */ 472 +/* return < 0 if error. See bdrv_write() for the return codes */
446 int bdrv_read(BlockDriverState *bs, int64_t sector_num, 473 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
447 uint8_t *buf, int nb_sectors) 474 uint8_t *buf, int nb_sectors)
448 { 475 {
449 BlockDriver *drv = bs->drv; 476 BlockDriver *drv = bs->drv;
450 477
451 - if (!bs->inserted)  
452 - return -1; 478 + if (!drv)
  479 + return -ENOMEDIUM;
453 480
454 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 481 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
455 memcpy(buf, bs->boot_sector_data, 512); 482 memcpy(buf, bs->boot_sector_data, 512);
@@ -466,7 +493,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, @@ -466,7 +493,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
466 if (ret < 0) 493 if (ret < 0)
467 return ret; 494 return ret;
468 else if (ret != len) 495 else if (ret != len)
469 - return -EIO; 496 + return -EINVAL;
470 else 497 else
471 return 0; 498 return 0;
472 } else { 499 } else {
@@ -474,15 +501,20 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, @@ -474,15 +501,20 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
474 } 501 }
475 } 502 }
476 503
477 -/* return < 0 if error */ 504 +/* Return < 0 if error. Important errors are:
  505 + -EIO generic I/O error (may happen for all errors)
  506 + -ENOMEDIUM No media inserted.
  507 + -EINVAL Invalid sector number or nb_sectors
  508 + -EACCES Trying to write a read-only device
  509 +*/
478 int bdrv_write(BlockDriverState *bs, int64_t sector_num, 510 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
479 const uint8_t *buf, int nb_sectors) 511 const uint8_t *buf, int nb_sectors)
480 { 512 {
481 BlockDriver *drv = bs->drv; 513 BlockDriver *drv = bs->drv;
482 - if (!bs->inserted)  
483 - return -1; 514 + if (!bs->drv)
  515 + return -ENOMEDIUM;
484 if (bs->read_only) 516 if (bs->read_only)
485 - return -1; 517 + return -EACCES;
486 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 518 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
487 memcpy(bs->boot_sector_data, buf, 512); 519 memcpy(bs->boot_sector_data, buf, 512);
488 } 520 }
@@ -501,7 +533,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, @@ -501,7 +533,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
501 } 533 }
502 } 534 }
503 535
504 -/* not necessary now */  
505 static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, 536 static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
506 uint8_t *buf, int count1) 537 uint8_t *buf, int count1)
507 { 538 {
@@ -603,7 +634,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, @@ -603,7 +634,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
603 BlockDriver *drv = bs->drv; 634 BlockDriver *drv = bs->drv;
604 635
605 if (!drv) 636 if (!drv)
606 - return -ENOENT; 637 + return -ENOMEDIUM;
607 if (!drv->bdrv_pread) 638 if (!drv->bdrv_pread)
608 return bdrv_pread_em(bs, offset, buf1, count1); 639 return bdrv_pread_em(bs, offset, buf1, count1);
609 return drv->bdrv_pread(bs, offset, buf1, count1); 640 return drv->bdrv_pread(bs, offset, buf1, count1);
@@ -618,7 +649,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, @@ -618,7 +649,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
618 BlockDriver *drv = bs->drv; 649 BlockDriver *drv = bs->drv;
619 650
620 if (!drv) 651 if (!drv)
621 - return -ENOENT; 652 + return -ENOMEDIUM;
622 if (!drv->bdrv_pwrite) 653 if (!drv->bdrv_pwrite)
623 return bdrv_pwrite_em(bs, offset, buf1, count1); 654 return bdrv_pwrite_em(bs, offset, buf1, count1);
624 return drv->bdrv_pwrite(bs, offset, buf1, count1); 655 return drv->bdrv_pwrite(bs, offset, buf1, count1);
@@ -631,7 +662,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) @@ -631,7 +662,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
631 { 662 {
632 BlockDriver *drv = bs->drv; 663 BlockDriver *drv = bs->drv;
633 if (!drv) 664 if (!drv)
634 - return -ENOENT; 665 + return -ENOMEDIUM;
635 if (!drv->bdrv_truncate) 666 if (!drv->bdrv_truncate)
636 return -ENOTSUP; 667 return -ENOTSUP;
637 return drv->bdrv_truncate(bs, offset); 668 return drv->bdrv_truncate(bs, offset);
@@ -644,7 +675,7 @@ int64_t bdrv_getlength(BlockDriverState *bs) @@ -644,7 +675,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
644 { 675 {
645 BlockDriver *drv = bs->drv; 676 BlockDriver *drv = bs->drv;
646 if (!drv) 677 if (!drv)
647 - return -ENOENT; 678 + return -ENOMEDIUM;
648 if (!drv->bdrv_getlength) { 679 if (!drv->bdrv_getlength) {
649 /* legacy mode */ 680 /* legacy mode */
650 return bs->total_sectors * SECTOR_SIZE; 681 return bs->total_sectors * SECTOR_SIZE;
@@ -652,9 +683,16 @@ int64_t bdrv_getlength(BlockDriverState *bs) @@ -652,9 +683,16 @@ int64_t bdrv_getlength(BlockDriverState *bs)
652 return drv->bdrv_getlength(bs); 683 return drv->bdrv_getlength(bs);
653 } 684 }
654 685
  686 +/* return 0 as number of sectors if no device present or error */
655 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 687 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
656 { 688 {
657 - *nb_sectors_ptr = bs->total_sectors; 689 + int64_t length;
  690 + length = bdrv_getlength(bs);
  691 + if (length < 0)
  692 + length = 0;
  693 + else
  694 + length = length >> SECTOR_BITS;
  695 + *nb_sectors_ptr = length;
658 } 696 }
659 697
660 /* force a given boot sector. */ 698 /* force a given boot sector. */
@@ -715,21 +753,7 @@ int bdrv_is_read_only(BlockDriverState *bs) @@ -715,21 +753,7 @@ int bdrv_is_read_only(BlockDriverState *bs)
715 return bs->read_only; 753 return bs->read_only;
716 } 754 }
717 755
718 -int bdrv_is_inserted(BlockDriverState *bs)  
719 -{  
720 - return bs->inserted;  
721 -}  
722 -  
723 -int bdrv_is_locked(BlockDriverState *bs)  
724 -{  
725 - return bs->locked;  
726 -}  
727 -  
728 -void bdrv_set_locked(BlockDriverState *bs, int locked)  
729 -{  
730 - bs->locked = locked;  
731 -}  
732 - 756 +/* XXX: no longer used */
733 void bdrv_set_change_cb(BlockDriverState *bs, 757 void bdrv_set_change_cb(BlockDriverState *bs,
734 void (*change_cb)(void *opaque), void *opaque) 758 void (*change_cb)(void *opaque), void *opaque)
735 { 759 {
@@ -761,7 +785,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key) @@ -761,7 +785,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
761 785
762 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 786 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
763 { 787 {
764 - if (!bs->inserted || !bs->drv) { 788 + if (!bs->drv) {
765 buf[0] = '\0'; 789 buf[0] = '\0';
766 } else { 790 } else {
767 pstrcpy(buf, buf_size, bs->drv->format_name); 791 pstrcpy(buf, buf_size, bs->drv->format_name);
@@ -833,7 +857,7 @@ void bdrv_info(void) @@ -833,7 +857,7 @@ void bdrv_info(void)
833 if (bs->removable) { 857 if (bs->removable) {
834 term_printf(" locked=%d", bs->locked); 858 term_printf(" locked=%d", bs->locked);
835 } 859 }
836 - if (bs->inserted) { 860 + if (bs->drv) {
837 term_printf(" file=%s", bs->filename); 861 term_printf(" file=%s", bs->filename);
838 if (bs->backing_file[0] != '\0') 862 if (bs->backing_file[0] != '\0')
839 term_printf(" backing_file=%s", bs->backing_file); 863 term_printf(" backing_file=%s", bs->backing_file);
@@ -863,7 +887,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, @@ -863,7 +887,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
863 { 887 {
864 BlockDriver *drv = bs->drv; 888 BlockDriver *drv = bs->drv;
865 if (!drv) 889 if (!drv)
866 - return -ENOENT; 890 + return -ENOMEDIUM;
867 if (!drv->bdrv_write_compressed) 891 if (!drv->bdrv_write_compressed)
868 return -ENOTSUP; 892 return -ENOTSUP;
869 return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); 893 return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
@@ -873,7 +897,7 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) @@ -873,7 +897,7 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
873 { 897 {
874 BlockDriver *drv = bs->drv; 898 BlockDriver *drv = bs->drv;
875 if (!drv) 899 if (!drv)
876 - return -ENOENT; 900 + return -ENOMEDIUM;
877 if (!drv->bdrv_get_info) 901 if (!drv->bdrv_get_info)
878 return -ENOTSUP; 902 return -ENOTSUP;
879 memset(bdi, 0, sizeof(*bdi)); 903 memset(bdi, 0, sizeof(*bdi));
@@ -888,7 +912,7 @@ int bdrv_snapshot_create(BlockDriverState *bs, @@ -888,7 +912,7 @@ int bdrv_snapshot_create(BlockDriverState *bs,
888 { 912 {
889 BlockDriver *drv = bs->drv; 913 BlockDriver *drv = bs->drv;
890 if (!drv) 914 if (!drv)
891 - return -ENOENT; 915 + return -ENOMEDIUM;
892 if (!drv->bdrv_snapshot_create) 916 if (!drv->bdrv_snapshot_create)
893 return -ENOTSUP; 917 return -ENOTSUP;
894 return drv->bdrv_snapshot_create(bs, sn_info); 918 return drv->bdrv_snapshot_create(bs, sn_info);
@@ -899,7 +923,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, @@ -899,7 +923,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
899 { 923 {
900 BlockDriver *drv = bs->drv; 924 BlockDriver *drv = bs->drv;
901 if (!drv) 925 if (!drv)
902 - return -ENOENT; 926 + return -ENOMEDIUM;
903 if (!drv->bdrv_snapshot_goto) 927 if (!drv->bdrv_snapshot_goto)
904 return -ENOTSUP; 928 return -ENOTSUP;
905 return drv->bdrv_snapshot_goto(bs, snapshot_id); 929 return drv->bdrv_snapshot_goto(bs, snapshot_id);
@@ -909,7 +933,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) @@ -909,7 +933,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
909 { 933 {
910 BlockDriver *drv = bs->drv; 934 BlockDriver *drv = bs->drv;
911 if (!drv) 935 if (!drv)
912 - return -ENOENT; 936 + return -ENOMEDIUM;
913 if (!drv->bdrv_snapshot_delete) 937 if (!drv->bdrv_snapshot_delete)
914 return -ENOTSUP; 938 return -ENOTSUP;
915 return drv->bdrv_snapshot_delete(bs, snapshot_id); 939 return drv->bdrv_snapshot_delete(bs, snapshot_id);
@@ -920,7 +944,7 @@ int bdrv_snapshot_list(BlockDriverState *bs, @@ -920,7 +944,7 @@ int bdrv_snapshot_list(BlockDriverState *bs,
920 { 944 {
921 BlockDriver *drv = bs->drv; 945 BlockDriver *drv = bs->drv;
922 if (!drv) 946 if (!drv)
923 - return -ENOENT; 947 + return -ENOMEDIUM;
924 if (!drv->bdrv_snapshot_list) 948 if (!drv->bdrv_snapshot_list)
925 return -ENOTSUP; 949 return -ENOTSUP;
926 return drv->bdrv_snapshot_list(bs, psn_info); 950 return drv->bdrv_snapshot_list(bs, psn_info);
@@ -1001,7 +1025,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, @@ -1001,7 +1025,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
1001 { 1025 {
1002 BlockDriver *drv = bs->drv; 1026 BlockDriver *drv = bs->drv;
1003 1027
1004 - if (!bs->inserted) 1028 + if (!drv)
1005 return NULL; 1029 return NULL;
1006 1030
1007 /* XXX: we assume that nb_sectors == 0 is suppored by the async read */ 1031 /* 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, @@ -1021,7 +1045,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
1021 { 1045 {
1022 BlockDriver *drv = bs->drv; 1046 BlockDriver *drv = bs->drv;
1023 1047
1024 - if (!bs->inserted) 1048 + if (!drv)
1025 return NULL; 1049 return NULL;
1026 if (bs->read_only) 1050 if (bs->read_only)
1027 return NULL; 1051 return NULL;
@@ -1170,6 +1194,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, @@ -1170,6 +1194,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
1170 void bdrv_init(void) 1194 void bdrv_init(void)
1171 { 1195 {
1172 bdrv_register(&bdrv_raw); 1196 bdrv_register(&bdrv_raw);
  1197 + bdrv_register(&bdrv_host_device);
1173 #ifndef _WIN32 1198 #ifndef _WIN32
1174 bdrv_register(&bdrv_cow); 1199 bdrv_register(&bdrv_cow);
1175 #endif 1200 #endif
@@ -1211,3 +1236,78 @@ void qemu_aio_release(void *p) @@ -1211,3 +1236,78 @@ void qemu_aio_release(void *p)
1211 acb->next = drv->free_aiocb; 1236 acb->next = drv->free_aiocb;
1212 drv->free_aiocb = acb; 1237 drv->free_aiocb = acb;
1213 } 1238 }
  1239 +
  1240 +/**************************************************************/
  1241 +/* removable device support */
  1242 +
  1243 +/**
  1244 + * Return TRUE if the media is present
  1245 + */
  1246 +int bdrv_is_inserted(BlockDriverState *bs)
  1247 +{
  1248 + BlockDriver *drv = bs->drv;
  1249 + int ret;
  1250 + if (!drv)
  1251 + return 0;
  1252 + if (!drv->bdrv_is_inserted)
  1253 + return 1;
  1254 + ret = drv->bdrv_is_inserted(bs);
  1255 + return ret;
  1256 +}
  1257 +
  1258 +/**
  1259 + * Return TRUE if the media changed since the last call to this
  1260 + * function. It is currently only used for floppy disks
  1261 + */
  1262 +int bdrv_media_changed(BlockDriverState *bs)
  1263 +{
  1264 + BlockDriver *drv = bs->drv;
  1265 + int ret;
  1266 +
  1267 + if (!drv || !drv->bdrv_media_changed)
  1268 + ret = -ENOTSUP;
  1269 + else
  1270 + ret = drv->bdrv_media_changed(bs);
  1271 + if (ret == -ENOTSUP)
  1272 + ret = bs->media_changed;
  1273 + bs->media_changed = 0;
  1274 + return ret;
  1275 +}
  1276 +
  1277 +/**
  1278 + * If eject_flag is TRUE, eject the media. Otherwise, close the tray
  1279 + */
  1280 +void bdrv_eject(BlockDriverState *bs, int eject_flag)
  1281 +{
  1282 + BlockDriver *drv = bs->drv;
  1283 + int ret;
  1284 +
  1285 + if (!drv || !drv->bdrv_eject) {
  1286 + ret = -ENOTSUP;
  1287 + } else {
  1288 + ret = drv->bdrv_eject(bs, eject_flag);
  1289 + }
  1290 + if (ret == -ENOTSUP) {
  1291 + if (eject_flag)
  1292 + bdrv_close(bs);
  1293 + }
  1294 +}
  1295 +
  1296 +int bdrv_is_locked(BlockDriverState *bs)
  1297 +{
  1298 + return bs->locked;
  1299 +}
  1300 +
  1301 +/**
  1302 + * Lock or unlock the media (if it is locked, the user won't be able
  1303 + * to eject it manually).
  1304 + */
  1305 +void bdrv_set_locked(BlockDriverState *bs, int locked)
  1306 +{
  1307 + BlockDriver *drv = bs->drv;
  1308 +
  1309 + bs->locked = locked;
  1310 + if (drv && drv->bdrv_set_locked) {
  1311 + drv->bdrv_set_locked(bs, locked);
  1312 + }
  1313 +}
block_int.h
@@ -70,6 +70,12 @@ struct BlockDriver { @@ -70,6 +70,12 @@ struct BlockDriver {
70 QEMUSnapshotInfo **psn_info); 70 QEMUSnapshotInfo **psn_info);
71 int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); 71 int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
72 72
  73 + /* removable device specific */
  74 + int (*bdrv_is_inserted)(BlockDriverState *bs);
  75 + int (*bdrv_media_changed)(BlockDriverState *bs);
  76 + int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
  77 + int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
  78 +
73 BlockDriverAIOCB *free_aiocb; 79 BlockDriverAIOCB *free_aiocb;
74 struct BlockDriver *next; 80 struct BlockDriver *next;
75 }; 81 };
@@ -78,7 +84,6 @@ struct BlockDriverState { @@ -78,7 +84,6 @@ struct BlockDriverState {
78 int64_t total_sectors; /* if we are reading a disk image, give its 84 int64_t total_sectors; /* if we are reading a disk image, give its
79 size in sectors */ 85 size in sectors */
80 int read_only; /* if true, the media is read only */ 86 int read_only; /* if true, the media is read only */
81 - int inserted; /* if true, the media is present */  
82 int removable; /* if true, the media can be removed */ 87 int removable; /* if true, the media can be removed */
83 int locked; /* if true, the media cannot temporarily be ejected */ 88 int locked; /* if true, the media cannot temporarily be ejected */
84 int encrypted; /* if true, the media is encrypted */ 89 int encrypted; /* if true, the media is encrypted */
@@ -86,7 +91,7 @@ struct BlockDriverState { @@ -86,7 +91,7 @@ struct BlockDriverState {
86 void (*change_cb)(void *opaque); 91 void (*change_cb)(void *opaque);
87 void *change_opaque; 92 void *change_opaque;
88 93
89 - BlockDriver *drv; 94 + BlockDriver *drv; /* NULL means no media */
90 void *opaque; 95 void *opaque;
91 96
92 int boot_sector_enabled; 97 int boot_sector_enabled;
@@ -96,7 +101,8 @@ struct BlockDriverState { @@ -96,7 +101,8 @@ struct BlockDriverState {
96 char backing_file[1024]; /* if non zero, the image is a diff of 101 char backing_file[1024]; /* if non zero, the image is a diff of
97 this file image */ 102 this file image */
98 int is_temporary; 103 int is_temporary;
99 - 104 + int media_changed;
  105 +
100 BlockDriverState *backing_hd; 106 BlockDriverState *backing_hd;
101 /* async read/write emulation */ 107 /* async read/write emulation */
102 108
qemu-doc.texi
@@ -206,7 +206,7 @@ Select the emulated machine (@code{-M ?} for list) @@ -206,7 +206,7 @@ Select the emulated machine (@code{-M ?} for list)
206 @item -fda file 206 @item -fda file
207 @item -fdb file 207 @item -fdb file
208 Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can 208 Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
209 -use the host floppy by using @file{/dev/fd0} as filename. 209 +use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}).
210 210
211 @item -hda file 211 @item -hda file
212 @item -hdb file 212 @item -hdb file
@@ -217,7 +217,7 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}). @@ -217,7 +217,7 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
217 @item -cdrom file 217 @item -cdrom file
218 Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and 218 Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
219 @option{-cdrom} at the same time). You can use the host CD-ROM by 219 @option{-cdrom} at the same time). You can use the host CD-ROM by
220 -using @file{/dev/cdrom} as filename. 220 +using @file{/dev/cdrom} as filename (@pxref{host_drives}).
221 221
222 @item -boot [a|c|d] 222 @item -boot [a|c|d]
223 Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is 223 Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is
@@ -916,6 +916,7 @@ snapshots. @@ -916,6 +916,7 @@ snapshots.
916 * disk_images_snapshot_mode:: Snapshot mode 916 * disk_images_snapshot_mode:: Snapshot mode
917 * vm_snapshots:: VM snapshots 917 * vm_snapshots:: VM snapshots
918 * qemu_img_invocation:: qemu-img Invocation 918 * qemu_img_invocation:: qemu-img Invocation
  919 +* host_drives:: Using host drives
919 * disk_images_fat_images:: Virtual FAT disk images 920 * disk_images_fat_images:: Virtual FAT disk images
920 @end menu 921 @end menu
921 922
@@ -997,6 +998,57 @@ state is not saved or restored properly (in particular USB). @@ -997,6 +998,57 @@ state is not saved or restored properly (in particular USB).
997 998
998 @include qemu-img.texi 999 @include qemu-img.texi
999 1000
  1001 +@node host_drives
  1002 +@subsection Using host drives
  1003 +
  1004 +In addition to disk image files, QEMU can directly access host
  1005 +devices. We describe here the usage for QEMU version >= 0.8.3.
  1006 +
  1007 +@subsubsection Linux
  1008 +
  1009 +On Linux, you can directly use the host device filename instead of a
  1010 +disk image filename provided you have enough proviledge to access
  1011 +it. For example, use @file{/dev/cdrom} to access to the CDROM or
  1012 +@file{/dev/fd0} for the floppy.
  1013 +
  1014 +@table
  1015 +@item CD
  1016 +You can specify a CDROM device even if no CDROM is loaded. QEMU has
  1017 +specific code to detect CDROM insertion or removal. CDROM ejection by
  1018 +the guest OS is supported. Currently only data CDs are supported.
  1019 +@item Floppy
  1020 +You can specify a floppy device even if no floppy is loaded. Floppy
  1021 +removal is currently not detected accurately (if you change floppy
  1022 +without doing floppy access while the floppy is not loaded, the guest
  1023 +OS will think that the same floppy is loaded).
  1024 +@item Hard disks
  1025 +Hard disks can be used. Normally you must specify the whole disk
  1026 +(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can
  1027 +see it as a partitioned disk. WARNING: unless you know what you do, it
  1028 +is better to only make READ-ONLY accesses to the hard disk otherwise
  1029 +you may corrupt your host data (use the @option{-snapshot} command
  1030 +line option or modify the device permissions accordingly).
  1031 +@end table
  1032 +
  1033 +@subsubsection Windows
  1034 +
  1035 +On Windows you can use any host drives as QEMU drive. The prefered
  1036 +syntax is the driver letter (e.g. @file{d:}). The alternate syntax
  1037 +@file{\\.\d:} is supported. @file{/dev/cdrom} is supported as an alias
  1038 +to the first CDROM drive.
  1039 +
  1040 +Currently there is no specific code to handle removable medias, so it
  1041 +is better to use the @code{change} or @code{eject} monitor commands to
  1042 +change or eject media.
  1043 +
  1044 +@subsubsection Mac OS X
  1045 +
  1046 +@file{/dev/cdrom} is an alias to the first CDROM.
  1047 +
  1048 +Currently there is no specific code to handle removable medias, so it
  1049 +is better to use the @code{change} or @code{eject} monitor commands to
  1050 +change or eject media.
  1051 +
1000 @node disk_images_fat_images 1052 @node disk_images_fat_images
1001 @subsection Virtual FAT disk images 1053 @subsection Virtual FAT disk images
1002 1054
@@ -50,6 +50,7 @@ @@ -50,6 +50,7 @@
50 #define fsync _commit 50 #define fsync _commit
51 #define lseek _lseeki64 51 #define lseek _lseeki64
52 #define ENOTSUP 4096 52 #define ENOTSUP 4096
  53 +#define ENOMEDIUM 4097
53 extern int qemu_ftruncate64(int, int64_t); 54 extern int qemu_ftruncate64(int, int64_t);
54 #define ftruncate qemu_ftruncate64 55 #define ftruncate qemu_ftruncate64
55 56
@@ -502,6 +503,7 @@ typedef struct BlockDriverState BlockDriverState; @@ -502,6 +503,7 @@ typedef struct BlockDriverState BlockDriverState;
502 typedef struct BlockDriver BlockDriver; 503 typedef struct BlockDriver BlockDriver;
503 504
504 extern BlockDriver bdrv_raw; 505 extern BlockDriver bdrv_raw;
  506 +extern BlockDriver bdrv_host_device;
505 extern BlockDriver bdrv_cow; 507 extern BlockDriver bdrv_cow;
506 extern BlockDriver bdrv_qcow; 508 extern BlockDriver bdrv_qcow;
507 extern BlockDriver bdrv_vmdk; 509 extern BlockDriver bdrv_vmdk;
@@ -604,8 +606,10 @@ int bdrv_get_translation_hint(BlockDriverState *bs); @@ -604,8 +606,10 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
604 int bdrv_is_removable(BlockDriverState *bs); 606 int bdrv_is_removable(BlockDriverState *bs);
605 int bdrv_is_read_only(BlockDriverState *bs); 607 int bdrv_is_read_only(BlockDriverState *bs);
606 int bdrv_is_inserted(BlockDriverState *bs); 608 int bdrv_is_inserted(BlockDriverState *bs);
  609 +int bdrv_media_changed(BlockDriverState *bs);
607 int bdrv_is_locked(BlockDriverState *bs); 610 int bdrv_is_locked(BlockDriverState *bs);
608 void bdrv_set_locked(BlockDriverState *bs, int locked); 611 void bdrv_set_locked(BlockDriverState *bs, int locked);
  612 +void bdrv_eject(BlockDriverState *bs, int eject_flag);
609 void bdrv_set_change_cb(BlockDriverState *bs, 613 void bdrv_set_change_cb(BlockDriverState *bs,
610 void (*change_cb)(void *opaque), void *opaque); 614 void (*change_cb)(void *opaque), void *opaque);
611 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); 615 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);