Revision 7ad9be64

b/block/vvfat.c
1
/* vim:set shiftwidth=4 ts=8: */
1
/* vim:set shiftwidth=4 ts=4: */
2 2
/*
3 3
 * QEMU Block driver for virtual VFAT (shadows a local directory)
4 4
 *
......
28 28
#include "block/block_int.h"
29 29
#include "qemu/module.h"
30 30
#include "migration/migration.h"
31
#include "qapi/qmp/qint.h"
32
#include "qapi/qmp/qbool.h"
31 33

  
32 34
#ifndef S_IWGRP
33 35
#define S_IWGRP 0
......
988 990
    s->bs = bs;
989 991
}
990 992

  
991
static int vvfat_open(BlockDriverState *bs, const char* dirname,
993
static QemuOptsList runtime_opts = {
994
    .name = "vvfat",
995
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
996
    .desc = {
997
        {
998
            .name = "dir",
999
            .type = QEMU_OPT_STRING,
1000
            .help = "Host directory to map to the vvfat device",
1001
        },
1002
        {
1003
            .name = "fat-type",
1004
            .type = QEMU_OPT_NUMBER,
1005
            .help = "FAT type (12, 16 or 32)",
1006
        },
1007
        {
1008
            .name = "floppy",
1009
            .type = QEMU_OPT_BOOL,
1010
            .help = "Create a floppy rather than a hard disk image",
1011
        },
1012
        {
1013
            .name = "rw",
1014
            .type = QEMU_OPT_BOOL,
1015
            .help = "Make the image writable",
1016
        },
1017
        { /* end of list */ }
1018
    },
1019
};
1020

  
1021
static void vvfat_parse_filename(const char *filename, QDict *options,
1022
                                 Error **errp)
1023
{
1024
    int fat_type = 0;
1025
    bool floppy = false;
1026
    bool rw = false;
1027
    int i;
1028

  
1029
    if (!strstart(filename, "fat:", NULL)) {
1030
        error_setg(errp, "File name string must start with 'fat:'");
1031
        return;
1032
    }
1033

  
1034
    /* Parse options */
1035
    if (strstr(filename, ":32:")) {
1036
        fat_type = 32;
1037
    } else if (strstr(filename, ":16:")) {
1038
        fat_type = 16;
1039
    } else if (strstr(filename, ":12:")) {
1040
        fat_type = 12;
1041
    }
1042

  
1043
    if (strstr(filename, ":floppy:")) {
1044
        floppy = true;
1045
    }
1046

  
1047
    if (strstr(filename, ":rw:")) {
1048
        rw = true;
1049
    }
1050

  
1051
    /* Get the directory name without options */
1052
    i = strrchr(filename, ':') - filename;
1053
    assert(i >= 3);
1054
    if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1055
        /* workaround for DOS drive names */
1056
        filename += i - 1;
1057
    } else {
1058
        filename += i + 1;
1059
    }
1060

  
1061
    /* Fill in the options QDict */
1062
    qdict_put(options, "dir", qstring_from_str(filename));
1063
    qdict_put(options, "fat-type", qint_from_int(fat_type));
1064
    qdict_put(options, "floppy", qbool_from_int(floppy));
1065
    qdict_put(options, "rw", qbool_from_int(rw));
1066
}
1067

  
1068
static int vvfat_open(BlockDriverState *bs, const char* dummy,
992 1069
                      QDict *options, int flags)
993 1070
{
994 1071
    BDRVVVFATState *s = bs->opaque;
995
    int i, cyls, heads, secs;
1072
    int cyls, heads, secs;
1073
    bool floppy;
1074
    const char *dirname;
1075
    QemuOpts *opts;
1076
    Error *local_err = NULL;
1077
    int ret;
996 1078

  
997 1079
#ifdef DEBUG
998 1080
    vvv = s;
......
1003 1085
    setbuf(stderr, NULL);
1004 1086
})
1005 1087

  
1088
    opts = qemu_opts_create_nofail(&runtime_opts);
1089
    qemu_opts_absorb_qdict(opts, options, &local_err);
1090
    if (error_is_set(&local_err)) {
1091
        qerror_report_err(local_err);
1092
        error_free(local_err);
1093
        ret = -EINVAL;
1094
        goto fail;
1095
    }
1096

  
1097
    dirname = qemu_opt_get(opts, "dir");
1098
    if (!dirname) {
1099
        qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires "
1100
                      "a 'dir' option");
1101
        ret = -EINVAL;
1102
        goto fail;
1103
    }
1104

  
1105
    s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1106
    floppy = qemu_opt_get_bool(opts, "floppy", false);
1107

  
1108
    if (floppy) {
1109
        /* 1.44MB or 2.88MB floppy.  2.88MB can be FAT12 (default) or FAT16. */
1110
        if (!s->fat_type) {
1111
            s->fat_type = 12;
1112
            secs = 36;
1113
            s->sectors_per_cluster = 2;
1114
        } else {
1115
            secs = s->fat_type == 12 ? 18 : 36;
1116
            s->sectors_per_cluster = 1;
1117
        }
1118
        s->first_sectors_number = 1;
1119
        cyls = 80;
1120
        heads = 2;
1121
    } else {
1122
        /* 32MB or 504MB disk*/
1123
        if (!s->fat_type) {
1124
            s->fat_type = 16;
1125
        }
1126
        cyls = s->fat_type == 12 ? 64 : 1024;
1127
        heads = 16;
1128
        secs = 63;
1129
    }
