I've tried this patch and it worked for me. Small disk was created for the small folder, and it worked in MS-DOS. Larger disk was automatically selected for the folder larger than 504Mb. It worked only under Windows.
Pavel Dovgalyuk > -----Original Message----- > From: Arkasha [mailto:ivanovrka...@gmail.com] > Sent: Thursday, August 23, 2018 4:38 PM > To: qemu-devel@nongnu.org > Cc: kw...@redhat.com; mre...@redhat.com; pavel.dovga...@ispras.ru; Arkasha > Subject: [PATCH V2] block: increased maximum size of vvfat devices > > This fixes the problem of the impossibility to create > FAT16 disks larger than 504 mb: > The change CHS made it possible to obtain a larger disk. > Also, auto-detection of disk parameters was added depending > on the volume of the connected files: > The size of all folders and files on the created disk is calculated > and the size of the FAT table is added. > This size allows to choose the future size of the FAT drive > from the standard limitations. > > Signed-off-by: Arkasha <ivanovrka...@gmail.com> > --- > block/vvfat.c | 96 > ++++++++++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 86 insertions(+), 10 deletions(-) > > diff --git a/block/vvfat.c b/block/vvfat.c > index fc41841..4409233 100644 > --- a/block/vvfat.c > +++ b/block/vvfat.c > @@ -77,6 +77,47 @@ static void checkpoint(void); > #define DIR_KANJI_FAKE 0x05 > #define DIR_FREE 0x00 > > +static bool check_size(uint32_t offset_to_bootsector, int cyls, int heads, > + int secs, uint8_t sectors_per_cluster, int fat_type, > + long int sum, long int size_disk) > +{ > + uint32_t sector_count = cyls * heads * secs - offset_to_bootsector; > + int i = 1 + sectors_per_cluster * 0x200 * 8 / fat_type; > + uint16_t sectors_per_fat = (sector_count + i) / i; > + /*size + FAT1 and FAT2 table size*/ > + if ((sum + sectors_per_fat * 512 * 2) < size_disk) { > + return true; > + } > + return false; > +} > + > +static long int find_size(const char *dirname, unsigned int cluster) > +{ > + long int sum = 0; > + DIR *dir = opendir(dirname); > + struct dirent *entry; > + while ((entry = readdir(dir))) { > + unsigned int length = strlen(dirname) + 2 + strlen(entry->d_name); > + char *buffer; > + struct stat st; > + buffer = g_malloc(length); > + snprintf(buffer, length, "%s/%s", dirname, entry->d_name); > + if (stat(buffer, &st) < 0) { > + g_free(buffer); > + continue; > + } > + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..") > + && S_ISDIR(st.st_mode)) { > + sum += find_size(buffer, cluster); > + } > + g_free(buffer); > + sum += (st.st_size + cluster - 1) / (cluster) * (cluster); > + } > + closedir(dir); > + return sum; > +} > + > + > /* dynamic array functions */ > typedef struct array_t { > char* pointer; > @@ -948,8 +988,6 @@ static int init_directories(BDRVVVFATState* s, > /* Now build FAT, and write back information into directory */ > init_fat(s); > > - /* TODO: if there are more entries, bootsector has to be adjusted! */ > - s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; > s->cluster_count=sector2cluster(s, s->sector_count); > > mapping = array_get_next(&(s->mapping)); > @@ -1154,12 +1192,12 @@ static int vvfat_open(BlockDriverState *bs, QDict > *options, int flags, > { > BDRVVVFATState *s = bs->opaque; > int cyls, heads, secs; > + long int size_disk; > bool floppy; > const char *dirname, *label; > QemuOpts *opts; > Error *local_err = NULL; > int ret; > - > #ifdef DEBUG > vvv = s; > #endif > @@ -1181,6 +1219,29 @@ static int vvfat_open(BlockDriverState *bs, QDict > *options, int flags, > > s->fat_type = qemu_opt_get_number(opts, "fat-type", 0); > floppy = qemu_opt_get_bool(opts, "floppy", false); > + unsigned int cluster; > + long int sum = 0; > + if (floppy) { > + if (!s->fat_type) { > + s->sectors_per_cluster = 2; > + } else { > + s->sectors_per_cluster = 1; > + } > + } else if (s->fat_type == 12) { > + s->offset_to_bootsector = 0x3f; > + s->sectors_per_cluster = 0x10; > + } else { > + s->offset_to_bootsector = 0x3f; > + /* LATER TODO: if FAT32, adjust */ > + s->sectors_per_cluster = 0x80; > + } > + > + cluster = s->sectors_per_cluster * 0x200; > + sum += find_size(dirname, cluster); > + /* TODO: if there are more entries, bootsector has to be adjusted! */ > + s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; > + /*File size + boot sector size + root directory size*/ > + sum += 512 + s->root_entries * 32; > > memset(s->volume_label, ' ', sizeof(s->volume_label)); > label = qemu_opt_get(opts, "label"); > @@ -1201,24 +1262,41 @@ static int vvfat_open(BlockDriverState *bs, QDict > *options, int flags, > 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; > } > cyls = 80; > heads = 2; > } else { > - /* 32MB or 504MB disk*/ > if (!s->fat_type) { > s->fat_type = 16; > } > - s->offset_to_bootsector = 0x3f; > + size_disk = 528482304; > cyls = s->fat_type == 12 ? 64 : 1024; > heads = 16; > secs = 63; > - } > + if (!check_size(s->offset_to_bootsector, cyls, heads, > + secs, s->sectors_per_cluster, > + s->fat_type, sum, size_disk)) { > + if (s->fat_type > 12) { > + size_disk = 4294950912; > + cyls = 8322; > + heads = 16; > + secs = 63; > > + } else { > + fprintf(stderr, "Requires Fat16 or Fat32\n"); > + return -2; > + } > + if (!check_size(s->offset_to_bootsector, cyls, heads, > + secs, s->sectors_per_cluster, > + s->fat_type, sum, size_disk)) { > + fprintf(stderr, "Folder is larger than %f GB\n", > + (float)size_disk / 1073741824); > + return -2; > + } > + } > + } > switch (s->fat_type) { > case 32: > warn_report("FAT32 has not been tested. You are welcome to do so!"); > @@ -1235,8 +1313,6 @@ static int vvfat_open(BlockDriverState *bs, QDict > *options, int flags, > > s->bs = bs; > > - /* LATER TODO: if FAT32, adjust */ > - s->sectors_per_cluster=0x10; > > s->current_cluster=0xffffffff; > > -- > 2.7.4