1 /* 2 * Block driver for RAW files (win32) 3 * 4 * Copyright (c) 2006 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "qapi/error.h" 27 #include "qemu/cutils.h" 28 #include "block/block-io.h" 29 #include "block/block_int.h" 30 #include "qemu/module.h" 31 #include "qemu/option.h" 32 #include "block/raw-aio.h" 33 #include "trace.h" 34 #include "block/thread-pool.h" 35 #include "qemu/iov.h" 36 #include "qapi/qmp/qdict.h" 37 #include "qapi/qmp/qstring.h" 38 #include <windows.h> 39 #include <winioctl.h> 40 41 #define FTYPE_FILE 0 42 #define FTYPE_CD 1 43 #define FTYPE_HARDDISK 2 44 45 typedef struct RawWin32AIOData { 46 BlockDriverState *bs; 47 HANDLE hfile; 48 struct iovec *aio_iov; 49 int aio_niov; 50 size_t aio_nbytes; 51 off64_t aio_offset; 52 int aio_type; 53 } RawWin32AIOData; 54 55 typedef struct BDRVRawState { 56 HANDLE hfile; 57 int type; 58 char drive_path[16]; /* format: "d:\" */ 59 QEMUWin32AIOState *aio; 60 } BDRVRawState; 61 62 typedef struct BDRVRawReopenState { 63 HANDLE hfile; 64 } BDRVRawReopenState; 65 66 /* 67 * Read/writes the data to/from a given linear buffer. 68 * 69 * Returns the number of bytes handles or -errno in case of an error. Short 70 * reads are only returned if the end of the file is reached. 71 */ 72 static size_t handle_aiocb_rw(RawWin32AIOData *aiocb) 73 { 74 size_t offset = 0; 75 int i; 76 77 for (i = 0; i < aiocb->aio_niov; i++) { 78 OVERLAPPED ov; 79 DWORD ret, ret_count, len; 80 81 memset(&ov, 0, sizeof(ov)); 82 ov.Offset = (aiocb->aio_offset + offset); 83 ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32; 84 len = aiocb->aio_iov[i].iov_len; 85 if (aiocb->aio_type & QEMU_AIO_WRITE) { 86 ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base, 87 len, &ret_count, &ov); 88 } else { 89 ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base, 90 len, &ret_count, &ov); 91 } 92 if (!ret) { 93 ret_count = 0; 94 } 95 if (ret_count != len) { 96 offset += ret_count; 97 break; 98 } 99 offset += len; 100 } 101 102 return offset; 103 } 104 105 static int aio_worker(void *arg) 106 { 107 RawWin32AIOData *aiocb = arg; 108 ssize_t ret = 0; 109 size_t count; 110 111 switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) { 112 case QEMU_AIO_READ: 113 count = handle_aiocb_rw(aiocb); 114 if (count < aiocb->aio_nbytes) { 115 /* A short read means that we have reached EOF. Pad the buffer 116 * with zeros for bytes after EOF. */ 117 iov_memset(aiocb->aio_iov, aiocb->aio_niov, count, 118 0, aiocb->aio_nbytes - count); 119 120 count = aiocb->aio_nbytes; 121 } 122 if (count == aiocb->aio_nbytes) { 123 ret = 0; 124 } else { 125 ret = -EINVAL; 126 } 127 break; 128 case QEMU_AIO_WRITE: 129 count = handle_aiocb_rw(aiocb); 130 if (count == aiocb->aio_nbytes) { 131 ret = 0; 132 } else { 133 ret = -EINVAL; 134 } 135 break; 136 case QEMU_AIO_FLUSH: 137 if (!FlushFileBuffers(aiocb->hfile)) { 138 return -EIO; 139 } 140 break; 141 default: 142 fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); 143 ret = -EINVAL; 144 break; 145 } 146 147 g_free(aiocb); 148 return ret; 149 } 150 151 static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, 152 int64_t offset, QEMUIOVector *qiov, int count, 153 BlockCompletionFunc *cb, void *opaque, int type) 154 { 155 RawWin32AIOData *acb = g_new(RawWin32AIOData, 1); 156 ThreadPool *pool; 157 158 acb->bs = bs; 159 acb->hfile = hfile; 160 acb->aio_type = type; 161 162 if (qiov) { 163 acb->aio_iov = qiov->iov; 164 acb->aio_niov = qiov->niov; 165 assert(qiov->size == count); 166 } 167 acb->aio_nbytes = count; 168 acb->aio_offset = offset; 169 170 trace_file_paio_submit(acb, opaque, offset, count, type); 171 pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); 172 return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); 173 } 174 175 int qemu_ftruncate64(int fd, int64_t length) 176 { 177 LARGE_INTEGER li; 178 DWORD dw; 179 LONG high; 180 HANDLE h; 181 BOOL res; 182 183 if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) 184 return -1; 185 186 h = (HANDLE)_get_osfhandle(fd); 187 188 /* get current position, ftruncate do not change position */ 189 li.HighPart = 0; 190 li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); 191 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 192 return -1; 193 } 194 195 high = length >> 32; 196 dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN); 197 if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 198 return -1; 199 } 200 res = SetEndOfFile(h); 201 202 /* back to old position */ 203 SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); 204 return res ? 0 : -1; 205 } 206 207 static int set_sparse(int fd) 208 { 209 DWORD returned; 210 return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, 211 NULL, 0, NULL, 0, &returned, NULL); 212 } 213 214 static void raw_detach_aio_context(BlockDriverState *bs) 215 { 216 BDRVRawState *s = bs->opaque; 217 218 if (s->aio) { 219 win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); 220 } 221 } 222 223 static void raw_attach_aio_context(BlockDriverState *bs, 224 AioContext *new_context) 225 { 226 BDRVRawState *s = bs->opaque; 227 228 if (s->aio) { 229 win32_aio_attach_aio_context(s->aio, new_context); 230 } 231 } 232 233 static void raw_probe_alignment(BlockDriverState *bs, Error **errp) 234 { 235 BDRVRawState *s = bs->opaque; 236 DWORD sectorsPerCluster, freeClusters, totalClusters, count; 237 DISK_GEOMETRY_EX dg; 238 BOOL status; 239 240 if (s->type == FTYPE_CD) { 241 bs->bl.request_alignment = 2048; 242 return; 243 } 244 if (s->type == FTYPE_HARDDISK) { 245 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 246 NULL, 0, &dg, sizeof(dg), &count, NULL); 247 if (status != 0) { 248 bs->bl.request_alignment = dg.Geometry.BytesPerSector; 249 return; 250 } 251 /* try GetDiskFreeSpace too */ 252 } 253 254 if (s->drive_path[0]) { 255 GetDiskFreeSpace(s->drive_path, §orsPerCluster, 256 &dg.Geometry.BytesPerSector, 257 &freeClusters, &totalClusters); 258 bs->bl.request_alignment = dg.Geometry.BytesPerSector; 259 return; 260 } 261 262 /* XXX Does Windows support AIO on less than 512-byte alignment? */ 263 bs->bl.request_alignment = 512; 264 } 265 266 static void raw_parse_flags(int flags, bool use_aio, int *access_flags, 267 DWORD *overlapped) 268 { 269 assert(access_flags != NULL); 270 assert(overlapped != NULL); 271 272 if (flags & BDRV_O_RDWR) { 273 *access_flags = GENERIC_READ | GENERIC_WRITE; 274 } else { 275 *access_flags = GENERIC_READ; 276 } 277 278 *overlapped = FILE_ATTRIBUTE_NORMAL; 279 if (use_aio) { 280 *overlapped |= FILE_FLAG_OVERLAPPED; 281 } 282 if (flags & BDRV_O_NOCACHE) { 283 *overlapped |= FILE_FLAG_NO_BUFFERING; 284 } 285 } 286 287 static void raw_parse_filename(const char *filename, QDict *options, 288 Error **errp) 289 { 290 bdrv_parse_filename_strip_prefix(filename, "file:", options); 291 } 292 293 static QemuOptsList raw_runtime_opts = { 294 .name = "raw", 295 .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head), 296 .desc = { 297 { 298 .name = "filename", 299 .type = QEMU_OPT_STRING, 300 .help = "File name of the image", 301 }, 302 { 303 .name = "aio", 304 .type = QEMU_OPT_STRING, 305 .help = "host AIO implementation (threads, native)", 306 }, 307 { 308 .name = "locking", 309 .type = QEMU_OPT_STRING, 310 .help = "file locking mode (on/off/auto, default: auto)", 311 }, 312 { /* end of list */ } 313 }, 314 }; 315 316 static bool get_aio_option(QemuOpts *opts, int flags, Error **errp) 317 { 318 BlockdevAioOptions aio, aio_default; 319 320 aio_default = (flags & BDRV_O_NATIVE_AIO) ? BLOCKDEV_AIO_OPTIONS_NATIVE 321 : BLOCKDEV_AIO_OPTIONS_THREADS; 322 aio = qapi_enum_parse(&BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"), 323 aio_default, errp); 324 325 switch (aio) { 326 case BLOCKDEV_AIO_OPTIONS_NATIVE: 327 return true; 328 case BLOCKDEV_AIO_OPTIONS_THREADS: 329 return false; 330 default: 331 error_setg(errp, "Invalid AIO option"); 332 } 333 return false; 334 } 335 336 static int raw_open(BlockDriverState *bs, QDict *options, int flags, 337 Error **errp) 338 { 339 BDRVRawState *s = bs->opaque; 340 int access_flags; 341 DWORD overlapped; 342 QemuOpts *opts; 343 Error *local_err = NULL; 344 const char *filename; 345 bool use_aio; 346 OnOffAuto locking; 347 int ret; 348 349 s->type = FTYPE_FILE; 350 351 opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); 352 if (!qemu_opts_absorb_qdict(opts, options, errp)) { 353 ret = -EINVAL; 354 goto fail; 355 } 356 357 locking = qapi_enum_parse(&OnOffAuto_lookup, 358 qemu_opt_get(opts, "locking"), 359 ON_OFF_AUTO_AUTO, &local_err); 360 if (local_err) { 361 error_propagate(errp, local_err); 362 ret = -EINVAL; 363 goto fail; 364 } 365 switch (locking) { 366 case ON_OFF_AUTO_ON: 367 error_setg(errp, "locking=on is not supported on Windows"); 368 ret = -EINVAL; 369 goto fail; 370 case ON_OFF_AUTO_OFF: 371 case ON_OFF_AUTO_AUTO: 372 break; 373 default: 374 g_assert_not_reached(); 375 } 376 377 filename = qemu_opt_get(opts, "filename"); 378 379 use_aio = get_aio_option(opts, flags, &local_err); 380 if (local_err) { 381 error_propagate(errp, local_err); 382 ret = -EINVAL; 383 goto fail; 384 } 385 386 raw_parse_flags(flags, use_aio, &access_flags, &overlapped); 387 388 if (filename[0] && filename[1] == ':') { 389 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]); 390 } else if (filename[0] == '\\' && filename[1] == '\\') { 391 s->drive_path[0] = 0; 392 } else { 393 /* Relative path. */ 394 char buf[MAX_PATH]; 395 GetCurrentDirectory(MAX_PATH, buf); 396 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]); 397 } 398 399 s->hfile = CreateFile(filename, access_flags, 400 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 401 OPEN_EXISTING, overlapped, NULL); 402 if (s->hfile == INVALID_HANDLE_VALUE) { 403 int err = GetLastError(); 404 405 error_setg_win32(errp, err, "Could not open '%s'", filename); 406 if (err == ERROR_ACCESS_DENIED) { 407 ret = -EACCES; 408 } else { 409 ret = -EINVAL; 410 } 411 goto fail; 412 } 413 414 if (use_aio) { 415 s->aio = win32_aio_init(); 416 if (s->aio == NULL) { 417 CloseHandle(s->hfile); 418 error_setg(errp, "Could not initialize AIO"); 419 ret = -EINVAL; 420 goto fail; 421 } 422 423 ret = win32_aio_attach(s->aio, s->hfile); 424 if (ret < 0) { 425 win32_aio_cleanup(s->aio); 426 CloseHandle(s->hfile); 427 error_setg_errno(errp, -ret, "Could not enable AIO"); 428 goto fail; 429 } 430 431 win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs)); 432 } 433 434 /* When extending regular files, we get zeros from the OS */ 435 bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; 436 437 ret = 0; 438 fail: 439 qemu_opts_del(opts); 440 return ret; 441 } 442 443 static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs, 444 int64_t offset, int64_t bytes, 445 QEMUIOVector *qiov, BdrvRequestFlags flags, 446 BlockCompletionFunc *cb, void *opaque) 447 { 448 BDRVRawState *s = bs->opaque; 449 if (s->aio) { 450 return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov, 451 cb, opaque, QEMU_AIO_READ); 452 } else { 453 return paio_submit(bs, s->hfile, offset, qiov, bytes, 454 cb, opaque, QEMU_AIO_READ); 455 } 456 } 457 458 static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs, 459 int64_t offset, int64_t bytes, 460 QEMUIOVector *qiov, BdrvRequestFlags flags, 461 BlockCompletionFunc *cb, void *opaque) 462 { 463 BDRVRawState *s = bs->opaque; 464 if (s->aio) { 465 return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov, 466 cb, opaque, QEMU_AIO_WRITE); 467 } else { 468 return paio_submit(bs, s->hfile, offset, qiov, bytes, 469 cb, opaque, QEMU_AIO_WRITE); 470 } 471 } 472 473 static BlockAIOCB *raw_aio_flush(BlockDriverState *bs, 474 BlockCompletionFunc *cb, void *opaque) 475 { 476 BDRVRawState *s = bs->opaque; 477 return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH); 478 } 479 480 static void raw_close(BlockDriverState *bs) 481 { 482 BDRVRawState *s = bs->opaque; 483 484 if (s->aio) { 485 win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); 486 win32_aio_cleanup(s->aio); 487 s->aio = NULL; 488 } 489 490 CloseHandle(s->hfile); 491 if (bs->open_flags & BDRV_O_TEMPORARY) { 492 unlink(bs->filename); 493 } 494 } 495 496 static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, 497 bool exact, PreallocMode prealloc, 498 BdrvRequestFlags flags, Error **errp) 499 { 500 BDRVRawState *s = bs->opaque; 501 LONG low, high; 502 DWORD dwPtrLow; 503 504 if (prealloc != PREALLOC_MODE_OFF) { 505 error_setg(errp, "Unsupported preallocation mode '%s'", 506 PreallocMode_str(prealloc)); 507 return -ENOTSUP; 508 } 509 510 low = offset; 511 high = offset >> 32; 512 513 /* 514 * An error has occurred if the return value is INVALID_SET_FILE_POINTER 515 * and GetLastError doesn't return NO_ERROR. 516 */ 517 dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN); 518 if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 519 error_setg_win32(errp, GetLastError(), "SetFilePointer error"); 520 return -EIO; 521 } 522 if (SetEndOfFile(s->hfile) == 0) { 523 error_setg_win32(errp, GetLastError(), "SetEndOfFile error"); 524 return -EIO; 525 } 526 return 0; 527 } 528 529 static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) 530 { 531 BDRVRawState *s = bs->opaque; 532 LARGE_INTEGER l; 533 ULARGE_INTEGER available, total, total_free; 534 DISK_GEOMETRY_EX dg; 535 DWORD count; 536 BOOL status; 537 538 switch(s->type) { 539 case FTYPE_FILE: 540 l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); 541 if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) 542 return -EIO; 543 break; 544 case FTYPE_CD: 545 if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) 546 return -EIO; 547 l.QuadPart = total.QuadPart; 548 break; 549 case FTYPE_HARDDISK: 550 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 551 NULL, 0, &dg, sizeof(dg), &count, NULL); 552 if (status != 0) { 553 l = dg.DiskSize; 554 } 555 break; 556 default: 557 return -EIO; 558 } 559 return l.QuadPart; 560 } 561 562 static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs) 563 { 564 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, 565 DWORD * high); 566 get_compressed_t get_compressed; 567 struct _stati64 st; 568 const char *filename = bs->filename; 569 /* WinNT support GetCompressedFileSize to determine allocate size */ 570 get_compressed = 571 (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), 572 "GetCompressedFileSizeA"); 573 if (get_compressed) { 574 DWORD high, low; 575 low = get_compressed(filename, &high); 576 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) { 577 return (((int64_t) high) << 32) + low; 578 } 579 } 580 581 if (_stati64(filename, &st) < 0) { 582 return -1; 583 } 584 return st.st_size; 585 } 586 587 static int raw_co_create(BlockdevCreateOptions *options, Error **errp) 588 { 589 BlockdevCreateOptionsFile *file_opts; 590 int fd; 591 592 assert(options->driver == BLOCKDEV_DRIVER_FILE); 593 file_opts = &options->u.file; 594 595 if (file_opts->has_preallocation) { 596 error_setg(errp, "Preallocation is not supported on Windows"); 597 return -EINVAL; 598 } 599 if (file_opts->has_nocow) { 600 error_setg(errp, "nocow is not supported on Windows"); 601 return -EINVAL; 602 } 603 604 fd = qemu_create(file_opts->filename, O_WRONLY | O_TRUNC | O_BINARY, 605 0644, errp); 606 if (fd < 0) { 607 return -EIO; 608 } 609 set_sparse(fd); 610 ftruncate(fd, file_opts->size); 611 qemu_close(fd); 612 613 return 0; 614 } 615 616 static int coroutine_fn GRAPH_RDLOCK 617 raw_co_create_opts(BlockDriver *drv, const char *filename, 618 QemuOpts *opts, Error **errp) 619 { 620 BlockdevCreateOptions options; 621 int64_t total_size = 0; 622 623 strstart(filename, "file:", &filename); 624 625 /* Read out options */ 626 total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 627 BDRV_SECTOR_SIZE); 628 629 options = (BlockdevCreateOptions) { 630 .driver = BLOCKDEV_DRIVER_FILE, 631 .u.file = { 632 .filename = (char *) filename, 633 .size = total_size, 634 .has_preallocation = false, 635 .has_nocow = false, 636 }, 637 }; 638 return raw_co_create(&options, errp); 639 } 640 641 static int raw_reopen_prepare(BDRVReopenState *state, 642 BlockReopenQueue *queue, Error **errp) 643 { 644 BDRVRawState *s = state->bs->opaque; 645 BDRVRawReopenState *rs; 646 int access_flags; 647 DWORD overlapped; 648 int ret = 0; 649 650 if (s->type != FTYPE_FILE) { 651 error_setg(errp, "Can only reopen files"); 652 return -EINVAL; 653 } 654 655 rs = g_new0(BDRVRawReopenState, 1); 656 657 /* 658 * We do not support changing any options (only flags). By leaving 659 * all options in state->options, we tell the generic reopen code 660 * that we do not support changing any of them, so it will verify 661 * that their values did not change. 662 */ 663 664 raw_parse_flags(state->flags, s->aio != NULL, &access_flags, &overlapped); 665 rs->hfile = CreateFile(state->bs->filename, access_flags, 666 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 667 OPEN_EXISTING, overlapped, NULL); 668 669 if (rs->hfile == INVALID_HANDLE_VALUE) { 670 int err = GetLastError(); 671 672 error_setg_win32(errp, err, "Could not reopen '%s'", 673 state->bs->filename); 674 if (err == ERROR_ACCESS_DENIED) { 675 ret = -EACCES; 676 } else { 677 ret = -EINVAL; 678 } 679 goto fail; 680 } 681 682 if (s->aio) { 683 ret = win32_aio_attach(s->aio, rs->hfile); 684 if (ret < 0) { 685 error_setg_errno(errp, -ret, "Could not enable AIO"); 686 CloseHandle(rs->hfile); 687 goto fail; 688 } 689 } 690 691 state->opaque = rs; 692 693 return 0; 694 695 fail: 696 g_free(rs); 697 state->opaque = NULL; 698 699 return ret; 700 } 701 702 static void raw_reopen_commit(BDRVReopenState *state) 703 { 704 BDRVRawState *s = state->bs->opaque; 705 BDRVRawReopenState *rs = state->opaque; 706 707 assert(rs != NULL); 708 709 CloseHandle(s->hfile); 710 s->hfile = rs->hfile; 711 712 g_free(rs); 713 state->opaque = NULL; 714 } 715 716 static void raw_reopen_abort(BDRVReopenState *state) 717 { 718 BDRVRawReopenState *rs = state->opaque; 719 720 if (!rs) { 721 return; 722 } 723 724 if (rs->hfile != INVALID_HANDLE_VALUE) { 725 CloseHandle(rs->hfile); 726 } 727 728 g_free(rs); 729 state->opaque = NULL; 730 } 731 732 static QemuOptsList raw_create_opts = { 733 .name = "raw-create-opts", 734 .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), 735 .desc = { 736 { 737 .name = BLOCK_OPT_SIZE, 738 .type = QEMU_OPT_SIZE, 739 .help = "Virtual disk size" 740 }, 741 { /* end of list */ } 742 } 743 }; 744 745 BlockDriver bdrv_file = { 746 .format_name = "file", 747 .protocol_name = "file", 748 .instance_size = sizeof(BDRVRawState), 749 .bdrv_needs_filename = true, 750 .bdrv_parse_filename = raw_parse_filename, 751 .bdrv_file_open = raw_open, 752 .bdrv_refresh_limits = raw_probe_alignment, 753 .bdrv_close = raw_close, 754 .bdrv_co_create_opts = raw_co_create_opts, 755 .bdrv_has_zero_init = bdrv_has_zero_init_1, 756 757 .bdrv_reopen_prepare = raw_reopen_prepare, 758 .bdrv_reopen_commit = raw_reopen_commit, 759 .bdrv_reopen_abort = raw_reopen_abort, 760 761 .bdrv_aio_preadv = raw_aio_preadv, 762 .bdrv_aio_pwritev = raw_aio_pwritev, 763 .bdrv_aio_flush = raw_aio_flush, 764 765 .bdrv_co_truncate = raw_co_truncate, 766 .bdrv_co_getlength = raw_co_getlength, 767 .bdrv_co_get_allocated_file_size 768 = raw_co_get_allocated_file_size, 769 770 .create_opts = &raw_create_opts, 771 }; 772 773 /***********************************************/ 774 /* host device */ 775 776 static int find_cdrom(char *cdrom_name, int cdrom_name_size) 777 { 778 char drives[256], *pdrv = drives; 779 UINT type; 780 781 memset(drives, 0, sizeof(drives)); 782 GetLogicalDriveStrings(sizeof(drives), drives); 783 while(pdrv[0] != '\0') { 784 type = GetDriveType(pdrv); 785 switch(type) { 786 case DRIVE_CDROM: 787 snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]); 788 return 0; 789 break; 790 } 791 pdrv += lstrlen(pdrv) + 1; 792 } 793 return -1; 794 } 795 796 static int find_device_type(BlockDriverState *bs, const char *filename) 797 { 798 BDRVRawState *s = bs->opaque; 799 UINT type; 800 const char *p; 801 802 if (strstart(filename, "\\\\.\\", &p) || 803 strstart(filename, "//./", &p)) { 804 if (stristart(p, "PhysicalDrive", NULL)) 805 return FTYPE_HARDDISK; 806 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); 807 type = GetDriveType(s->drive_path); 808 switch (type) { 809 case DRIVE_REMOVABLE: 810 case DRIVE_FIXED: 811 return FTYPE_HARDDISK; 812 case DRIVE_CDROM: 813 return FTYPE_CD; 814 default: 815 return FTYPE_FILE; 816 } 817 } else { 818 return FTYPE_FILE; 819 } 820 } 821 822 static int hdev_probe_device(const char *filename) 823 { 824 if (strstart(filename, "/dev/cdrom", NULL)) 825 return 100; 826 if (is_windows_drive(filename)) 827 return 100; 828 return 0; 829 } 830 831 static void hdev_parse_filename(const char *filename, QDict *options, 832 Error **errp) 833 { 834 bdrv_parse_filename_strip_prefix(filename, "host_device:", options); 835 } 836 837 static void hdev_refresh_limits(BlockDriverState *bs, Error **errp) 838 { 839 /* XXX Does Windows support AIO on less than 512-byte alignment? */ 840 bs->bl.request_alignment = 512; 841 } 842 843 static int hdev_open(BlockDriverState *bs, QDict *options, int flags, 844 Error **errp) 845 { 846 BDRVRawState *s = bs->opaque; 847 int access_flags, create_flags; 848 int ret = 0; 849 DWORD overlapped; 850 char device_name[64]; 851 852 Error *local_err = NULL; 853 const char *filename; 854 bool use_aio; 855 856 QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, 857 &error_abort); 858 if (!qemu_opts_absorb_qdict(opts, options, errp)) { 859 ret = -EINVAL; 860 goto done; 861 } 862 863 filename = qemu_opt_get(opts, "filename"); 864 865 use_aio = get_aio_option(opts, flags, &local_err); 866 if (!local_err && use_aio) { 867 error_setg(&local_err, "AIO is not supported on Windows host devices"); 868 } 869 if (local_err) { 870 error_propagate(errp, local_err); 871 ret = -EINVAL; 872 goto done; 873 } 874 875 if (strstart(filename, "/dev/cdrom", NULL)) { 876 if (find_cdrom(device_name, sizeof(device_name)) < 0) { 877 error_setg(errp, "Could not open CD-ROM drive"); 878 ret = -ENOENT; 879 goto done; 880 } 881 filename = device_name; 882 } else { 883 /* transform drive letters into device name */ 884 if (((filename[0] >= 'a' && filename[0] <= 'z') || 885 (filename[0] >= 'A' && filename[0] <= 'Z')) && 886 filename[1] == ':' && filename[2] == '\0') { 887 snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]); 888 filename = device_name; 889 } 890 } 891 s->type = find_device_type(bs, filename); 892 893 raw_parse_flags(flags, use_aio, &access_flags, &overlapped); 894 895 create_flags = OPEN_EXISTING; 896 897 s->hfile = CreateFile(filename, access_flags, 898 FILE_SHARE_READ, NULL, 899 create_flags, overlapped, NULL); 900 if (s->hfile == INVALID_HANDLE_VALUE) { 901 int err = GetLastError(); 902 903 if (err == ERROR_ACCESS_DENIED) { 904 ret = -EACCES; 905 } else { 906 ret = -EINVAL; 907 } 908 error_setg_errno(errp, -ret, "Could not open device"); 909 goto done; 910 } 911 912 done: 913 qemu_opts_del(opts); 914 return ret; 915 } 916 917 static BlockDriver bdrv_host_device = { 918 .format_name = "host_device", 919 .protocol_name = "host_device", 920 .instance_size = sizeof(BDRVRawState), 921 .bdrv_needs_filename = true, 922 .bdrv_parse_filename = hdev_parse_filename, 923 .bdrv_probe_device = hdev_probe_device, 924 .bdrv_file_open = hdev_open, 925 .bdrv_close = raw_close, 926 .bdrv_refresh_limits = hdev_refresh_limits, 927 928 .bdrv_aio_preadv = raw_aio_preadv, 929 .bdrv_aio_pwritev = raw_aio_pwritev, 930 .bdrv_aio_flush = raw_aio_flush, 931 932 .bdrv_detach_aio_context = raw_detach_aio_context, 933 .bdrv_attach_aio_context = raw_attach_aio_context, 934 935 .bdrv_co_getlength = raw_co_getlength, 936 .has_variable_length = true, 937 .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, 938 }; 939 940 static void bdrv_file_init(void) 941 { 942 bdrv_register(&bdrv_file); 943 bdrv_register(&bdrv_host_device); 944 } 945 946 block_init(bdrv_file_init); 947