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 46 #ifdef __sun__
47 47 #include <sys/dkio.h>
48 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 75 #endif
  76 +} BDRVRawState;
  77 +
  78 +static int fd_open(BlockDriverState *bs);
111 79  
112 80 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
113 81 {
114 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 85 open_flags = O_BINARY;
144 86 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
145 87 open_flags |= O_RDWR;
... ... @@ -150,9 +92,15 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
150 92 if (flags & BDRV_O_CREAT)
151 93 open_flags |= O_CREAT | O_TRUNC;
152 94  
  95 + s->type = FTYPE_FILE;
  96 +
153 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 104 s->fd = fd;
157 105 return 0;
158 106 }
... ... @@ -180,6 +128,10 @@ static int raw_pread(BlockDriverState *bs, int64_t offset,
180 128 BDRVRawState *s = bs->opaque;
181 129 int ret;
182 130  
  131 + ret = fd_open(bs);
  132 + if (ret < 0)
  133 + return ret;
  134 +
183 135 lseek(s->fd, offset, SEEK_SET);
184 136 ret = read(s->fd, buf, count);
185 137 return ret;
... ... @@ -191,13 +143,17 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
191 143 BDRVRawState *s = bs->opaque;
192 144 int ret;
193 145  
  146 + ret = fd_open(bs);
  147 + if (ret < 0)
  148 + return ret;
  149 +
194 150 lseek(s->fd, offset, SEEK_SET);
195 151 ret = write(s->fd, buf, count);
196 152 return ret;
197 153 }
198 154  
199 155 /***********************************************************/
200   -/* Unix AOP using POSIX AIO */
  156 +/* Unix AIO using POSIX AIO */
201 157  
202 158 typedef struct RawAIOCB {
203 159 BlockDriverAIOCB common;
... ... @@ -236,15 +192,18 @@ void qemu_aio_init(void)
236 192 act.sa_handler = aio_signal_handler;
237 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 199 struct aioinit ai;
242 200 memset(&ai, 0, sizeof(ai));
243   - ai.aio_threads = 2;
  201 + ai.aio_threads = 1;
244 202 ai.aio_num = 1;
245 203 ai.aio_idle_time = 365 * 100000;
246 204 aio_init(&ai);
247 205 }
  206 +#endif
248 207 }
249 208  
250 209 void qemu_aio_poll(void)
... ... @@ -270,7 +229,7 @@ void qemu_aio_poll(void)
270 229 if (ret == acb->aiocb.aio_nbytes)
271 230 ret = 0;
272 231 else
273   - ret = -1;
  232 + ret = -EINVAL;
274 233 } else {
275 234 ret = -ret;
276 235 }
... ... @@ -329,6 +288,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
329 288 BDRVRawState *s = bs->opaque;
330 289 RawAIOCB *acb;
331 290  
  291 + if (fd_open(bs) < 0)
  292 + return NULL;
  293 +
