|
|
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: #include "qemu-timer.h" ! 26: #include "block_int.h" ! 27: #include "module.h" ! 28: #include <windows.h> ! 29: #include <winioctl.h> ! 30: ! 31: #define FTYPE_FILE 0 ! 32: #define FTYPE_CD 1 ! 33: #define FTYPE_HARDDISK 2 ! 34: ! 35: typedef struct BDRVRawState { ! 36: HANDLE hfile; ! 37: int type; ! 38: char drive_path[16]; /* format: "d:\" */ ! 39: } BDRVRawState; ! 40: ! 41: int qemu_ftruncate64(int fd, int64_t length) ! 42: { ! 43: LARGE_INTEGER li; ! 44: LONG high; ! 45: HANDLE h; ! 46: BOOL res; ! 47: ! 48: if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) ! 49: return -1; ! 50: ! 51: h = (HANDLE)_get_osfhandle(fd); ! 52: ! 53: /* get current position, ftruncate do not change position */ ! 54: li.HighPart = 0; ! 55: li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); ! 56: if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) ! 57: return -1; ! 58: ! 59: high = length >> 32; ! 60: if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN)) ! 61: return -1; ! 62: res = SetEndOfFile(h); ! 63: ! 64: /* back to old position */ ! 65: SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); ! 66: return res ? 0 : -1; ! 67: } ! 68: ! 69: static int set_sparse(int fd) ! 70: { ! 71: DWORD returned; ! 72: return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, ! 73: NULL, 0, NULL, 0, &returned, NULL); ! 74: } ! 75: ! 76: static int raw_open(BlockDriverState *bs, const char *filename, int flags) ! 77: { ! 78: BDRVRawState *s = bs->opaque; ! 79: int access_flags, create_flags; ! 80: DWORD overlapped; ! 81: ! 82: s->type = FTYPE_FILE; ! 83: ! 84: if ((flags & BDRV_O_ACCESS) == O_RDWR) { ! 85: access_flags = GENERIC_READ | GENERIC_WRITE; ! 86: } else { ! 87: access_flags = GENERIC_READ; ! 88: } ! 89: if (flags & BDRV_O_CREAT) { ! 90: create_flags = CREATE_ALWAYS; ! 91: } else { ! 92: create_flags = OPEN_EXISTING; ! 93: } ! 94: overlapped = FILE_ATTRIBUTE_NORMAL; ! 95: if ((flags & BDRV_O_NOCACHE)) ! 96: overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; ! 97: else if (!(flags & BDRV_O_CACHE_WB)) ! 98: overlapped |= FILE_FLAG_WRITE_THROUGH; ! 99: s->hfile = CreateFile(filename, access_flags, ! 100: FILE_SHARE_READ, NULL, ! 101: create_flags, overlapped, NULL); ! 102: if (s->hfile == INVALID_HANDLE_VALUE) { ! 103: int err = GetLastError(); ! 104: ! 105: if (err == ERROR_ACCESS_DENIED) ! 106: return -EACCES; ! 107: return -1; ! 108: } ! 109: return 0; ! 110: } ! 111: ! 112: static int raw_read(BlockDriverState *bs, int64_t sector_num, ! 113: uint8_t *buf, int nb_sectors) ! 114: { ! 115: BDRVRawState *s = bs->opaque; ! 116: OVERLAPPED ov; ! 117: DWORD ret_count; ! 118: int ret; ! 119: int64_t offset = sector_num * 512; ! 120: int count = nb_sectors * 512; ! 121: ! 122: memset(&ov, 0, sizeof(ov)); ! 123: ov.Offset = offset; ! 124: ov.OffsetHigh = offset >> 32; ! 125: ret = ReadFile(s->hfile, buf, count, &ret_count, &ov); ! 126: if (!ret) ! 127: return ret_count; ! 128: if (ret_count == count) ! 129: ret_count = 0; ! 130: return ret_count; ! 131: } ! 132: ! 133: static int raw_write(BlockDriverState *bs, int64_t sector_num, ! 134: const uint8_t *buf, int nb_sectors) ! 135: { ! 136: BDRVRawState *s = bs->opaque; ! 137: OVERLAPPED ov; ! 138: DWORD ret_count; ! 139: int ret; ! 140: int64_t offset = sector_num * 512; ! 141: int count = nb_sectors * 512; ! 142: ! 143: memset(&ov, 0, sizeof(ov)); ! 144: ov.Offset = offset; ! 145: ov.OffsetHigh = offset >> 32; ! 146: ret = WriteFile(s->hfile, buf, count, &ret_count, &ov); ! 147: if (!ret) ! 148: return ret_count; ! 149: if (ret_count == count) ! 150: ret_count = 0; ! 151: return ret_count; ! 152: } ! 153: ! 154: static void raw_flush(BlockDriverState *bs) ! 155: { ! 156: BDRVRawState *s = bs->opaque; ! 157: FlushFileBuffers(s->hfile); ! 158: } ! 159: ! 160: static void raw_close(BlockDriverState *bs) ! 161: { ! 162: BDRVRawState *s = bs->opaque; ! 163: CloseHandle(s->hfile); ! 164: } ! 165: ! 166: static int raw_truncate(BlockDriverState *bs, int64_t offset) ! 167: { ! 168: BDRVRawState *s = bs->opaque; ! 169: LONG low, high; ! 170: ! 171: low = offset; ! 172: high = offset >> 32; ! 173: if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN)) ! 174: return -EIO; ! 175: if (!SetEndOfFile(s->hfile)) ! 176: return -EIO; ! 177: return 0; ! 178: } ! 179: ! 180: static int64_t raw_getlength(BlockDriverState *bs) ! 181: { ! 182: BDRVRawState *s = bs->opaque; ! 183: LARGE_INTEGER l; ! 184: ULARGE_INTEGER available, total, total_free; ! 185: DISK_GEOMETRY_EX dg; ! 186: DWORD count; ! 187: BOOL status; ! 188: ! 189: switch(s->type) { ! 190: case FTYPE_FILE: ! 191: l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); ! 192: if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) ! 193: return -EIO; ! 194: break; ! 195: case FTYPE_CD: ! 196: if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) ! 197: return -EIO; ! 198: l.QuadPart = total.QuadPart; ! 199: break; ! 200: case FTYPE_HARDDISK: ! 201: status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, ! 202: NULL, 0, &dg, sizeof(dg), &count, NULL); ! 203: if (status != 0) { ! 204: l = dg.DiskSize; ! 205: } ! 206: break; ! 207: default: ! 208: return -EIO; ! 209: } ! 210: return l.QuadPart; ! 211: } ! 212: ! 213: static int raw_create(const char *filename, QEMUOptionParameter *options) ! 214: { ! 215: int fd; ! 216: int64_t total_size = 0; ! 217: ! 218: /* Read out options */ ! 219: while (options && options->name) { ! 220: if (!strcmp(options->name, BLOCK_OPT_SIZE)) { ! 221: total_size = options->value.n / 512; ! 222: } ! 223: options++; ! 224: } ! 225: ! 226: fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, ! 227: 0644); ! 228: if (fd < 0) ! 229: return -EIO; ! 230: set_sparse(fd); ! 231: ftruncate(fd, total_size * 512); ! 232: close(fd); ! 233: return 0; ! 234: } ! 235: ! 236: static QEMUOptionParameter raw_create_options[] = { ! 237: { ! 238: .name = BLOCK_OPT_SIZE, ! 239: .type = OPT_SIZE, ! 240: .help = "Virtual disk size" ! 241: }, ! 242: { NULL } ! 243: }; ! 244: ! 245: static BlockDriver bdrv_raw = { ! 246: .format_name = "raw", ! 247: .instance_size = sizeof(BDRVRawState), ! 248: .bdrv_open = raw_open, ! 249: .bdrv_close = raw_close, ! 250: .bdrv_create = raw_create, ! 251: .bdrv_flush = raw_flush, ! 252: .bdrv_read = raw_read, ! 253: .bdrv_write = raw_write, ! 254: .bdrv_truncate = raw_truncate, ! 255: .bdrv_getlength = raw_getlength, ! 256: ! 257: .create_options = raw_create_options, ! 258: }; ! 259: ! 260: /***********************************************/ ! 261: /* host device */ ! 262: ! 263: static int find_cdrom(char *cdrom_name, int cdrom_name_size) ! 264: { ! 265: char drives[256], *pdrv = drives; ! 266: UINT type; ! 267: ! 268: memset(drives, 0, sizeof(drives)); ! 269: GetLogicalDriveStrings(sizeof(drives), drives); ! 270: while(pdrv[0] != '\0') { ! 271: type = GetDriveType(pdrv); ! 272: switch(type) { ! 273: case DRIVE_CDROM: ! 274: snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]); ! 275: return 0; ! 276: break; ! 277: } ! 278: pdrv += lstrlen(pdrv) + 1; ! 279: } ! 280: return -1; ! 281: } ! 282: ! 283: static int find_device_type(BlockDriverState *bs, const char *filename) ! 284: { ! 285: BDRVRawState *s = bs->opaque; ! 286: UINT type; ! 287: const char *p; ! 288: ! 289: if (strstart(filename, "\\\\.\\", &p) || ! 290: strstart(filename, "//./", &p)) { ! 291: if (stristart(p, "PhysicalDrive", NULL)) ! 292: return FTYPE_HARDDISK; ! 293: snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); ! 294: type = GetDriveType(s->drive_path); ! 295: switch (type) { ! 296: case DRIVE_REMOVABLE: ! 297: case DRIVE_FIXED: ! 298: return FTYPE_HARDDISK; ! 299: case DRIVE_CDROM: ! 300: return FTYPE_CD; ! 301: default: ! 302: return FTYPE_FILE; ! 303: } ! 304: } else { ! 305: return FTYPE_FILE; ! 306: } ! 307: } ! 308: ! 309: static int hdev_probe_device(const char *filename) ! 310: { ! 311: if (strstart(filename, "/dev/cdrom", NULL)) ! 312: return 100; ! 313: if (is_windows_drive(filename)) ! 314: return 100; ! 315: return 0; ! 316: } ! 317: ! 318: static int hdev_open(BlockDriverState *bs, const char *filename, int flags) ! 319: { ! 320: BDRVRawState *s = bs->opaque; ! 321: int access_flags, create_flags; ! 322: DWORD overlapped; ! 323: char device_name[64]; ! 324: ! 325: if (strstart(filename, "/dev/cdrom", NULL)) { ! 326: if (find_cdrom(device_name, sizeof(device_name)) < 0) ! 327: return -ENOENT; ! 328: filename = device_name; ! 329: } else { ! 330: /* transform drive letters into device name */ ! 331: if (((filename[0] >= 'a' && filename[0] <= 'z') || ! 332: (filename[0] >= 'A' && filename[0] <= 'Z')) && ! 333: filename[1] == ':' && filename[2] == '\0') { ! 334: snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]); ! 335: filename = device_name; ! 336: } ! 337: } ! 338: s->type = find_device_type(bs, filename); ! 339: ! 340: if ((flags & BDRV_O_ACCESS) == O_RDWR) { ! 341: access_flags = GENERIC_READ | GENERIC_WRITE; ! 342: } else { ! 343: access_flags = GENERIC_READ; ! 344: } ! 345: create_flags = OPEN_EXISTING; ! 346: ! 347: overlapped = FILE_ATTRIBUTE_NORMAL; ! 348: if ((flags & BDRV_O_NOCACHE)) ! 349: overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; ! 350: else if (!(flags & BDRV_O_CACHE_WB)) ! 351: overlapped |= FILE_FLAG_WRITE_THROUGH; ! 352: s->hfile = CreateFile(filename, access_flags, ! 353: FILE_SHARE_READ, NULL, ! 354: create_flags, overlapped, NULL); ! 355: if (s->hfile == INVALID_HANDLE_VALUE) { ! 356: int err = GetLastError(); ! 357: ! 358: if (err == ERROR_ACCESS_DENIED) ! 359: return -EACCES; ! 360: return -1; ! 361: } ! 362: return 0; ! 363: } ! 364: ! 365: #if 0 ! 366: /***********************************************/ ! 367: /* removable device additional commands */ ! 368: ! 369: static int raw_is_inserted(BlockDriverState *bs) ! 370: { ! 371: return 1; ! 372: } ! 373: ! 374: static int raw_media_changed(BlockDriverState *bs) ! 375: { ! 376: return -ENOTSUP; ! 377: } ! 378: ! 379: static int raw_eject(BlockDriverState *bs, int eject_flag) ! 380: { ! 381: DWORD ret_count; ! 382: ! 383: if (s->type == FTYPE_FILE) ! 384: return -ENOTSUP; ! 385: if (eject_flag) { ! 386: DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, ! 387: NULL, 0, NULL, 0, &lpBytesReturned, NULL); ! 388: } else { ! 389: DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, ! 390: NULL, 0, NULL, 0, &lpBytesReturned, NULL); ! 391: } ! 392: } ! 393: ! 394: static int raw_set_locked(BlockDriverState *bs, int locked) ! 395: { ! 396: return -ENOTSUP; ! 397: } ! 398: #endif ! 399: ! 400: static BlockDriver bdrv_host_device = { ! 401: .format_name = "host_device", ! 402: .instance_size = sizeof(BDRVRawState), ! 403: .bdrv_probe_device = hdev_probe_device, ! 404: .bdrv_open = hdev_open, ! 405: .bdrv_close = raw_close, ! 406: .bdrv_flush = raw_flush, ! 407: ! 408: .bdrv_read = raw_read, ! 409: .bdrv_write = raw_write, ! 410: .bdrv_getlength = raw_getlength, ! 411: }; ! 412: ! 413: static void bdrv_raw_init(void) ! 414: { ! 415: bdrv_register(&bdrv_raw); ! 416: bdrv_register(&bdrv_host_device); ! 417: } ! 418: ! 419: block_init(bdrv_raw_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.