xref: /openbmc/qemu/block/file-win32.c (revision 954a6c4f)
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 
25 #include "qemu/osdep.h"
26 #include "qapi/error.h"
27 #include "qemu/cutils.h"
28 #include "block/block_int.h"
29 #include "qemu/module.h"
30 #include "qemu/option.h"
31 #include "block/raw-aio.h"
32 #include "trace.h"
33 #include "block/thread-pool.h"
34 #include "qemu/iov.h"
35 #include "qapi/qmp/qdict.h"
36 #include "qapi/qmp/qstring.h"
37 #include <windows.h>
38 #include <winioctl.h>
39 
40 #define FTYPE_FILE 0
41 #define FTYPE_CD     1
42 #define FTYPE_HARDDISK 2
43 
44 typedef struct RawWin32AIOData {
45     BlockDriverState *bs;
46     HANDLE hfile;
47     struct iovec *aio_iov;
48     int aio_niov;
49     size_t aio_nbytes;
50     off64_t aio_offset;
51     int aio_type;
52 } RawWin32AIOData;
53 
54 typedef struct BDRVRawState {
55     HANDLE hfile;
56     int type;
57     char drive_path[16]; /* format: "d:\" */
58     QEMUWin32AIOState *aio;
59 } BDRVRawState;
60 
61 typedef struct BDRVRawReopenState {
62     HANDLE hfile;
63 } BDRVRawReopenState;
64 
65 /*
66  * Read/writes the data to/from a given linear buffer.
67  *
68  * Returns the number of bytes handles or -errno in case of an error. Short
69  * reads are only returned if the end of the file is reached.
70  */
71 static size_t handle_aiocb_rw(RawWin32AIOData *aiocb)
72 {
73     size_t offset = 0;
74     int i;
75 
76     for (i = 0; i < aiocb->aio_niov; i++) {
77         OVERLAPPED ov;
78         DWORD ret, ret_count, len;
79 
80         memset(&ov, 0, sizeof(ov));
81         ov.Offset = (aiocb->aio_offset + offset);
82         ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32;
83         len = aiocb->aio_iov[i].iov_len;
84         if (aiocb->aio_type & QEMU_AIO_WRITE) {
85             ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
86                             len, &ret_count, &ov);
87         } else {
88             ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
89                            len, &ret_count, &ov);
90         }
91         if (!ret) {
92             ret_count = 0;
93         }
94         if (ret_count != len) {
95             offset += ret_count;
96             break;
97         }
98         offset += len;
99     }
100 
101     return offset;
102 }
103 
104 static int aio_worker(void *arg)
105 {
106     RawWin32AIOData *aiocb = arg;
107     ssize_t ret = 0;
108     size_t count;
109 
110     switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
111     case QEMU_AIO_READ:
112         count = handle_aiocb_rw(aiocb);
113         if (count < aiocb->aio_nbytes) {
114             /* A short read means that we have reached EOF. Pad the buffer
115              * with zeros for bytes after EOF. */
116             iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
117                       0, aiocb->aio_nbytes - count);
118 
119             count = aiocb->aio_nbytes;
120         }
121         if (count == aiocb->aio_nbytes) {
122             ret = 0;
123         } else {
124             ret = -EINVAL;
125         }
126         break;
127     case QEMU_AIO_WRITE:
128         count = handle_aiocb_rw(aiocb);
129         if (count == aiocb->aio_nbytes) {
130             ret = 0;
131         } else {
132             ret = -EINVAL;
133         }
134         break;
135     case QEMU_AIO_FLUSH:
136         if (!FlushFileBuffers(aiocb->hfile)) {
137             return -EIO;
138         }
139         break;
140     default:
141         fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
142         ret = -EINVAL;
143         break;
144     }
145 
146     g_free(aiocb);
147     return ret;
148 }
149 
150 static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
151         int64_t offset, QEMUIOVector *qiov, int count,
152         BlockCompletionFunc *cb, void *opaque, int type)
153 {
154     RawWin32AIOData *acb = g_new(RawWin32AIOData, 1);
155     ThreadPool *pool;
156 
157     acb->bs = bs;
158     acb->hfile = hfile;
159     acb->aio_type = type;
160 
161     if (qiov) {
162         acb->aio_iov = qiov->iov;
163         acb->aio_niov = qiov->niov;
164         assert(qiov->size == count);
165     }
166     acb->aio_nbytes = count;
167     acb->aio_offset = offset;
168 
169     trace_file_paio_submit(acb, opaque, offset, count, type);
170     pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
171     return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
172 }
173 
174 int qemu_ftruncate64(int fd, int64_t length)
175 {
176     LARGE_INTEGER li;
177     DWORD dw;
178     LONG high;
179     HANDLE h;
180     BOOL res;
181 
182     if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
183         return -1;
184 
185     h = (HANDLE)_get_osfhandle(fd);
186 
187     /* get current position, ftruncate do not change position */
188     li.HighPart = 0;
189     li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
190     if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
191         return -1;
192     }
193 
194     high = length >> 32;
195     dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
196     if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
197         return -1;
198     }
199     res = SetEndOfFile(h);
200 
201     /* back to old position */
202     SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
203     return res ? 0 : -1;
204 }
205 
206 static int set_sparse(int fd)
207 {
208     DWORD returned;
209     return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
210                                  NULL, 0, NULL, 0, &returned, NULL);
211 }
212 
213 static void raw_detach_aio_context(BlockDriverState *bs)
214 {
215     BDRVRawState *s = bs->opaque;
216 
217     if (s->aio) {
218         win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs));
219     }
220 }
221 
222 static void raw_attach_aio_context(BlockDriverState *bs,
223                                    AioContext *new_context)
224 {
225     BDRVRawState *s = bs->opaque;
226 
227     if (s->aio) {
228         win32_aio_attach_aio_context(s->aio, new_context);
229     }
230 }
231 
232 static void raw_probe_alignment(BlockDriverState *bs, Error **errp)
233 {
234     BDRVRawState *s = bs->opaque;
235     DWORD sectorsPerCluster, freeClusters, totalClusters, count;
236     DISK_GEOMETRY_EX dg;
237     BOOL status;
238 
239     if (s->type == FTYPE_CD) {
240         bs->bl.request_alignment = 2048;
241         return;
242     }
243     if (s->type == FTYPE_HARDDISK) {
244         status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
245                                  NULL, 0, &dg, sizeof(dg), &count, NULL);
246         if (status != 0) {
247             bs->bl.request_alignment = dg.Geometry.BytesPerSector;
248             return;
249         }
250         /* try GetDiskFreeSpace too */
251     }
252 
253     if (s->drive_path[0]) {
254         GetDiskFreeSpace(s->drive_path, &sectorsPerCluster,
255                          &dg.Geometry.BytesPerSector,
256                          &freeClusters, &totalClusters);
257         bs->bl.request_alignment = dg.Geometry.BytesPerSector;
258         return;
259     }
260 
261     /* XXX Does Windows support AIO on less than 512-byte alignment? */
262     bs->bl.request_alignment = 512;
263 }
264 
265 static void raw_parse_flags(int flags, bool use_aio, int *access_flags,
266                             DWORD *overlapped)
267 {
268     assert(access_flags != NULL);
269     assert(overlapped != NULL);
270 
271     if (flags & BDRV_O_RDWR) {
272         *access_flags = GENERIC_READ | GENERIC_WRITE;
273     } else {
274         *access_flags = GENERIC_READ;
275     }
276 
277     *overlapped = FILE_ATTRIBUTE_NORMAL;
278     if (use_aio) {
279         *overlapped |= FILE_FLAG_OVERLAPPED;
280     }
281     if (flags & BDRV_O_NOCACHE) {
282         *overlapped |= FILE_FLAG_NO_BUFFERING;
283     }
284 }
285 
286 static void raw_parse_filename(const char *filename, QDict *options,
287                                Error **errp)
288 {
289     bdrv_parse_filename_strip_prefix(filename, "file:", options);
290 }
291 
292 static QemuOptsList raw_runtime_opts = {
293     .name = "raw",
294     .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
295     .desc = {
296         {
297             .name = "filename",
298             .type = QEMU_OPT_STRING,
299             .help = "File name of the image",
300         },
301         {
302             .name = "aio",
303             .type = QEMU_OPT_STRING,
304             .help = "host AIO implementation (threads, native)",
305         },
306         {
307             .name = "locking",
308             .type = QEMU_OPT_STRING,
309             .help = "file locking mode (on/off/auto, default: auto)",
310         },
311         { /* end of list */ }
312     },
313 };
314 
315 static bool get_aio_option(QemuOpts *opts, int flags, Error **errp)
316 {
317     BlockdevAioOptions aio, aio_default;
318 
319     aio_default = (flags & BDRV_O_NATIVE_AIO) ? BLOCKDEV_AIO_OPTIONS_NATIVE
320                                               : BLOCKDEV_AIO_OPTIONS_THREADS;
321     aio = qapi_enum_parse(&BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"),
322                           aio_default, errp);
323 
324     switch (aio) {
325     case BLOCKDEV_AIO_OPTIONS_NATIVE:
326         return true;
327     case BLOCKDEV_AIO_OPTIONS_THREADS:
328         return false;
329     default:
330         error_setg(errp, "Invalid AIO option");
331     }
332     return false;
333 }
334 
335 static int raw_open(BlockDriverState *bs, QDict *options, int flags,
336                     Error **errp)
337 {
338     BDRVRawState *s = bs->opaque;
339     int access_flags;
340     DWORD overlapped;
341     QemuOpts *opts;
342     Error *local_err = NULL;
343     const char *filename;
344     bool use_aio;
345     OnOffAuto locking;
346     int ret;
347 
348     s->type = FTYPE_FILE;
349 
350     opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
351     if (!qemu_opts_absorb_qdict(opts, options, errp)) {
352         ret = -EINVAL;
353         goto fail;
354     }
355 
356     locking = qapi_enum_parse(&OnOffAuto_lookup,
357                               qemu_opt_get(opts, "locking"),
358                               ON_OFF_AUTO_AUTO, &local_err);
359     if (local_err) {
360         error_propagate(errp, local_err);
361         ret = -EINVAL;
362         goto fail;
363     }
364     switch (locking) {
365     case ON_OFF_AUTO_ON:
366         error_setg(errp, "locking=on is not supported on Windows");
367         ret = -EINVAL;
368         goto fail;
369     case ON_OFF_AUTO_OFF:
370     case ON_OFF_AUTO_AUTO:
371         break;
372     default:
373         g_assert_not_reached();
374     }
375 
376     filename = qemu_opt_get(opts, "filename");
377 
378     use_aio = get_aio_option(opts, flags, &local_err);
379     if (local_err) {
380         error_propagate(errp, local_err);
381         ret = -EINVAL;
382         goto fail;
383     }
384 
385     raw_parse_flags(flags, use_aio, &access_flags, &overlapped);
386 
387     if (filename[0] && filename[1] == ':') {
388         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]);
389     } else if (filename[0] == '\\' && filename[1] == '\\') {
390         s->drive_path[0] = 0;
391     } else {
392         /* Relative path.  */
393         char buf[MAX_PATH];
394         GetCurrentDirectory(MAX_PATH, buf);
395         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]);
396     }
397 
398     s->hfile = CreateFile(filename, access_flags,
399                           FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
400                           OPEN_EXISTING, overlapped, NULL);
401     if (s->hfile == INVALID_HANDLE_VALUE) {
402         int err = GetLastError();
403 
404         error_setg_win32(errp, err, "Could not open '%s'", filename);
405         if (err == ERROR_ACCESS_DENIED) {
406             ret = -EACCES;
407         } else {
408             ret = -EINVAL;
409         }
410         goto fail;
411     }
412 
413     if (use_aio) {
414         s->aio = win32_aio_init();
415         if (s->aio == NULL) {
416             CloseHandle(s->hfile);
417             error_setg(errp, "Could not initialize AIO");
418             ret = -EINVAL;
419             goto fail;
420         }
421 
422         ret = win32_aio_attach(s->aio, s->hfile);
423         if (ret < 0) {
424             win32_aio_cleanup(s->aio);
425             CloseHandle(s->hfile);
426             error_setg_errno(errp, -ret, "Could not enable AIO");
427             goto fail;
428         }
429 
430         win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs));
431     }
432 
433     /* When extending regular files, we get zeros from the OS */
434     bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
435 
436     ret = 0;
437 fail:
438     qemu_opts_del(opts);
439     return ret;
440 }
441 
442 static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs,
443                                   int64_t offset, int64_t bytes,
444                                   QEMUIOVector *qiov, BdrvRequestFlags flags,
445                                   BlockCompletionFunc *cb, void *opaque)
446 {
447     BDRVRawState *s = bs->opaque;
448     if (s->aio) {
449         return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov,
450                                 cb, opaque, QEMU_AIO_READ);
451     } else {
452         return paio_submit(bs, s->hfile, offset, qiov, bytes,
453                            cb, opaque, QEMU_AIO_READ);
454     }
455 }
456 
457 static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs,
458                                    int64_t offset, int64_t bytes,
459                                    QEMUIOVector *qiov, BdrvRequestFlags flags,
460                                    BlockCompletionFunc *cb, void *opaque)
461 {
462     BDRVRawState *s = bs->opaque;
463     if (s->aio) {
464         return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov,
465                                 cb, opaque, QEMU_AIO_WRITE);
466     } else {
467         return paio_submit(bs, s->hfile, offset, qiov, bytes,
468                            cb, opaque, QEMU_AIO_WRITE);
469     }
470 }
471 
472 static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
473                          BlockCompletionFunc *cb, void *opaque)
474 {
475     BDRVRawState *s = bs->opaque;
476     return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
477 }
478 
479 static void raw_close(BlockDriverState *bs)
480 {
481     BDRVRawState *s = bs->opaque;
482 
483     if (s->aio) {
484         win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs));
485         win32_aio_cleanup(s->aio);
486         s->aio = NULL;
487     }
488 
489     CloseHandle(s->hfile);
490     if (bs->open_flags & BDRV_O_TEMPORARY) {
491         unlink(bs->filename);
492     }
493 }
494 
495 static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
496                                         bool exact, PreallocMode prealloc,
497                                         BdrvRequestFlags flags, Error **errp)
498 {
499     BDRVRawState *s = bs->opaque;
500     LONG low, high;
501     DWORD dwPtrLow;
502 
503     if (prealloc != PREALLOC_MODE_OFF) {
504         error_setg(errp, "Unsupported preallocation mode '%s'",
505                    PreallocMode_str(prealloc));
506         return -ENOTSUP;
507     }
508 
509     low = offset;
510     high = offset >> 32;
511 
512     /*
513      * An error has occurred if the return value is INVALID_SET_FILE_POINTER
514      * and GetLastError doesn't return NO_ERROR.
515      */
516     dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN);
517     if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
518         error_setg_win32(errp, GetLastError(), "SetFilePointer error");
519         return -EIO;
520     }
521     if (SetEndOfFile(s->hfile) == 0) {
522         error_setg_win32(errp, GetLastError(), "SetEndOfFile error");
523         return -EIO;
524     }
525     return 0;
526 }
527 
528 static int64_t raw_getlength(BlockDriverState *bs)
529 {
530     BDRVRawState *s = bs->opaque;
531     LARGE_INTEGER l;
532     ULARGE_INTEGER available, total, total_free;
533     DISK_GEOMETRY_EX dg;
534     DWORD count;
535     BOOL status;
536 
537     switch(s->type) {
538     case FTYPE_FILE:
539         l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
540         if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
541             return -EIO;
542         break;
543     case FTYPE_CD:
544         if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
545             return -EIO;
546         l.QuadPart = total.QuadPart;
547         break;
548     case FTYPE_HARDDISK:
549         status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
550                                  NULL, 0, &dg, sizeof(dg), &count, NULL);
551         if (status != 0) {
552             l = dg.DiskSize;
553         }
554         break;
555     default:
556         return -EIO;
557     }
558     return l.QuadPart;
559 }
560 
561 static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
562 {
563     typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
564                                               DWORD * high);
565     get_compressed_t get_compressed;
566     struct _stati64 st;
567     const char *filename = bs->filename;
568     /* WinNT support GetCompressedFileSize to determine allocate size */
569     get_compressed =
570         (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
571                                             "GetCompressedFileSizeA");
572     if (get_compressed) {
573         DWORD high, low;
574         low = get_compressed(filename, &high);
575         if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
576             return (((int64_t) high) << 32) + low;
577         }
578     }
579 
580     if (_stati64(filename, &st) < 0) {
581         return -1;
582     }
583     return st.st_size;
584 }
585 
586 static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
587 {
588     BlockdevCreateOptionsFile *file_opts;
589     int fd;
590 
591     assert(options->driver == BLOCKDEV_DRIVER_FILE);
592     file_opts = &options->u.file;
593 
594     if (file_opts->has_preallocation) {
595         error_setg(errp, "Preallocation is not supported on Windows");
596         return -EINVAL;
597     }
598     if (file_opts->has_nocow) {
599         error_setg(errp, "nocow is not supported on Windows");
600         return -EINVAL;
601     }
602 
603     fd = qemu_create(file_opts->filename, O_WRONLY | O_TRUNC | O_BINARY,
604                      0644, errp);
605     if (fd < 0) {
606         return -EIO;
607     }
608     set_sparse(fd);
609     ftruncate(fd, file_opts->size);
610     qemu_close(fd);
611 
612     return 0;
613 }
614 
615 static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
616                                            const char *filename,
617                                            QemuOpts *opts,
618                                            Error **errp)
619 {
620     BlockdevCreateOptions options;
621     int64_t total_size = 0;
622 
623     strstart(filename, "file:", &filename);
624 
625     /* Read out options */
626     total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
627                           BDRV_SECTOR_SIZE);
628 
629     options = (BlockdevCreateOptions) {
630         .driver     = BLOCKDEV_DRIVER_FILE,
631         .u.file     = {
632             .filename           = (char *) filename,
633             .size               = total_size,
634             .has_preallocation  = false,
635             .has_nocow          = false,
636         },
637     };
638     return raw_co_create(&options, errp);
639 }
640 
641 static int raw_reopen_prepare(BDRVReopenState *state,
642                               BlockReopenQueue *queue, Error **errp)
643 {
644     BDRVRawState *s = state->bs->opaque;
645     BDRVRawReopenState *rs;
646     int access_flags;
647     DWORD overlapped;
648     int ret = 0;
649 
650     if (s->type != FTYPE_FILE) {
651         error_setg(errp, "Can only reopen files");
652         return -EINVAL;
653     }
654 
655     rs = g_new0(BDRVRawReopenState, 1);
656 
657     /*
658      * We do not support changing any options (only flags). By leaving
659      * all options in state->options, we tell the generic reopen code
660      * that we do not support changing any of them, so it will verify
661      * that their values did not change.
662      */
663 
664     raw_parse_flags(state->flags, s->aio != NULL, &access_flags, &overlapped);
665     rs->hfile = CreateFile(state->bs->filename, access_flags,
666                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
667                            OPEN_EXISTING, overlapped, NULL);
668 
669     if (rs->hfile == INVALID_HANDLE_VALUE) {
670         int err = GetLastError();
671 
672         error_setg_win32(errp, err, "Could not reopen '%s'",
673                          state->bs->filename);
674         if (err == ERROR_ACCESS_DENIED) {
675             ret = -EACCES;
676         } else {
677             ret = -EINVAL;
678         }
679         goto fail;
680     }
681 
682     if (s->aio) {
683         ret = win32_aio_attach(s->aio, rs->hfile);
684         if (ret < 0) {
685             error_setg_errno(errp, -ret, "Could not enable AIO");
686             CloseHandle(rs->hfile);
687             goto fail;
688         }
689     }
690 
691     state->opaque = rs;
692 
693     return 0;
694 
695 fail:
696     g_free(rs);
697     state->opaque = NULL;
698 
699     return ret;
700 }
701 
702 static void raw_reopen_commit(BDRVReopenState *state)
703 {
704     BDRVRawState *s = state->bs->opaque;
705     BDRVRawReopenState *rs = state->opaque;
706 
707     assert(rs != NULL);
708 
709     CloseHandle(s->hfile);
710     s->hfile = rs->hfile;
711 
712     g_free(rs);
713     state->opaque = NULL;
714 }
715 
716 static void raw_reopen_abort(BDRVReopenState *state)
717 {
718     BDRVRawReopenState *rs = state->opaque;
719 
720     if (!rs) {
721         return;
722     }
723 
724     if (rs->hfile != INVALID_HANDLE_VALUE) {
725         CloseHandle(rs->hfile);
726     }
727 
728     g_free(rs);
729     state->opaque = NULL;
730 }
731 
732 static QemuOptsList raw_create_opts = {
733     .name = "raw-create-opts",
734     .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
735     .desc = {
736         {
737             .name = BLOCK_OPT_SIZE,
738             .type = QEMU_OPT_SIZE,
739             .help = "Virtual disk size"
740         },
741         { /* end of list */ }
742     }
743 };
744 
745 BlockDriver bdrv_file = {
746     .format_name	= "file",
747     .protocol_name	= "file",
748     .instance_size	= sizeof(BDRVRawState),
749     .bdrv_needs_filename = true,
750     .bdrv_parse_filename = raw_parse_filename,
751     .bdrv_file_open     = raw_open,
752     .bdrv_refresh_limits = raw_probe_alignment,
753     .bdrv_close         = raw_close,
754     .bdrv_co_create_opts = raw_co_create_opts,
755     .bdrv_has_zero_init = bdrv_has_zero_init_1,
756 
757     .bdrv_reopen_prepare = raw_reopen_prepare,
758     .bdrv_reopen_commit  = raw_reopen_commit,
759     .bdrv_reopen_abort   = raw_reopen_abort,
760 
761     .bdrv_aio_preadv    = raw_aio_preadv,
762     .bdrv_aio_pwritev   = raw_aio_pwritev,
763     .bdrv_aio_flush     = raw_aio_flush,
764 
765     .bdrv_co_truncate   = raw_co_truncate,
766     .bdrv_getlength	= raw_getlength,
767     .bdrv_get_allocated_file_size
768                         = raw_get_allocated_file_size,
769 
770     .create_opts        = &raw_create_opts,
771 };
772 
773 /***********************************************/
774 /* host device */
775 
776 static int find_cdrom(char *cdrom_name, int cdrom_name_size)
777 {
778     char drives[256], *pdrv = drives;
779     UINT type;
780 
781     memset(drives, 0, sizeof(drives));
782     GetLogicalDriveStrings(sizeof(drives), drives);
783     while(pdrv[0] != '\0') {
784         type = GetDriveType(pdrv);
785         switch(type) {
786         case DRIVE_CDROM:
787             snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
788             return 0;
789             break;
790         }
791         pdrv += lstrlen(pdrv) + 1;
792     }
793     return -1;
794 }
795 
796 static int find_device_type(BlockDriverState *bs, const char *filename)
797 {
798     BDRVRawState *s = bs->opaque;
799     UINT type;
800     const char *p;
801 
802     if (strstart(filename, "\\\\.\\", &p) ||
803         strstart(filename, "//./", &p)) {
804         if (stristart(p, "PhysicalDrive", NULL))
805             return FTYPE_HARDDISK;
806         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
807         type = GetDriveType(s->drive_path);
808         switch (type) {
809         case DRIVE_REMOVABLE:
810         case DRIVE_FIXED:
811             return FTYPE_HARDDISK;
812         case DRIVE_CDROM:
813             return FTYPE_CD;
814         default:
815             return FTYPE_FILE;
816         }
817     } else {
818         return FTYPE_FILE;
819     }
820 }
821 
822 static int hdev_probe_device(const char *filename)
823 {
824     if (strstart(filename, "/dev/cdrom", NULL))
825         return 100;
826     if (is_windows_drive(filename))
827         return 100;
828     return 0;
829 }
830 
831 static void hdev_parse_filename(const char *filename, QDict *options,
832                                 Error **errp)
833 {
834     bdrv_parse_filename_strip_prefix(filename, "host_device:", options);
835 }
836 
837 static void hdev_refresh_limits(BlockDriverState *bs, Error **errp)
838 {
839     /* XXX Does Windows support AIO on less than 512-byte alignment? */
840     bs->bl.request_alignment = 512;
841 }
842 
843 static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
844                      Error **errp)
845 {
846     BDRVRawState *s = bs->opaque;
847     int access_flags, create_flags;
848     int ret = 0;
849     DWORD overlapped;
850     char device_name[64];
851 
852     Error *local_err = NULL;
853     const char *filename;
854     bool use_aio;
855 
856     QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0,
857                                       &error_abort);
858     if (!qemu_opts_absorb_qdict(opts, options, errp)) {
859         ret = -EINVAL;
860         goto done;
861     }
862 
863     filename = qemu_opt_get(opts, "filename");
864 
865     use_aio = get_aio_option(opts, flags, &local_err);
866     if (!local_err && use_aio) {
867         error_setg(&local_err, "AIO is not supported on Windows host devices");
868     }
869     if (local_err) {
870         error_propagate(errp, local_err);
871         ret = -EINVAL;
872         goto done;
873     }
874 
875     if (strstart(filename, "/dev/cdrom", NULL)) {
876         if (find_cdrom(device_name, sizeof(device_name)) < 0) {
877             error_setg(errp, "Could not open CD-ROM drive");
878             ret = -ENOENT;
879             goto done;
880         }
881         filename = device_name;
882     } else {
883         /* transform drive letters into device name */
884         if (((filename[0] >= 'a' && filename[0] <= 'z') ||
885              (filename[0] >= 'A' && filename[0] <= 'Z')) &&
886             filename[1] == ':' && filename[2] == '\0') {
887             snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
888             filename = device_name;
889         }
890     }
891     s->type = find_device_type(bs, filename);
892 
893     raw_parse_flags(flags, use_aio, &access_flags, &overlapped);
894 
895     create_flags = OPEN_EXISTING;
896 
897     s->hfile = CreateFile(filename, access_flags,
898                           FILE_SHARE_READ, NULL,
899                           create_flags, overlapped, NULL);
900     if (s->hfile == INVALID_HANDLE_VALUE) {
901         int err = GetLastError();
902 
903         if (err == ERROR_ACCESS_DENIED) {
904             ret = -EACCES;
905         } else {
906             ret = -EINVAL;
907         }
908         error_setg_errno(errp, -ret, "Could not open device");
909         goto done;
910     }
911 
912 done:
913     qemu_opts_del(opts);
914     return ret;
915 }
916 
917 static BlockDriver bdrv_host_device = {
918     .format_name	= "host_device",
919     .protocol_name	= "host_device",
920     .instance_size	= sizeof(BDRVRawState),
921     .bdrv_needs_filename = true,
922     .bdrv_parse_filename = hdev_parse_filename,
923     .bdrv_probe_device	= hdev_probe_device,
924     .bdrv_file_open	= hdev_open,
925     .bdrv_close		= raw_close,
926     .bdrv_refresh_limits = hdev_refresh_limits,
927 
928     .bdrv_aio_preadv    = raw_aio_preadv,
929     .bdrv_aio_pwritev   = raw_aio_pwritev,
930     .bdrv_aio_flush     = raw_aio_flush,
931 
932     .bdrv_detach_aio_context = raw_detach_aio_context,
933     .bdrv_attach_aio_context = raw_attach_aio_context,
934 
935     .bdrv_getlength      = raw_getlength,
936     .has_variable_length = true,
937 
938     .bdrv_get_allocated_file_size
939                         = raw_get_allocated_file_size,
940 };
941 
942 static void bdrv_file_init(void)
943 {
944     bdrv_register(&bdrv_file);
945     bdrv_register(&bdrv_host_device);
946 }
947 
948 block_init(bdrv_file_init);
949