cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

file-win32.c (27060B)


      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
     44typedef 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
     54typedef struct BDRVRawState {
     55    HANDLE hfile;
     56    int type;
     57    char drive_path[16]; /* format: "d:\" */
     58    QEMUWin32AIOState *aio;
     59} BDRVRawState;
     60
     61typedef 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 */
     71static 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
    104static 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
    150static 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
    174int 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
    206static 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
    213static 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
    222static 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
    232static 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
    265static 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
    286static void raw_parse_filename(const char *filename, QDict *options,
    287                               Error **errp)
    288{
    289    bdrv_parse_filename_strip_prefix(filename, "file:", options);
    290}
    291
    292static 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
    315static 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
    335static 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;
    437fail:
    438    qemu_opts_del(opts);
    439    return ret;
    440}
    441
    442static 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
    457static 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
    472static 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
    479static 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
    495static 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
    528static 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
    561static 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
    586static 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
    615static 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
    641static 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
    695fail:
    696    g_free(rs);
    697    state->opaque = NULL;
    698
    699    return ret;
    700}
    701
    702static 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
    716static 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
    732static 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
    745BlockDriver 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
    776static 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
    796static 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
    822static 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
    831static 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
    837static 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
    843static 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
    912done:
    913    qemu_opts_del(opts);
    914    return ret;
    915}
    916
    917static 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
    942static void bdrv_file_init(void)
    943{
    944    bdrv_register(&bdrv_file);
    945    bdrv_register(&bdrv_host_device);
    946}
    947
    948block_init(bdrv_file_init);