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 39fc4edb84SPaolo Bonzini typedef struct RawWin32AIOData { 40fc4edb84SPaolo Bonzini BlockDriverState *bs; 41fc4edb84SPaolo Bonzini HANDLE hfile; 42fc4edb84SPaolo Bonzini struct iovec *aio_iov; 43fc4edb84SPaolo Bonzini int aio_niov; 44fc4edb84SPaolo Bonzini size_t aio_nbytes; 45fc4edb84SPaolo Bonzini off64_t aio_offset; 46fc4edb84SPaolo Bonzini int aio_type; 47fc4edb84SPaolo Bonzini } RawWin32AIOData; 48fc4edb84SPaolo Bonzini 49223d4670Sths typedef struct BDRVRawState { 50223d4670Sths HANDLE hfile; 51223d4670Sths int type; 52223d4670Sths char drive_path[16]; /* format: "d:\" */ 53a2736526SPaolo Bonzini QEMUWin32AIOState *aio; 54223d4670Sths } BDRVRawState; 55223d4670Sths 56fc4edb84SPaolo Bonzini /* 57fc4edb84SPaolo Bonzini * Read/writes the data to/from a given linear buffer. 58fc4edb84SPaolo Bonzini * 59fc4edb84SPaolo Bonzini * Returns the number of bytes handles or -errno in case of an error. Short 60fc4edb84SPaolo Bonzini * reads are only returned if the end of the file is reached. 61fc4edb84SPaolo Bonzini */ 62fc4edb84SPaolo Bonzini static size_t handle_aiocb_rw(RawWin32AIOData *aiocb) 63fc4edb84SPaolo Bonzini { 64fc4edb84SPaolo Bonzini size_t offset = 0; 65fc4edb84SPaolo Bonzini int i; 66fc4edb84SPaolo Bonzini 67fc4edb84SPaolo Bonzini for (i = 0; i < aiocb->aio_niov; i++) { 68fc4edb84SPaolo Bonzini OVERLAPPED ov; 69fc4edb84SPaolo Bonzini DWORD ret, ret_count, len; 70fc4edb84SPaolo Bonzini 71fc4edb84SPaolo Bonzini memset(&ov, 0, sizeof(ov)); 72fc4edb84SPaolo Bonzini ov.Offset = (aiocb->aio_offset + offset); 73fc4edb84SPaolo Bonzini ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32; 74fc4edb84SPaolo Bonzini len = aiocb->aio_iov[i].iov_len; 75fc4edb84SPaolo Bonzini if (aiocb->aio_type & QEMU_AIO_WRITE) { 76fc4edb84SPaolo Bonzini ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base, 77fc4edb84SPaolo Bonzini len, &ret_count, &ov); 78fc4edb84SPaolo Bonzini } else { 79fc4edb84SPaolo Bonzini ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base, 80fc4edb84SPaolo Bonzini len, &ret_count, &ov); 81fc4edb84SPaolo Bonzini } 82fc4edb84SPaolo Bonzini if (!ret) { 83fc4edb84SPaolo Bonzini ret_count = 0; 84fc4edb84SPaolo Bonzini } 85fc4edb84SPaolo Bonzini if (ret_count != len) { 8656e023afSTal Kain offset += ret_count; 87fc4edb84SPaolo Bonzini break; 88fc4edb84SPaolo Bonzini } 89fc4edb84SPaolo Bonzini offset += len; 90fc4edb84SPaolo Bonzini } 91fc4edb84SPaolo Bonzini 92fc4edb84SPaolo Bonzini return offset; 93fc4edb84SPaolo Bonzini } 94fc4edb84SPaolo Bonzini 95fc4edb84SPaolo Bonzini static int aio_worker(void *arg) 96fc4edb84SPaolo Bonzini { 97fc4edb84SPaolo Bonzini RawWin32AIOData *aiocb = arg; 98fc4edb84SPaolo Bonzini ssize_t ret = 0; 99fc4edb84SPaolo Bonzini size_t count; 100fc4edb84SPaolo Bonzini 101fc4edb84SPaolo Bonzini switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) { 102fc4edb84SPaolo Bonzini case QEMU_AIO_READ: 103fc4edb84SPaolo Bonzini count = handle_aiocb_rw(aiocb); 104fc4edb84SPaolo Bonzini if (count < aiocb->aio_nbytes && aiocb->bs->growable) { 105fc4edb84SPaolo Bonzini /* A short read means that we have reached EOF. Pad the buffer 106fc4edb84SPaolo Bonzini * with zeros for bytes after EOF. */ 107fc4edb84SPaolo Bonzini iov_memset(aiocb->aio_iov, aiocb->aio_niov, count, 108fc4edb84SPaolo Bonzini 0, aiocb->aio_nbytes - count); 109fc4edb84SPaolo Bonzini 110fc4edb84SPaolo Bonzini count = aiocb->aio_nbytes; 111fc4edb84SPaolo Bonzini } 112fc4edb84SPaolo Bonzini if (count == aiocb->aio_nbytes) { 113fc4edb84SPaolo Bonzini ret = 0; 114fc4edb84SPaolo Bonzini } else { 115fc4edb84SPaolo Bonzini ret = -EINVAL; 116fc4edb84SPaolo Bonzini } 117fc4edb84SPaolo Bonzini break; 118fc4edb84SPaolo Bonzini case QEMU_AIO_WRITE: 119fc4edb84SPaolo Bonzini count = handle_aiocb_rw(aiocb); 120fc4edb84SPaolo Bonzini if (count == aiocb->aio_nbytes) { 121fc4edb84SPaolo Bonzini count = 0; 122fc4edb84SPaolo Bonzini } else { 123fc4edb84SPaolo Bonzini count = -EINVAL; 124fc4edb84SPaolo Bonzini } 125fc4edb84SPaolo Bonzini break; 126fc4edb84SPaolo Bonzini case QEMU_AIO_FLUSH: 127fc4edb84SPaolo Bonzini if (!FlushFileBuffers(aiocb->hfile)) { 128fc4edb84SPaolo Bonzini return -EIO; 129fc4edb84SPaolo Bonzini } 130fc4edb84SPaolo Bonzini break; 131fc4edb84SPaolo Bonzini default: 132fc4edb84SPaolo Bonzini fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); 133fc4edb84SPaolo Bonzini ret = -EINVAL; 134fc4edb84SPaolo Bonzini break; 135fc4edb84SPaolo Bonzini } 136fc4edb84SPaolo Bonzini 137fc4edb84SPaolo Bonzini g_slice_free(RawWin32AIOData, aiocb); 138fc4edb84SPaolo Bonzini return ret; 139fc4edb84SPaolo Bonzini } 140fc4edb84SPaolo Bonzini 1417c84b1b8SMarkus Armbruster static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, 142fc4edb84SPaolo Bonzini int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 143097310b5SMarkus Armbruster BlockCompletionFunc *cb, void *opaque, int type) 144fc4edb84SPaolo Bonzini { 145fc4edb84SPaolo Bonzini RawWin32AIOData *acb = g_slice_new(RawWin32AIOData); 146c4d9d196SStefan Hajnoczi ThreadPool *pool; 147fc4edb84SPaolo Bonzini 148fc4edb84SPaolo Bonzini acb->bs = bs; 149fc4edb84SPaolo Bonzini acb->hfile = hfile; 150fc4edb84SPaolo Bonzini acb->aio_type = type; 151fc4edb84SPaolo Bonzini 152fc4edb84SPaolo Bonzini if (qiov) { 153fc4edb84SPaolo Bonzini acb->aio_iov = qiov->iov; 154fc4edb84SPaolo Bonzini acb->aio_niov = qiov->niov; 155fc4edb84SPaolo Bonzini } 156fc4edb84SPaolo Bonzini acb->aio_nbytes = nb_sectors * 512; 157fc4edb84SPaolo Bonzini acb->aio_offset = sector_num * 512; 158fc4edb84SPaolo Bonzini 159fc4edb84SPaolo Bonzini trace_paio_submit(acb, opaque, sector_num, nb_sectors, type); 160c4d9d196SStefan Hajnoczi pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); 161c4d9d196SStefan Hajnoczi return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); 162fc4edb84SPaolo Bonzini } 163fc4edb84SPaolo Bonzini 164223d4670Sths int qemu_ftruncate64(int fd, int64_t length) 165223d4670Sths { 166223d4670Sths LARGE_INTEGER li; 1672c993ec2SStefan Weil DWORD dw; 168223d4670Sths LONG high; 169223d4670Sths HANDLE h; 170223d4670Sths BOOL res; 171223d4670Sths 172223d4670Sths if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) 173223d4670Sths return -1; 174223d4670Sths 175223d4670Sths h = (HANDLE)_get_osfhandle(fd); 176223d4670Sths 177223d4670Sths /* get current position, ftruncate do not change position */ 178223d4670Sths li.HighPart = 0; 179223d4670Sths li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); 1802c993ec2SStefan Weil if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 181223d4670Sths return -1; 1822c993ec2SStefan Weil } 183223d4670Sths 184223d4670Sths high = length >> 32; 1852c993ec2SStefan Weil dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN); 1862c993ec2SStefan Weil if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 187223d4670Sths return -1; 1882c993ec2SStefan Weil } 189223d4670Sths res = SetEndOfFile(h); 190223d4670Sths 191223d4670Sths /* back to old position */ 192223d4670Sths SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); 193223d4670Sths return res ? 0 : -1; 194223d4670Sths } 195223d4670Sths 196223d4670Sths static int set_sparse(int fd) 197223d4670Sths { 198223d4670Sths DWORD returned; 199223d4670Sths return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, 200223d4670Sths NULL, 0, NULL, 0, &returned, NULL); 201223d4670Sths } 202223d4670Sths 20385ebd381SStefan Hajnoczi static void raw_detach_aio_context(BlockDriverState *bs) 20485ebd381SStefan Hajnoczi { 20585ebd381SStefan Hajnoczi BDRVRawState *s = bs->opaque; 20685ebd381SStefan Hajnoczi 20785ebd381SStefan Hajnoczi if (s->aio) { 20885ebd381SStefan Hajnoczi win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); 20985ebd381SStefan Hajnoczi } 21085ebd381SStefan Hajnoczi } 21185ebd381SStefan Hajnoczi 21285ebd381SStefan Hajnoczi static void raw_attach_aio_context(BlockDriverState *bs, 21385ebd381SStefan Hajnoczi AioContext *new_context) 21485ebd381SStefan Hajnoczi { 21585ebd381SStefan Hajnoczi BDRVRawState *s = bs->opaque; 21685ebd381SStefan Hajnoczi 21785ebd381SStefan Hajnoczi if (s->aio) { 21885ebd381SStefan Hajnoczi win32_aio_attach_aio_context(s->aio, new_context); 21985ebd381SStefan Hajnoczi } 22085ebd381SStefan Hajnoczi } 22185ebd381SStefan Hajnoczi 222c25f53b0SPaolo Bonzini static void raw_probe_alignment(BlockDriverState *bs) 223c25f53b0SPaolo Bonzini { 224c25f53b0SPaolo Bonzini BDRVRawState *s = bs->opaque; 225c25f53b0SPaolo Bonzini DWORD sectorsPerCluster, freeClusters, totalClusters, count; 226c25f53b0SPaolo Bonzini DISK_GEOMETRY_EX dg; 227c25f53b0SPaolo Bonzini BOOL status; 228c25f53b0SPaolo Bonzini 229c25f53b0SPaolo Bonzini if (s->type == FTYPE_CD) { 230c25f53b0SPaolo Bonzini bs->request_alignment = 2048; 231c25f53b0SPaolo Bonzini return; 232c25f53b0SPaolo Bonzini } 233c25f53b0SPaolo Bonzini if (s->type == FTYPE_HARDDISK) { 234c25f53b0SPaolo Bonzini status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 235c25f53b0SPaolo Bonzini NULL, 0, &dg, sizeof(dg), &count, NULL); 236c25f53b0SPaolo Bonzini if (status != 0) { 237c25f53b0SPaolo Bonzini bs->request_alignment = dg.Geometry.BytesPerSector; 238c25f53b0SPaolo Bonzini return; 239c25f53b0SPaolo Bonzini } 240c25f53b0SPaolo Bonzini /* try GetDiskFreeSpace too */ 241c25f53b0SPaolo Bonzini } 242c25f53b0SPaolo Bonzini 243c25f53b0SPaolo Bonzini if (s->drive_path[0]) { 244c25f53b0SPaolo Bonzini GetDiskFreeSpace(s->drive_path, §orsPerCluster, 245c25f53b0SPaolo Bonzini &dg.Geometry.BytesPerSector, 246c25f53b0SPaolo Bonzini &freeClusters, &totalClusters); 247c25f53b0SPaolo Bonzini bs->request_alignment = dg.Geometry.BytesPerSector; 248c25f53b0SPaolo Bonzini } 249c25f53b0SPaolo Bonzini } 250c25f53b0SPaolo Bonzini 2516a8dc042SJeff Cody static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped) 2526a8dc042SJeff Cody { 2536a8dc042SJeff Cody assert(access_flags != NULL); 2546a8dc042SJeff Cody assert(overlapped != NULL); 2556a8dc042SJeff Cody 2566a8dc042SJeff Cody if (flags & BDRV_O_RDWR) { 2576a8dc042SJeff Cody *access_flags = GENERIC_READ | GENERIC_WRITE; 2586a8dc042SJeff Cody } else { 2596a8dc042SJeff Cody *access_flags = GENERIC_READ; 2606a8dc042SJeff Cody } 2616a8dc042SJeff Cody 2626a8dc042SJeff Cody *overlapped = FILE_ATTRIBUTE_NORMAL; 263a2736526SPaolo Bonzini if (flags & BDRV_O_NATIVE_AIO) { 264a2736526SPaolo Bonzini *overlapped |= FILE_FLAG_OVERLAPPED; 265a2736526SPaolo Bonzini } 2666a8dc042SJeff Cody if (flags & BDRV_O_NOCACHE) { 2676a8dc042SJeff Cody *overlapped |= FILE_FLAG_NO_BUFFERING; 2686a8dc042SJeff Cody } 2696a8dc042SJeff Cody } 2706a8dc042SJeff Cody 2717dc74db8SMax Reitz static void raw_parse_filename(const char *filename, QDict *options, 2727dc74db8SMax Reitz Error **errp) 2737dc74db8SMax Reitz { 2747dc74db8SMax Reitz /* The filename does not have to be prefixed by the protocol name, since 2757dc74db8SMax Reitz * "file" is the default protocol; therefore, the return value of this 2767dc74db8SMax Reitz * function call can be ignored. */ 2777dc74db8SMax Reitz strstart(filename, "file:", &filename); 2787dc74db8SMax Reitz 2797dc74db8SMax Reitz qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); 2807dc74db8SMax Reitz } 2817dc74db8SMax Reitz 2828a79380bSKevin Wolf static QemuOptsList raw_runtime_opts = { 2838a79380bSKevin Wolf .name = "raw", 2848a79380bSKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head), 2858a79380bSKevin Wolf .desc = { 2868a79380bSKevin Wolf { 2878a79380bSKevin Wolf .name = "filename", 2888a79380bSKevin Wolf .type = QEMU_OPT_STRING, 2898a79380bSKevin Wolf .help = "File name of the image", 2908a79380bSKevin Wolf }, 2918a79380bSKevin Wolf { /* end of list */ } 2928a79380bSKevin Wolf }, 2938a79380bSKevin Wolf }; 2948a79380bSKevin Wolf 295015a1036SMax Reitz static int raw_open(BlockDriverState *bs, QDict *options, int flags, 296015a1036SMax Reitz Error **errp) 297223d4670Sths { 298223d4670Sths BDRVRawState *s = bs->opaque; 2999a2d77adSChristoph Hellwig int access_flags; 300223d4670Sths DWORD overlapped; 3018a79380bSKevin Wolf QemuOpts *opts; 3028a79380bSKevin Wolf Error *local_err = NULL; 3038a79380bSKevin Wolf const char *filename; 3048a79380bSKevin Wolf int ret; 305223d4670Sths 306223d4670Sths s->type = FTYPE_FILE; 307223d4670Sths 30887ea75d5SPeter Crosthwaite opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); 3098a79380bSKevin Wolf qemu_opts_absorb_qdict(opts, options, &local_err); 31084d18f06SMarkus Armbruster if (local_err) { 311c6252b7cSMax Reitz error_propagate(errp, local_err); 3128a79380bSKevin Wolf ret = -EINVAL; 3138a79380bSKevin Wolf goto fail; 3148a79380bSKevin Wolf } 3158a79380bSKevin Wolf 3168a79380bSKevin Wolf filename = qemu_opt_get(opts, "filename"); 3178a79380bSKevin Wolf 3186a8dc042SJeff Cody raw_parse_flags(flags, &access_flags, &overlapped); 3199a2d77adSChristoph Hellwig 320c25f53b0SPaolo Bonzini if (filename[0] && filename[1] == ':') { 321c25f53b0SPaolo Bonzini snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]); 322c25f53b0SPaolo Bonzini } else if (filename[0] == '\\' && filename[1] == '\\') { 323c25f53b0SPaolo Bonzini s->drive_path[0] = 0; 324c25f53b0SPaolo Bonzini } else { 325c25f53b0SPaolo Bonzini /* Relative path. */ 326c25f53b0SPaolo Bonzini char buf[MAX_PATH]; 327c25f53b0SPaolo Bonzini GetCurrentDirectory(MAX_PATH, buf); 328c25f53b0SPaolo Bonzini snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]); 329c25f53b0SPaolo Bonzini } 330c25f53b0SPaolo Bonzini 331223d4670Sths s->hfile = CreateFile(filename, access_flags, 332223d4670Sths FILE_SHARE_READ, NULL, 3339a2d77adSChristoph Hellwig OPEN_EXISTING, overlapped, NULL); 334223d4670Sths if (s->hfile == INVALID_HANDLE_VALUE) { 335223d4670Sths int err = GetLastError(); 336223d4670Sths 3378a79380bSKevin Wolf if (err == ERROR_ACCESS_DENIED) { 3388a79380bSKevin Wolf ret = -EACCES; 3398a79380bSKevin Wolf } else { 3408a79380bSKevin Wolf ret = -EINVAL; 3418a79380bSKevin Wolf } 3428a79380bSKevin Wolf goto fail; 343a2736526SPaolo Bonzini } 344a2736526SPaolo Bonzini 345a2736526SPaolo Bonzini if (flags & BDRV_O_NATIVE_AIO) { 34699cc5989SStefan Hajnoczi s->aio = win32_aio_init(); 34799cc5989SStefan Hajnoczi if (s->aio == NULL) { 34899cc5989SStefan Hajnoczi CloseHandle(s->hfile); 34999cc5989SStefan Hajnoczi error_setg(errp, "Could not initialize AIO"); 35099cc5989SStefan Hajnoczi ret = -EINVAL; 35199cc5989SStefan Hajnoczi goto fail; 35299cc5989SStefan Hajnoczi } 35399cc5989SStefan Hajnoczi 35499cc5989SStefan Hajnoczi ret = win32_aio_attach(s->aio, s->hfile); 355a2736526SPaolo Bonzini if (ret < 0) { 35699cc5989SStefan Hajnoczi win32_aio_cleanup(s->aio); 357a2736526SPaolo Bonzini CloseHandle(s->hfile); 358c6252b7cSMax Reitz error_setg_errno(errp, -ret, "Could not enable AIO"); 3598a79380bSKevin Wolf goto fail; 360a2736526SPaolo Bonzini } 36185ebd381SStefan Hajnoczi 36285ebd381SStefan Hajnoczi win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs)); 363223d4670Sths } 3648a79380bSKevin Wolf 365c25f53b0SPaolo Bonzini raw_probe_alignment(bs); 3668a79380bSKevin Wolf ret = 0; 3678a79380bSKevin Wolf fail: 3688a79380bSKevin Wolf qemu_opts_del(opts); 3698a79380bSKevin Wolf return ret; 370223d4670Sths } 371223d4670Sths 3727c84b1b8SMarkus Armbruster static BlockAIOCB *raw_aio_readv(BlockDriverState *bs, 373fc4edb84SPaolo Bonzini int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 374097310b5SMarkus Armbruster BlockCompletionFunc *cb, void *opaque) 375223d4670Sths { 376223d4670Sths BDRVRawState *s = bs->opaque; 377a2736526SPaolo Bonzini if (s->aio) { 378a2736526SPaolo Bonzini return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov, 379a2736526SPaolo Bonzini nb_sectors, cb, opaque, QEMU_AIO_READ); 380a2736526SPaolo Bonzini } else { 381fc4edb84SPaolo Bonzini return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors, 382fc4edb84SPaolo Bonzini cb, opaque, QEMU_AIO_READ); 383223d4670Sths } 384a2736526SPaolo Bonzini } 385223d4670Sths 3867c84b1b8SMarkus Armbruster static BlockAIOCB *raw_aio_writev(BlockDriverState *bs, 387fc4edb84SPaolo Bonzini int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 388097310b5SMarkus Armbruster BlockCompletionFunc *cb, void *opaque) 389223d4670Sths { 390223d4670Sths BDRVRawState *s = bs->opaque; 391a2736526SPaolo Bonzini if (s->aio) { 392a2736526SPaolo Bonzini return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov, 393a2736526SPaolo Bonzini nb_sectors, cb, opaque, QEMU_AIO_WRITE); 394a2736526SPaolo Bonzini } else { 395fc4edb84SPaolo Bonzini return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors, 396fc4edb84SPaolo Bonzini cb, opaque, QEMU_AIO_WRITE); 397223d4670Sths } 398a2736526SPaolo Bonzini } 399223d4670Sths 4007c84b1b8SMarkus Armbruster static BlockAIOCB *raw_aio_flush(BlockDriverState *bs, 401097310b5SMarkus Armbruster BlockCompletionFunc *cb, void *opaque) 402223d4670Sths { 403223d4670Sths BDRVRawState *s = bs->opaque; 404fc4edb84SPaolo Bonzini return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH); 405223d4670Sths } 406223d4670Sths 407223d4670Sths static void raw_close(BlockDriverState *bs) 408223d4670Sths { 409223d4670Sths BDRVRawState *s = bs->opaque; 41099cc5989SStefan Hajnoczi 41199cc5989SStefan Hajnoczi if (s->aio) { 41285ebd381SStefan Hajnoczi win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); 41399cc5989SStefan Hajnoczi win32_aio_cleanup(s->aio); 41499cc5989SStefan Hajnoczi s->aio = NULL; 41599cc5989SStefan Hajnoczi } 41699cc5989SStefan Hajnoczi 417223d4670Sths CloseHandle(s->hfile); 4188bfea15dSKevin Wolf if (bs->open_flags & BDRV_O_TEMPORARY) { 4198bfea15dSKevin Wolf unlink(bs->filename); 4208bfea15dSKevin Wolf } 421223d4670Sths } 422223d4670Sths 423223d4670Sths static int raw_truncate(BlockDriverState *bs, int64_t offset) 424223d4670Sths { 425223d4670Sths BDRVRawState *s = bs->opaque; 426b9e82a59Sblueswir1 LONG low, high; 427fbcad04dSFabien Chouteau DWORD dwPtrLow; 428223d4670Sths 429223d4670Sths low = offset; 430223d4670Sths high = offset >> 32; 431fbcad04dSFabien Chouteau 432fbcad04dSFabien Chouteau /* 433fbcad04dSFabien Chouteau * An error has occurred if the return value is INVALID_SET_FILE_POINTER 434fbcad04dSFabien Chouteau * and GetLastError doesn't return NO_ERROR. 435fbcad04dSFabien Chouteau */ 436fbcad04dSFabien Chouteau dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN); 437fbcad04dSFabien Chouteau if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { 438fccedc62SStefan Weil fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError()); 439223d4670Sths return -EIO; 440fbcad04dSFabien Chouteau } 441fbcad04dSFabien Chouteau if (SetEndOfFile(s->hfile) == 0) { 442fccedc62SStefan Weil fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError()); 443223d4670Sths return -EIO; 444fbcad04dSFabien Chouteau } 445223d4670Sths return 0; 446223d4670Sths } 447223d4670Sths 448223d4670Sths static int64_t raw_getlength(BlockDriverState *bs) 449223d4670Sths { 450223d4670Sths BDRVRawState *s = bs->opaque; 451223d4670Sths LARGE_INTEGER l; 452223d4670Sths ULARGE_INTEGER available, total, total_free; 453223d4670Sths DISK_GEOMETRY_EX dg; 454223d4670Sths DWORD count; 455223d4670Sths BOOL status; 456223d4670Sths 457223d4670Sths switch(s->type) { 458223d4670Sths case FTYPE_FILE: 459b9e82a59Sblueswir1 l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); 460223d4670Sths if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) 461223d4670Sths return -EIO; 462223d4670Sths break; 463223d4670Sths case FTYPE_CD: 464223d4670Sths if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) 465223d4670Sths return -EIO; 466223d4670Sths l.QuadPart = total.QuadPart; 467223d4670Sths break; 468223d4670Sths case FTYPE_HARDDISK: 469223d4670Sths status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 470223d4670Sths NULL, 0, &dg, sizeof(dg), &count, NULL); 471223d4670Sths if (status != 0) { 472223d4670Sths l = dg.DiskSize; 473223d4670Sths } 474223d4670Sths break; 475223d4670Sths default: 476223d4670Sths return -EIO; 477223d4670Sths } 478223d4670Sths return l.QuadPart; 479223d4670Sths } 480223d4670Sths 4814a1d5e1fSFam Zheng static int64_t raw_get_allocated_file_size(BlockDriverState *bs) 4824a1d5e1fSFam Zheng { 4834a1d5e1fSFam Zheng typedef DWORD (WINAPI * get_compressed_t)(const char *filename, 4844a1d5e1fSFam Zheng DWORD * high); 4854a1d5e1fSFam Zheng get_compressed_t get_compressed; 4864a1d5e1fSFam Zheng struct _stati64 st; 4874a1d5e1fSFam Zheng const char *filename = bs->filename; 4884a1d5e1fSFam Zheng /* WinNT support GetCompressedFileSize to determine allocate size */ 4894a1d5e1fSFam Zheng get_compressed = 4904a1d5e1fSFam Zheng (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), 4914a1d5e1fSFam Zheng "GetCompressedFileSizeA"); 4924a1d5e1fSFam Zheng if (get_compressed) { 4934a1d5e1fSFam Zheng DWORD high, low; 4944a1d5e1fSFam Zheng low = get_compressed(filename, &high); 4954a1d5e1fSFam Zheng if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) { 4964a1d5e1fSFam Zheng return (((int64_t) high) << 32) + low; 4974a1d5e1fSFam Zheng } 4984a1d5e1fSFam Zheng } 4994a1d5e1fSFam Zheng 5004a1d5e1fSFam Zheng if (_stati64(filename, &st) < 0) { 5014a1d5e1fSFam Zheng return -1; 5024a1d5e1fSFam Zheng } 5034a1d5e1fSFam Zheng return st.st_size; 5044a1d5e1fSFam Zheng } 5054a1d5e1fSFam Zheng 506ddef7699SChunyan Liu static int raw_create(const char *filename, QemuOpts *opts, Error **errp) 507223d4670Sths { 508223d4670Sths int fd; 5090e7e1989SKevin Wolf int64_t total_size = 0; 510223d4670Sths 511d5546c5eSMax Reitz strstart(filename, "file:", &filename); 512d5546c5eSMax Reitz 5130e7e1989SKevin Wolf /* Read out options */ 514180e9526SHu Tao total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 515c2eb918eSHu Tao BDRV_SECTOR_SIZE); 516223d4670Sths 5176165f4d8SCorey Bryant fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 518223d4670Sths 0644); 519c6252b7cSMax Reitz if (fd < 0) { 520c6252b7cSMax Reitz error_setg_errno(errp, errno, "Could not create file"); 521223d4670Sths return -EIO; 522c6252b7cSMax Reitz } 523223d4670Sths set_sparse(fd); 524180e9526SHu Tao ftruncate(fd, total_size); 5252e1e79daSCorey Bryant qemu_close(fd); 526223d4670Sths return 0; 527223d4670Sths } 528223d4670Sths 529ddef7699SChunyan Liu 530ddef7699SChunyan Liu static QemuOptsList raw_create_opts = { 531ddef7699SChunyan Liu .name = "raw-create-opts", 532ddef7699SChunyan Liu .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), 533ddef7699SChunyan Liu .desc = { 534db08adf5SKevin Wolf { 535db08adf5SKevin Wolf .name = BLOCK_OPT_SIZE, 536ddef7699SChunyan Liu .type = QEMU_OPT_SIZE, 537db08adf5SKevin Wolf .help = "Virtual disk size" 538db08adf5SKevin Wolf }, 539ddef7699SChunyan Liu { /* end of list */ } 540ddef7699SChunyan Liu } 5410e7e1989SKevin Wolf }; 5420e7e1989SKevin Wolf 543*5f535a94SMax Reitz BlockDriver bdrv_file = { 54484a12e66SChristoph Hellwig .format_name = "file", 54584a12e66SChristoph Hellwig .protocol_name = "file", 546f1b2f712Saliguori .instance_size = sizeof(BDRVRawState), 547030be321SBenoît Canet .bdrv_needs_filename = true, 5487dc74db8SMax Reitz .bdrv_parse_filename = raw_parse_filename, 54966f82ceeSKevin Wolf .bdrv_file_open = raw_open, 550f1b2f712Saliguori .bdrv_close = raw_close, 551c282e1fdSChunyan Liu .bdrv_create = raw_create, 5523ac21627SPeter Lieven .bdrv_has_zero_init = bdrv_has_zero_init_1, 553c68b89acSKevin Wolf 554fc4edb84SPaolo Bonzini .bdrv_aio_readv = raw_aio_readv, 555fc4edb84SPaolo Bonzini .bdrv_aio_writev = raw_aio_writev, 556fc4edb84SPaolo Bonzini .bdrv_aio_flush = raw_aio_flush, 557c68b89acSKevin Wolf 558223d4670Sths .bdrv_truncate = raw_truncate, 559223d4670Sths .bdrv_getlength = raw_getlength, 5604a1d5e1fSFam Zheng .bdrv_get_allocated_file_size 5614a1d5e1fSFam Zheng = raw_get_allocated_file_size, 5620e7e1989SKevin Wolf 563ddef7699SChunyan Liu .create_opts = &raw_create_opts, 564223d4670Sths }; 565223d4670Sths 566223d4670Sths /***********************************************/ 567223d4670Sths /* host device */ 568223d4670Sths 569223d4670Sths static int find_cdrom(char *cdrom_name, int cdrom_name_size) 570223d4670Sths { 571223d4670Sths char drives[256], *pdrv = drives; 572223d4670Sths UINT type; 573223d4670Sths 574223d4670Sths memset(drives, 0, sizeof(drives)); 575223d4670Sths GetLogicalDriveStrings(sizeof(drives), drives); 576223d4670Sths while(pdrv[0] != '\0') { 577223d4670Sths type = GetDriveType(pdrv); 578223d4670Sths switch(type) { 579223d4670Sths case DRIVE_CDROM: 580223d4670Sths snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]); 581223d4670Sths return 0; 582223d4670Sths break; 583223d4670Sths } 584223d4670Sths pdrv += lstrlen(pdrv) + 1; 585223d4670Sths } 586223d4670Sths return -1; 587223d4670Sths } 588223d4670Sths 589223d4670Sths static int find_device_type(BlockDriverState *bs, const char *filename) 590223d4670Sths { 591223d4670Sths BDRVRawState *s = bs->opaque; 592223d4670Sths UINT type; 593223d4670Sths const char *p; 594223d4670Sths 595223d4670Sths if (strstart(filename, "\\\\.\\", &p) || 596223d4670Sths strstart(filename, "//./", &p)) { 597223d4670Sths if (stristart(p, "PhysicalDrive", NULL)) 598223d4670Sths return FTYPE_HARDDISK; 599223d4670Sths snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); 600223d4670Sths type = GetDriveType(s->drive_path); 6013060cd14Saliguori switch (type) { 6023060cd14Saliguori case DRIVE_REMOVABLE: 6033060cd14Saliguori case DRIVE_FIXED: 6043060cd14Saliguori return FTYPE_HARDDISK; 6053060cd14Saliguori case DRIVE_CDROM: 606223d4670Sths return FTYPE_CD; 6073060cd14Saliguori default: 608223d4670Sths return FTYPE_FILE; 6093060cd14Saliguori } 610223d4670Sths } else { 611223d4670Sths return FTYPE_FILE; 612223d4670Sths } 613223d4670Sths } 614223d4670Sths 615508c7cb3SChristoph Hellwig static int hdev_probe_device(const char *filename) 616508c7cb3SChristoph Hellwig { 617508c7cb3SChristoph Hellwig if (strstart(filename, "/dev/cdrom", NULL)) 618508c7cb3SChristoph Hellwig return 100; 619508c7cb3SChristoph Hellwig if (is_windows_drive(filename)) 620508c7cb3SChristoph Hellwig return 100; 621508c7cb3SChristoph Hellwig return 0; 622508c7cb3SChristoph Hellwig } 623508c7cb3SChristoph Hellwig 62457ed25b1SMax Reitz static void hdev_parse_filename(const char *filename, QDict *options, 62557ed25b1SMax Reitz Error **errp) 62657ed25b1SMax Reitz { 62757ed25b1SMax Reitz /* The prefix is optional, just as for "file". */ 62857ed25b1SMax Reitz strstart(filename, "host_device:", &filename); 62957ed25b1SMax Reitz 63057ed25b1SMax Reitz qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); 63157ed25b1SMax Reitz } 63257ed25b1SMax Reitz 633015a1036SMax Reitz static int hdev_open(BlockDriverState *bs, QDict *options, int flags, 634015a1036SMax Reitz Error **errp) 635223d4670Sths { 636223d4670Sths BDRVRawState *s = bs->opaque; 637223d4670Sths int access_flags, create_flags; 63868dc0364SStefan Weil int ret = 0; 639223d4670Sths DWORD overlapped; 640223d4670Sths char device_name[64]; 64168dc0364SStefan Weil 64268dc0364SStefan Weil Error *local_err = NULL; 64368dc0364SStefan Weil const char *filename; 64468dc0364SStefan Weil 64587ea75d5SPeter Crosthwaite QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, 64687ea75d5SPeter Crosthwaite &error_abort); 64768dc0364SStefan Weil qemu_opts_absorb_qdict(opts, options, &local_err); 64884d18f06SMarkus Armbruster if (local_err) { 649c6252b7cSMax Reitz error_propagate(errp, local_err); 65068dc0364SStefan Weil ret = -EINVAL; 65168dc0364SStefan Weil goto done; 65268dc0364SStefan Weil } 65368dc0364SStefan Weil 65468dc0364SStefan Weil filename = qemu_opt_get(opts, "filename"); 655223d4670Sths 656223d4670Sths if (strstart(filename, "/dev/cdrom", NULL)) { 65768dc0364SStefan Weil if (find_cdrom(device_name, sizeof(device_name)) < 0) { 658c6252b7cSMax Reitz error_setg(errp, "Could not open CD-ROM drive"); 65968dc0364SStefan Weil ret = -ENOENT; 66068dc0364SStefan Weil goto done; 66168dc0364SStefan Weil } 662223d4670Sths filename = device_name; 663223d4670Sths } else { 664223d4670Sths /* transform drive letters into device name */ 665223d4670Sths if (((filename[0] >= 'a' && filename[0] <= 'z') || 666223d4670Sths (filename[0] >= 'A' && filename[0] <= 'Z')) && 667223d4670Sths filename[1] == ':' && filename[2] == '\0') { 668223d4670Sths snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]); 669223d4670Sths filename = device_name; 670223d4670Sths } 671223d4670Sths } 672223d4670Sths s->type = find_device_type(bs, filename); 673223d4670Sths 6746a8dc042SJeff Cody raw_parse_flags(flags, &access_flags, &overlapped); 6756a8dc042SJeff Cody 676223d4670Sths create_flags = OPEN_EXISTING; 677223d4670Sths 678223d4670Sths s->hfile = CreateFile(filename, access_flags, 679223d4670Sths FILE_SHARE_READ, NULL, 680223d4670Sths create_flags, overlapped, NULL); 681223d4670Sths if (s->hfile == INVALID_HANDLE_VALUE) { 682223d4670Sths int err = GetLastError(); 683223d4670Sths 68468dc0364SStefan Weil if (err == ERROR_ACCESS_DENIED) { 68568dc0364SStefan Weil ret = -EACCES; 68668dc0364SStefan Weil } else { 68745d57f6eSMax Reitz ret = -EINVAL; 688223d4670Sths } 68945d57f6eSMax Reitz error_setg_errno(errp, -ret, "Could not open device"); 69068dc0364SStefan Weil goto done; 69168dc0364SStefan Weil } 69268dc0364SStefan Weil 69368dc0364SStefan Weil done: 69468dc0364SStefan Weil qemu_opts_del(opts); 69568dc0364SStefan Weil return ret; 696223d4670Sths } 697223d4670Sths 6985efa9d5aSAnthony Liguori static BlockDriver bdrv_host_device = { 699e60f469cSaurel32 .format_name = "host_device", 70084a12e66SChristoph Hellwig .protocol_name = "host_device", 701e60f469cSaurel32 .instance_size = sizeof(BDRVRawState), 702030be321SBenoît Canet .bdrv_needs_filename = true, 70357ed25b1SMax Reitz .bdrv_parse_filename = hdev_parse_filename, 704508c7cb3SChristoph Hellwig .bdrv_probe_device = hdev_probe_device, 70566f82ceeSKevin Wolf .bdrv_file_open = hdev_open, 706e60f469cSaurel32 .bdrv_close = raw_close, 707223d4670Sths 708fc4edb84SPaolo Bonzini .bdrv_aio_readv = raw_aio_readv, 709fc4edb84SPaolo Bonzini .bdrv_aio_writev = raw_aio_writev, 710fc4edb84SPaolo Bonzini .bdrv_aio_flush = raw_aio_flush, 711c68b89acSKevin Wolf 71285ebd381SStefan Hajnoczi .bdrv_detach_aio_context = raw_detach_aio_context, 71385ebd381SStefan Hajnoczi .bdrv_attach_aio_context = raw_attach_aio_context, 71485ebd381SStefan Hajnoczi 715223d4670Sths .bdrv_getlength = raw_getlength, 716b94a2610SKevin Wolf .has_variable_length = true, 717b94a2610SKevin Wolf 7184a1d5e1fSFam Zheng .bdrv_get_allocated_file_size 7194a1d5e1fSFam Zheng = raw_get_allocated_file_size, 720223d4670Sths }; 7215efa9d5aSAnthony Liguori 72284a12e66SChristoph Hellwig static void bdrv_file_init(void) 7235efa9d5aSAnthony Liguori { 72484a12e66SChristoph Hellwig bdrv_register(&bdrv_file); 7255efa9d5aSAnthony Liguori bdrv_register(&bdrv_host_device); 7265efa9d5aSAnthony Liguori } 7275efa9d5aSAnthony Liguori 72884a12e66SChristoph Hellwig block_init(bdrv_file_init); 729