vvfat: Use bdrv_open options instead of filename

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Kevin Wolf 2013-04-12 19:42:04 +02:00
parent c8c96350e0
commit 7ad9be64e8
1 changed files with 168 additions and 60 deletions

View File

@ -1,4 +1,4 @@
/* vim:set shiftwidth=4 ts=8: */ /* vim:set shiftwidth=4 ts=4: */
/* /*
* QEMU Block driver for virtual VFAT (shadows a local directory) * QEMU Block driver for virtual VFAT (shadows a local directory)
* *
@ -28,6 +28,8 @@
#include "block/block_int.h" #include "block/block_int.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "migration/migration.h" #include "migration/migration.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qbool.h"
#ifndef S_IWGRP #ifndef S_IWGRP
#define S_IWGRP 0 #define S_IWGRP 0
@ -988,11 +990,91 @@ static void vvfat_rebind(BlockDriverState *bs)
s->bs = 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) QDict *options, int flags)
{ {
BDRVVVFATState *s = bs->opaque; 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 #ifdef DEBUG
vvv = s; vvv = s;
@ -1003,6 +1085,65 @@ DLOG(if (stderr == NULL) {
setbuf(stderr, NULL); setbuf(stderr, NULL);
}) })
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;
}
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;
}
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;
secs = 36;
s->sectors_per_cluster = 2;
} else {
secs = s->fat_type == 12 ? 18 : 36;
s->sectors_per_cluster = 1;
}
s->first_sectors_number = 1;
cyls = 80;
heads = 2;
} else {
/* 32MB or 504MB disk*/
if (!s->fat_type) {
s->fat_type = 16;
}
cyls = s->fat_type == 12 ? 64 : 1024;
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; s->bs = bs;
/* LATER TODO: if FAT32, adjust */ /* LATER TODO: if FAT32, adjust */
@ -1018,63 +1159,24 @@ DLOG(if (stderr == NULL) {
s->fat2 = NULL; s->fat2 = NULL;
s->downcase_short_names = 1; s->downcase_short_names = 1;
if (!strstart(dirname, "fat:", NULL))
return -1;
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;
}
if (strstr(dirname, ":floppy:")) {
/* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
if (!s->fat_type) {
s->fat_type = 12;
secs = 36;
s->sectors_per_cluster=2;
} else {
secs = s->fat_type == 12 ? 18 : 36;
s->sectors_per_cluster=1;
}
s->first_sectors_number = 1;
cyls = 80;
heads = 2;
} else {
/* 32MB or 504MB disk*/
if (!s->fat_type) {
s->fat_type = 16;
}
cyls = s->fat_type == 12 ? 64 : 1024;
heads = 16;
secs = 63;
}
fprintf(stderr, "vvfat %s chs %d,%d,%d\n", fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
dirname, cyls, heads, secs); dirname, cyls, heads, secs);
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
if (strstr(dirname, ":rw:")) { if (qemu_opt_get_bool(opts, "rw", false)) {
if (enable_write_target(s)) if (enable_write_target(s)) {
return -1; ret = -EIO;
bs->read_only = 0; 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; bs->total_sectors = cyls * heads * secs;
if (init_directories(s, dirname, 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; s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
@ -1094,7 +1196,10 @@ DLOG(if (stderr == NULL) {
migrate_add_blocker(s->migration_blocker); 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) static inline void vvfat_close_current_file(BDRVVVFATState *s)
@ -2866,15 +2971,18 @@ static void vvfat_close(BlockDriverState *bs)
} }
static BlockDriver bdrv_vvfat = { static BlockDriver bdrv_vvfat = {
.format_name = "vvfat", .format_name = "vvfat",
.instance_size = sizeof(BDRVVVFATState), .protocol_name = "fat",
.bdrv_file_open = vvfat_open, .instance_size = sizeof(BDRVVVFATState),
.bdrv_rebind = vvfat_rebind,
.bdrv_read = vvfat_co_read, .bdrv_parse_filename = vvfat_parse_filename,
.bdrv_write = vvfat_co_write, .bdrv_file_open = vvfat_open,
.bdrv_close = vvfat_close, .bdrv_close = vvfat_close,
.bdrv_co_is_allocated = vvfat_co_is_allocated, .bdrv_rebind = vvfat_rebind,
.protocol_name = "fat",
.bdrv_read = vvfat_co_read,
.bdrv_write = vvfat_co_write,
.bdrv_co_is_allocated = vvfat_co_is_allocated,
}; };
static void bdrv_vvfat_init(void) static void bdrv_vvfat_init(void)