file-win32.c (27060B)
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_int.h" 29#include "qemu/module.h" 30#include "qemu/option.h" 31#include "block/raw-aio.h" 32#include "trace.h" 33#include "block/thread-pool.h" 34#include "qemu/iov.h" 35#include "qapi/qmp/qdict.h" 36#include "qapi/qmp/qstring.h" 37#include <windows.h> 38#include <winioctl.h> 39 40#define FTYPE_FILE 0 41#define FTYPE_CD 1 42#define FTYPE_HARDDISK 2 43 44typedef struct RawWin32AIOData { 45 BlockDriverState *bs; 46 HANDLE hfile; 47 struct iovec *aio_iov; 48 int aio_niov; 49 size_t aio_nbytes; 50 off64_t aio_offset; 51 int aio_type; 52} RawWin32AIOData; 53 54typedef struct BDRVRawState { 55 HANDLE hfile; 56 int type; 57 char drive_path[16]; /* format: "d:\" */ 58 QEMUWin32AIOState *aio; 59} BDRVRawState; 60 61typedef struct BDRVRawReopenState { 62 HANDLE hfile; 63} BDRVRawReopenState; 64 65/* 66 * Read/writes the data to/from a given linear buffer. 67 * 68 * Returns the number of bytes handles or -errno in case of an error. Short 69 * reads are only returned if the end of the file is reached. 70 */ 71static size_t handle_aiocb_rw(RawWin32AIOData *aiocb) 72{ 73 size_t offset = 0; 74 int i; 75 76 for (i = 0; i < aiocb->aio_niov; i++) { 77 OVERLAPPED ov; 78 DWORD ret, ret_count, len; 79 80 memset(&ov, 0, sizeof(ov)); 81 ov.Offset = (aiocb->aio_offset + offset); 82 ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32; 83 len = aiocb->aio_iov[i].iov_len; 84 if (aiocb->aio_type & QEMU_AIO_WRITE) { 85 ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base, 86 len, &ret_count, &ov); 87 } else { 88 ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base, 89 len, &ret_count, &ov); 90 } 91 if (!ret) { 92 ret_count = 0; 93 } 94 if (ret_count != len) { 95 offset += ret_count; 96 break; 97 } 98 offset += len; 99 } 100 101 return offset; 102} 103 104static int aio_worker(void *arg) 105{ 106 RawWin32AIOData *aiocb = arg; 107 ssize_t ret = 0; 108 size_t count; 109 110 switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) { 111 case QEMU_AIO_READ: 112 count = handle_aiocb_rw(aiocb); 113 if (count < aiocb->aio_nbytes) { 114 /* A short read means that we have reached EOF. Pad the buffer 115 * with zeros for bytes after EOF. */ 116 iov_memset(aiocb->aio_iov, aiocb->aio_niov, count, 117 0, aiocb->aio_nbytes - count); 118 119 count = aiocb->aio_nbytes; 120 } 121 if (count == aiocb->aio_nbytes) { 122 ret = 0; 123 } else { 124 ret = -EINVAL; 125 } 126 break; 127 case QEMU_AIO_WRITE: 128 count = handle_aiocb_rw(aiocb); 129 if (count == aiocb->aio_nbytes) { 130 ret = 0; 131 } else { 132 ret = -EINVAL; 133 } 134 break; 135 case QEMU_AIO_FLUSH: 136 if (!FlushFileBuffers(aiocb->hfile)) { 137 return -EIO; 138 } 139 break; 140 default: 141 fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); 142 ret = -EINVAL; 143 break; 144 } 145 146 g_free(aiocb); 147 return ret; 148} 149 150static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, 151 int64_t offset, QEMUIOVector *qiov, int count, 152 BlockCompletionFunc *cb, void *opaque, int type) 153{ 154 RawWin32AIOData *acb = g_new(RawWin32AIOData, 1); 155 ThreadPool *pool; 156 157 acb->bs = bs; 158 acb->hfile = hfile; 159 acb->aio_type = type; 160 161 if (qiov) { 162 acb->aio_iov = qiov->iov; 163 acb->aio_niov = qiov->niov; 164 assert(qiov->size == count); 165 } 166 acb->aio_nbytes = count; 167 acb->aio_offset = offset; 168 169 trace_file_paio_submit(acb, opaque, offset, count, type); 170 pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); 171 return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); 172} 173 174int qemu_ftruncate64(int fd, int64_t length) 175{ 176 LARGE_INTEGER li; 177 DWORD dw; 178 LONG high; 179 HANDLE h; 180 BOOL res; 181 182 if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) 183 return -1; 184 185 h = (HANDLE)_get_osfhandle(fd); 186 187 /* get current position, ftruncate do not change position */ 188 li.HighPart = 0; 189 li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); 190 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 191 return -1; 192 } 193 194 high = length >> 32; 195 dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN); 196 if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 197 return -1; 198 } 199 res = SetEndOfFile(h); 200 201 /* back to old position */ 202 SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); 203 return res ? 0 : -1; 204} 205 206static int set_sparse(int fd) 207{ 208 DWORD returned; 209 return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, 210 NULL, 0, NULL, 0, &returned, NULL); 211} 212 213static void raw_detach_aio_context(BlockDriverState *bs) 214{ 215 BDRVRawState *s = bs->opaque; 216 217 if (s->aio) { 218 win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); 219 } 220} 221 222static void raw_attach_aio_context(BlockDriverState *bs, 223 AioContext *new_context) 224{ 225 BDRVRawState *s = bs->opaque; 226 227 if (s->aio) { 228 win32_aio_attach_aio_context(s->aio, new_context); 229 } 230} 231 232static void raw_probe_alignment(BlockDriverState *bs, Error **errp) 233{ 234 BDRVRawState *s = bs->opaque; 235 DWORD sectorsPerCluster, freeClusters, totalClusters, count; 236 DISK_GEOMETRY_EX dg; 237 BOOL status; 238 239 if (s->type == FTYPE_CD) { 240 bs->bl.request_alignment = 2048; 241 return; 242 } 243 if (s->type == FTYPE_HARDDISK) { 244 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 245 NULL, 0, &dg, sizeof(dg), &count, NULL); 246 if (status != 0) { 247 bs->bl.request_alignment = dg.Geometry.BytesPerSector; 248 return; 249 } 250 /* try GetDiskFreeSpace too */ 251 } 252 253 if (s->drive_path[0]) { 254 GetDiskFreeSpace(s->drive_path, §orsPerCluster, 255 &dg.Geometry.BytesPerSector, 256 &freeClusters, &totalClusters); 257 bs->bl.request_alignment = dg.Geometry.BytesPerSector; 258 return; 259 } 260 261 /* XXX Does Windows support AIO on less than 512-byte alignment? */ 262 bs->bl.request_alignment = 512; 263} 264 265static void raw_parse_flags(int flags, bool use_aio, int *access_flags, 266 DWORD *overlapped) 267{ 268 assert(access_flags != NULL); 269 assert(overlapped != NULL); 270 271 if (flags & BDRV_O_RDWR) { 272 *access_flags = GENERIC_READ | GENERIC_WRITE; 273 } else { 274 *access_flags = GENERIC_READ; 275 } 276 277 *overlapped = FILE_ATTRIBUTE_NORMAL; 278 if (use_aio) { 279 *overlapped |= FILE_FLAG_OVERLAPPED; 280 } 281 if (flags & BDRV_O_NOCACHE) { 282 *overlapped |= FILE_FLAG_NO_BUFFERING; 283 } 284} 285 286static void raw_parse_filename(const char *filename, QDict *options, 287 Error **errp) 288{ 289 bdrv_parse_filename_strip_prefix(filename, "file:", options); 290} 291 292static QemuOptsList raw_runtime_opts = { 293 .name = "raw", 294 .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head), 295 .desc = { 296 { 297 .name = "filename", 298 .type = QEMU_OPT_STRING, 299 .help = "File name of the image", 300 }, 301 { 302 .name = "aio", 303 .type = QEMU_OPT_STRING, 304 .help = "host AIO implementation (threads, native)", 305 }, 306 { 307 .name = "locking", 308 .type = QEMU_OPT_STRING, 309 .help = "file locking mode (on/off/auto, default: auto)", 310 }, 311 { /* end of list */ } 312 }, 313}; 314 315static bool get_aio_option(QemuOpts *opts, int flags, Error **errp) 316{ 317 BlockdevAioOptions aio, aio_default; 318 319 aio_default = (flags & BDRV_O_NATIVE_AIO) ? BLOCKDEV_AIO_OPTIONS_NATIVE 320 : BLOCKDEV_AIO_OPTIONS_THREADS; 321 aio = qapi_enum_parse(&BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"), 322 aio_default, errp); 323 324 switch (aio) { 325 case BLOCKDEV_AIO_OPTIONS_NATIVE: 326 return true; 327 case BLOCKDEV_AIO_OPTIONS_THREADS: 328 return false; 329 default: 330 error_setg(errp, "Invalid AIO option"); 331 } 332 return false; 333} 334 335static int raw_open(BlockDriverState *bs, QDict *options, int flags, 336 Error **errp) 337{ 338 BDRVRawState *s = bs->opaque; 339 int access_flags; 340 DWORD overlapped; 341 QemuOpts *opts; 342 Error *local_err = NULL; 343 const char *filename; 344 bool use_aio; 345 OnOffAuto locking; 346 int ret; 347 348 s->type = FTYPE_FILE; 349 350 opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); 351 if (!qemu_opts_absorb_qdict(opts, options, errp)) { 352 ret = -EINVAL; 353 goto fail; 354 } 355 356 locking = qapi_enum_parse(&OnOffAuto_lookup, 357 qemu_opt_get(opts, "locking"), 358 ON_OFF_AUTO_AUTO, &local_err); 359 if (local_err) { 360 error_propagate(errp, local_err); 361 ret = -EINVAL; 362 goto fail; 363 } 364 switch (locking) { 365 case ON_OFF_AUTO_ON: 366 error_setg(errp, "locking=on is not supported on Windows"); 367 ret = -EINVAL; 368 goto fail; 369 case ON_OFF_AUTO_OFF: 370 case ON_OFF_AUTO_AUTO: 371 break; 372 default: 373 g_assert_not_reached(); 374 } 375 376 filename = qemu_opt_get(opts, "filename"); 377 378 use_aio = get_aio_option(opts, flags, &local_err); 379 if (local_err) { 380 error_propagate(errp, local_err); 381 ret = -EINVAL; 382 goto fail; 383 } 384 385 raw_parse_flags(flags, use_aio, &access_flags, &overlapped); 386 387 if (filename[0] && filename[1] == ':') { 388 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]); 389 } else if (filename[0] == '\\' && filename[1] == '\\') { 390 s->drive_path[0] = 0; 391 } else { 392 /* Relative path. */ 393 char buf[MAX_PATH]; 394 GetCurrentDirectory(MAX_PATH, buf); 395 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]); 396 } 397 398 s->hfile = CreateFile(filename, access_flags, 399 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 400 OPEN_EXISTING, overlapped, NULL); 401 if (s->hfile == INVALID_HANDLE_VALUE) { 402 int err = GetLastError(); 403 404 error_setg_win32(errp, err, "Could not open '%s'", filename); 405 if (err == ERROR_ACCESS_DENIED) { 406 ret = -EACCES; 407 } else { 408 ret = -EINVAL; 409 } 410 goto fail; 411 } 412 413 if (use_aio) { 414 s->aio = win32_aio_init(); 415 if (s->aio == NULL) { 416 CloseHandle(s->hfile); 417 error_setg(errp, "Could not initialize AIO"); 418 ret = -EINVAL; 419 goto fail; 420 } 421 422 ret = win32_aio_attach(s->aio, s->hfile); 423 if (ret < 0) { 424 win32_aio_cleanup(s->aio); 425 CloseHandle(s->hfile); 426 error_setg_errno(errp, -ret, "Could not enable AIO"); 427 goto fail; 428 } 429 430 win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs)); 431 } 432 433 /* When extending regular files, we get zeros from the OS */ 434 bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; 435 436 ret = 0; 437fail: 438 qemu_opts_del(opts); 439 return ret; 440} 441 442static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs, 443 int64_t offset, int64_t bytes, 444 QEMUIOVector *qiov, BdrvRequestFlags flags, 445 BlockCompletionFunc *cb, void *opaque) 446{ 447 BDRVRawState *s = bs->opaque; 448 if (s->aio) { 449 return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov, 450 cb, opaque, QEMU_AIO_READ); 451 } else { 452 return paio_submit(bs, s->hfile, offset, qiov, bytes, 453 cb, opaque, QEMU_AIO_READ); 454 } 455} 456 457static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs, 458 int64_t offset, int64_t bytes, 459 QEMUIOVector *qiov, BdrvRequestFlags flags, 460 BlockCompletionFunc *cb, void *opaque) 461{ 462 BDRVRawState *s = bs->opaque; 463 if (s->aio) { 464 return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov, 465 cb, opaque, QEMU_AIO_WRITE); 466 } else { 467 return paio_submit(bs, s->hfile, offset, qiov, bytes, 468 cb, opaque, QEMU_AIO_WRITE); 469 } 470} 471 472static BlockAIOCB *raw_aio_flush(BlockDriverState *bs, 473 BlockCompletionFunc *cb, void *opaque) 474{ 475 BDRVRawState *s = bs->opaque; 476 return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH); 477} 478 479static void raw_close(BlockDriverState *bs) 480{ 481 BDRVRawState *s = bs->opaque; 482 483 if (s->aio) { 484 win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); 485 win32_aio_cleanup(s->aio); 486 s->aio = NULL; 487 } 488 489 CloseHandle(s->hfile); 490 if (bs->open_flags & BDRV_O_TEMPORARY) { 491 unlink(bs->filename); 492 } 493} 494 495static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, 496 bool exact, PreallocMode prealloc, 497 BdrvRequestFlags flags, Error **errp) 498{ 499 BDRVRawState *s = bs->opaque; 500 LONG low, high; 501 DWORD dwPtrLow; 502 503 if (prealloc != PREALLOC_MODE_OFF) { 504 error_setg(errp, "Unsupported preallocation mode '%s'", 505 PreallocMode_str(prealloc)); 506 return -ENOTSUP; 507 } 508 509 low = offset; 510 high = offset >> 32; 511 512 /* 513 * An error has occurred if the return value is INVALID_SET_FILE_POINTER 514 * and GetLastError doesn't return NO_ERROR. 515 */ 516 dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN); 517 if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 518 error_setg_win32(errp, GetLastError(), "SetFilePointer error"); 519 return -EIO; 520 } 521 if (SetEndOfFile(s->hfile) == 0) { 522 error_setg_win32(errp, GetLastError(), "SetEndOfFile error"); 523 return -EIO; 524 } 525 return 0; 526} 527 528static int64_t raw_getlength(BlockDriverState *bs) 529{ 530 BDRVRawState *s = bs->opaque; 531 LARGE_INTEGER l; 532 ULARGE_INTEGER available, total, total_free; 533 DISK_GEOMETRY_EX dg; 534 DWORD count; 535 BOOL status; 536 537 switch(s->type) { 538 case FTYPE_FILE: 539 l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); 540 if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) 541 return -EIO; 542 break; 543 case FTYPE_CD: 544 if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) 545 return -EIO; 546 l.QuadPart = total.QuadPart; 547 break; 548 case FTYPE_HARDDISK: 549 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 550 NULL, 0, &dg, sizeof(dg), &count, NULL); 551 if (status != 0) { 552 l = dg.DiskSize; 553 } 554 break; 555 default: 556 return -EIO; 557 } 558 return l.QuadPart; 559} 560 561static int64_t raw_get_allocated_file_size(BlockDriverState *bs) 562{ 563 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, 564 DWORD * high); 565 get_compressed_t get_compressed; 566 struct _stati64 st; 567 const char *filename = bs->filename; 568 /* WinNT support GetCompressedFileSize to determine allocate size */ 569 get_compressed = 570 (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), 571 "GetCompressedFileSizeA"); 572 if (get_compressed) { 573 DWORD high, low; 574 low = get_compressed(filename, &high); 575 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) { 576 return (((int64_t) high) << 32) + low; 577 } 578 } 579 580 if (_stati64(filename, &st) < 0) { 581 return -1; 582 } 583 return st.st_size; 584} 585 586static int raw_co_create(BlockdevCreateOptions *options, Error **errp) 587{ 588 BlockdevCreateOptionsFile *file_opts; 589 int fd; 590 591 assert(options->driver == BLOCKDEV_DRIVER_FILE); 592 file_opts = &options->u.file; 593 594 if (file_opts->has_preallocation) { 595 error_setg(errp, "Preallocation is not supported on Windows"); 596 return -EINVAL; 597 } 598 if (file_opts->has_nocow) { 599 error_setg(errp, "nocow is not supported on Windows"); 600 return -EINVAL; 601 } 602 603 fd = qemu_create(file_opts->filename, O_WRONLY | O_TRUNC | O_BINARY, 604 0644, errp); 605 if (fd < 0) { 606 return -EIO; 607 } 608 set_sparse(fd); 609 ftruncate(fd, file_opts->size); 610 qemu_close(fd); 611 612 return 0; 613} 614 615static int coroutine_fn raw_co_create_opts(BlockDriver *drv, 616 const char *filename, 617 QemuOpts *opts, 618 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 641static 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 695fail: 696 g_free(rs); 697 state->opaque = NULL; 698 699 return ret; 700} 701 702static 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 716static 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 732static 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 745BlockDriver 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_getlength = raw_getlength, 767 .bdrv_get_allocated_file_size 768 = raw_get_allocated_file_size, 769 770 .create_opts = &raw_create_opts, 771}; 772 773/***********************************************/ 774/* host device */ 775 776static 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 796static 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 822static 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 831static 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 837static 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 843static 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 912done: 913 qemu_opts_del(opts); 914 return ret; 915} 916 917static 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_getlength = raw_getlength, 936 .has_variable_length = true, 937 938 .bdrv_get_allocated_file_size 939 = raw_get_allocated_file_size, 940}; 941 942static void bdrv_file_init(void) 943{ 944 bdrv_register(&bdrv_file); 945 bdrv_register(&bdrv_host_device); 946} 947 948block_init(bdrv_file_init);