4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 #include <sys/types.h>
48 #include <nbdkit-plugin.h>
50 #include "byte-swapping.h"
52 #include "get_current_dir_name.h"
56 #include "virtual-floppy.h"
58 /* This is the Windows 98 OEM name, and some sites recommend using it
59 * for greatest compatibility.
61 #define OEM_NAME "MSWIN4.1"
63 static ssize_t
visit (const char *dir
, struct virtual_floppy
*floppy
);
64 static int visit_subdirectory (const char *dir
, const char *name
, const struct stat
*statbuf
, size_t di
, struct virtual_floppy
*floppy
);
65 static int visit_file (const char *dir
, const char *name
, const struct stat
*statbuf
, size_t di
, struct virtual_floppy
*floppy
);
66 static int create_mbr (struct virtual_floppy
*floppy
);
67 static void chs_too_large (uint8_t *out
);
68 static int create_partition_boot_sector (const char *label
, struct virtual_floppy
*floppy
);
69 static int create_fsinfo (struct virtual_floppy
*floppy
);
70 static int create_fat (struct virtual_floppy
*floppy
);
71 static void write_fat_file (uint32_t first_cluster
, uint32_t nr_clusters
, struct virtual_floppy
*floppy
);
72 static int create_regions (struct virtual_floppy
*floppy
);
75 init_virtual_floppy (struct virtual_floppy
*floppy
)
77 memset (floppy
, 0, sizeof *floppy
);
78 init_regions (&floppy
->regions
);
80 /* Assert that the on disk struct sizes are correct. */
81 assert (sizeof (struct dir_entry
) == 32);
82 assert (sizeof (struct lfn_entry
) == 32);
83 assert (sizeof (struct bootsector
) == 512);
84 assert (sizeof (struct fsinfo
) == 512);
88 create_virtual_floppy (const char *dir
, const char *label
, uint64_t size
,
89 struct virtual_floppy
*floppy
)
92 uint64_t nr_bytes
, nr_clusters
;
93 uint64_t data_used_size
;
96 if (visit (dir
, floppy
) == -1)
99 nbdkit_debug ("floppy: %zu directories and %zu files",
100 floppy
->dirs
.len
, floppy
->files
.len
);
102 /* Create the on disk directory tables. */
103 for (i
= 0; i
< floppy
->dirs
.len
; ++i
) {
104 if (create_directory (i
, label
, floppy
) == -1)
108 /* We now have a complete list of directories and files, and
109 * directories have been converted to on disk directory tables. So
110 * we can assign them to clusters and also precisely calculate the
111 * size of the data region and hence the size of the FAT.
113 * The first cluster number is always 2 (0 and 1 are reserved), and
114 * (in this implementation) always contains the root directory.
118 for (i
= 0; i
< floppy
->dirs
.len
; ++i
) {
119 floppy
->dirs
.ptr
[i
].first_cluster
= cluster
;
121 ROUND_UP (floppy
->dirs
.ptr
[i
].table
.len
* sizeof (struct dir_entry
),
123 data_used_size
+= nr_bytes
;
124 nr_clusters
= nr_bytes
/ CLUSTER_SIZE
;
125 if (cluster
+ nr_clusters
> UINT32_MAX
)
127 floppy
->dirs
.ptr
[i
].nr_clusters
= nr_clusters
;
128 cluster
+= nr_clusters
;
130 for (i
= 0; i
< floppy
->files
.len
; ++i
) {
131 floppy
->files
.ptr
[i
].first_cluster
= cluster
;
132 nr_bytes
= ROUND_UP (floppy
->files
.ptr
[i
].statbuf
.st_size
, CLUSTER_SIZE
);
133 data_used_size
+= nr_bytes
;
134 nr_clusters
= nr_bytes
/ CLUSTER_SIZE
;
135 if (cluster
+ nr_clusters
> UINT32_MAX
)
137 floppy
->files
.ptr
[i
].nr_clusters
= nr_clusters
;
138 cluster
+= nr_clusters
;
142 uint64_t data_size
= size
- (2080 * SECTOR_SIZE
);
143 data_size
= data_size
- 2 * DIV_ROUND_UP ((data_size
/ CLUSTER_SIZE
+ 2) * 4,
144 CLUSTER_SIZE
) * CLUSTER_SIZE
;
145 if (data_used_size
> data_size
) {
146 nbdkit_error ("filesystem is larger than \"size\" bytes");
149 floppy
->data_size
= data_size
;
151 floppy
->data_size
= data_used_size
;
154 floppy
->data_clusters
= floppy
->data_size
/ CLUSTER_SIZE
;
155 floppy
->data_used_clusters
= data_used_size
/ CLUSTER_SIZE
;
157 /* Despite its name, FAT32 only allows 28 bit cluster numbers, so
158 * give an error if we go beyond this.
160 if (floppy
->data_clusters
>= 0x10000000) {
162 nbdkit_error ("disk image is too large for the FAT32 disk format");
166 nbdkit_debug ("floppy: %" PRIu64
" data clusters, "
167 "largest cluster number %" PRIu32
", "
169 floppy
->data_clusters
,
173 floppy
->fat_entries
= floppy
->data_clusters
+ 2;
174 floppy
->fat_clusters
= DIV_ROUND_UP (floppy
->fat_entries
* 4, CLUSTER_SIZE
);
176 nbdkit_debug ("floppy: %" PRIu64
" FAT entries", floppy
->fat_entries
);
178 /* We can now decide where we will place the FATs and data region on disk. */
179 floppy
->fat2_start_sector
=
180 2080 + floppy
->fat_clusters
* SECTORS_PER_CLUSTER
;
181 floppy
->data_start_sector
=
182 floppy
->fat2_start_sector
+ floppy
->fat_clusters
* SECTORS_PER_CLUSTER
;
183 floppy
->data_last_sector
=
184 floppy
->data_start_sector
+ floppy
->data_clusters
* SECTORS_PER_CLUSTER
- 1;
186 /* We now have to go back and update the cluster numbers in the
187 * directory entries (which we didn't have available during
188 * create_directory above).
190 for (i
= 0; i
< floppy
->dirs
.len
; ++i
) {
191 if (update_directory_first_cluster (i
, floppy
) == -1)
196 if (create_mbr (floppy
) == -1)
199 /* Create partition first sector. */
200 if (create_partition_boot_sector (label
, floppy
) == -1)
203 /* Create filesystem information sector. */
204 if (create_fsinfo (floppy
) == -1)
207 /* Allocate and populate FAT. */
208 if (create_fat (floppy
) == -1)
211 /* Now we know how large everything is we can create the virtual
214 if (create_regions (floppy
) == -1)
217 /* Check that if a size was specified, we ended up with it. */
219 assert (virtual_size (&floppy
->regions
) == size
);
225 free_virtual_floppy (struct virtual_floppy
*floppy
)
229 free_regions (&floppy
->regions
);
233 for (i
= 0; i
< floppy
->files
.len
; ++i
) {
234 free (floppy
->files
.ptr
[i
].name
);
235 free (floppy
->files
.ptr
[i
].host_path
);
237 free (floppy
->files
.ptr
);
239 for (i
= 0; i
< floppy
->dirs
.len
; ++i
) {
240 free (floppy
->dirs
.ptr
[i
].name
);
241 free (floppy
->dirs
.ptr
[i
].subdirs
.ptr
);
242 free (floppy
->dirs
.ptr
[i
].fileidxs
.ptr
);
243 free (floppy
->dirs
.ptr
[i
].table
.ptr
);
245 free (floppy
->dirs
.ptr
);
248 /* Visit files and directories.
250 * This constructs the floppy->dirs and floppy->files lists.
252 * Returns the directory index, or -1 on error.
255 visit (const char *dir
, struct virtual_floppy
*floppy
)
259 CLEANUP_FREE
char *origdir
= NULL
;
265 /* Reserve a new index in the directory array. Note that the root
266 * directory will always be at dirs[0].
268 memset (&null_dir
, 0, sizeof null_dir
);
269 di
= floppy
->dirs
.len
;
270 if (dirs_append (&floppy
->dirs
, null_dir
) == -1) {
271 nbdkit_error ("realloc: %m");
275 /* Because this is called from get_ready, before nbdkit daemonizes
276 * or starts any threads, it's safe to use chdir here and greatly
277 * simplifies the code. However we must chdir back to the original
278 * directory at the end.
280 origdir
= get_current_dir_name ();
281 if (origdir
== NULL
) {
282 nbdkit_error ("get_current_dir_name: %m");
285 if (chdir (dir
) == -1) {
286 nbdkit_error ("chdir: %s: %m", dir
);
292 nbdkit_error ("opendir: %s: %m", dir
);
296 while (errno
= 0, (d
= readdir (DIR)) != NULL
) {
297 if (strcmp (d
->d_name
, ".") == 0 ||
298 strcmp (d
->d_name
, "..") == 0)
301 if (lstat (d
->d_name
, &statbuf
) == -1) {
302 nbdkit_error ("stat: %s/%s: %m", dir
, d
->d_name
);
307 if (S_ISDIR (statbuf
.st_mode
)) {
308 if (visit_subdirectory (dir
, d
->d_name
, &statbuf
, di
, floppy
) == -1)
312 else if (S_ISREG (statbuf
.st_mode
)) {
313 if (visit_file (dir
, d
->d_name
, &statbuf
, di
, floppy
) == -1)
316 /* else ALL other file types are ignored - see documentation. */
319 /* Did readdir fail? */
321 nbdkit_error ("readdir: %s: %m", dir
);
325 if (closedir (DIR) == -1) {
326 nbdkit_error ("closedir: %s: %m", dir
);
330 if (chdir (origdir
) == -1) {
331 nbdkit_error ("chdir: %s: %m", origdir
);
340 #if defined (__GNUC__) && __GNUC__ >= 5
341 #pragma GCC diagnostic push
342 #pragma GCC diagnostic ignored "-Wunused-result"
345 #if defined (__GNUC__) && __GNUC__ >= 5
346 #pragma GCC diagnostic pop
353 /* This is called to visit a subdirectory in a directory. It
354 * recursively calls the visit() function, and then adds the
355 * subdirectory to the list of subdirectories in the parent.
358 visit_subdirectory (const char *dir
, const char *name
,
359 const struct stat
*statbuf
, size_t di
,
360 struct virtual_floppy
*floppy
)
362 CLEANUP_FREE
char *subdir
= NULL
;
363 ssize_t sdi
; /* subdirectory index */
365 if (asprintf (&subdir
, "%s/%s", dir
, name
) == -1) {
366 nbdkit_error ("asprintf: %m");
369 /* Recursively visit this directory. As a side effect this adds the
370 * new subdirectory to the global list of directories, and returns
371 * the index in that list (sdi).
373 sdi
= visit (subdir
, floppy
);
377 /* We must set sdi->name because visit() cannot set it. */
378 floppy
->dirs
.ptr
[sdi
].name
= strdup (name
);
379 if (floppy
->dirs
.ptr
[sdi
].name
== NULL
) {
380 nbdkit_error ("strdup: %m");
383 floppy
->dirs
.ptr
[sdi
].statbuf
= *statbuf
;
384 floppy
->dirs
.ptr
[sdi
].pdi
= di
;
386 /* Add to the list of subdirs in the parent directory (di). */
387 if (idxs_append (&floppy
->dirs
.ptr
[di
].subdirs
, sdi
) == -1) {
388 nbdkit_error ("realloc: %m");
395 /* This is called to visit a file in a directory. It performs some
396 * checks and then adds the file to the global list of files, and also
397 * adds the file to the list of files in the parent directory.
400 visit_file (const char *dir
, const char *name
,
401 const struct stat
*statbuf
, size_t di
,
402 struct virtual_floppy
*floppy
)
404 struct file new_file
;
408 if (asprintf (&host_path
, "%s/%s", dir
, name
) == -1) {
409 nbdkit_error ("asprintf: %m");
413 if (statbuf
->st_size
>= UINT32_MAX
) {
414 nbdkit_error ("%s: file is larger than maximum supported by VFAT",
420 /* Append to global list of files. */
421 memset (&new_file
, 0, sizeof new_file
);
422 new_file
.name
= strdup (name
);
423 if (new_file
.name
== NULL
) {
424 nbdkit_error ("strdup: %m");
428 new_file
.host_path
= host_path
;
429 new_file
.statbuf
= *statbuf
;
430 fi
= floppy
->files
.len
;
431 if (files_append (&floppy
->files
, new_file
) == -1) {
432 nbdkit_error ("realloc: %m");
433 free (new_file
.name
);
438 /* Add to the list of files in the parent directory (di). */
439 if (idxs_append (&floppy
->dirs
.ptr
[di
].fileidxs
, fi
) == -1) {
440 nbdkit_error ("realloc: %m");
447 /* Create the Master Boot Record sector of the disk. */
449 create_mbr (struct virtual_floppy
*floppy
)
451 uint32_t num_sectors
;
452 uint64_t last_sector
;
454 /* The last sector number in the partition. */
456 floppy
->data_start_sector
457 + floppy
->data_clusters
* SECTORS_PER_CLUSTER
460 nbdkit_debug ("floppy: last sector %" PRIu64
, last_sector
);
462 if (last_sector
>= UINT32_MAX
) {
463 nbdkit_error ("disk image is too large for the MBR disk format");
466 num_sectors
= last_sector
- 2048 + 1;
468 memcpy (floppy
->mbr
.oem_name
, OEM_NAME
, sizeof floppy
->mbr
.oem_name
);
470 /* We could choose a random disk signature, but it seems safer to
471 * leave the field zero.
473 floppy
->mbr
.disk_signature
= htole32 (0);
474 floppy
->mbr
.boot_signature
[0] = 0x55;
475 floppy
->mbr
.boot_signature
[1] = 0xAA;
477 /* Only one partition. */
478 floppy
->mbr
.partition
[0].bootable
= 0;
479 chs_too_large (floppy
->mbr
.partition
[0].chs
);
480 floppy
->mbr
.partition
[0].part_type
= 0x0c;
481 chs_too_large (floppy
->mbr
.partition
[0].chs2
);
482 floppy
->mbr
.partition
[0].start_sector
= htole32 (2048);
483 floppy
->mbr
.partition
[0].num_sectors
= htole32 (num_sectors
);
489 chs_too_large (uint8_t *out
)
491 const int c
= 1023, h
= 254, s
= 63;
494 out
[1] = (c
& 0x300) >> 2 | s
;
499 create_partition_boot_sector (const char *label
, struct virtual_floppy
*floppy
)
501 memcpy (floppy
->bootsect
.oem_name
, OEM_NAME
,
502 sizeof floppy
->bootsect
.oem_name
);
504 floppy
->bootsect
.bytes_per_sector
= htole16 (SECTOR_SIZE
);
505 floppy
->bootsect
.sectors_per_cluster
= SECTORS_PER_CLUSTER
;
506 floppy
->bootsect
.reserved_sectors
= htole16 (32);
507 floppy
->bootsect
.nr_fats
= 2;
508 floppy
->bootsect
.nr_root_dir_entries
= htole16 (0);
509 floppy
->bootsect
.old_nr_sectors
= htole16 (0);
510 floppy
->bootsect
.media_descriptor
= 0xf8;
511 floppy
->bootsect
.old_sectors_per_fat
= htole16 (0);
512 floppy
->bootsect
.sectors_per_track
= htole16 (0);
513 floppy
->bootsect
.nr_heads
= htole16 (0);
514 floppy
->bootsect
.nr_hidden_sectors
= htole32 (0);
515 floppy
->bootsect
.nr_sectors
= htole32 (floppy
->data_last_sector
- 2048 + 1);
517 floppy
->bootsect
.sectors_per_fat
=
518 htole32 (floppy
->fat_clusters
* SECTORS_PER_CLUSTER
);
519 floppy
->bootsect
.mirroring
= htole16 (0);
520 floppy
->bootsect
.fat_version
= htole16 (0);
521 floppy
->bootsect
.root_directory_cluster
= htole32 (2);
522 floppy
->bootsect
.fsinfo_sector
= htole16 (1);
523 floppy
->bootsect
.backup_bootsect
= htole16 (6);
524 floppy
->bootsect
.physical_drive_number
= 0;
525 floppy
->bootsect
.extended_boot_signature
= 0x29;
526 /* The volume ID should be generated based on the filesystem
527 * creation date and time, but the old qemu VVFAT driver just used a
530 floppy
->bootsect
.volume_id
= htole32 (0x01020304);
531 pad_string (label
, 11, floppy
->bootsect
.volume_label
);
532 memcpy (floppy
->bootsect
.fstype
, "FAT32 ", 8);
534 floppy
->bootsect
.boot_signature
[0] = 0x55;
535 floppy
->bootsect
.boot_signature
[1] = 0xAA;
541 create_fsinfo (struct virtual_floppy
*floppy
)
543 floppy
->fsinfo
.signature
[0] = 0x52; /* "RRaA" */
544 floppy
->fsinfo
.signature
[1] = 0x52;
545 floppy
->fsinfo
.signature
[2] = 0x61;
546 floppy
->fsinfo
.signature
[3] = 0x41;
547 floppy
->fsinfo
.signature2
[0] = 0x72; /* "rrAa" */
548 floppy
->fsinfo
.signature2
[1] = 0x72;
549 floppy
->fsinfo
.signature2
[2] = 0x41;
550 floppy
->fsinfo
.signature2
[3] = 0x61;
551 floppy
->fsinfo
.free_data_clusters
= htole32 (floppy
->data_clusters
-
552 floppy
->data_used_clusters
);
553 floppy
->fsinfo
.last_free_cluster
= htole32 (2 + floppy
->data_used_clusters
);
554 floppy
->fsinfo
.signature3
[0] = 0x00;
555 floppy
->fsinfo
.signature3
[1] = 0x00;
556 floppy
->fsinfo
.signature3
[2] = 0x55;
557 floppy
->fsinfo
.signature3
[3] = 0xAA;
561 /* Allocate and populate the File Allocation Table. */
563 create_fat (struct virtual_floppy
*floppy
)
567 /* Note there is only one copy held in memory. The two FAT
568 * regions in the virtual disk point to the same copy.
570 floppy
->fat
= calloc (floppy
->fat_entries
, 4);
571 if (floppy
->fat
== NULL
) {
572 nbdkit_error ("calloc: %m");
576 /* Populate the FAT. First two entries are reserved and
577 * contain standard data.
579 floppy
->fat
[0] = htole32 (0x0ffffff8);
580 floppy
->fat
[1] = htole32 (0x0fffffff);
582 for (i
= 0; i
< floppy
->dirs
.len
; ++i
) {
583 write_fat_file (floppy
->dirs
.ptr
[i
].first_cluster
,
584 floppy
->dirs
.ptr
[i
].nr_clusters
, floppy
);
586 for (i
= 0; i
< floppy
->files
.len
; ++i
) {
587 write_fat_file (floppy
->files
.ptr
[i
].first_cluster
,
588 floppy
->files
.ptr
[i
].nr_clusters
, floppy
);
595 write_fat_file (uint32_t first_cluster
, uint32_t nr_clusters
,
596 struct virtual_floppy
*floppy
)
600 /* It's possible for files to have zero size. These don't occupy
601 * any space in the disk or FAT so we just skip them here.
603 if (nr_clusters
== 0)
606 for (cl
= 0; cl
< nr_clusters
- 1; ++cl
) {
607 assert (first_cluster
+ cl
< floppy
->fat_entries
);
608 /* Directories and files are stored contiguously so the entry in
609 * the FAT always points to the next cluster (except for the
610 * last one, handled below).
612 floppy
->fat
[first_cluster
+ cl
] = htole32 (first_cluster
+ cl
+ 1);
615 /* Last cluster / end of file marker. */
616 floppy
->fat
[first_cluster
+ cl
] = htole32 (0x0fffffff);
619 /* Lay out the final virtual disk. */
621 create_regions (struct virtual_floppy
*floppy
)
625 /* MBR + free space to pad the partition to sector 2048. */
626 if (append_region_len (&floppy
->regions
, "MBR",
627 SECTOR_SIZE
, 0, 2048*SECTOR_SIZE
,
628 region_data
, (void *) &floppy
->mbr
) == -1)
631 /* Partition boot sector. */
632 if (append_region_len (&floppy
->regions
, "partition boot sector",
634 region_data
, (void *) &floppy
->bootsect
) == -1)
637 /* Filesystem information sector. */
638 if (append_region_len (&floppy
->regions
, "filesystem information sector",
640 region_data
, (void *) &floppy
->fsinfo
) == -1)
643 /* Free space (reserved sectors 2-5). */
644 if (append_region_len (&floppy
->regions
, "reserved sectors 2-5",
649 /* Backup boot sector. */
650 if (append_region_len (&floppy
->regions
, "backup boot sector",
652 region_data
, (void *) &floppy
->bootsect
) == -1)
655 /* Free space (reserved sectors 7-31). */
656 if (append_region_len (&floppy
->regions
, "reserved sectors 7-31",
657 25*SECTOR_SIZE
, 0, 0,
661 /* First copy of FAT. */
662 if (append_region_len (&floppy
->regions
, "FAT #1",
663 floppy
->fat_entries
*4, 0, CLUSTER_SIZE
,
664 region_data
, (void *) floppy
->fat
) == -1)
667 /* Check that fat2_start_sector and region calculation match. */
668 assert (virtual_size (&floppy
->regions
) ==
669 floppy
->fat2_start_sector
* SECTOR_SIZE
);
671 /* Second copy of FAT. */
672 if (append_region_len (&floppy
->regions
, "FAT #2",
673 floppy
->fat_entries
*4, 0, CLUSTER_SIZE
,
674 region_data
, (void *) floppy
->fat
) == -1)
677 /* Check that data_start_sector and region calculation match. */
678 assert (virtual_size (&floppy
->regions
) ==
679 floppy
->data_start_sector
* SECTOR_SIZE
);
681 /* Now we're into the data region. We add all directory tables
684 for (i
= 0; i
< floppy
->dirs
.len
; ++i
) {
685 /* Directories can never be completely empty because of the volume
686 * label (root) or "." and ".." entries (non-root).
688 assert (floppy
->dirs
.ptr
[i
].table
.len
> 0);
690 if (append_region_len (&floppy
->regions
,
691 i
== 0 ? "root directory" : floppy
->dirs
.ptr
[i
].name
,
692 floppy
->dirs
.ptr
[i
].table
.len
*
693 sizeof (struct dir_entry
),
696 (void *) floppy
->dirs
.ptr
[i
].table
.ptr
) == -1)
701 for (i
= 0; i
< floppy
->files
.len
; ++i
) {
702 /* It's possible for a file to have zero size, in which case it
703 * doesn't occupy a region or cluster.
705 if (floppy
->files
.ptr
[i
].statbuf
.st_size
== 0)
708 if (append_region_len (&floppy
->regions
, floppy
->files
.ptr
[i
].name
,
709 floppy
->files
.ptr
[i
].statbuf
.st_size
,
711 region_file
, i
) == -1)
715 /* Append region for empty data region if we have extra space. */
716 if (floppy
->data_used_clusters
!= floppy
->data_clusters
) {
717 uint64_t clusters
= floppy
->data_clusters
- floppy
->data_used_clusters
;
718 if (append_region_len (&floppy
->regions
, "data padding",
719 clusters
* CLUSTER_SIZE
, 0, CLUSTER_SIZE
,
724 nbdkit_debug ("floppy: %zu regions, "
725 "total disk size %" PRIi64
,
726 nr_regions (&floppy
->regions
),
727 virtual_size (&floppy
->regions
));