Commit 19cb37389f4641d48803f0c5d72708749cbcf318
1 parent
66c6ef76
better support of host drives
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2124 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
808 additions
and
164 deletions
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 */ | ... | ... |
block.c
| ... | ... | @@ -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 | ... | ... |
vl.h
| ... | ... | @@ -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); | ... | ... |