1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
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];
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:
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:
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:
266: CancelIo(s->hfile);
267: qemu_aio_release(acb);
268: #endif
269: }
270: #endif
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,
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:
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:
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:
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,
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: };