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