|
|
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.