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