1130

  
1131
    switch (s->fat_type) {
1132
    case 32:
1133
	    fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
1134
                "You are welcome to do so!\n");
1135
        break;
1136
    case 16:
1137
    case 12:
1138
        break;
1139
    default:
1140
        qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only "
1141
                      "12, 16 and 32");
1142
        ret = -EINVAL;
1143
        goto fail;
1144
    }
1145

  
1146

  
1006 1147
    s->bs = bs;
1007 1148

  
1008 1149
    /* LATER TODO: if FAT32, adjust */
......
1018 1159
    s->fat2 = NULL;
1019 1160
    s->downcase_short_names = 1;
1020 1161

  
1021
    if (!strstart(dirname, "fat:", NULL))
1022
	return -1;
1023

  
1024
    if (strstr(dirname, ":32:")) {
1025
	fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1026
	s->fat_type = 32;
1027
    } else if (strstr(dirname, ":16:")) {
1028
	s->fat_type = 16;
1029
    } else if (strstr(dirname, ":12:")) {
1030
	s->fat_type = 12;
1031
    }
1032

  
1033
    if (strstr(dirname, ":floppy:")) {
1034
	/* 1.44MB or 2.88MB floppy.  2.88MB can be FAT12 (default) or FAT16. */
1035
	if (!s->fat_type) {
1036
	    s->fat_type = 12;
1037
            secs = 36;
1038
	    s->sectors_per_cluster=2;
1039
	} else {
1040
            secs = s->fat_type == 12 ? 18 : 36;
1041
	    s->sectors_per_cluster=1;
1042
	}
1043
	s->first_sectors_number = 1;
1044
        cyls = 80;
1045
        heads = 2;
1046
    } else {
1047
	/* 32MB or 504MB disk*/
1048
	if (!s->fat_type) {
1049
	    s->fat_type = 16;
1050
	}
1051
        cyls = s->fat_type == 12 ? 64 : 1024;
1052
        heads = 16;
1053
        secs = 63;
1054
    }
1055 1162
    fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1056 1163
            dirname, cyls, heads, secs);
1057 1164

  
1058 1165
    s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
1059 1166

  
1060
    if (strstr(dirname, ":rw:")) {
1061
	if (enable_write_target(s))
1062
	    return -1;
1063
	bs->read_only = 0;
1167
    if (qemu_opt_get_bool(opts, "rw", false)) {
1168
        if (enable_write_target(s)) {
1169
            ret = -EIO;
1170
            goto fail;
1171
        }
1172
        bs->read_only = 0;
1064 1173
    }
1065 1174

  
1066
    i = strrchr(dirname, ':') - dirname;
1067
    assert(i >= 3);
1068
    if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
1069
	/* workaround for DOS drive names */
1070
	dirname += i-1;
1071
    else
1072
	dirname += i+1;
1073

  
1074 1175
    bs->total_sectors = cyls * heads * secs;
1075 1176

  
1076 1177
    if (init_directories(s, dirname, heads, secs)) {
1077
	return -1;
1178
        ret = -EIO;
1179
        goto fail;
1078 1180
    }
1079 1181

  
1080 1182
    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
......
1094 1196
        migrate_add_blocker(s->migration_blocker);
1095 1197
    }
1096 1198

  
1097
    return 0;
1199
    ret = 0;
1200
fail:
1201
    qemu_opts_del(opts);
1202
    return ret;
1098 1203
}
1099 1204

  
1100 1205
static inline void vvfat_close_current_file(BDRVVVFATState *s)
......
2866 2971
}
2867 2972

  
2868 2973
static BlockDriver bdrv_vvfat = {
2869
    .format_name	= "vvfat",
2870
    .instance_size	= sizeof(BDRVVVFATState),
2871
    .bdrv_file_open	= vvfat_open,
2872
    .bdrv_rebind	= vvfat_rebind,
2873
    .bdrv_read          = vvfat_co_read,
2874
    .bdrv_write         = vvfat_co_write,
2875
    .bdrv_close		= vvfat_close,
2876
    .bdrv_co_is_allocated = vvfat_co_is_allocated,
2877
    .protocol_name	= "fat",
2974
    .format_name            = "vvfat",
2975
    .protocol_name          = "fat",
2976
    .instance_size          = sizeof(BDRVVVFATState),
2977

  
2978
    .bdrv_parse_filename    = vvfat_parse_filename,
2979
    .bdrv_file_open         = vvfat_open,
2980
    .bdrv_close             = vvfat_close,
2981
    .bdrv_rebind            = vvfat_rebind,
2982

  
2983
    .bdrv_read              = vvfat_co_read,
2984
    .bdrv_write             = vvfat_co_write,
2985
    .bdrv_co_is_allocated   = vvfat_co_is_allocated,
2878 2986
};
2879 2987

  
2880 2988
static void bdrv_vvfat_init(void)

Also available in: Unified diff