diff --git a/block/vvfat.c b/block/vvfat.c index 3c0ab6c228..cb124d4650 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -39,6 +39,7 @@ #include "qemu/ctype.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "qemu/units.h" #ifndef S_IWGRP #define S_IWGRP 0 @@ -336,6 +337,9 @@ typedef struct BDRVVVFATState { int downcase_short_names; Error *migration_blocker; +#ifdef EMSCRIPTEN + GHashTable *write_overlay; +#endif } BDRVVVFATState; /* take the sector position spos and convert it to Cylinder/Head/Sector position @@ -1246,10 +1250,13 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, s->bs = bs; #ifdef EMSCRIPTEN - if (!floppy && s->fat_type == 32) { + if (!floppy && s->fat_type == 16) { + s->sectors_per_cluster = 0x10; + total_sectors = 32ULL * MiB / BDRV_SECTOR_SIZE; + } else if (!floppy && s->fat_type == 32) { /* Browser SD Geometry - A larger cluster keeps the synthesized 32 GiB FAT near 4 MiB. */ s->sectors_per_cluster = 0x40; - total_sectors = 32ULL * 1024 * 1024 * 1024 / BDRV_SECTOR_SIZE; + total_sectors = 32ULL * GiB / BDRV_SECTOR_SIZE; } else #endif { @@ -1516,6 +1523,18 @@ vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sector for(i=0;i= bs->total_sectors) return -1; +#ifdef EMSCRIPTEN + if (s->write_overlay) { + int64_t key = sector_num; + const uint8_t *overlay = g_hash_table_lookup(s->write_overlay, + &key); + if (overlay) { + memcpy(buf + i * BDRV_SECTOR_SIZE, overlay, + BDRV_SECTOR_SIZE); + continue; + } + } +#endif if (s->qcow) { int64_t n; int ret; @@ -3027,6 +3046,19 @@ vvfat_write(BlockDriverState *bs, int64_t sector_num, DLOG(checkpoint()); +#ifdef EMSCRIPTEN + if (s->write_overlay) { + for (i = 0; i < nb_sectors; i++) { + int64_t *key = g_new(int64_t, 1); + uint8_t *sector = g_malloc(BDRV_SECTOR_SIZE); + *key = sector_num + i; + memcpy(sector, buf + i * BDRV_SECTOR_SIZE, BDRV_SECTOR_SIZE); + g_hash_table_replace(s->write_overlay, key, sector); + } + return 0; + } +#endif + /* Check if we're operating in read-only mode */ if (s->qcow == NULL) { return -EACCES; @@ -3129,7 +3161,8 @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, nb_sectors * BDRV_SECTOR_SIZE, buf, 0); if (ret < 0) { - fprintf(stderr, "Error writing to qcow backend\n"); + fprintf(stderr, "Error writing to qcow backend: %s (%d)\n", + strerror(-ret), ret); return ret; } @@ -3205,6 +3238,12 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) int size = sector2cluster(s, s->sector_count); QDict *options; +#ifdef EMSCRIPTEN + s->write_overlay = g_hash_table_new_full(g_int64_hash, g_int64_equal, + g_free, g_free); + return 0; +#endif + s->used_clusters = g_malloc0(size); array_init(&(s->commits), sizeof(commit_t)); @@ -3280,6 +3319,9 @@ static void vvfat_close(BlockDriverState *bs) if (s->qcow) { migrate_del_blocker(&s->migration_blocker); } +#ifdef EMSCRIPTEN + g_clear_pointer(&s->write_overlay, g_hash_table_destroy); +#endif } static const char *const vvfat_strong_runtime_opts[] = {