332 294 acb = qemu_aio_get(bs, cb, opaque);
333 295 if (!acb)
334 296 return NULL;
... ... @@ -405,12 +367,17 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
405 367 static void raw_close(BlockDriverState *bs)
406 368 {
407 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 376 static int raw_truncate(BlockDriverState *bs, int64_t offset)
412 377 {
413 378 BDRVRawState *s = bs->opaque;
  379 + if (s->type != FTYPE_FILE)
  380 + return -ENOTSUP;
414 381 if (ftruncate(s->fd, offset) < 0)
415 382 return -errno;
416 383 return 0;
... ... @@ -428,6 +395,11 @@ static int64_t raw_getlength(BlockDriverState *bs)
428 395 struct dk_minfo minfo;
429 396 int rv;
430 397 #endif
  398 + int ret;
  399 +
  400 + ret = fd_open(bs);
  401 + if (ret < 0)
  402 + return ret;
431 403  
432 404 #ifdef _BSD
433 405 if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
... ... @@ -455,12 +427,6 @@ static int64_t raw_getlength(BlockDriverState *bs)
455 427 {
456 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 430 return size;
465 431 }
466 432  
... ... @@ -509,13 +475,358 @@ BlockDriver bdrv_raw = {
509 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 818 #else /* _WIN32 */
513 819  
514 820 /* XXX: use another file ? */
515 821 #include <winioctl.h>
516 822  
  823 +#define FTYPE_FILE 0
  824 +#define FTYPE_CD 1
  825 +
517 826 typedef struct BDRVRawState {
518 827 HANDLE hfile;
  828 + int type;
  829 + char drive_letter[2];
519 830 } BDRVRawState;
520 831  
521 832 typedef struct RawAIOCB {
... ... @@ -565,6 +876,23 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
565 876 BDRVRawState *s = bs->opaque;
566 877 int access_flags, create_flags;
567 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 897 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
570 898 access_flags = GENERIC_READ | GENERIC_WRITE;
... ... @@ -765,10 +1093,22 @@ static int64_t raw_getlength(BlockDriverState *bs)
765 1093 {
766 1094 BDRVRawState *s = bs->opaque;
767 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 1112 return l.QuadPart;
773 1113 }
774 1114  
... ... @@ -833,4 +1173,146 @@ BlockDriver bdrv_raw = {
833 1173 .bdrv_truncate = raw_truncate,
834 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 1318 #endif /* _WIN32 */
... ...
... ... @@ -181,24 +181,37 @@ void get_tmp_filename(char *filename, int size)
181 181 }
182 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 198 static BlockDriver *find_protocol(const char *filename)
185 199 {
186 200 BlockDriver *drv1;
187 201 char protocol[128];
188 202 int len;
189 203 const char *p;
  204 +
  205 +#ifdef _WIN32
  206 + if (is_windows_drive(filename))
  207 + return &bdrv_raw;
  208 +#endif
190 209 p = strchr(filename, ':');
191 210 if (!p)
192 211 return &bdrv_raw;
193 212 len = p - filename;
194 213 if (len > sizeof(protocol) - 1)
195 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 215 memcpy(protocol, filename, len);
203 216 protocol[len] = '\0';
204 217 for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
... ... @@ -218,14 +231,28 @@ static BlockDriver *find_image_format(const char *filename)
218 231 uint8_t buf[2048];
219 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 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 253 if (drv == &bdrv_vvfat)
225 254 return drv;
226   - if (strstart(filename, "/dev/", NULL))
227   - return &bdrv_raw;
228   -
  255 +
229 256 ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
230 257 if (ret < 0)
231 258 return NULL;
... ... @@ -362,9 +389,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
362 389 goto fail;
363 390 }
364 391  
365   - bs->inserted = 1;
366   -
367 392 /* call the change callback */
  393 + bs->media_changed = 1;
368 394 if (bs->change_cb)
369 395 bs->change_cb(bs->change_opaque);
370 396  
... ... @@ -373,7 +399,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
373 399  
374 400 void bdrv_close(BlockDriverState *bs)
375 401 {
376   - if (bs->inserted) {
  402 + if (bs->drv) {
377 403 if (bs->backing_hd)
378 404 bdrv_delete(bs->backing_hd);
379 405 bs->drv->bdrv_close(bs);
... ... @@ -385,9 +411,9 @@ void bdrv_close(BlockDriverState *bs)
385 411 #endif
386 412 bs->opaque = NULL;
387 413 bs->drv = NULL;
388   - bs->inserted = 0;
389 414  
390 415 /* call the change callback */
  416 + bs->media_changed = 1;
391 417 if (bs->change_cb)
392 418 bs->change_cb(bs->change_opaque);
393 419 }
... ... @@ -403,12 +429,13 @@ void bdrv_delete(BlockDriverState *bs)
403 429 /* commit COW file into the raw image */
404 430 int bdrv_commit(BlockDriverState *bs)
405 431 {
  432 + BlockDriver *drv = bs->drv;
406 433 int64_t i, total_sectors;
407 434 int n, j;
408 435 unsigned char sector[512];
409 436  
410   - if (!bs->inserted)
411   - return -ENOENT;
  437 + if (!drv)
  438 + return -ENOMEDIUM;
412 439  
413 440 if (bs->read_only) {
414 441 return -EACCES;
... ... @@ -420,7 +447,7 @@ int bdrv_commit(BlockDriverState *bs)
420 447  
421 448 total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
422 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 451 for(j = 0; j < n; j++) {
425 452 if (bdrv_read(bs, i, sector, 1) != 0) {
426 453 return -EIO;
... ... @@ -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 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 473 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
447 474 uint8_t *buf, int nb_sectors)
448 475 {
449 476 BlockDriver *drv = bs->drv;
450 477  
451   - if (!bs->inserted)
452   - return -1;
  478 + if (!drv)
  479 + return -ENOMEDIUM;
453 480  
454 481 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
455 482 memcpy(buf, bs->boot_sector_data, 512);
... ... @@ -466,7 +493,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
466 493 if (ret < 0)
467 494 return ret;
468 495 else if (ret != len)
469   - return -EIO;
  496 + return -EINVAL;
470 497 else
471 498 return 0;
472 499 } else {
... ... @@ -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 510 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
479 511 const uint8_t *buf, int nb_sectors)
480 512 {
481 513 BlockDriver *drv = bs->drv;
482   - if (!bs->inserted)
483   - return -1;
  514 + if (!bs->drv)
  515 + return -ENOMEDIUM;
484 516 if (bs->read_only)
485   - return -1;
  517 + return -EACCES;
486 518 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
487 519 memcpy(bs->boot_sector_data, buf, 512);
488 520 }
... ... @@ -501,7 +533,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
501 533 }
502 534 }
503 535  
504   -/* not necessary now */
505 536 static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
506 537 uint8_t *buf, int count1)
507 538 {
... ... @@ -603,7 +634,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
603 634 BlockDriver *drv = bs->drv;
604 635  
605 636 if (!drv)
606   - return -ENOENT;
  637 + return -ENOMEDIUM;
607 638 if (!drv->bdrv_pread)
608 639 return bdrv_pread_em(bs, offset, buf1, count1);
609 640 return drv->bdrv_pread(bs, offset, buf1, count1);
... ... @@ -618,7 +649,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
618 649 BlockDriver *drv = bs->drv;
619 650  
620 651 if (!drv)
621   - return -ENOENT;
  652 + return -ENOMEDIUM;
622 653 if (!drv->bdrv_pwrite)
623 654 return bdrv_pwrite_em(bs, offset, buf1, count1);
624 655 return drv->bdrv_pwrite(bs, offset, buf1, count1);
... ... @@ -631,7 +662,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
631 662 {
632 663 BlockDriver *drv = bs->drv;
633 664 if (!drv)
634   - return -ENOENT;
  665 + return -ENOMEDIUM;
635 666 if (!drv->bdrv_truncate)
636 667 return -ENOTSUP;
637 668 return drv->bdrv_truncate(bs, offset);
... ... @@ -644,7 +675,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
644 675 {
645 676 BlockDriver *drv = bs->drv;
646 677 if (!drv)
647   - return -ENOENT;
  678 + return -ENOMEDIUM;
648 679 if (!drv->bdrv_getlength) {
649 680 /* legacy mode */
650 681 return bs->total_sectors * SECTOR_SIZE;
... ... @@ -652,9 +683,16 @@ int64_t bdrv_getlength(BlockDriverState *bs)
652 683 return drv->bdrv_getlength(bs);
653 684 }
654 685  
  686 +/* return 0 as number of sectors if no device present or error */
655 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 698 /* force a given boot sector. */
... ... @@ -715,21 +753,7 @@ int bdrv_is_read_only(BlockDriverState *bs)
715 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 757 void bdrv_set_change_cb(BlockDriverState *bs,
734 758 void (*change_cb)(void *opaque), void *opaque)
735 759 {
... ... @@ -761,7 +785,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
761 785  
762 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 789 buf[0] = '\0';
766 790 } else {
767 791 pstrcpy(buf, buf_size, bs->drv->format_name);
... ... @@ -833,7 +857,7 @@ void bdrv_info(void)
833 857 if (bs->removable) {
834 858 term_printf(" locked=%d", bs->locked);
835 859 }
836   - if (bs->inserted) {
  860 + if (bs->drv) {
837 861 term_printf(" file=%s", bs->filename);
838 862 if (bs->backing_file[0] != '\0')
839 863 term_printf(" backing_file=%s", bs->backing_file);
... ... @@ -863,7 +887,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
863 887 {
864 888 BlockDriver *drv = bs->drv;
865 889 if (!drv)
866   - return -ENOENT;
  890 + return -ENOMEDIUM;
867 891 if (!drv->bdrv_write_compressed)
868 892 return -ENOTSUP;
869 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 897 {
874 898 BlockDriver *drv = bs->drv;
875 899 if (!drv)
876   - return -ENOENT;
  900 + return -ENOMEDIUM;
877 901 if (!drv->bdrv_get_info)
878 902 return -ENOTSUP;
879 903 memset(bdi, 0, sizeof(*bdi));
... ... @@ -888,7 +912,7 @@ int bdrv_snapshot_create(BlockDriverState *bs,
888 912 {
889 913 BlockDriver *drv = bs->drv;
890 914 if (!drv)
891   - return -ENOENT;
  915 + return -ENOMEDIUM;
892 916 if (!drv->bdrv_snapshot_create)
893 917 return -ENOTSUP;
894 918 return drv->bdrv_snapshot_create(bs, sn_info);
... ... @@ -899,7 +923,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
899 923 {
900 924 BlockDriver *drv = bs->drv;
901 925 if (!drv)
902   - return -ENOENT;
  926 + return -ENOMEDIUM;
903 927 if (!drv->bdrv_snapshot_goto)
904 928 return -ENOTSUP;
905 929 return drv->bdrv_snapshot_goto(bs, snapshot_id);
... ... @@ -909,7 +933,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
909 933 {
910 934 BlockDriver *drv = bs->drv;
911 935 if (!drv)
912   - return -ENOENT;
  936 + return -ENOMEDIUM;
913 937 if (!drv->bdrv_snapshot_delete)
914 938 return -ENOTSUP;
915 939 return drv->bdrv_snapshot_delete(bs, snapshot_id);
... ... @@ -920,7 +944,7 @@ int bdrv_snapshot_list(BlockDriverState *bs,
920 944 {
921 945 BlockDriver *drv = bs->drv;
922 946 if (!drv)
923   - return -ENOENT;
  947 + return -ENOMEDIUM;
924 948 if (!drv->bdrv_snapshot_list)
925 949 return -ENOTSUP;
926 950 return drv->bdrv_snapshot_list(bs, psn_info);
... ... @@ -1001,7 +1025,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
1001 1025 {
1002 1026 BlockDriver *drv = bs->drv;
1003 1027  
1004   - if (!bs->inserted)
  1028 + if (!drv)
1005 1029 return NULL;
1006 1030  
1007 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 1045 {
1022 1046 BlockDriver *drv = bs->drv;
1023 1047  
1024   - if (!bs->inserted)
  1048 + if (!drv)
1025 1049 return NULL;
1026 1050 if (bs->read_only)
1027 1051 return NULL;
... ... @@ -1170,6 +1194,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
1170 1194 void bdrv_init(void)
1171 1195 {
1172 1196 bdrv_register(&bdrv_raw);
  1197 + bdrv_register(&bdrv_host_device);
1173 1198 #ifndef _WIN32
1174 1199 bdrv_register(&bdrv_cow);
1175 1200 #endif
... ... @@ -1211,3 +1236,78 @@ void qemu_aio_release(void *p)
1211 1236 acb->next = drv->free_aiocb;
1212 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 70 QEMUSnapshotInfo **psn_info);
71 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 79 BlockDriverAIOCB *free_aiocb;
74 80 struct BlockDriver *next;
75 81 };
... ... @@ -78,7 +84,6 @@ struct BlockDriverState {
78 84 int64_t total_sectors; /* if we are reading a disk image, give its
79 85 size in sectors */
80 86 int read_only; /* if true, the media is read only */
81   - int inserted; /* if true, the media is present */
82 87 int removable; /* if true, the media can be removed */
83 88 int locked; /* if true, the media cannot temporarily be ejected */
84 89 int encrypted; /* if true, the media is encrypted */
... ... @@ -86,7 +91,7 @@ struct BlockDriverState {
86 91 void (*change_cb)(void *opaque);
87 92 void *change_opaque;
88 93  
89   - BlockDriver *drv;
  94 + BlockDriver *drv; /* NULL means no media */
90 95 void *opaque;
91 96  
92 97 int boot_sector_enabled;
... ... @@ -96,7 +101,8 @@ struct BlockDriverState {
96 101 char backing_file[1024]; /* if non zero, the image is a diff of
97 102 this file image */
98 103 int is_temporary;
99   -
  104 + int media_changed;
  105 +
100 106 BlockDriverState *backing_hd;
101 107 /* async read/write emulation */
102 108  
... ...
qemu-doc.texi
... ... @@ -206,7 +206,7 @@ Select the emulated machine (@code{-M ?} for list)
206 206 @item -fda file
207 207 @item -fdb file
208 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 211 @item -hda file
212 212 @item -hdb file
... ... @@ -217,7 +217,7 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
217 217 @item -cdrom file
218 218 Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
219 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 222 @item -boot [a|c|d]
223 223 Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is
... ... @@ -916,6 +916,7 @@ snapshots.
916 916 * disk_images_snapshot_mode:: Snapshot mode
917 917 * vm_snapshots:: VM snapshots
918 918 * qemu_img_invocation:: qemu-img Invocation
  919 +* host_drives:: Using host drives
919 920 * disk_images_fat_images:: Virtual FAT disk images
920 921 @end menu
921 922  
... ... @@ -997,6 +998,57 @@ state is not saved or restored properly (in particular USB).
997 998  
998 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 1052 @node disk_images_fat_images
1001 1053 @subsection Virtual FAT disk images
1002 1054  
... ...
... ... @@ -50,6 +50,7 @@
50 50 #define fsync _commit
51 51 #define lseek _lseeki64
52 52 #define ENOTSUP 4096
  53 +#define ENOMEDIUM 4097
53 54 extern int qemu_ftruncate64(int, int64_t);
54 55 #define ftruncate qemu_ftruncate64
55 56  
... ... @@ -502,6 +503,7 @@ typedef struct BlockDriverState BlockDriverState;
502 503 typedef struct BlockDriver BlockDriver;
503 504  
504 505 extern BlockDriver bdrv_raw;
  506 +extern BlockDriver bdrv_host_device;
505 507 extern BlockDriver bdrv_cow;
506 508 extern BlockDriver bdrv_qcow;
507 509 extern BlockDriver bdrv_vmdk;
... ... @@ -604,8 +606,10 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
604 606 int bdrv_is_removable(BlockDriverState *bs);
605 607 int bdrv_is_read_only(BlockDriverState *bs);
606 608 int bdrv_is_inserted(BlockDriverState *bs);
  609 +int bdrv_media_changed(BlockDriverState *bs);
607 610 int bdrv_is_locked(BlockDriverState *bs);
608 611 void bdrv_set_locked(BlockDriverState *bs, int locked);
  612 +void bdrv_eject(BlockDriverState *bs, int eject_flag);
609 613 void bdrv_set_change_cb(BlockDriverState *bs,
610 614 void (*change_cb)(void *opaque), void *opaque);
611 615 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
... ...