xref: /qemu/block/file-win32.c (revision 3ac216270a62418519c08e88c17005a8f1539cf2)
1223d4670Sths /*
2223d4670Sths  * Block driver for RAW files (win32)
3223d4670Sths  *
4223d4670Sths  * Copyright (c) 2006 Fabrice Bellard
5223d4670Sths  *
6223d4670Sths  * Permission is hereby granted, free of charge, to any person obtaining a copy
7223d4670Sths  * of this software and associated documentation files (the "Software"), to deal
8223d4670Sths  * in the Software without restriction, including without limitation the rights
9223d4670Sths  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10223d4670Sths  * copies of the Software, and to permit persons to whom the Software is
11223d4670Sths  * furnished to do so, subject to the following conditions:
12223d4670Sths  *
13223d4670Sths  * The above copyright notice and this permission notice shall be included in
14223d4670Sths  * all copies or substantial portions of the Software.
15223d4670Sths  *
16223d4670Sths  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17223d4670Sths  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18223d4670Sths  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19223d4670Sths  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20223d4670Sths  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21223d4670Sths  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22223d4670Sths  * THE SOFTWARE.
23223d4670Sths  */
24223d4670Sths #include "qemu-common.h"
251de7afc9SPaolo Bonzini #include "qemu/timer.h"
26737e150eSPaolo Bonzini #include "block/block_int.h"
271de7afc9SPaolo Bonzini #include "qemu/module.h"
28fc4edb84SPaolo Bonzini #include "raw-aio.h"
29fc4edb84SPaolo Bonzini #include "trace.h"
30737e150eSPaolo Bonzini #include "block/thread-pool.h"
311de7afc9SPaolo Bonzini #include "qemu/iov.h"
3249dc768dSaliguori #include <windows.h>
33223d4670Sths #include <winioctl.h>
34223d4670Sths 
35223d4670Sths #define FTYPE_FILE 0
36223d4670Sths #define FTYPE_CD     1
37223d4670Sths #define FTYPE_HARDDISK 2
38223d4670Sths 
39a2736526SPaolo Bonzini static QEMUWin32AIOState *aio;
40a2736526SPaolo Bonzini 
41fc4edb84SPaolo Bonzini typedef struct RawWin32AIOData {
42fc4edb84SPaolo Bonzini     BlockDriverState *bs;
43fc4edb84SPaolo Bonzini     HANDLE hfile;
44fc4edb84SPaolo Bonzini     struct iovec *aio_iov;
45fc4edb84SPaolo Bonzini     int aio_niov;
46fc4edb84SPaolo Bonzini     size_t aio_nbytes;
47fc4edb84SPaolo Bonzini     off64_t aio_offset;
48fc4edb84SPaolo Bonzini     int aio_type;
49fc4edb84SPaolo Bonzini } RawWin32AIOData;
50fc4edb84SPaolo Bonzini 
51223d4670Sths typedef struct BDRVRawState {
52223d4670Sths     HANDLE hfile;
53223d4670Sths     int type;
54223d4670Sths     char drive_path[16]; /* format: "d:\" */
55a2736526SPaolo Bonzini     QEMUWin32AIOState *aio;
56223d4670Sths } BDRVRawState;
57223d4670Sths 
58fc4edb84SPaolo Bonzini /*
59fc4edb84SPaolo Bonzini  * Read/writes the data to/from a given linear buffer.
60fc4edb84SPaolo Bonzini  *
61fc4edb84SPaolo Bonzini  * Returns the number of bytes handles or -errno in case of an error. Short
62fc4edb84SPaolo Bonzini  * reads are only returned if the end of the file is reached.
63fc4edb84SPaolo Bonzini  */
64fc4edb84SPaolo Bonzini static size_t handle_aiocb_rw(RawWin32AIOData *aiocb)
65fc4edb84SPaolo Bonzini {
66fc4edb84SPaolo Bonzini     size_t offset = 0;
67fc4edb84SPaolo Bonzini     int i;
68fc4edb84SPaolo Bonzini 
69fc4edb84SPaolo Bonzini     for (i = 0; i < aiocb->aio_niov; i++) {
70fc4edb84SPaolo Bonzini         OVERLAPPED ov;
71fc4edb84SPaolo Bonzini         DWORD ret, ret_count, len;
72fc4edb84SPaolo Bonzini 
73fc4edb84SPaolo Bonzini         memset(&ov, 0, sizeof(ov));
74fc4edb84SPaolo Bonzini         ov.Offset = (aiocb->aio_offset + offset);
75fc4edb84SPaolo Bonzini         ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32;
76fc4edb84SPaolo Bonzini         len = aiocb->aio_iov[i].iov_len;
77fc4edb84SPaolo Bonzini         if (aiocb->aio_type & QEMU_AIO_WRITE) {
78fc4edb84SPaolo Bonzini             ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
79fc4edb84SPaolo Bonzini                             len, &ret_count, &ov);
80fc4edb84SPaolo Bonzini         } else {
81fc4edb84SPaolo Bonzini             ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
82fc4edb84SPaolo Bonzini                            len, &ret_count, &ov);
83fc4edb84SPaolo Bonzini         }
84fc4edb84SPaolo Bonzini         if (!ret) {
85fc4edb84SPaolo Bonzini             ret_count = 0;
86fc4edb84SPaolo Bonzini         }
87fc4edb84SPaolo Bonzini         if (ret_count != len) {
88fc4edb84SPaolo Bonzini             break;
89fc4edb84SPaolo Bonzini         }
90fc4edb84SPaolo Bonzini         offset += len;
91fc4edb84SPaolo Bonzini     }
92fc4edb84SPaolo Bonzini 
93fc4edb84SPaolo Bonzini     return offset;
94fc4edb84SPaolo Bonzini }
95fc4edb84SPaolo Bonzini 
96fc4edb84SPaolo Bonzini static int aio_worker(void *arg)
97fc4edb84SPaolo Bonzini {
98fc4edb84SPaolo Bonzini     RawWin32AIOData *aiocb = arg;
99fc4edb84SPaolo Bonzini     ssize_t ret = 0;
100fc4edb84SPaolo Bonzini     size_t count;
101fc4edb84SPaolo Bonzini 
102fc4edb84SPaolo Bonzini     switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
103fc4edb84SPaolo Bonzini     case QEMU_AIO_READ:
104fc4edb84SPaolo Bonzini         count = handle_aiocb_rw(aiocb);
105fc4edb84SPaolo Bonzini         if (count < aiocb->aio_nbytes && aiocb->bs->growable) {
106fc4edb84SPaolo Bonzini             /* A short read means that we have reached EOF. Pad the buffer
107fc4edb84SPaolo Bonzini              * with zeros for bytes after EOF. */
108fc4edb84SPaolo Bonzini             iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
109fc4edb84SPaolo Bonzini                       0, aiocb->aio_nbytes - count);
110fc4edb84SPaolo Bonzini 
111fc4edb84SPaolo Bonzini             count = aiocb->aio_nbytes;
112fc4edb84SPaolo Bonzini         }
113fc4edb84SPaolo Bonzini         if (count == aiocb->aio_nbytes) {
114fc4edb84SPaolo Bonzini             ret = 0;
115fc4edb84SPaolo Bonzini         } else {
116fc4edb84SPaolo Bonzini             ret = -EINVAL;
117fc4edb84SPaolo Bonzini         }
118fc4edb84SPaolo Bonzini         break;
119fc4edb84SPaolo Bonzini     case QEMU_AIO_WRITE:
120fc4edb84SPaolo Bonzini         count = handle_aiocb_rw(aiocb);
121fc4edb84SPaolo Bonzini         if (count == aiocb->aio_nbytes) {
122fc4edb84SPaolo Bonzini             count = 0;
123fc4edb84SPaolo Bonzini         } else {
124fc4edb84SPaolo Bonzini             count = -EINVAL;
125fc4edb84SPaolo Bonzini         }
126fc4edb84SPaolo Bonzini         break;
127fc4edb84SPaolo Bonzini     case QEMU_AIO_FLUSH:
128fc4edb84SPaolo Bonzini         if (!FlushFileBuffers(aiocb->hfile)) {
129fc4edb84SPaolo Bonzini             return -EIO;
130fc4edb84SPaolo Bonzini         }
131fc4edb84SPaolo Bonzini         break;
132fc4edb84SPaolo Bonzini     default:
133fc4edb84SPaolo Bonzini         fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
134fc4edb84SPaolo Bonzini         ret = -EINVAL;
135fc4edb84SPaolo Bonzini         break;
136fc4edb84SPaolo Bonzini     }
137fc4edb84SPaolo Bonzini 
138fc4edb84SPaolo Bonzini     g_slice_free(RawWin32AIOData, aiocb);
139fc4edb84SPaolo Bonzini     return ret;
140fc4edb84SPaolo Bonzini }
141fc4edb84SPaolo Bonzini 
142fc4edb84SPaolo Bonzini static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
143fc4edb84SPaolo Bonzini         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
144fc4edb84SPaolo Bonzini         BlockDriverCompletionFunc *cb, void *opaque, int type)
145fc4edb84SPaolo Bonzini {
146fc4edb84SPaolo Bonzini     RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
147c4d9d196SStefan Hajnoczi     ThreadPool *pool;
148fc4edb84SPaolo Bonzini 
149fc4edb84SPaolo Bonzini     acb->bs = bs;
150fc4edb84SPaolo Bonzini     acb->hfile = hfile;
151fc4edb84SPaolo Bonzini     acb->aio_type = type;
152fc4edb84SPaolo Bonzini 
153fc4edb84SPaolo Bonzini     if (qiov) {
154fc4edb84SPaolo Bonzini         acb->aio_iov = qiov->iov;
155fc4edb84SPaolo Bonzini         acb->aio_niov = qiov->niov;
156fc4edb84SPaolo Bonzini     }
157fc4edb84SPaolo Bonzini     acb->aio_nbytes = nb_sectors * 512;
158fc4edb84SPaolo Bonzini     acb->aio_offset = sector_num * 512;
159fc4edb84SPaolo Bonzini 
160fc4edb84SPaolo Bonzini     trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
161c4d9d196SStefan Hajnoczi     pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
162c4d9d196SStefan Hajnoczi     return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
163fc4edb84SPaolo Bonzini }
164fc4edb84SPaolo Bonzini 
165223d4670Sths int qemu_ftruncate64(int fd, int64_t length)
166223d4670Sths {
167223d4670Sths     LARGE_INTEGER li;
1682c993ec2SStefan Weil     DWORD dw;
169223d4670Sths     LONG high;
170223d4670Sths     HANDLE h;
171223d4670Sths     BOOL res;
172223d4670Sths 
173223d4670Sths     if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
174223d4670Sths 	return -1;
175223d4670Sths 
176223d4670Sths     h = (HANDLE)_get_osfhandle(fd);
177223d4670Sths 
178223d4670Sths     /* get current position, ftruncate do not change position */
179223d4670Sths     li.HighPart = 0;
180223d4670Sths     li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
1812c993ec2SStefan Weil     if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
182223d4670Sths 	return -1;
1832c993ec2SStefan Weil     }
184223d4670Sths 
185223d4670Sths     high = length >> 32;
1862c993ec2SStefan Weil     dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
1872c993ec2SStefan Weil     if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
188223d4670Sths 	return -1;
1892c993ec2SStefan Weil     }
190223d4670Sths     res = SetEndOfFile(h);
191223d4670Sths 
192223d4670Sths     /* back to old position */
193223d4670Sths     SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
194223d4670Sths     return res ? 0 : -1;
195223d4670Sths }
196223d4670Sths 
197223d4670Sths static int set_sparse(int fd)
198223d4670Sths {
199223d4670Sths     DWORD returned;
200223d4670Sths     return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
201223d4670Sths 				 NULL, 0, NULL, 0, &returned, NULL);
202223d4670Sths }
203223d4670Sths 
2046a8dc042SJeff Cody static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
2056a8dc042SJeff Cody {
2066a8dc042SJeff Cody     assert(access_flags != NULL);
2076a8dc042SJeff Cody     assert(overlapped != NULL);
2086a8dc042SJeff Cody 
2096a8dc042SJeff Cody     if (flags & BDRV_O_RDWR) {
2106a8dc042SJeff Cody         *access_flags = GENERIC_READ | GENERIC_WRITE;
2116a8dc042SJeff Cody     } else {
2126a8dc042SJeff Cody         *access_flags = GENERIC_READ;
2136a8dc042SJeff Cody     }
2146a8dc042SJeff Cody 
2156a8dc042SJeff Cody     *overlapped = FILE_ATTRIBUTE_NORMAL;
216a2736526SPaolo Bonzini     if (flags & BDRV_O_NATIVE_AIO) {
217a2736526SPaolo Bonzini         *overlapped |= FILE_FLAG_OVERLAPPED;
218a2736526SPaolo Bonzini     }
2196a8dc042SJeff Cody     if (flags & BDRV_O_NOCACHE) {
2206a8dc042SJeff Cody         *overlapped |= FILE_FLAG_NO_BUFFERING;
2216a8dc042SJeff Cody     }
2226a8dc042SJeff Cody }
2236a8dc042SJeff Cody 
2248a79380bSKevin Wolf static QemuOptsList raw_runtime_opts = {
2258a79380bSKevin Wolf     .name = "raw",
2268a79380bSKevin Wolf     .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
2278a79380bSKevin Wolf     .desc = {
2288a79380bSKevin Wolf         {
2298a79380bSKevin Wolf             .name = "filename",
2308a79380bSKevin Wolf             .type = QEMU_OPT_STRING,
2318a79380bSKevin Wolf             .help = "File name of the image",
2328a79380bSKevin Wolf         },
2338a79380bSKevin Wolf         { /* end of list */ }
2348a79380bSKevin Wolf     },
2358a79380bSKevin Wolf };
2368a79380bSKevin Wolf 
23756d1b4d2SKevin Wolf static int raw_open(BlockDriverState *bs, QDict *options, int flags)
238223d4670Sths {
239223d4670Sths     BDRVRawState *s = bs->opaque;
2409a2d77adSChristoph Hellwig     int access_flags;
241223d4670Sths     DWORD overlapped;
2428a79380bSKevin Wolf     QemuOpts *opts;
2438a79380bSKevin Wolf     Error *local_err = NULL;
2448a79380bSKevin Wolf     const char *filename;
2458a79380bSKevin Wolf     int ret;
246223d4670Sths 
247223d4670Sths     s->type = FTYPE_FILE;
248223d4670Sths 
2498a79380bSKevin Wolf     opts = qemu_opts_create_nofail(&raw_runtime_opts);
2508a79380bSKevin Wolf     qemu_opts_absorb_qdict(opts, options, &local_err);
2518a79380bSKevin Wolf     if (error_is_set(&local_err)) {
2528a79380bSKevin Wolf         qerror_report_err(local_err);
2538a79380bSKevin Wolf         error_free(local_err);
2548a79380bSKevin Wolf         ret = -EINVAL;
2558a79380bSKevin Wolf         goto fail;
2568a79380bSKevin Wolf     }
2578a79380bSKevin Wolf 
2588a79380bSKevin Wolf     filename = qemu_opt_get(opts, "filename");
2598a79380bSKevin Wolf 
2606a8dc042SJeff Cody     raw_parse_flags(flags, &access_flags, &overlapped);
2619a2d77adSChristoph Hellwig 
262a2736526SPaolo Bonzini     if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
263a2736526SPaolo Bonzini         aio = win32_aio_init();
264a2736526SPaolo Bonzini         if (aio == NULL) {
2658a79380bSKevin Wolf             ret = -EINVAL;
2668a79380bSKevin Wolf             goto fail;
267a2736526SPaolo Bonzini         }
268a2736526SPaolo Bonzini     }
269a2736526SPaolo Bonzini 
270223d4670Sths     s->hfile = CreateFile(filename, access_flags,
271223d4670Sths                           FILE_SHARE_READ, NULL,
2729a2d77adSChristoph Hellwig                           OPEN_EXISTING, overlapped, NULL);
273223d4670Sths     if (s->hfile == INVALID_HANDLE_VALUE) {
274223d4670Sths         int err = GetLastError();
275223d4670Sths 
2768a79380bSKevin Wolf         if (err == ERROR_ACCESS_DENIED) {
2778a79380bSKevin Wolf             ret = -EACCES;
2788a79380bSKevin Wolf         } else {
2798a79380bSKevin Wolf             ret = -EINVAL;
2808a79380bSKevin Wolf         }
2818a79380bSKevin Wolf         goto fail;
282a2736526SPaolo Bonzini     }
283a2736526SPaolo Bonzini 
284a2736526SPaolo Bonzini     if (flags & BDRV_O_NATIVE_AIO) {
2858a79380bSKevin Wolf         ret = win32_aio_attach(aio, s->hfile);
286a2736526SPaolo Bonzini         if (ret < 0) {
287a2736526SPaolo Bonzini             CloseHandle(s->hfile);
2888a79380bSKevin Wolf             goto fail;
289a2736526SPaolo Bonzini         }
290a2736526SPaolo Bonzini         s->aio = aio;
291223d4670Sths     }
2928a79380bSKevin Wolf 
2938a79380bSKevin Wolf     ret = 0;
2948a79380bSKevin Wolf fail:
2958a79380bSKevin Wolf     qemu_opts_del(opts);
2968a79380bSKevin Wolf     return ret;
297223d4670Sths }
298223d4670Sths 
299fc4edb84SPaolo Bonzini static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
300fc4edb84SPaolo Bonzini                          int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
301fc4edb84SPaolo Bonzini                          BlockDriverCompletionFunc *cb, void *opaque)
302223d4670Sths {
303223d4670Sths     BDRVRawState *s = bs->opaque;
304a2736526SPaolo Bonzini     if (s->aio) {
305a2736526SPaolo Bonzini         return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
306a2736526SPaolo Bonzini                                 nb_sectors, cb, opaque, QEMU_AIO_READ);
307a2736526SPaolo Bonzini     } else {
308fc4edb84SPaolo Bonzini         return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
309fc4edb84SPaolo Bonzini                            cb, opaque, QEMU_AIO_READ);
310223d4670Sths     }
311a2736526SPaolo Bonzini }
312223d4670Sths 
313fc4edb84SPaolo Bonzini static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
314fc4edb84SPaolo Bonzini                           int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
315fc4edb84SPaolo Bonzini                           BlockDriverCompletionFunc *cb, void *opaque)
316223d4670Sths {
317223d4670Sths     BDRVRawState *s = bs->opaque;
318a2736526SPaolo Bonzini     if (s->aio) {
319a2736526SPaolo Bonzini         return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
320a2736526SPaolo Bonzini                                 nb_sectors, cb, opaque, QEMU_AIO_WRITE);
321a2736526SPaolo Bonzini     } else {
322fc4edb84SPaolo Bonzini         return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
323fc4edb84SPaolo Bonzini                            cb, opaque, QEMU_AIO_WRITE);
324223d4670Sths     }
325a2736526SPaolo Bonzini }
326223d4670Sths 
327fc4edb84SPaolo Bonzini static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
328fc4edb84SPaolo Bonzini                          BlockDriverCompletionFunc *cb, void *opaque)
329223d4670Sths {
330223d4670Sths     BDRVRawState *s = bs->opaque;
331fc4edb84SPaolo Bonzini     return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
332223d4670Sths }
333223d4670Sths 
334223d4670Sths static void raw_close(BlockDriverState *bs)
335223d4670Sths {
336223d4670Sths     BDRVRawState *s = bs->opaque;
337223d4670Sths     CloseHandle(s->hfile);
338223d4670Sths }
339223d4670Sths 
340223d4670Sths static int raw_truncate(BlockDriverState *bs, int64_t offset)
341223d4670Sths {
342223d4670Sths     BDRVRawState *s = bs->opaque;
343b9e82a59Sblueswir1     LONG low, high;
344fbcad04dSFabien Chouteau     DWORD dwPtrLow;
345223d4670Sths 
346223d4670Sths     low = offset;
347223d4670Sths     high = offset >> 32;
348fbcad04dSFabien Chouteau 
349fbcad04dSFabien Chouteau     /*
350fbcad04dSFabien Chouteau      * An error has occurred if the return value is INVALID_SET_FILE_POINTER
351fbcad04dSFabien Chouteau      * and GetLastError doesn't return NO_ERROR.
352fbcad04dSFabien Chouteau      */
353fbcad04dSFabien Chouteau     dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN);
354fbcad04dSFabien Chouteau     if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
355fccedc62SStefan Weil         fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError());
356223d4670Sths         return -EIO;
357fbcad04dSFabien Chouteau     }
358fbcad04dSFabien Chouteau     if (SetEndOfFile(s->hfile) == 0) {
359fccedc62SStefan Weil         fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError());
360223d4670Sths         return -EIO;
361fbcad04dSFabien Chouteau     }
362223d4670Sths     return 0;
363223d4670Sths }
364223d4670Sths 
365223d4670Sths static int64_t raw_getlength(BlockDriverState *bs)
366223d4670Sths {
367223d4670Sths     BDRVRawState *s = bs->opaque;
368223d4670Sths     LARGE_INTEGER l;
369223d4670Sths     ULARGE_INTEGER available, total, total_free;
370223d4670Sths     DISK_GEOMETRY_EX dg;
371223d4670Sths     DWORD count;
372223d4670Sths     BOOL status;
373223d4670Sths 
374223d4670Sths     switch(s->type) {
375223d4670Sths     case FTYPE_FILE:
376b9e82a59Sblueswir1         l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
377223d4670Sths         if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
378223d4670Sths             return -EIO;
379223d4670Sths         break;
380223d4670Sths     case FTYPE_CD:
381223d4670Sths         if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
382223d4670Sths             return -EIO;
383223d4670Sths         l.QuadPart = total.QuadPart;
384223d4670Sths         break;
385223d4670Sths     case FTYPE_HARDDISK:
386223d4670Sths         status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
387223d4670Sths                                  NULL, 0, &dg, sizeof(dg), &count, NULL);
388223d4670Sths         if (status != 0) {
389223d4670Sths             l = dg.DiskSize;
390223d4670Sths         }
391223d4670Sths         break;
392223d4670Sths     default:
393223d4670Sths         return -EIO;
394223d4670Sths     }
395223d4670Sths     return l.QuadPart;
396223d4670Sths }
397223d4670Sths 
3984a1d5e1fSFam Zheng static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
3994a1d5e1fSFam Zheng {
4004a1d5e1fSFam Zheng     typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
4014a1d5e1fSFam Zheng                                               DWORD * high);
4024a1d5e1fSFam Zheng     get_compressed_t get_compressed;
4034a1d5e1fSFam Zheng     struct _stati64 st;
4044a1d5e1fSFam Zheng     const char *filename = bs->filename;
4054a1d5e1fSFam Zheng     /* WinNT support GetCompressedFileSize to determine allocate size */
4064a1d5e1fSFam Zheng     get_compressed =
4074a1d5e1fSFam Zheng         (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
4084a1d5e1fSFam Zheng                                             "GetCompressedFileSizeA");
4094a1d5e1fSFam Zheng     if (get_compressed) {
4104a1d5e1fSFam Zheng         DWORD high, low;
4114a1d5e1fSFam Zheng         low = get_compressed(filename, &high);
4124a1d5e1fSFam Zheng         if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
4134a1d5e1fSFam Zheng             return (((int64_t) high) << 32) + low;
4144a1d5e1fSFam Zheng         }
4154a1d5e1fSFam Zheng     }
4164a1d5e1fSFam Zheng 
4174a1d5e1fSFam Zheng     if (_stati64(filename, &st) < 0) {
4184a1d5e1fSFam Zheng         return -1;
4194a1d5e1fSFam Zheng     }
4204a1d5e1fSFam Zheng     return st.st_size;
4214a1d5e1fSFam Zheng }
4224a1d5e1fSFam Zheng 
4230e7e1989SKevin Wolf static int raw_create(const char *filename, QEMUOptionParameter *options)
424223d4670Sths {
425223d4670Sths     int fd;
4260e7e1989SKevin Wolf     int64_t total_size = 0;
427223d4670Sths 
4280e7e1989SKevin Wolf     /* Read out options */
4290e7e1989SKevin Wolf     while (options && options->name) {
4300e7e1989SKevin Wolf         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
4310e7e1989SKevin Wolf             total_size = options->value.n / 512;
4320e7e1989SKevin Wolf         }
4330e7e1989SKevin Wolf         options++;
4340e7e1989SKevin Wolf     }
435223d4670Sths 
4366165f4d8SCorey Bryant     fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
437223d4670Sths                    0644);
438223d4670Sths     if (fd < 0)
439223d4670Sths         return -EIO;
440223d4670Sths     set_sparse(fd);
441223d4670Sths     ftruncate(fd, total_size * 512);
4422e1e79daSCorey Bryant     qemu_close(fd);
443223d4670Sths     return 0;
444223d4670Sths }
445223d4670Sths 
4460e7e1989SKevin Wolf static QEMUOptionParameter raw_create_options[] = {
447db08adf5SKevin Wolf     {
448db08adf5SKevin Wolf         .name = BLOCK_OPT_SIZE,
449db08adf5SKevin Wolf         .type = OPT_SIZE,
450db08adf5SKevin Wolf         .help = "Virtual disk size"
451db08adf5SKevin Wolf     },
4520e7e1989SKevin Wolf     { NULL }
4530e7e1989SKevin Wolf };
4540e7e1989SKevin Wolf 
45584a12e66SChristoph Hellwig static BlockDriver bdrv_file = {
45684a12e66SChristoph Hellwig     .format_name	= "file",
45784a12e66SChristoph Hellwig     .protocol_name	= "file",
458f1b2f712Saliguori     .instance_size	= sizeof(BDRVRawState),
45966f82ceeSKevin Wolf     .bdrv_file_open	= raw_open,
460f1b2f712Saliguori     .bdrv_close		= raw_close,
461f1b2f712Saliguori     .bdrv_create	= raw_create,
462*3ac21627SPeter Lieven     .bdrv_has_zero_init = bdrv_has_zero_init_1,
463c68b89acSKevin Wolf 
464fc4edb84SPaolo Bonzini     .bdrv_aio_readv     = raw_aio_readv,
465fc4edb84SPaolo Bonzini     .bdrv_aio_writev    = raw_aio_writev,
466fc4edb84SPaolo Bonzini     .bdrv_aio_flush     = raw_aio_flush,
467c68b89acSKevin Wolf 
468223d4670Sths     .bdrv_truncate	= raw_truncate,
469223d4670Sths     .bdrv_getlength	= raw_getlength,
4704a1d5e1fSFam Zheng     .bdrv_get_allocated_file_size
4714a1d5e1fSFam Zheng                         = raw_get_allocated_file_size,
4720e7e1989SKevin Wolf 
4730e7e1989SKevin Wolf     .create_options = raw_create_options,
474223d4670Sths };
475223d4670Sths 
476223d4670Sths /***********************************************/
477223d4670Sths /* host device */
478223d4670Sths 
479223d4670Sths static int find_cdrom(char *cdrom_name, int cdrom_name_size)
480223d4670Sths {
481223d4670Sths     char drives[256], *pdrv = drives;
482223d4670Sths     UINT type;
483223d4670Sths 
484223d4670Sths     memset(drives, 0, sizeof(drives));
485223d4670Sths     GetLogicalDriveStrings(sizeof(drives), drives);
486223d4670Sths     while(pdrv[0] != '\0') {
487223d4670Sths         type = GetDriveType(pdrv);
488223d4670Sths         switch(type) {
489223d4670Sths         case DRIVE_CDROM:
490223d4670Sths             snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
491223d4670Sths             return 0;
492223d4670Sths             break;
493223d4670Sths         }
494223d4670Sths         pdrv += lstrlen(pdrv) + 1;
495223d4670Sths     }
496223d4670Sths     return -1;
497223d4670Sths }
498223d4670Sths 
499223d4670Sths static int find_device_type(BlockDriverState *bs, const char *filename)
500223d4670Sths {
501223d4670Sths     BDRVRawState *s = bs->opaque;
502223d4670Sths     UINT type;
503223d4670Sths     const char *p;
504223d4670Sths 
505223d4670Sths     if (strstart(filename, "\\\\.\\", &p) ||
506223d4670Sths         strstart(filename, "//./", &p)) {
507223d4670Sths         if (stristart(p, "PhysicalDrive", NULL))
508223d4670Sths             return FTYPE_HARDDISK;
509223d4670Sths         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
510223d4670Sths         type = GetDriveType(s->drive_path);
5113060cd14Saliguori         switch (type) {
5123060cd14Saliguori         case DRIVE_REMOVABLE:
5133060cd14Saliguori         case DRIVE_FIXED:
5143060cd14Saliguori             return FTYPE_HARDDISK;
5153060cd14Saliguori         case DRIVE_CDROM:
516223d4670Sths             return FTYPE_CD;
5173060cd14Saliguori         default:
518223d4670Sths             return FTYPE_FILE;
5193060cd14Saliguori         }
520223d4670Sths     } else {
521223d4670Sths         return FTYPE_FILE;
522223d4670Sths     }
523223d4670Sths }
524223d4670Sths 
525508c7cb3SChristoph Hellwig static int hdev_probe_device(const char *filename)
526508c7cb3SChristoph Hellwig {
527508c7cb3SChristoph Hellwig     if (strstart(filename, "/dev/cdrom", NULL))
528508c7cb3SChristoph Hellwig         return 100;
529508c7cb3SChristoph Hellwig     if (is_windows_drive(filename))
530508c7cb3SChristoph Hellwig         return 100;
531508c7cb3SChristoph Hellwig     return 0;
532508c7cb3SChristoph Hellwig }
533508c7cb3SChristoph Hellwig 
53456d1b4d2SKevin Wolf static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
535223d4670Sths {
536223d4670Sths     BDRVRawState *s = bs->opaque;
537223d4670Sths     int access_flags, create_flags;
538223d4670Sths     DWORD overlapped;
539223d4670Sths     char device_name[64];
5408a79380bSKevin Wolf     const char *filename = qdict_get_str(options, "filename");
541223d4670Sths 
542223d4670Sths     if (strstart(filename, "/dev/cdrom", NULL)) {
543223d4670Sths         if (find_cdrom(device_name, sizeof(device_name)) < 0)
544223d4670Sths             return -ENOENT;
545223d4670Sths         filename = device_name;
546223d4670Sths     } else {
547223d4670Sths         /* transform drive letters into device name */
548223d4670Sths         if (((filename[0] >= 'a' && filename[0] <= 'z') ||
549223d4670Sths              (filename[0] >= 'A' && filename[0] <= 'Z')) &&
550223d4670Sths             filename[1] == ':' && filename[2] == '\0') {
551223d4670Sths             snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
552223d4670Sths             filename = device_name;
553223d4670Sths         }
554223d4670Sths     }
555223d4670Sths     s->type = find_device_type(bs, filename);
556223d4670Sths 
5576a8dc042SJeff Cody     raw_parse_flags(flags, &access_flags, &overlapped);
5586a8dc042SJeff Cody 
559223d4670Sths     create_flags = OPEN_EXISTING;
560223d4670Sths 
561223d4670Sths     s->hfile = CreateFile(filename, access_flags,
562223d4670Sths                           FILE_SHARE_READ, NULL,
563223d4670Sths                           create_flags, overlapped, NULL);
564223d4670Sths     if (s->hfile == INVALID_HANDLE_VALUE) {
565223d4670Sths         int err = GetLastError();
566223d4670Sths 
567223d4670Sths         if (err == ERROR_ACCESS_DENIED)
568223d4670Sths             return -EACCES;
569223d4670Sths         return -1;
570223d4670Sths     }
571223d4670Sths     return 0;
572223d4670Sths }
573223d4670Sths 
5745efa9d5aSAnthony Liguori static BlockDriver bdrv_host_device = {
575e60f469cSaurel32     .format_name	= "host_device",
57684a12e66SChristoph Hellwig     .protocol_name	= "host_device",
577e60f469cSaurel32     .instance_size	= sizeof(BDRVRawState),
578508c7cb3SChristoph Hellwig     .bdrv_probe_device	= hdev_probe_device,
57966f82ceeSKevin Wolf     .bdrv_file_open	= hdev_open,
580e60f469cSaurel32     .bdrv_close		= raw_close,
581223d4670Sths 
582fc4edb84SPaolo Bonzini     .bdrv_aio_readv     = raw_aio_readv,
583fc4edb84SPaolo Bonzini     .bdrv_aio_writev    = raw_aio_writev,
584fc4edb84SPaolo Bonzini     .bdrv_aio_flush     = raw_aio_flush,
585c68b89acSKevin Wolf 
586223d4670Sths     .bdrv_getlength	= raw_getlength,
5874a1d5e1fSFam Zheng     .bdrv_get_allocated_file_size
5884a1d5e1fSFam Zheng                         = raw_get_allocated_file_size,
589223d4670Sths };
5905efa9d5aSAnthony Liguori 
59184a12e66SChristoph Hellwig static void bdrv_file_init(void)
5925efa9d5aSAnthony Liguori {
59384a12e66SChristoph Hellwig     bdrv_register(&bdrv_file);
5945efa9d5aSAnthony Liguori     bdrv_register(&bdrv_host_device);
5955efa9d5aSAnthony Liguori }
5965efa9d5aSAnthony Liguori 
59784a12e66SChristoph Hellwig block_init(bdrv_file_init);
598