Loading block/vvfat.c +168 −60 Original line number Diff line number Diff line /* vim:set shiftwidth=4 ts=8: */ /* vim:set shiftwidth=4 ts=4: */ /* * QEMU Block driver for virtual VFAT (shadows a local directory) * Loading Loading @@ -28,6 +28,8 @@ #include "block/block_int.h" #include "qemu/module.h" #include "migration/migration.h" #include "qapi/qmp/qint.h" #include "qapi/qmp/qbool.h" #ifndef S_IWGRP #define S_IWGRP 0 Loading Loading @@ -988,11 +990,91 @@ static void vvfat_rebind(BlockDriverState *bs) s->bs = bs; } static int vvfat_open(BlockDriverState *bs, const char* dirname, static QemuOptsList runtime_opts = { .name = "vvfat", .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), .desc = { { .name = "dir", .type = QEMU_OPT_STRING, .help = "Host directory to map to the vvfat device", }, { .name = "fat-type", .type = QEMU_OPT_NUMBER, .help = "FAT type (12, 16 or 32)", }, { .name = "floppy", .type = QEMU_OPT_BOOL, .help = "Create a floppy rather than a hard disk image", }, { .name = "rw", .type = QEMU_OPT_BOOL, .help = "Make the image writable", }, { /* end of list */ } }, }; static void vvfat_parse_filename(const char *filename, QDict *options, Error **errp) { int fat_type = 0; bool floppy = false; bool rw = false; int i; if (!strstart(filename, "fat:", NULL)) { error_setg(errp, "File name string must start with 'fat:'"); return; } /* Parse options */ if (strstr(filename, ":32:")) { fat_type = 32; } else if (strstr(filename, ":16:")) { fat_type = 16; } else if (strstr(filename, ":12:")) { fat_type = 12; } if (strstr(filename, ":floppy:")) { floppy = true; } if (strstr(filename, ":rw:")) { rw = true; } /* Get the directory name without options */ i = strrchr(filename, ':') - filename; assert(i >= 3); if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) { /* workaround for DOS drive names */ filename += i - 1; } else { filename += i + 1; } /* Fill in the options QDict */ qdict_put(options, "dir", qstring_from_str(filename)); qdict_put(options, "fat-type", qint_from_int(fat_type)); qdict_put(options, "floppy", qbool_from_int(floppy)); qdict_put(options, "rw", qbool_from_int(rw)); } static int vvfat_open(BlockDriverState *bs, const char* dummy, QDict *options, int flags) { BDRVVVFATState *s = bs->opaque; int i, cyls, heads, secs; int cyls, heads, secs; bool floppy; const char *dirname; QemuOpts *opts; Error *local_err = NULL; int ret; #ifdef DEBUG vvv = s; Loading @@ -1003,34 +1085,27 @@ DLOG(if (stderr == NULL) { setbuf(stderr, NULL); }) s->bs = bs; /* LATER TODO: if FAT32, adjust */ s->sectors_per_cluster=0x10; s->current_cluster=0xffffffff; s->first_sectors_number=0x40; /* read only is the default for safety */ bs->read_only = 1; s->qcow = s->write_target = NULL; s->qcow_filename = NULL; s->fat2 = NULL; s->downcase_short_names = 1; if (!strstart(dirname, "fat:", NULL)) return -1; opts = qemu_opts_create_nofail(&runtime_opts); qemu_opts_absorb_qdict(opts, options, &local_err); if (error_is_set(&local_err)) { qerror_report_err(local_err); error_free(local_err); ret = -EINVAL; goto fail; } if (strstr(dirname, ":32:")) { fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); s->fat_type = 32; } else if (strstr(dirname, ":16:")) { s->fat_type = 16; } else if (strstr(dirname, ":12:")) { s->fat_type = 12; dirname = qemu_opt_get(opts, "dir"); if (!dirname) { qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires " "a 'dir' option"); ret = -EINVAL; goto fail; } if (strstr(dirname, ":floppy:")) { s->fat_type = qemu_opt_get_number(opts, "fat-type", 0); floppy = qemu_opt_get_bool(opts, "floppy", false); if (floppy) { /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */ if (!s->fat_type) { s->fat_type = 12; Loading @@ -1052,29 +1127,56 @@ DLOG(if (stderr == NULL) { heads = 16; secs = 63; } switch (s->fat_type) { case 32: fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. " "You are welcome to do so!\n"); break; case 16: case 12: break; default: qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only " "12, 16 and 32"); ret = -EINVAL; goto fail; } s->bs = bs; /* LATER TODO: if FAT32, adjust */ s->sectors_per_cluster=0x10; s->current_cluster=0xffffffff; s->first_sectors_number=0x40; /* read only is the default for safety */ bs->read_only = 1; s->qcow = s->write_target = NULL; s->qcow_filename = NULL; s->fat2 = NULL; s->downcase_short_names = 1; fprintf(stderr, "vvfat %s chs %d,%d,%d\n", dirname, cyls, heads, secs); s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); if (strstr(dirname, ":rw:")) { if (enable_write_target(s)) return -1; if (qemu_opt_get_bool(opts, "rw", false)) { if (enable_write_target(s)) { ret = -EIO; goto fail; } bs->read_only = 0; } i = strrchr(dirname, ':') - dirname; assert(i >= 3); if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1])) /* workaround for DOS drive names */ dirname += i-1; else dirname += i+1; bs->total_sectors = cyls * heads * secs; if (init_directories(s, dirname, heads, secs)) { return -1; ret = -EIO; goto fail; } s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count; Loading @@ -1094,7 +1196,10 @@ DLOG(if (stderr == NULL) { migrate_add_blocker(s->migration_blocker); } return 0; ret = 0; fail: qemu_opts_del(opts); return ret; } static inline void vvfat_close_current_file(BDRVVVFATState *s) Loading Loading @@ -2867,14 +2972,17 @@ static void vvfat_close(BlockDriverState *bs) static BlockDriver bdrv_vvfat = { .format_name = "vvfat", .protocol_name = "fat", .instance_size = sizeof(BDRVVVFATState), .bdrv_parse_filename = vvfat_parse_filename, .bdrv_file_open = vvfat_open, .bdrv_close = vvfat_close, .bdrv_rebind = vvfat_rebind, .bdrv_read = vvfat_co_read, .bdrv_write = vvfat_co_write, .bdrv_close = vvfat_close, .bdrv_co_is_allocated = vvfat_co_is_allocated, .protocol_name = "fat", }; static void bdrv_vvfat_init(void) Loading Loading
block/vvfat.c +168 −60 Original line number Diff line number Diff line /* vim:set shiftwidth=4 ts=8: */ /* vim:set shiftwidth=4 ts=4: */ /* * QEMU Block driver for virtual VFAT (shadows a local directory) * Loading Loading @@ -28,6 +28,8 @@ #include "block/block_int.h" #include "qemu/module.h" #include "migration/migration.h" #include "qapi/qmp/qint.h" #include "qapi/qmp/qbool.h" #ifndef S_IWGRP #define S_IWGRP 0 Loading Loading @@ -988,11 +990,91 @@ static void vvfat_rebind(BlockDriverState *bs) s->bs = bs; } static int vvfat_open(BlockDriverState *bs, const char* dirname, static QemuOptsList runtime_opts = { .name = "vvfat", .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), .desc = { { .name = "dir", .type = QEMU_OPT_STRING, .help = "Host directory to map to the vvfat device", }, { .name = "fat-type", .type = QEMU_OPT_NUMBER, .help = "FAT type (12, 16 or 32)", }, { .name = "floppy", .type = QEMU_OPT_BOOL, .help = "Create a floppy rather than a hard disk image", }, { .name = "rw", .type = QEMU_OPT_BOOL, .help = "Make the image writable", }, { /* end of list */ } }, }; static void vvfat_parse_filename(const char *filename, QDict *options, Error **errp) { int fat_type = 0; bool floppy = false; bool rw = false; int i; if (!strstart(filename, "fat:", NULL)) { error_setg(errp, "File name string must start with 'fat:'"); return; } /* Parse options */ if (strstr(filename, ":32:")) { fat_type = 32; } else if (strstr(filename, ":16:")) { fat_type = 16; } else if (strstr(filename, ":12:")) { fat_type = 12; } if (strstr(filename, ":floppy:")) { floppy = true; } if (strstr(filename, ":rw:")) { rw = true; } /* Get the directory name without options */ i = strrchr(filename, ':') - filename; assert(i >= 3); if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) { /* workaround for DOS drive names */ filename += i - 1; } else { filename += i + 1; } /* Fill in the options QDict */ qdict_put(options, "dir", qstring_from_str(filename)); qdict_put(options, "fat-type", qint_from_int(fat_type)); qdict_put(options, "floppy", qbool_from_int(floppy)); qdict_put(options, "rw", qbool_from_int(rw)); } static int vvfat_open(BlockDriverState *bs, const char* dummy, QDict *options, int flags) { BDRVVVFATState *s = bs->opaque; int i, cyls, heads, secs; int cyls, heads, secs; bool floppy; const char *dirname; QemuOpts *opts; Error *local_err = NULL; int ret; #ifdef DEBUG vvv = s; Loading @@ -1003,34 +1085,27 @@ DLOG(if (stderr == NULL) { setbuf(stderr, NULL); }) s->bs = bs; /* LATER TODO: if FAT32, adjust */ s->sectors_per_cluster=0x10; s->current_cluster=0xffffffff; s->first_sectors_number=0x40; /* read only is the default for safety */ bs->read_only = 1; s->qcow = s->write_target = NULL; s->qcow_filename = NULL; s->fat2 = NULL; s->downcase_short_names = 1; if (!strstart(dirname, "fat:", NULL)) return -1; opts = qemu_opts_create_nofail(&runtime_opts); qemu_opts_absorb_qdict(opts, options, &local_err); if (error_is_set(&local_err)) { qerror_report_err(local_err); error_free(local_err); ret = -EINVAL; goto fail; } if (strstr(dirname, ":32:")) { fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); s->fat_type = 32; } else if (strstr(dirname, ":16:")) { s->fat_type = 16; } else if (strstr(dirname, ":12:")) { s->fat_type = 12; dirname = qemu_opt_get(opts, "dir"); if (!dirname) { qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires " "a 'dir' option"); ret = -EINVAL; goto fail; } if (strstr(dirname, ":floppy:")) { s->fat_type = qemu_opt_get_number(opts, "fat-type", 0); floppy = qemu_opt_get_bool(opts, "floppy", false); if (floppy) { /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */ if (!s->fat_type) { s->fat_type = 12; Loading @@ -1052,29 +1127,56 @@ DLOG(if (stderr == NULL) { heads = 16; secs = 63; } switch (s->fat_type) { case 32: fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. " "You are welcome to do so!\n"); break; case 16: case 12: break; default: qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only " "12, 16 and 32"); ret = -EINVAL; goto fail; } s->bs = bs; /* LATER TODO: if FAT32, adjust */ s->sectors_per_cluster=0x10; s->current_cluster=0xffffffff; s->first_sectors_number=0x40; /* read only is the default for safety */ bs->read_only = 1; s->qcow = s->write_target = NULL; s->qcow_filename = NULL; s->fat2 = NULL; s->downcase_short_names = 1; fprintf(stderr, "vvfat %s chs %d,%d,%d\n", dirname, cyls, heads, secs); s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); if (strstr(dirname, ":rw:")) { if (enable_write_target(s)) return -1; if (qemu_opt_get_bool(opts, "rw", false)) { if (enable_write_target(s)) { ret = -EIO; goto fail; } bs->read_only = 0; } i = strrchr(dirname, ':') - dirname; assert(i >= 3); if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1])) /* workaround for DOS drive names */ dirname += i-1; else dirname += i+1; bs->total_sectors = cyls * heads * secs; if (init_directories(s, dirname, heads, secs)) { return -1; ret = -EIO; goto fail; } s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count; Loading @@ -1094,7 +1196,10 @@ DLOG(if (stderr == NULL) { migrate_add_blocker(s->migration_blocker); } return 0; ret = 0; fail: qemu_opts_del(opts); return ret; } static inline void vvfat_close_current_file(BDRVVVFATState *s) Loading Loading @@ -2867,14 +2972,17 @@ static void vvfat_close(BlockDriverState *bs) static BlockDriver bdrv_vvfat = { .format_name = "vvfat", .protocol_name = "fat", .instance_size = sizeof(BDRVVVFATState), .bdrv_parse_filename = vvfat_parse_filename, .bdrv_file_open = vvfat_open, .bdrv_close = vvfat_close, .bdrv_rebind = vvfat_rebind, .bdrv_read = vvfat_co_read, .bdrv_write = vvfat_co_write, .bdrv_close = vvfat_close, .bdrv_co_is_allocated = vvfat_co_is_allocated, .protocol_name = "fat", }; static void bdrv_vvfat_init(void) Loading