From: Nolan Leake <nolan@sigbus.net> This is useful for at least 2 use cases: - Testing support for non-full filesystem - In conjuction with the CoW plugin, for making a writable filesystem. There is also a small bugfix, the partition bootsector didn't account for the 2048 sector offset to the start of the partition when calculating the number of sectors in the partition. Signed-off-by: Nolan Leake <nolan@sigbus.net> --- plugins/floppy/virtual-floppy.h | 2 ++ plugins/floppy/floppy.c | 9 ++++++- plugins/floppy/virtual-floppy.c | 43 +++++++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/plugins/floppy/virtual-floppy.h b/plugins/floppy/virtual-floppy.h index e5e1e3c9..b3eac24e 100644 --- a/plugins/floppy/virtual-floppy.h +++ b/plugins/floppy/virtual-floppy.h @@ -198,6 +198,7 @@ struct virtual_floppy { uint64_t fat_clusters; /* Size of FAT (clusters on disk). */ uint64_t data_size; /* Size of data region (bytes). */ uint64_t data_clusters; /* Size of data region (clusters). */ + uint64_t data_used_clusters; /* Size of the used part of the data region. */ /* The disk layout: * sector 0: MBR @@ -229,6 +230,7 @@ struct virtual_floppy { extern void init_virtual_floppy (struct virtual_floppy *floppy) __attribute__((__nonnull__ (1))); extern int create_virtual_floppy (const char *dir, const char *label, + uint64_t size, struct virtual_floppy *floppy) __attribute__((__nonnull__ (1, 2, 3))); extern void free_virtual_floppy (struct virtual_floppy *floppy) diff --git a/plugins/floppy/floppy.c b/plugins/floppy/floppy.c index 3f5220b2..24850300 100644 --- a/plugins/floppy/floppy.c +++ b/plugins/floppy/floppy.c @@ -50,6 +50,9 @@ static char *dir = NULL; /* Volume label. */ static const char *label = "NBDKITFLOPY"; +/* Filesystem size. */ +static uint64_t size = 0; + /* Virtual floppy. */ static struct virtual_floppy floppy; @@ -82,6 +85,10 @@ floppy_config (const char *key, const char *value) else if (strcmp (key, "label") == 0) { label = value; } + else if (strcmp (key, "size") == 0) { + if (nbdkit_parse_uint64_t ("size", value, &size) == -1) + return -1; + } else { nbdkit_error ("unknown parameter '%s'", key); return -1; @@ -109,7 +116,7 @@ floppy_config_complete (void) static int floppy_get_ready (void) { - return create_virtual_floppy (dir, label, &floppy); + return create_virtual_floppy (dir, label, size, &floppy); } static void * diff --git a/plugins/floppy/virtual-floppy.c b/plugins/floppy/virtual-floppy.c index 60916fc5..2d5fe72d 100644 --- a/plugins/floppy/virtual-floppy.c +++ b/plugins/floppy/virtual-floppy.c @@ -85,11 +85,12 @@ init_virtual_floppy (struct virtual_floppy *floppy) } int -create_virtual_floppy (const char *dir, const char *label, +create_virtual_floppy (const char *dir, const char *label, uint64_t size, struct virtual_floppy *floppy) { size_t i; uint64_t nr_bytes, nr_clusters; + uint64_t data_used_size; uint32_t cluster; if (visit (dir, floppy) == -1) @@ -112,14 +113,14 @@ create_virtual_floppy (const char *dir, const char *label, * The first cluster number is always 2 (0 and 1 are reserved), and * (in this implementation) always contains the root directory. */ - floppy->data_size = 0; + data_used_size = 0; cluster = 2; for (i = 0; i < floppy->dirs.size; ++i) { floppy->dirs.ptr[i].first_cluster = cluster; nr_bytes = ROUND_UP (floppy->dirs.ptr[i].table.size * sizeof (struct dir_entry), CLUSTER_SIZE); - floppy->data_size += nr_bytes; + data_used_size += nr_bytes; nr_clusters = nr_bytes / CLUSTER_SIZE; if (cluster + nr_clusters > UINT32_MAX) goto too_big; @@ -129,7 +130,7 @@ create_virtual_floppy (const char *dir, const char *label, for (i = 0; i < floppy->files.size; ++i) { floppy->files.ptr[i].first_cluster = cluster; nr_bytes = ROUND_UP (floppy->files.ptr[i].statbuf.st_size, CLUSTER_SIZE); - floppy->data_size += nr_bytes; + data_used_size += nr_bytes; nr_clusters = nr_bytes / CLUSTER_SIZE; if (cluster + nr_clusters > UINT32_MAX) goto too_big; @@ -137,7 +138,21 @@ create_virtual_floppy (const char *dir, const char *label, cluster += nr_clusters; } + if (size > 0) { + uint64_t data_size = size - (2080 * SECTOR_SIZE); + data_size = data_size - 2 * DIV_ROUND_UP((data_size / CLUSTER_SIZE + 2) * 4, + CLUSTER_SIZE) * CLUSTER_SIZE; + if (data_used_size > data_size) { + nbdkit_error ("filesystem is larger than \"size\" bytes"); + return -1; + } + floppy->data_size = data_size; + } else { + floppy->data_size = data_used_size; + } + floppy->data_clusters = floppy->data_size / CLUSTER_SIZE; + floppy->data_used_clusters = data_used_size / CLUSTER_SIZE; /* Despite its name, FAT32 only allows 28 bit cluster numbers, so * give an error if we go beyond this. @@ -199,6 +214,10 @@ create_virtual_floppy (const char *dir, const char *label, if (create_regions (floppy) == -1) return -1; + /* Check that if a size was specified, we ended up with it. */ + if (size > 0) + assert (virtual_size (&floppy->regions) == size); + return 0; } @@ -488,7 +507,7 @@ create_partition_boot_sector (const char *label, struct virtual_floppy *floppy) floppy->bootsect.sectors_per_track = htole16 (0); floppy->bootsect.nr_heads = htole16 (0); floppy->bootsect.nr_hidden_sectors = htole32 (0); - floppy->bootsect.nr_sectors = htole32 (floppy->data_last_sector + 1); + floppy->bootsect.nr_sectors = htole32 (floppy->data_last_sector - 2048 + 1); floppy->bootsect.sectors_per_fat = htole32 (floppy->fat_clusters * SECTORS_PER_CLUSTER); @@ -524,8 +543,9 @@ create_fsinfo (struct virtual_floppy *floppy) floppy->fsinfo.signature2[1] = 0x72; floppy->fsinfo.signature2[2] = 0x41; floppy->fsinfo.signature2[3] = 0x61; - floppy->fsinfo.free_data_clusters = htole32 (0); - floppy->fsinfo.last_free_cluster = htole32 (2 + floppy->data_clusters); + floppy->fsinfo.free_data_clusters = htole32 (floppy->data_clusters - + floppy->data_used_clusters); + floppy->fsinfo.last_free_cluster = htole32 (2 + floppy->data_used_clusters); floppy->fsinfo.signature3[0] = 0x00; floppy->fsinfo.signature3[1] = 0x00; floppy->fsinfo.signature3[2] = 0x55; @@ -687,6 +707,15 @@ create_regions (struct virtual_floppy *floppy) return -1; } + /* Append region for empty data region if we have extra space. */ + if (floppy->data_used_clusters != floppy->data_clusters) { + uint64_t clusters = (floppy->data_clusters - floppy->data_used_clusters); + if (append_region_len (&floppy->regions, "data padding", + clusters * CLUSTER_SIZE, 0, CLUSTER_SIZE, + region_zero) == -1) + return -1; + } + nbdkit_debug ("floppy: %zu regions, " "total disk size %" PRIi64, nr_regions (&floppy->regions), -- 2.32.0