Annotation of qemu/block-raw-win32.c, revision 1.1
1.1 ! root 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: #include "qemu-common.h"
! 25: #ifndef QEMU_IMG
! 26: #include "qemu-timer.h"
! 27: #include "exec-all.h"
! 28: #endif
! 29: #include "block_int.h"
! 30: #include <assert.h>
! 31: #include <winioctl.h>
! 32:
! 33: #define FTYPE_FILE 0
! 34: #define FTYPE_CD 1
! 35: #define FTYPE_HARDDISK 2
! 36:
! 37: typedef struct BDRVRawState {
! 38: HANDLE hfile;
! 39: int type;
! 40: char drive_path[16]; /* format: "d:\" */
! 41: } BDRVRawState;
! 42:
! 43: typedef struct RawAIOCB {
! 44: BlockDriverAIOCB common;
! 45: HANDLE hEvent;
! 46: OVERLAPPED ov;
! 47: int count;
! 48: } RawAIOCB;
! 49:
! 50: int qemu_ftruncate64(int fd, int64_t length)
! 51: {
! 52: LARGE_INTEGER li;
! 53: LONG high;
! 54: HANDLE h;
! 55: BOOL res;
! 56:
! 57: if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
! 58: return -1;
! 59:
! 60: h = (HANDLE)_get_osfhandle(fd);
! 61:
! 62: /* get current position, ftruncate do not change position */
! 63: li.HighPart = 0;
! 64: li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
! 65: if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
! 66: return -1;
! 67:
! 68: high = length >> 32;
! 69: if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
! 70: return -1;
! 71: res = SetEndOfFile(h);
! 72:
! 73: /* back to old position */
! 74: SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
! 75: return res ? 0 : -1;
! 76: }
! 77:
! 78: static int set_sparse(int fd)
! 79: {
! 80: DWORD returned;
! 81: return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
! 82: NULL, 0, NULL, 0, &returned, NULL);
! 83: }
! 84:
! 85: static int raw_open(BlockDriverState *bs, const char *filename, int flags)
! 86: {
! 87: BDRVRawState *s = bs->opaque;
! 88: int access_flags, create_flags;
! 89: DWORD overlapped;
! 90:
! 91: s->type = FTYPE_FILE;
! 92:
! 93: if ((flags & BDRV_O_ACCESS) == O_RDWR) {
! 94: access_flags = GENERIC_READ | GENERIC_WRITE;
! 95: } else {
! 96: access_flags = GENERIC_READ;
! 97: }
! 98: if (flags & BDRV_O_CREAT) {
! 99: create_flags = CREATE_ALWAYS;
! 100: } else {
! 101: create_flags = OPEN_EXISTING;
! 102: }
! 103: #ifdef QEMU_IMG
! 104: overlapped = FILE_ATTRIBUTE_NORMAL;
! 105: #else
! 106: overlapped = FILE_FLAG_OVERLAPPED;
! 107: #endif
! 108: if (flags & BDRV_O_DIRECT)
! 109: overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
! 110: s->hfile = CreateFile(filename, access_flags,
! 111: FILE_SHARE_READ, NULL,
! 112: create_flags, overlapped, NULL);
! 113: if (s->hfile == INVALID_HANDLE_VALUE) {
! 114: int err = GetLastError();
! 115:
! 116: if (err == ERROR_ACCESS_DENIED)
! 117: return -EACCES;
! 118: return -1;
! 119: }
! 120: return 0;
! 121: }
! 122:
! 123: static int raw_pread(BlockDriverState *bs, int64_t offset,
! 124: uint8_t *buf, int count)
! 125: {
! 126: BDRVRawState *s = bs->opaque;
! 127: OVERLAPPED ov;
! 128: DWORD ret_count;
! 129: int ret;
! 130:
! 131: memset(&ov, 0, sizeof(ov));
! 132: ov.Offset = offset;
! 133: ov.OffsetHigh = offset >> 32;
! 134: ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
! 135: if (!ret) {
! 136: ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
! 137: if (!ret)
! 138: return -EIO;
! 139: else
! 140: return ret_count;
! 141: }
! 142: return ret_count;
! 143: }
! 144:
! 145: static int raw_pwrite(BlockDriverState *bs, int64_t offset,
! 146: const uint8_t *buf, int count)
! 147: {
! 148: BDRVRawState *s = bs->opaque;
! 149: OVERLAPPED ov;
! 150: DWORD ret_count;
! 151: int ret;
! 152:
! 153: memset(&ov, 0, sizeof(ov));
! 154: ov.Offset = offset;
! 155: ov.OffsetHigh = offset >> 32;
! 156: ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
! 157: if (!ret) {
! 158: ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
! 159: if (!ret)
! 160: return -EIO;
! 161: else
! 162: return ret_count;
! 163: }
! 164: return ret_count;
! 165: }
! 166:
! 167: #if 0
! 168: #ifndef QEMU_IMG
! 169: static void raw_aio_cb(void *opaque)
! 170: {
! 171: RawAIOCB *acb = opaque;
! 172: BlockDriverState *bs = acb->common.bs;
! 173: BDRVRawState *s = bs->opaque;
! 174: DWORD ret_count;
! 175: int ret;
! 176:
! 177: ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
! 178: if (!ret || ret_count != acb->count) {
! 179: acb->common.cb(acb->common.opaque, -EIO);
! 180: } else {
! 181: acb->common.cb(acb->common.opaque, 0);
! 182: }
! 183: }
! 184: #endif
! 185:
! 186: static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
! 187: int64_t sector_num, uint8_t *buf, int nb_sectors,
! 188: BlockDriverCompletionFunc *cb, void *opaque)
! 189: {
! 190: RawAIOCB *acb;
! 191: int64_t offset;
! 192:
! 193: acb = qemu_aio_get(bs, cb, opaque);
! 194: if (acb->hEvent) {
! 195: acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
! 196: if (!acb->hEvent) {
! 197: qemu_aio_release(acb);
! 198: return NULL;
! 199: }
! 200: }
! 201: memset(&acb->ov, 0, sizeof(acb->ov));
! 202: offset = sector_num * 512;
! 203: acb->ov.Offset = offset;
! 204: acb->ov.OffsetHigh = offset >> 32;
! 205: acb->ov.hEvent = acb->hEvent;
! 206: acb->count = nb_sectors * 512;
! 207: #ifndef QEMU_IMG
! 208: qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
! 209: #endif
! 210: return acb;
! 211: }
! 212:
! 213: static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
! 214: int64_t sector_num, uint8_t *buf, int nb_sectors,
! 215: BlockDriverCompletionFunc *cb, void *opaque)
! 216: {
! 217: BDRVRawState *s = bs->opaque;
! 218: RawAIOCB *acb;
! 219: int ret;
! 220:
! 221: acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
! 222: if (!acb)
! 223: return NULL;
! 224: ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
! 225: if (!ret) {
! 226: qemu_aio_release(acb);
! 227: return NULL;
! 228: }
! 229: #ifdef QEMU_IMG
! 230: qemu_aio_release(acb);
! 231: #endif
! 232: return (BlockDriverAIOCB *)acb;
! 233: }
! 234:
! 235: static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
! 236: int64_t sector_num, uint8_t *buf, int nb_sectors,
! 237: BlockDriverCompletionFunc *cb, void *opaque)
! 238: {
! 239: BDRVRawState *s = bs->opaque;
! 240: RawAIOCB *acb;
! 241: int ret;
! 242:
! 243: acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
! 244: if (!acb)
! 245: return NULL;
! 246: ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
! 247: if (!ret) {
! 248: qemu_aio_release(acb);
! 249: return NULL;
! 250: }
! 251: #ifdef QEMU_IMG
! 252: qemu_aio_release(acb);
! 253: #endif
! 254: return (BlockDriverAIOCB *)acb;
! 255: }
! 256:
! 257: static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
! 258: {
! 259: #ifndef QEMU_IMG
! 260: RawAIOCB *acb = (RawAIOCB *)blockacb;
! 261: BlockDriverState *bs = acb->common.bs;
! 262: BDRVRawState *s = bs->opaque;
! 263:
! 264: qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
! 265: /* XXX: if more than one async I/O it is not correct */
! 266: CancelIo(s->hfile);
! 267: qemu_aio_release(acb);
! 268: #endif
! 269: }
! 270: #endif /* #if 0 */
! 271:
! 272: static void raw_flush(BlockDriverState *bs)
! 273: {
! 274: BDRVRawState *s = bs->opaque;
! 275: FlushFileBuffers(s->hfile);
! 276: }
! 277:
! 278: static void raw_close(BlockDriverState *bs)
! 279: {
! 280: BDRVRawState *s = bs->opaque;
! 281: CloseHandle(s->hfile);
! 282: }
! 283:
! 284: static int raw_truncate(BlockDriverState *bs, int64_t offset)
! 285: {
! 286: BDRVRawState *s = bs->opaque;
! 287: DWORD low, high;
! 288:
! 289: low = offset;
! 290: high = offset >> 32;
! 291: if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
! 292: return -EIO;
! 293: if (!SetEndOfFile(s->hfile))
! 294: return -EIO;
! 295: return 0;
! 296: }
! 297:
! 298: static int64_t raw_getlength(BlockDriverState *bs)
! 299: {
! 300: BDRVRawState *s = bs->opaque;
! 301: LARGE_INTEGER l;
! 302: ULARGE_INTEGER available, total, total_free;
! 303: DISK_GEOMETRY_EX dg;
! 304: DWORD count;
! 305: BOOL status;
! 306:
! 307: switch(s->type) {
! 308: case FTYPE_FILE:
! 309: l.LowPart = GetFileSize(s->hfile, &l.HighPart);
! 310: if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
! 311: return -EIO;
! 312: break;
! 313: case FTYPE_CD:
! 314: if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
! 315: return -EIO;
! 316: l.QuadPart = total.QuadPart;
! 317: break;
! 318: case FTYPE_HARDDISK:
! 319: status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
! 320: NULL, 0, &dg, sizeof(dg), &count, NULL);
! 321: if (status != 0) {
! 322: l = dg.DiskSize;
! 323: }
! 324: break;
! 325: default:
! 326: return -EIO;
! 327: }
! 328: return l.QuadPart;
! 329: }
! 330:
! 331: static int raw_create(const char *filename, int64_t total_size,
! 332: const char *backing_file, int flags)
! 333: {
! 334: int fd;
! 335:
! 336: if (flags || backing_file)
! 337: return -ENOTSUP;
! 338:
! 339: fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
! 340: 0644);
! 341: if (fd < 0)
! 342: return -EIO;
! 343: set_sparse(fd);
! 344: ftruncate(fd, total_size * 512);
! 345: close(fd);
! 346: return 0;
! 347: }
! 348:
! 349: void qemu_aio_init(void)
! 350: {
! 351: }
! 352:
! 353: void qemu_aio_poll(void)
! 354: {
! 355: }
! 356:
! 357: void qemu_aio_flush(void)
! 358: {
! 359: }
! 360:
! 361: void qemu_aio_wait_start(void)
! 362: {
! 363: }
! 364:
! 365: void qemu_aio_wait(void)
! 366: {
! 367: #ifndef QEMU_IMG
! 368: qemu_bh_poll();
! 369: #endif
! 370: }
! 371:
! 372: void qemu_aio_wait_end(void)
! 373: {
! 374: }
! 375:
! 376: BlockDriver bdrv_raw = {
! 377: "raw",
! 378: sizeof(BDRVRawState),
! 379: NULL, /* no probe for protocols */
! 380: raw_open,
! 381: NULL,
! 382: NULL,
! 383: raw_close,
! 384: raw_create,
! 385: raw_flush,
! 386:
! 387: #if 0
! 388: .bdrv_aio_read = raw_aio_read,
! 389: .bdrv_aio_write = raw_aio_write,
! 390: .bdrv_aio_cancel = raw_aio_cancel,
! 391: .aiocb_size = sizeof(RawAIOCB);
! 392: #endif
! 393: .protocol_name = "file",
! 394: .bdrv_pread = raw_pread,
! 395: .bdrv_pwrite = raw_pwrite,
! 396: .bdrv_truncate = raw_truncate,
! 397: .bdrv_getlength = raw_getlength,
! 398: };
! 399:
! 400: /***********************************************/
! 401: /* host device */
! 402:
! 403: static int find_cdrom(char *cdrom_name, int cdrom_name_size)
! 404: {
! 405: char drives[256], *pdrv = drives;
! 406: UINT type;
! 407:
! 408: memset(drives, 0, sizeof(drives));
! 409: GetLogicalDriveStrings(sizeof(drives), drives);
! 410: while(pdrv[0] != '\0') {
! 411: type = GetDriveType(pdrv);
! 412: switch(type) {
! 413: case DRIVE_CDROM:
! 414: snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
! 415: return 0;
! 416: break;
! 417: }
! 418: pdrv += lstrlen(pdrv) + 1;
! 419: }
! 420: return -1;
! 421: }
! 422:
! 423: static int find_device_type(BlockDriverState *bs, const char *filename)
! 424: {
! 425: BDRVRawState *s = bs->opaque;
! 426: UINT type;
! 427: const char *p;
! 428:
! 429: if (strstart(filename, "\\\\.\\", &p) ||
! 430: strstart(filename, "//./", &p)) {
! 431: if (stristart(p, "PhysicalDrive", NULL))
! 432: return FTYPE_HARDDISK;
! 433: snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
! 434: type = GetDriveType(s->drive_path);
! 435: if (type == DRIVE_CDROM)
! 436: return FTYPE_CD;
! 437: else
! 438: return FTYPE_FILE;
! 439: } else {
! 440: return FTYPE_FILE;
! 441: }
! 442: }
! 443:
! 444: static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
! 445: {
! 446: BDRVRawState *s = bs->opaque;
! 447: int access_flags, create_flags;
! 448: DWORD overlapped;
! 449: char device_name[64];
! 450:
! 451: if (strstart(filename, "/dev/cdrom", NULL)) {
! 452: if (find_cdrom(device_name, sizeof(device_name)) < 0)
! 453: return -ENOENT;
! 454: filename = device_name;
! 455: } else {
! 456: /* transform drive letters into device name */
! 457: if (((filename[0] >= 'a' && filename[0] <= 'z') ||
! 458: (filename[0] >= 'A' && filename[0] <= 'Z')) &&
! 459: filename[1] == ':' && filename[2] == '\0') {
! 460: snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
! 461: filename = device_name;
! 462: }
! 463: }
! 464: s->type = find_device_type(bs, filename);
! 465:
! 466: if ((flags & BDRV_O_ACCESS) == O_RDWR) {
! 467: access_flags = GENERIC_READ | GENERIC_WRITE;
! 468: } else {
! 469: access_flags = GENERIC_READ;
! 470: }
! 471: create_flags = OPEN_EXISTING;
! 472:
! 473: #ifdef QEMU_IMG
! 474: overlapped = FILE_ATTRIBUTE_NORMAL;
! 475: #else
! 476: overlapped = FILE_FLAG_OVERLAPPED;
! 477: #endif
! 478: if (flags & BDRV_O_DIRECT)
! 479: overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
! 480: s->hfile = CreateFile(filename, access_flags,
! 481: FILE_SHARE_READ, NULL,
! 482: create_flags, overlapped, NULL);
! 483: if (s->hfile == INVALID_HANDLE_VALUE) {
! 484: int err = GetLastError();
! 485:
! 486: if (err == ERROR_ACCESS_DENIED)
! 487: return -EACCES;
! 488: return -1;
! 489: }
! 490: return 0;
! 491: }
! 492:
! 493: #if 0
! 494: /***********************************************/
! 495: /* removable device additional commands */
! 496:
! 497: static int raw_is_inserted(BlockDriverState *bs)
! 498: {
! 499: return 1;
! 500: }
! 501:
! 502: static int raw_media_changed(BlockDriverState *bs)
! 503: {
! 504: return -ENOTSUP;
! 505: }
! 506:
! 507: static int raw_eject(BlockDriverState *bs, int eject_flag)
! 508: {
! 509: DWORD ret_count;
! 510:
! 511: if (s->type == FTYPE_FILE)
! 512: return -ENOTSUP;
! 513: if (eject_flag) {
! 514: DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
! 515: NULL, 0, NULL, 0, &lpBytesReturned, NULL);
! 516: } else {
! 517: DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
! 518: NULL, 0, NULL, 0, &lpBytesReturned, NULL);
! 519: }
! 520: }
! 521:
! 522: static int raw_set_locked(BlockDriverState *bs, int locked)
! 523: {
! 524: return -ENOTSUP;
! 525: }
! 526: #endif
! 527:
! 528: BlockDriver bdrv_host_device = {
! 529: "host_device",
! 530: sizeof(BDRVRawState),
! 531: NULL, /* no probe for protocols */
! 532: hdev_open,
! 533: NULL,
! 534: NULL,
! 535: raw_close,
! 536: NULL,
! 537: raw_flush,
! 538:
! 539: #if 0
! 540: .bdrv_aio_read = raw_aio_read,
! 541: .bdrv_aio_write = raw_aio_write,
! 542: .bdrv_aio_cancel = raw_aio_cancel,
! 543: .aiocb_size = sizeof(RawAIOCB);
! 544: #endif
! 545: .bdrv_pread = raw_pread,
! 546: .bdrv_pwrite = raw_pwrite,
! 547: .bdrv_getlength = raw_getlength,
! 548: };
unix.superglobalmegacorp.com