Update Red Hat Copyright Notices
[nbdkit.git] / plugins / floppy / virtual-floppy.c
blob2a6871bce6be0d0a8b33067aaae0623253ccda0a
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <inttypes.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <dirent.h>
44 #include <assert.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
48 #include <nbdkit-plugin.h>
50 #include "byte-swapping.h"
51 #include "cleanup.h"
52 #include "get_current_dir_name.h"
53 #include "regions.h"
54 #include "rounding.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);
74 void
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);
87 int
88 create_virtual_floppy (const char *dir, const char *label, uint64_t size,
89 struct virtual_floppy *floppy)
91 size_t i;
92 uint64_t nr_bytes, nr_clusters;
93 uint64_t data_used_size;
94 uint32_t cluster;
96 if (visit (dir, floppy) == -1)
97 return -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)
105 return -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.
116 data_used_size = 0;
117 cluster = 2;
118 for (i = 0; i < floppy->dirs.len; ++i) {
119 floppy->dirs.ptr[i].first_cluster = cluster;
120 nr_bytes =
121 ROUND_UP (floppy->dirs.ptr[i].table.len * sizeof (struct dir_entry),
122 CLUSTER_SIZE);
123 data_used_size += nr_bytes;
124 nr_clusters = nr_bytes / CLUSTER_SIZE;
125 if (cluster + nr_clusters > UINT32_MAX)
126 goto too_big;
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)
136 goto too_big;
137 floppy->files.ptr[i].nr_clusters = nr_clusters;
138 cluster += nr_clusters;
141 if (size > 0) {
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");
147 return -1;
149 floppy->data_size = data_size;
150 } else {
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) {
161 too_big:
162 nbdkit_error ("disk image is too large for the FAT32 disk format");
163 return -1;
166 nbdkit_debug ("floppy: %" PRIu64 " data clusters, "
167 "largest cluster number %" PRIu32 ", "
168 "%" PRIu64 " bytes",
169 floppy->data_clusters,
170 cluster-1,
171 floppy->data_size);
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)
192 return -1;
195 /* Create MBR. */
196 if (create_mbr (floppy) == -1)
197 return -1;
199 /* Create partition first sector. */
200 if (create_partition_boot_sector (label, floppy) == -1)
201 return -1;
203 /* Create filesystem information sector. */
204 if (create_fsinfo (floppy) == -1)
205 return -1;
207 /* Allocate and populate FAT. */
208 if (create_fat (floppy) == -1)
209 return -1;
211 /* Now we know how large everything is we can create the virtual
212 * disk regions.
214 if (create_regions (floppy) == -1)
215 return -1;
217 /* Check that if a size was specified, we ended up with it. */
218 if (size > 0)
219 assert (virtual_size (&floppy->regions) == size);
221 return 0;
224 void
225 free_virtual_floppy (struct virtual_floppy *floppy)
227 size_t i;
229 free_regions (&floppy->regions);
231 free (floppy->fat);
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.
254 static ssize_t
255 visit (const char *dir, struct virtual_floppy *floppy)
257 struct dir null_dir;
258 size_t di;
259 CLEANUP_FREE char *origdir = NULL;
260 DIR *DIR;
261 struct dirent *d;
262 int err;
263 struct stat statbuf;
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");
272 goto error0;
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");
283 goto error0;
285 if (chdir (dir) == -1) {
286 nbdkit_error ("chdir: %s: %m", dir);
287 goto error1;
290 DIR = opendir (".");
291 if (DIR == NULL) {
292 nbdkit_error ("opendir: %s: %m", dir);
293 goto error1;
296 while (errno = 0, (d = readdir (DIR)) != NULL) {
297 if (strcmp (d->d_name, ".") == 0 ||
298 strcmp (d->d_name, "..") == 0)
299 continue;
301 if (lstat (d->d_name, &statbuf) == -1) {
302 nbdkit_error ("stat: %s/%s: %m", dir, d->d_name);
303 goto error2;
306 /* Directory. */
307 if (S_ISDIR (statbuf.st_mode)) {
308 if (visit_subdirectory (dir, d->d_name, &statbuf, di, floppy) == -1)
309 goto error2;
311 /* Regular file. */
312 else if (S_ISREG (statbuf.st_mode)) {
313 if (visit_file (dir, d->d_name, &statbuf, di, floppy) == -1)
314 goto error2;
316 /* else ALL other file types are ignored - see documentation. */
319 /* Did readdir fail? */
320 if (errno != 0) {
321 nbdkit_error ("readdir: %s: %m", dir);
322 goto error2;
325 if (closedir (DIR) == -1) {
326 nbdkit_error ("closedir: %s: %m", dir);
327 goto error1;
330 if (chdir (origdir) == -1) {
331 nbdkit_error ("chdir: %s: %m", origdir);
332 goto error1;
334 return di;
336 error2:
337 closedir (DIR);
338 error1:
339 err = errno;
340 #if defined (__GNUC__) && __GNUC__ >= 5
341 #pragma GCC diagnostic push
342 #pragma GCC diagnostic ignored "-Wunused-result"
343 #endif
344 chdir (origdir);
345 #if defined (__GNUC__) && __GNUC__ >= 5
346 #pragma GCC diagnostic pop
347 #endif
348 errno = err;
349 error0:
350 return -1;
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.
357 static int
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");
367 return -1;
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);
374 if (sdi == -1)
375 return -1;
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");
381 return -1;
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");
389 return -1;
392 return 0;
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.
399 static int
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;
405 char *host_path;
406 size_t fi;
408 if (asprintf (&host_path, "%s/%s", dir, name) == -1) {
409 nbdkit_error ("asprintf: %m");
410 return -1;
413 if (statbuf->st_size >= UINT32_MAX) {
414 nbdkit_error ("%s: file is larger than maximum supported by VFAT",
415 host_path);
416 free (host_path);
417 return -1;
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");
425 free (host_path);
426 return -1;
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);
434 free (host_path);
435 return -1;
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");
441 return -1;
444 return 0;
447 /* Create the Master Boot Record sector of the disk. */
448 static int
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. */
455 last_sector =
456 floppy->data_start_sector
457 + floppy->data_clusters * SECTORS_PER_CLUSTER
458 - 1;
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");
464 return -1;
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);
485 return 0;
488 static void
489 chs_too_large (uint8_t *out)
491 const int c = 1023, h = 254, s = 63;
493 out[0] = h;
494 out[1] = (c & 0x300) >> 2 | s;
495 out[2] = c & 0xff;
498 static int
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
528 * fixed number here.
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;
537 return 0;
540 static int
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;
558 return 0;
561 /* Allocate and populate the File Allocation Table. */
562 static int
563 create_fat (struct virtual_floppy *floppy)
565 size_t i;
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");
573 return -1;
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);
591 return 0;
594 static void
595 write_fat_file (uint32_t first_cluster, uint32_t nr_clusters,
596 struct virtual_floppy *floppy)
598 uint32_t cl;
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)
604 return;
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. */
620 static int
621 create_regions (struct virtual_floppy *floppy)
623 size_t i;
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)
629 return -1;
631 /* Partition boot sector. */
632 if (append_region_len (&floppy->regions, "partition boot sector",
633 SECTOR_SIZE, 0, 0,
634 region_data, (void *) &floppy->bootsect) == -1)
635 return -1;
637 /* Filesystem information sector. */
638 if (append_region_len (&floppy->regions, "filesystem information sector",
639 SECTOR_SIZE, 0, 0,
640 region_data, (void *) &floppy->fsinfo) == -1)
641 return -1;
643 /* Free space (reserved sectors 2-5). */
644 if (append_region_len (&floppy->regions, "reserved sectors 2-5",
645 4*SECTOR_SIZE, 0, 0,
646 region_zero) == -1)
647 return -1;
649 /* Backup boot sector. */
650 if (append_region_len (&floppy->regions, "backup boot sector",
651 SECTOR_SIZE, 0, 0,
652 region_data, (void *) &floppy->bootsect) == -1)
653 return -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,
658 region_zero) == -1)
659 return -1;
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)
665 return -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)
675 return -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
682 * first.
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),
694 0, CLUSTER_SIZE,
695 region_data,
696 (void *) floppy->dirs.ptr[i].table.ptr) == -1)
697 return -1;
700 /* Add all files. */
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)
706 continue;
708 if (append_region_len (&floppy->regions, floppy->files.ptr[i].name,
709 floppy->files.ptr[i].statbuf.st_size,
710 0, CLUSTER_SIZE,
711 region_file, i) == -1)
712 return -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,
720 region_zero) == -1)
721 return -1;
724 nbdkit_debug ("floppy: %zu regions, "
725 "total disk size %" PRIi64,
726 nr_regions (&floppy->regions),
727 virtual_size (&floppy->regions));
729 return 0;