[Libguestfs] [PATCH nbdkit 1/5] floppy: support FAT FSes with unused space.

Richard W.M. Jones rjones at redhat.com
Wed Jun 16 16:15:40 UTC 2021


From: Nolan Leake <nolan at 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 at 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




More information about the Libguestfs mailing list