target-mips: implement FPU Flush-To-Zero mode
[qemu] / block-raw-win32.c
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 <assert.h>
28 #include <windows.h>
29 #include <winioctl.h>
30
31 //#define WIN32_AIO
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 WIN32_AIO
104     overlapped = FILE_FLAG_OVERLAPPED;
105 #else
106     overlapped = FILE_ATTRIBUTE_NORMAL;
107 #endif
108     if ((flags & BDRV_O_NOCACHE))
109         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
110     else if (!(flags & BDRV_O_CACHE_WB))
111         overlapped |= FILE_FLAG_WRITE_THROUGH;
112     s->hfile = CreateFile(filename, access_flags,
113                           FILE_SHARE_READ, NULL,
114                           create_flags, overlapped, NULL);
115     if (s->hfile == INVALID_HANDLE_VALUE) {
116         int err = GetLastError();
117
118         if (err == ERROR_ACCESS_DENIED)
119             return -EACCES;
120         return -1;
121     }
122     return 0;
123 }
124
125 static int raw_read(BlockDriverState *bs, int64_t sector_num,
126                     uint8_t *buf, int nb_sectors)
127 {
128     BDRVRawState *s = bs->opaque;
129     OVERLAPPED ov;
130     DWORD ret_count;
131     int ret;
132     int64_t offset = sector_num * 512;
133     int count = nb_sectors * 512;
134
135     memset(&ov, 0, sizeof(ov));
136     ov.Offset = offset;
137     ov.OffsetHigh = offset >> 32;
138     ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
139     if (!ret) {
140 #ifdef WIN32_AIO
141         ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
142         if (!ret)
143             return -EIO;
144         else
145 #endif
146             return ret_count;
147     }
148     if (ret_count == count)
149         ret_count = 0;
150     return ret_count;
151 }
152
153 static int raw_write(BlockDriverState *bs, int64_t sector_num,
154                      const uint8_t *buf, int nb_sectors)
155 {
156     BDRVRawState *s = bs->opaque;
157     OVERLAPPED ov;
158     DWORD ret_count;
159     int ret;
160     int64_t offset = sector_num * 512;
161     int count = nb_sectors * 512;
162
163     memset(&ov, 0, sizeof(ov));
164     ov.Offset = offset;
165     ov.OffsetHigh = offset >> 32;
166     ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
167     if (!ret) {
168 #ifdef WIN32_AIO
169         ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
170         if (!ret)
171             return -EIO;
172         else
173 #endif
174             return ret_count;
175     }
176     if (ret_count == count)
177         ret_count = 0;
178     return ret_count;
179 }
180
181 #ifdef WIN32_AIO
182 static void raw_aio_cb(void *opaque)
183 {
184     RawAIOCB *acb = opaque;
185     BlockDriverState *bs = acb->common.bs;
186     BDRVRawState *s = bs->opaque;
187     DWORD ret_count;
188     int ret;
189
190     ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
191     if (!ret || ret_count != acb->count) {
192         acb->common.cb(acb->common.opaque, -EIO);
193     } else {
194         acb->common.cb(acb->common.opaque, 0);
195     }
196 }
197
198 static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
199         int64_t sector_num, uint8_t *buf, int nb_sectors,
200         BlockDriverCompletionFunc *cb, void *opaque)
201 {
202     RawAIOCB *acb;
203     int64_t offset;
204
205     acb = qemu_aio_get(bs, cb, opaque);
206     if (acb->hEvent) {
207         acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
208         if (!acb->hEvent) {
209             qemu_aio_release(acb);
210             return NULL;
211         }
212     }
213     memset(&acb->ov, 0, sizeof(acb->ov));
214     offset = sector_num * 512;
215     acb->ov.Offset = offset;
216     acb->ov.OffsetHigh = offset >> 32;
217     acb->ov.hEvent = acb->hEvent;
218     acb->count = nb_sectors * 512;
219     qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
220     return acb;
221 }
222
223 static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
224         int64_t sector_num, uint8_t *buf, int nb_sectors,
225         BlockDriverCompletionFunc *cb, void *opaque)
226 {
227     BDRVRawState *s = bs->opaque;
228     RawAIOCB *acb;
229     int ret;
230
231     acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
232     if (!acb)
233         return NULL;
234     ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
235     if (!ret) {
236         qemu_aio_release(acb);
237         return NULL;
238     }
239     qemu_aio_release(acb);
240     return (BlockDriverAIOCB *)acb;
241 }
242
243 static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
244         int64_t sector_num, uint8_t *buf, int nb_sectors,
245         BlockDriverCompletionFunc *cb, void *opaque)
246 {
247     BDRVRawState *s = bs->opaque;
248     RawAIOCB *acb;
249     int ret;
250
251     acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
252     if (!acb)
253         return NULL;
254     ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
255     if (!ret) {
256         qemu_aio_release(acb);
257         return NULL;
258     }
259     qemu_aio_release(acb);
260     return (BlockDriverAIOCB *)acb;
261 }
262
263 static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
264 {
265     RawAIOCB *acb = (RawAIOCB *)blockacb;
266     BlockDriverState *bs = acb->common.bs;
267     BDRVRawState *s = bs->opaque;
268
269     qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
270     /* XXX: if more than one async I/O it is not correct */
271     CancelIo(s->hfile);
272     qemu_aio_release(acb);
273 }
274 #endif /* #if WIN32_AIO */
275
276 static void raw_flush(BlockDriverState *bs)
277 {
278     BDRVRawState *s = bs->opaque;
279     FlushFileBuffers(s->hfile);
280 }
281
282 static void raw_close(BlockDriverState *bs)
283 {
284     BDRVRawState *s = bs->opaque;
285     CloseHandle(s->hfile);
286 }
287
288 static int raw_truncate(BlockDriverState *bs, int64_t offset)
289 {
290     BDRVRawState *s = bs->opaque;
291     DWORD low, high;
292
293     low = offset;
294     high = offset >> 32;
295     if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
296         return -EIO;
297     if (!SetEndOfFile(s->hfile))
298         return -EIO;
299     return 0;
300 }
301
302 static int64_t raw_getlength(BlockDriverState *bs)
303 {
304     BDRVRawState *s = bs->opaque;
305     LARGE_INTEGER l;
306     ULARGE_INTEGER available, total, total_free;
307     DISK_GEOMETRY_EX dg;
308     DWORD count;
309     BOOL status;
310
311     switch(s->type) {
312     case FTYPE_FILE:
313         l.LowPart = GetFileSize(s->hfile, &l.HighPart);
314         if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
315             return -EIO;
316         break;
317     case FTYPE_CD:
318         if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
319             return -EIO;
320         l.QuadPart = total.QuadPart;
321         break;
322     case FTYPE_HARDDISK:
323         status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
324                                  NULL, 0, &dg, sizeof(dg), &count, NULL);
325         if (status != 0) {
326             l = dg.DiskSize;
327         }
328         break;
329     default:
330         return -EIO;
331     }
332     return l.QuadPart;
333 }
334
335 static int raw_create(const char *filename, int64_t total_size,
336                       const char *backing_file, int flags)
337 {
338     int fd;
339
340     if (flags || backing_file)
341         return -ENOTSUP;
342
343     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
344               0644);
345     if (fd < 0)
346         return -EIO;
347     set_sparse(fd);
348     ftruncate(fd, total_size * 512);
349     close(fd);
350     return 0;
351 }
352
353 BlockDriver bdrv_raw = {
354     "raw",
355     sizeof(BDRVRawState),
356     NULL, /* no probe for protocols */
357     raw_open,
358     NULL,
359     NULL,
360     raw_close,
361     raw_create,
362     raw_flush,
363
364 #ifdef WIN32_AIO
365     .bdrv_aio_read = raw_aio_read,
366     .bdrv_aio_write = raw_aio_write,
367     .bdrv_aio_cancel = raw_aio_cancel,
368     .aiocb_size = sizeof(RawAIOCB);
369 #endif
370     .bdrv_read = raw_read,
371     .bdrv_write = raw_write,
372     .bdrv_truncate = raw_truncate,
373     .bdrv_getlength = raw_getlength,
374 };
375
376 /***********************************************/
377 /* host device */
378
379 static int find_cdrom(char *cdrom_name, int cdrom_name_size)
380 {
381     char drives[256], *pdrv = drives;
382     UINT type;
383
384     memset(drives, 0, sizeof(drives));
385     GetLogicalDriveStrings(sizeof(drives), drives);
386     while(pdrv[0] != '\0') {
387         type = GetDriveType(pdrv);
388         switch(type) {
389         case DRIVE_CDROM:
390             snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
391             return 0;
392             break;
393         }
394         pdrv += lstrlen(pdrv) + 1;
395     }
396     return -1;
397 }
398
399 static int find_device_type(BlockDriverState *bs, const char *filename)
400 {
401     BDRVRawState *s = bs->opaque;
402     UINT type;
403     const char *p;
404
405     if (strstart(filename, "\\\\.\\", &p) ||
406         strstart(filename, "//./", &p)) {
407         if (stristart(p, "PhysicalDrive", NULL))
408             return FTYPE_HARDDISK;
409         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
410         type = GetDriveType(s->drive_path);
411         if (type == DRIVE_CDROM)
412             return FTYPE_CD;
413         else
414             return FTYPE_FILE;
415     } else {
416         return FTYPE_FILE;
417     }
418 }
419
420 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
421 {
422     BDRVRawState *s = bs->opaque;
423     int access_flags, create_flags;
424     DWORD overlapped;
425     char device_name[64];
426
427     if (strstart(filename, "/dev/cdrom", NULL)) {
428         if (find_cdrom(device_name, sizeof(device_name)) < 0)
429             return -ENOENT;
430         filename = device_name;
431     } else {
432         /* transform drive letters into device name */
433         if (((filename[0] >= 'a' && filename[0] <= 'z') ||
434              (filename[0] >= 'A' && filename[0] <= 'Z')) &&
435             filename[1] == ':' && filename[2] == '\0') {
436             snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
437             filename = device_name;
438         }
439     }
440     s->type = find_device_type(bs, filename);
441
442     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
443         access_flags = GENERIC_READ | GENERIC_WRITE;
444     } else {
445         access_flags = GENERIC_READ;
446     }
447     create_flags = OPEN_EXISTING;
448
449 #ifdef WIN32_AIO
450     overlapped = FILE_FLAG_OVERLAPPED;
451 #else
452     overlapped = FILE_ATTRIBUTE_NORMAL;
453 #endif
454     if ((flags & BDRV_O_NOCACHE))
455         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
456     else if (!(flags & BDRV_O_CACHE_WB))
457         overlapped |= FILE_FLAG_WRITE_THROUGH;
458     s->hfile = CreateFile(filename, access_flags,
459                           FILE_SHARE_READ, NULL,
460                           create_flags, overlapped, NULL);
461     if (s->hfile == INVALID_HANDLE_VALUE) {
462         int err = GetLastError();
463
464         if (err == ERROR_ACCESS_DENIED)
465             return -EACCES;
466         return -1;
467     }
468     return 0;
469 }
470
471 #if 0
472 /***********************************************/
473 /* removable device additional commands */
474
475 static int raw_is_inserted(BlockDriverState *bs)
476 {
477     return 1;
478 }
479
480 static int raw_media_changed(BlockDriverState *bs)
481 {
482     return -ENOTSUP;
483 }
484
485 static int raw_eject(BlockDriverState *bs, int eject_flag)
486 {
487     DWORD ret_count;
488
489     if (s->type == FTYPE_FILE)
490         return -ENOTSUP;
491     if (eject_flag) {
492         DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
493                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
494     } else {
495         DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
496                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
497     }
498 }
499
500 static int raw_set_locked(BlockDriverState *bs, int locked)
501 {
502     return -ENOTSUP;
503 }
504 #endif
505
506 BlockDriver bdrv_host_device = {
507     .format_name        = "host_device",
508     .instance_size      = sizeof(BDRVRawState),
509     .bdrv_open          = hdev_open,
510     .bdrv_close         = raw_close,
511     .bdrv_flush         = raw_flush,
512
513 #ifdef WIN32_AIO
514     .bdrv_aio_read      = raw_aio_read,
515     .bdrv_aio_write     = raw_aio_write,
516     .bdrv_aio_cancel    = raw_aio_cancel,
517     .aiocb_size         = sizeof(RawAIOCB);
518 #endif
519     .bdrv_read          = raw_read,
520     .bdrv_write         = raw_write,
521     .bdrv_getlength     = raw_getlength,
522 };