]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/makefs/ffs.c
Allocate extra inodes in makefs when leaving free space in UFS images.
[FreeBSD/FreeBSD.git] / usr.sbin / makefs / ffs.c
1 /*      $NetBSD: ffs.c,v 1.45 2011/10/09 22:49:26 christos Exp $        */
2
3 /*-
4  * SPDX-License-Identifier: BSD-4-Clause
5  *
6  * Copyright (c) 2001 Wasabi Systems, Inc.
7  * All rights reserved.
8  *
9  * Written by Luke Mewburn for Wasabi Systems, Inc.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed for the NetBSD Project by
22  *      Wasabi Systems, Inc.
23  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
24  *    or promote products derived from this software without specific prior
25  *    written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 /*
40  * Copyright (c) 1982, 1986, 1989, 1993
41  *      The Regents of the University of California.  All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  *
67  *      @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
68  */
69
70 #include <sys/cdefs.h>
71 __FBSDID("$FreeBSD$");
72
73 #if HAVE_NBTOOL_CONFIG_H
74 #include "nbtool_config.h"
75 #endif
76
77 #include <sys/param.h>
78
79 #include <sys/mount.h>
80
81 #include <assert.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <stdarg.h>
85 #include <stdint.h>
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <string.h>
89 #include <time.h>
90 #include <unistd.h>
91 #include <util.h>
92
93 #include "makefs.h"
94 #include "ffs.h"
95
96 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
97 #include <sys/statvfs.h>
98 #endif
99
100 #include <ufs/ufs/dinode.h>
101 #include <ufs/ufs/dir.h>
102 #include <ufs/ffs/fs.h>
103
104
105 #include "ffs/ufs_bswap.h"
106 #include "ffs/ufs_inode.h"
107 #include "ffs/newfs_extern.h"
108 #include "ffs/ffs_extern.h"
109
110 #undef DIP
111 #define DIP(dp, field) \
112         ((ffs_opts->version == 1) ? \
113         (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
114
115 /*
116  * Various file system defaults (cribbed from newfs(8)).
117  */
118 #define DFL_FRAGSIZE            4096            /* fragment size */
119 #define DFL_BLKSIZE             32768           /* block size */
120 #define DFL_SECSIZE             512             /* sector size */
121 #define DFL_CYLSPERGROUP        65536           /* cylinders per group */
122 #define DFL_FRAGSPERINODE       4               /* fragments per inode */
123 #define DFL_ROTDELAY            0               /* rotational delay */
124 #define DFL_NRPOS               1               /* rotational positions */
125 #define DFL_RPM                 3600            /* rpm of disk */
126 #define DFL_NSECTORS            64              /* # of sectors */
127 #define DFL_NTRACKS             16              /* # of tracks */
128
129
130 typedef struct {
131         u_char          *buf;           /* buf for directory */
132         doff_t          size;           /* full size of buf */
133         doff_t          cur;            /* offset of current entry */
134 } dirbuf_t;
135
136
137 static  int     ffs_create_image(const char *, fsinfo_t *);
138 static  void    ffs_dump_fsinfo(fsinfo_t *);
139 static  void    ffs_dump_dirbuf(dirbuf_t *, const char *, int);
140 static  void    ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int);
141 static  int     ffs_populate_dir(const char *, fsnode *, fsinfo_t *);
142 static  void    ffs_size_dir(fsnode *, fsinfo_t *);
143 static  void    ffs_validate(const char *, fsnode *, fsinfo_t *);
144 static  void    ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *);
145 static  void    ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *);
146 static  void    *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *,
147                                  fsnode *, fsinfo_t *);
148 static  void    *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *,
149                                  fsnode *, fsinfo_t *);
150
151
152         /* publicly visible functions */
153
154 void
155 ffs_prep_opts(fsinfo_t *fsopts)
156 {
157         ffs_opt_t *ffs_opts = ecalloc(1, sizeof(*ffs_opts));
158
159         const option_t ffs_options[] = {
160             { 'b', "bsize", &ffs_opts->bsize, OPT_INT32,
161               1, INT_MAX, "block size" },
162             { 'f', "fsize", &ffs_opts->fsize, OPT_INT32,
163               1, INT_MAX, "fragment size" },
164             { 'd', "density", &ffs_opts->density, OPT_INT32,
165               1, INT_MAX, "bytes per inode" },
166             { 'm', "minfree", &ffs_opts->minfree, OPT_INT32,
167               0, 99, "minfree" },
168             { 'M', "maxbpg", &ffs_opts->maxbpg, OPT_INT32,
169               1, INT_MAX, "max blocks per file in a cg" },
170             { 'a', "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32,
171               1, INT_MAX, "expected average file size" },
172             { 'n', "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32,
173               1, INT_MAX, "expected # of files per directory" },
174             { 'x', "extent", &ffs_opts->maxbsize, OPT_INT32,
175               1, INT_MAX, "maximum # extent size" },
176             { 'g', "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32,
177               1, INT_MAX, "max # of blocks per group" },
178             { 'v', "version", &ffs_opts->version, OPT_INT32,
179               1, 2, "UFS version" },
180             { 'o', "optimization", NULL, OPT_STRBUF,
181               0, 0, "Optimization (time|space)" },
182             { 'l', "label", ffs_opts->label, OPT_STRARRAY,
183               1, sizeof(ffs_opts->label), "UFS label" },
184             { 's', "softupdates", &ffs_opts->softupdates, OPT_INT32,
185               0, 1, "enable softupdates" },
186             { .name = NULL }
187         };
188
189         ffs_opts->bsize= -1;
190         ffs_opts->fsize= -1;
191         ffs_opts->cpg= -1;
192         ffs_opts->density= -1;
193         ffs_opts->min_inodes= false;
194         ffs_opts->minfree= -1;
195         ffs_opts->optimization= -1;
196         ffs_opts->maxcontig= -1;
197         ffs_opts->maxbpg= -1;
198         ffs_opts->avgfilesize= -1;
199         ffs_opts->avgfpdir= -1;
200         ffs_opts->version = 1;
201         ffs_opts->softupdates = 0;
202
203         fsopts->fs_specific = ffs_opts;
204         fsopts->fs_options = copy_opts(ffs_options);
205 }
206
207 void
208 ffs_cleanup_opts(fsinfo_t *fsopts)
209 {
210         free(fsopts->fs_specific);
211         free(fsopts->fs_options);
212 }
213
214 int
215 ffs_parse_opts(const char *option, fsinfo_t *fsopts)
216 {
217         ffs_opt_t       *ffs_opts = fsopts->fs_specific;
218         option_t *ffs_options = fsopts->fs_options;
219         char buf[1024];
220
221         int     rv;
222
223         assert(option != NULL);
224         assert(fsopts != NULL);
225         assert(ffs_opts != NULL);
226
227         if (debug & DEBUG_FS_PARSE_OPTS)
228                 printf("ffs_parse_opts: got `%s'\n", option);
229
230         rv = set_option(ffs_options, option, buf, sizeof(buf));
231         if (rv == -1)
232                 return 0;
233
234         if (ffs_options[rv].name == NULL)
235                 abort();
236
237         switch (ffs_options[rv].letter) {
238         case 'o':
239                 if (strcmp(buf, "time") == 0) {
240                         ffs_opts->optimization = FS_OPTTIME;
241                 } else if (strcmp(buf, "space") == 0) {
242                         ffs_opts->optimization = FS_OPTSPACE;
243                 } else {
244                         warnx("Invalid optimization `%s'", buf);
245                         return 0;
246                 }
247                 break;
248         default:
249                 break;
250         }
251         return 1;
252 }
253
254
255 void
256 ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
257 {
258         struct fs       *superblock;
259         struct timeval  start;
260
261         assert(image != NULL);
262         assert(dir != NULL);
263         assert(root != NULL);
264         assert(fsopts != NULL);
265
266         if (debug & DEBUG_FS_MAKEFS)
267                 printf("ffs_makefs: image %s directory %s root %p\n",
268                     image, dir, root);
269
270                 /* if user wants no free space, use minimum number of inodes */
271         if (fsopts->minsize == 0 && fsopts->freeblockpc == 0 &&
272             fsopts->freeblocks == 0)
273                 ((ffs_opt_t *)fsopts->fs_specific)->min_inodes = true;
274
275                 /* validate tree and options */
276         TIMER_START(start);
277         ffs_validate(dir, root, fsopts);
278         TIMER_RESULTS(start, "ffs_validate");
279
280         printf("Calculated size of `%s': %lld bytes, %lld inodes\n",
281             image, (long long)fsopts->size, (long long)fsopts->inodes);
282
283                 /* create image */
284         TIMER_START(start);
285         if (ffs_create_image(image, fsopts) == -1)
286                 errx(1, "Image file `%s' not created.", image);
287         TIMER_RESULTS(start, "ffs_create_image");
288
289         fsopts->curinode = UFS_ROOTINO;
290
291         if (debug & DEBUG_FS_MAKEFS)
292                 putchar('\n');
293
294                 /* populate image */
295         printf("Populating `%s'\n", image);
296         TIMER_START(start);
297         if (! ffs_populate_dir(dir, root, fsopts))
298                 errx(1, "Image file `%s' not populated.", image);
299         TIMER_RESULTS(start, "ffs_populate_dir");
300
301                 /* ensure no outstanding buffers remain */
302         if (debug & DEBUG_FS_MAKEFS)
303                 bcleanup();
304
305                 /* update various superblock parameters */
306         superblock = fsopts->superblock;
307         superblock->fs_fmod = 0;
308         superblock->fs_old_cstotal.cs_ndir   = superblock->fs_cstotal.cs_ndir;
309         superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree;
310         superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree;
311         superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree;
312
313                 /* write out superblock; image is now complete */
314         ffs_write_superblock(fsopts->superblock, fsopts);
315         if (close(fsopts->fd) == -1)
316                 err(1, "Closing `%s'", image);
317         fsopts->fd = -1;
318         printf("Image `%s' complete\n", image);
319 }
320
321         /* end of public functions */
322
323
324 static void
325 ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
326 {
327         int32_t ncg = 1;
328 #ifdef notyet
329         int32_t spc, nspf, ncyl, fssize;
330 #endif
331         ffs_opt_t       *ffs_opts = fsopts->fs_specific;
332
333         assert(dir != NULL);
334         assert(root != NULL);
335         assert(fsopts != NULL);
336         assert(ffs_opts != NULL);
337
338         if (debug & DEBUG_FS_VALIDATE) {
339                 printf("ffs_validate: before defaults set:\n");
340                 ffs_dump_fsinfo(fsopts);
341         }
342
343                 /* set FFS defaults */
344         if (fsopts->sectorsize == -1)
345                 fsopts->sectorsize = DFL_SECSIZE;
346         if (ffs_opts->fsize == -1)
347                 ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
348         if (ffs_opts->bsize == -1)
349                 ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize);
350         if (ffs_opts->cpg == -1)
351                 ffs_opts->cpg = DFL_CYLSPERGROUP;
352         else
353                 ffs_opts->cpgflg = 1;
354                                 /* fsopts->density is set below */
355         if (ffs_opts->nsectors == -1)
356                 ffs_opts->nsectors = DFL_NSECTORS;
357         if (ffs_opts->minfree == -1)
358                 ffs_opts->minfree = MINFREE;
359         if (ffs_opts->optimization == -1)
360                 ffs_opts->optimization = DEFAULTOPT;
361         if (ffs_opts->maxcontig == -1)
362                 ffs_opts->maxcontig =
363                     MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize);
364         /* XXX ondisk32 */
365         if (ffs_opts->maxbpg == -1)
366                 ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
367         if (ffs_opts->avgfilesize == -1)
368                 ffs_opts->avgfilesize = AVFILESIZ;
369         if (ffs_opts->avgfpdir == -1)
370                 ffs_opts->avgfpdir = AFPDIR;
371
372         if (fsopts->maxsize > 0 &&
373             roundup(fsopts->minsize, ffs_opts->bsize) > fsopts->maxsize)
374                 errx(1, "`%s' minsize of %lld rounded up to ffs bsize of %d "
375                     "exceeds maxsize %lld.  Lower bsize, or round the minimum "
376                     "and maximum sizes to bsize.", dir,
377                     (long long)fsopts->minsize, ffs_opts->bsize,
378                     (long long)fsopts->maxsize);
379
380                 /* calculate size of tree */
381         ffs_size_dir(root, fsopts);
382         fsopts->inodes += UFS_ROOTINO;          /* include first two inodes */
383
384         if (debug & DEBUG_FS_VALIDATE)
385                 printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n",
386                     (long long)fsopts->size, (long long)fsopts->inodes);
387
388                 /* add requested slop */
389         fsopts->size += fsopts->freeblocks;
390         fsopts->inodes += fsopts->freefiles;
391         if (fsopts->freefilepc > 0)
392                 fsopts->inodes =
393                     fsopts->inodes * (100 + fsopts->freefilepc) / 100;
394         if (fsopts->freeblockpc > 0)
395                 fsopts->size =
396                     fsopts->size * (100 + fsopts->freeblockpc) / 100;
397
398                 /* add space needed for superblocks */
399         /*
400          * The old SBOFF (SBLOCK_UFS1) is used here because makefs is
401          * typically used for small filesystems where space matters.
402          * XXX make this an option.
403          */
404         fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
405                 /* add space needed to store inodes, x3 for blockmaps, etc */
406         if (ffs_opts->version == 1)
407                 fsopts->size += ncg * DINODE1_SIZE *
408                     roundup(fsopts->inodes / ncg, 
409                         ffs_opts->bsize / DINODE1_SIZE);
410         else
411                 fsopts->size += ncg * DINODE2_SIZE *
412                     roundup(fsopts->inodes / ncg, 
413                         ffs_opts->bsize / DINODE2_SIZE);
414
415                 /* add minfree */
416         if (ffs_opts->minfree > 0)
417                 fsopts->size =
418                     fsopts->size * (100 + ffs_opts->minfree) / 100;
419         /*
420          * XXX  any other fs slop to add, such as csum's, bitmaps, etc ??
421          */
422
423         if (fsopts->size < fsopts->minsize)     /* ensure meets minimum size */
424                 fsopts->size = fsopts->minsize;
425
426                 /* round up to the next block */
427         fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
428
429                 /* round up to requested block size, if any */
430         if (fsopts->roundup > 0)
431                 fsopts->size = roundup(fsopts->size, fsopts->roundup);
432
433                 /* calculate density to just fit inodes if no free space */
434         if (ffs_opts->density == -1)
435                 ffs_opts->density = fsopts->size / fsopts->inodes + 1;
436
437         if (debug & DEBUG_FS_VALIDATE) {
438                 printf("ffs_validate: after defaults set:\n");
439                 ffs_dump_fsinfo(fsopts);
440                 printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n",
441                     dir, (long long)fsopts->size, (long long)fsopts->inodes);
442         }
443                 /* now check calculated sizes vs requested sizes */
444         if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
445                 errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
446                     dir, (long long)fsopts->size, (long long)fsopts->maxsize);
447         }
448 }
449
450
451 static void
452 ffs_dump_fsinfo(fsinfo_t *f)
453 {
454
455         ffs_opt_t       *fs = f->fs_specific;
456
457         printf("fsopts at %p\n", f);
458
459         printf("\tsize %lld, inodes %lld, curinode %u\n",
460             (long long)f->size, (long long)f->inodes, f->curinode);
461
462         printf("\tminsize %lld, maxsize %lld\n",
463             (long long)f->minsize, (long long)f->maxsize);
464         printf("\tfree files %lld, freefile %% %d\n",
465             (long long)f->freefiles, f->freefilepc);
466         printf("\tfree blocks %lld, freeblock %% %d\n",
467             (long long)f->freeblocks, f->freeblockpc);
468         printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
469
470         printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
471             fs->bsize, fs->fsize, fs->cpg, fs->density);
472         printf("\tnsectors %d, rpm %d, minfree %d\n",
473             fs->nsectors, fs->rpm, fs->minfree);
474         printf("\tmaxcontig %d, maxbpg %d\n",
475             fs->maxcontig, fs->maxbpg);
476         printf("\toptimization %s\n",
477             fs->optimization == FS_OPTSPACE ? "space" : "time");
478 }
479
480
481 static int
482 ffs_create_image(const char *image, fsinfo_t *fsopts)
483 {
484 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
485         struct statvfs  sfs;
486 #endif
487         struct fs       *fs;
488         char    *buf;
489         int     i, bufsize;
490         off_t   bufrem;
491         int     oflags = O_RDWR | O_CREAT;
492         time_t  tstamp;
493
494         assert (image != NULL);
495         assert (fsopts != NULL);
496
497                 /* create image */
498         if (fsopts->offset == 0)
499                 oflags |= O_TRUNC;
500         if ((fsopts->fd = open(image, oflags, 0666)) == -1) {
501                 warn("Can't open `%s' for writing", image);
502                 return (-1);
503         }
504
505                 /* zero image */
506 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
507         if (fstatvfs(fsopts->fd, &sfs) == -1) {
508 #endif
509                 bufsize = 8192;
510 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
511                 warn("can't fstatvfs `%s', using default %d byte chunk",
512                     image, bufsize);
513         } else
514                 bufsize = sfs.f_iosize;
515 #endif
516         bufrem = fsopts->size;
517         if (fsopts->sparse) {
518                 if (ftruncate(fsopts->fd, bufrem) == -1) {
519                         warn("sparse option disabled.");
520                         fsopts->sparse = 0;
521                 }
522         }
523         if (fsopts->sparse) {
524                 /* File truncated at bufrem. Remaining is 0 */
525                 bufrem = 0;
526                 buf = NULL;
527         } else {
528                 if (debug & DEBUG_FS_CREATE_IMAGE)
529                         printf("zero-ing image `%s', %lld sectors, "
530                             "using %d byte chunks\n", image, (long long)bufrem,
531                             bufsize);
532                 buf = ecalloc(1, bufsize);
533         }
534
535         if (fsopts->offset != 0)
536                 if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) {
537                         warn("can't seek");
538                         free(buf);
539                         return -1;
540                 }
541
542         while (bufrem > 0) {
543                 i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
544                 if (i == -1) {
545                         warn("zeroing image, %lld bytes to go",
546                             (long long)bufrem);
547                         free(buf);
548                         return (-1);
549                 }
550                 bufrem -= i;
551         }
552         if (buf)
553                 free(buf);
554
555                 /* make the file system */
556         if (debug & DEBUG_FS_CREATE_IMAGE)
557                 printf("calling mkfs(\"%s\", ...)\n", image);
558
559         if (stampst.st_ino != 0)
560                 tstamp = stampst.st_ctime;
561         else
562                 tstamp = start_time.tv_sec;
563
564         srandom(tstamp);
565
566         fs = ffs_mkfs(image, fsopts, tstamp);
567         fsopts->superblock = (void *)fs;
568         if (debug & DEBUG_FS_CREATE_IMAGE) {
569                 time_t t;
570
571                 t = (time_t)((struct fs *)fsopts->superblock)->fs_time;
572                 printf("mkfs returned %p; fs_time %s",
573                     fsopts->superblock, ctime(&t));
574                 printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n",
575                     (long long)fs->fs_cstotal.cs_nbfree,
576                     (long long)fs->fs_cstotal.cs_nffree,
577                     (long long)fs->fs_cstotal.cs_nifree,
578                     (long long)fs->fs_cstotal.cs_ndir);
579         }
580
581         if (fs->fs_cstotal.cs_nifree + UFS_ROOTINO < fsopts->inodes) {
582                 warnx(
583                 "Image file `%s' has %lld free inodes; %lld are required.",
584                     image,
585                     (long long)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO),
586                     (long long)fsopts->inodes);
587                 return (-1);
588         }
589         return (fsopts->fd);
590 }
591
592
593 static void
594 ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
595 {
596         struct direct   tmpdir;
597         fsnode *        node;
598         int             curdirsize, this;
599         ffs_opt_t       *ffs_opts = fsopts->fs_specific;
600
601         /* node may be NULL (empty directory) */
602         assert(fsopts != NULL);
603         assert(ffs_opts != NULL);
604
605         if (debug & DEBUG_FS_SIZE_DIR)
606                 printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
607                     (long long)fsopts->size, (long long)fsopts->inodes);
608
609 #define ADDDIRENT(e) do {                                               \
610         tmpdir.d_namlen = strlen((e));                                  \
611         this = DIRSIZ_SWAP(0, &tmpdir, 0);                                      \
612         if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)                       \
613                 printf("ADDDIRENT: was: %s (%d) this %d cur %d\n",      \
614                     e, tmpdir.d_namlen, this, curdirsize);              \
615         if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ))         \
616                 curdirsize = roundup(curdirsize, DIRBLKSIZ);            \
617         curdirsize += this;                                             \
618         if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)                       \
619                 printf("ADDDIRENT: now: %s (%d) this %d cur %d\n",      \
620                     e, tmpdir.d_namlen, this, curdirsize);              \
621 } while (0);
622
623         /*
624          * XXX  this needs to take into account extra space consumed
625          *      by indirect blocks, etc.
626          */
627 #define ADDSIZE(x) do {                                                 \
628         fsopts->size += roundup((x), ffs_opts->fsize);                  \
629 } while (0);
630
631         curdirsize = 0;
632         for (node = root; node != NULL; node = node->next) {
633                 ADDDIRENT(node->name);
634                 if (node == root) {                     /* we're at "." */
635                         assert(strcmp(node->name, ".") == 0);
636                         ADDDIRENT("..");
637                 } else if ((node->inode->flags & FI_SIZED) == 0) {
638                                 /* don't count duplicate names */
639                         node->inode->flags |= FI_SIZED;
640                         if (debug & DEBUG_FS_SIZE_DIR_NODE)
641                                 printf("ffs_size_dir: `%s' size %lld\n",
642                                     node->name,
643                                     (long long)node->inode->st.st_size);
644                         fsopts->inodes++;
645                         if (node->type == S_IFREG)
646                                 ADDSIZE(node->inode->st.st_size);
647                         if (node->type == S_IFLNK) {
648                                 size_t slen;
649
650                                 slen = strlen(node->symlink) + 1;
651                                 if (slen >= (ffs_opts->version == 1 ?
652                                                 UFS1_MAXSYMLINKLEN :
653                                                 UFS2_MAXSYMLINKLEN))
654                                         ADDSIZE(slen);
655                         }
656                 }
657                 if (node->type == S_IFDIR)
658                         ffs_size_dir(node->child, fsopts);
659         }
660         ADDSIZE(curdirsize);
661
662         if (debug & DEBUG_FS_SIZE_DIR)
663                 printf("ffs_size_dir: exit: size %lld inodes %lld\n",
664                     (long long)fsopts->size, (long long)fsopts->inodes);
665 }
666
667 static void *
668 ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
669                  fsnode *root, fsinfo_t *fsopts)
670 {
671         size_t slen;
672         void *membuf;
673         struct stat *st = stampst.st_ino != 0 ? &stampst : &cur->inode->st;
674
675         memset(dinp, 0, sizeof(*dinp));
676         dinp->di_mode = cur->inode->st.st_mode;
677         dinp->di_nlink = cur->inode->nlink;
678         dinp->di_size = cur->inode->st.st_size;
679 #if HAVE_STRUCT_STAT_ST_FLAGS
680         dinp->di_flags = cur->inode->st.st_flags;
681 #endif
682         dinp->di_gen = random();
683         dinp->di_uid = cur->inode->st.st_uid;
684         dinp->di_gid = cur->inode->st.st_gid;
685
686         dinp->di_atime = st->st_atime;
687         dinp->di_mtime = st->st_mtime;
688         dinp->di_ctime = st->st_ctime;
689 #if HAVE_STRUCT_STAT_ST_MTIMENSEC
690         dinp->di_atimensec = st->st_atimensec;
691         dinp->di_mtimensec = st->st_mtimensec;
692         dinp->di_ctimensec = st->st_ctimensec;
693 #endif
694                 /* not set: di_db, di_ib, di_blocks, di_spare */
695
696         membuf = NULL;
697         if (cur == root) {                      /* "."; write dirbuf */
698                 membuf = dbufp->buf;
699                 dinp->di_size = dbufp->size;
700         } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
701                 dinp->di_size = 0;      /* a device */
702                 dinp->di_rdev =
703                     ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap);
704         } else if (S_ISLNK(cur->type)) {        /* symlink */
705                 slen = strlen(cur->symlink);
706                 if (slen < UFS1_MAXSYMLINKLEN) {        /* short link */
707                         memcpy(dinp->di_db, cur->symlink, slen);
708                 } else
709                         membuf = cur->symlink;
710                 dinp->di_size = slen;
711         }
712         return membuf;
713 }
714
715 static void *
716 ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
717                  fsnode *root, fsinfo_t *fsopts)
718 {
719         size_t slen;
720         void *membuf;
721         struct stat *st = stampst.st_ino != 0 ? &stampst : &cur->inode->st;
722
723         memset(dinp, 0, sizeof(*dinp));
724         dinp->di_mode = cur->inode->st.st_mode;
725         dinp->di_nlink = cur->inode->nlink;
726         dinp->di_size = cur->inode->st.st_size;
727 #if HAVE_STRUCT_STAT_ST_FLAGS
728         dinp->di_flags = cur->inode->st.st_flags;
729 #endif
730         dinp->di_gen = random();
731         dinp->di_uid = cur->inode->st.st_uid;
732         dinp->di_gid = cur->inode->st.st_gid;
733
734         dinp->di_atime = st->st_atime;
735         dinp->di_mtime = st->st_mtime;
736         dinp->di_ctime = st->st_ctime;
737 #if HAVE_STRUCT_STAT_BIRTHTIME
738         dinp->di_birthtime = st->st_birthtime;
739 #else
740         dinp->di_birthtime = st->st_ctime;
741 #endif
742 #if HAVE_STRUCT_STAT_ST_MTIMENSEC
743         dinp->di_atimensec = st->st_atimensec;
744         dinp->di_mtimensec = st->st_mtimensec;
745         dinp->di_ctimensec = st->st_ctimensec;
746 #if HAVE_STRUCT_STAT_BIRTHTIME
747         dinp->di_birthnsec = st->st_birthtimensec;
748 #else
749         dinp->di_birthnsec = st->st_ctimensec;
750 #endif
751 #endif
752
753                 /* not set: di_db, di_ib, di_blocks, di_spare */
754
755         membuf = NULL;
756         if (cur == root) {                      /* "."; write dirbuf */
757                 membuf = dbufp->buf;
758                 dinp->di_size = dbufp->size;
759         } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
760                 dinp->di_size = 0;      /* a device */
761                 dinp->di_rdev =
762                     ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap);
763         } else if (S_ISLNK(cur->type)) {        /* symlink */
764                 slen = strlen(cur->symlink);
765                 if (slen < UFS2_MAXSYMLINKLEN) {        /* short link */
766                         memcpy(dinp->di_db, cur->symlink, slen);
767                 } else
768                         membuf = cur->symlink;
769                 dinp->di_size = slen;
770         }
771         return membuf;
772 }
773
774 static int
775 ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
776 {
777         fsnode          *cur;
778         dirbuf_t        dirbuf;
779         union dinode    din;
780         void            *membuf;
781         char            path[MAXPATHLEN + 1];
782         ffs_opt_t       *ffs_opts = fsopts->fs_specific;
783
784         assert(dir != NULL);
785         assert(root != NULL);
786         assert(fsopts != NULL);
787         assert(ffs_opts != NULL);
788
789         (void)memset(&dirbuf, 0, sizeof(dirbuf));
790
791         if (debug & DEBUG_FS_POPULATE)
792                 printf("ffs_populate_dir: PASS 1  dir %s node %p\n", dir, root);
793
794                 /*
795                  * pass 1: allocate inode numbers, build directory `file'
796                  */
797         for (cur = root; cur != NULL; cur = cur->next) {
798                 if ((cur->inode->flags & FI_ALLOCATED) == 0) {
799                         cur->inode->flags |= FI_ALLOCATED;
800                         if (cur == root && cur->parent != NULL)
801                                 cur->inode->ino = cur->parent->inode->ino;
802                         else {
803                                 cur->inode->ino = fsopts->curinode;
804                                 fsopts->curinode++;
805                         }
806                 }
807                 ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap);
808                 if (cur == root) {              /* we're at "."; add ".." */
809                         ffs_make_dirbuf(&dirbuf, "..",
810                             cur->parent == NULL ? cur : cur->parent->first,
811                             fsopts->needswap);
812                         root->inode->nlink++;   /* count my parent's link */
813                 } else if (cur->child != NULL)
814                         root->inode->nlink++;   /* count my child's link */
815
816                 /*
817                  * XXX  possibly write file and long symlinks here,
818                  *      ensuring that blocks get written before inodes?
819                  *      otoh, this isn't a real filesystem, so who
820                  *      cares about ordering? :-)
821                  */
822         }
823         if (debug & DEBUG_FS_POPULATE_DIRBUF)
824                 ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap);
825
826                 /*
827                  * pass 2: write out dirbuf, then non-directories at this level
828                  */
829         if (debug & DEBUG_FS_POPULATE)
830                 printf("ffs_populate_dir: PASS 2  dir %s\n", dir);
831         for (cur = root; cur != NULL; cur = cur->next) {
832                 if (cur->inode->flags & FI_WRITTEN)
833                         continue;               /* skip hard-linked entries */
834                 cur->inode->flags |= FI_WRITTEN;
835
836                 if (cur->contents == NULL) {
837                         if (snprintf(path, sizeof(path), "%s/%s/%s", cur->root,
838                             cur->path, cur->name) >= (int)sizeof(path))
839                                 errx(1, "Pathname too long.");
840                 }
841
842                 if (cur->child != NULL)
843                         continue;               /* child creates own inode */
844
845                                 /* build on-disk inode */
846                 if (ffs_opts->version == 1)
847                         membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
848                             root, fsopts);
849                 else
850                         membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur,
851                             root, fsopts);
852
853                 if (debug & DEBUG_FS_POPULATE_NODE) {
854                         printf("ffs_populate_dir: writing ino %d, %s",
855                             cur->inode->ino, inode_type(cur->type));
856                         if (cur->inode->nlink > 1)
857                                 printf(", nlink %d", cur->inode->nlink);
858                         putchar('\n');
859                 }
860
861                 if (membuf != NULL) {
862                         ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
863                 } else if (S_ISREG(cur->type)) {
864                         ffs_write_file(&din, cur->inode->ino,
865                             (cur->contents) ?  cur->contents : path, fsopts);
866                 } else {
867                         assert (! S_ISDIR(cur->type));
868                         ffs_write_inode(&din, cur->inode->ino, fsopts);
869                 }
870         }
871
872                 /*
873                  * pass 3: write out sub-directories
874                  */
875         if (debug & DEBUG_FS_POPULATE)
876                 printf("ffs_populate_dir: PASS 3  dir %s\n", dir);
877         for (cur = root; cur != NULL; cur = cur->next) {
878                 if (cur->child == NULL)
879                         continue;
880                 if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir,
881                     cur->name) >= sizeof(path))
882                         errx(1, "Pathname too long.");
883                 if (! ffs_populate_dir(path, cur->child, fsopts))
884                         return (0);
885         }
886
887         if (debug & DEBUG_FS_POPULATE)
888                 printf("ffs_populate_dir: DONE dir %s\n", dir);
889
890                 /* cleanup */
891         if (dirbuf.buf != NULL)
892                 free(dirbuf.buf);
893         return (1);
894 }
895
896
897 static void
898 ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
899 {
900         int     isfile, ffd;
901         char    *fbuf, *p;
902         off_t   bufleft, chunk, offset;
903         ssize_t nread;
904         struct inode    in;
905         struct buf *    bp;
906         ffs_opt_t       *ffs_opts = fsopts->fs_specific;
907         struct vnode vp = { fsopts, NULL };
908
909         assert (din != NULL);
910         assert (buf != NULL);
911         assert (fsopts != NULL);
912         assert (ffs_opts != NULL);
913
914         isfile = S_ISREG(DIP(din, mode));
915         fbuf = NULL;
916         ffd = -1;
917         p = NULL;
918
919         in.i_fs = (struct fs *)fsopts->superblock;
920         in.i_devvp = &vp;
921
922         if (debug & DEBUG_FS_WRITE_FILE) {
923                 printf(
924                     "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld",
925                     ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT),
926                     (long long)DIP(din, size));
927                 if (isfile)
928                         printf(", file '%s'\n", (char *)buf);
929                 else
930                         printf(", buffer %p\n", buf);
931         }
932
933         in.i_number = ino;
934         in.i_size = DIP(din, size);
935         if (ffs_opts->version == 1)
936                 memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
937                     sizeof(in.i_din.ffs1_din));
938         else
939                 memcpy(&in.i_din.ffs2_din, &din->ffs2_din,
940                     sizeof(in.i_din.ffs2_din));
941
942         if (DIP(din, size) == 0)
943                 goto write_inode_and_leave;             /* mmm, cheating */
944
945         if (isfile) {
946                 fbuf = emalloc(ffs_opts->bsize);
947                 if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
948                         err(EXIT_FAILURE, "Can't open `%s' for reading", (char *)buf);
949                 }
950         } else {
951                 p = buf;
952         }
953
954         chunk = 0;
955         for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
956                 chunk = MIN(bufleft, ffs_opts->bsize);
957                 if (!isfile)
958                         ;
959                 else if ((nread = read(ffd, fbuf, chunk)) == -1)
960                         err(EXIT_FAILURE, "Reading `%s', %lld bytes to go",
961                             (char *)buf, (long long)bufleft);
962                 else if (nread != chunk)
963                         errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, "
964                             "read %zd bytes, expected %ju bytes, does "
965                             "metalog size= attribute mismatch source size?",
966                             (char *)buf, (long long)bufleft, nread,
967                             (uintmax_t)chunk);
968                 else
969                         p = fbuf;
970                 offset = DIP(din, size) - bufleft;
971                 if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
972                         printf(
973                 "ffs_write_file: write %p offset %lld size %lld left %lld\n",
974                             p, (long long)offset,
975                             (long long)chunk, (long long)bufleft);
976         /*
977          * XXX  if holey support is desired, do the check here
978          *
979          * XXX  might need to write out last bit in fragroundup
980          *      sized chunk. however, ffs_balloc() handles this for us
981          */
982                 errno = ffs_balloc(&in, offset, chunk, &bp);
983  bad_ffs_write_file:
984                 if (errno != 0)
985                         err(1,
986                             "Writing inode %d (%s), bytes %lld + %lld",
987                             ino,
988                             isfile ? (char *)buf :
989                               inode_type(DIP(din, mode) & S_IFMT),
990                             (long long)offset, (long long)chunk);
991                 memcpy(bp->b_data, p, chunk);
992                 errno = bwrite(bp);
993                 if (errno != 0)
994                         goto bad_ffs_write_file;
995                 brelse(bp);
996                 if (!isfile)
997                         p += chunk;
998         }
999   
1000  write_inode_and_leave:
1001         ffs_write_inode(&in.i_din, in.i_number, fsopts);
1002         if (fbuf)
1003                 free(fbuf);
1004         if (ffd != -1)
1005                 close(ffd);
1006 }
1007
1008
1009 static void
1010 ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap)
1011 {
1012         doff_t          i;
1013         struct direct   *de;
1014         uint16_t        reclen;
1015
1016         assert (dbuf != NULL);
1017         assert (dir != NULL);
1018         printf("ffs_dump_dirbuf: dir %s size %d cur %d\n",
1019             dir, dbuf->size, dbuf->cur);
1020
1021         for (i = 0; i < dbuf->size; ) {
1022                 de = (struct direct *)(dbuf->buf + i);
1023                 reclen = ufs_rw16(de->d_reclen, needswap);
1024                 printf(
1025             " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n",
1026                     ufs_rw32(de->d_ino, needswap),
1027                     inode_type(DTTOIF(de->d_type)), i, reclen,
1028                     de->d_namlen, de->d_name);
1029                 i += reclen;
1030                 assert(reclen > 0);
1031         }
1032 }
1033
1034 static void
1035 ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
1036 {
1037         struct direct   de, *dp;
1038         uint16_t        llen, reclen;
1039         u_char          *newbuf;
1040
1041         assert (dbuf != NULL);
1042         assert (name != NULL);
1043         assert (node != NULL);
1044                                         /* create direct entry */
1045         (void)memset(&de, 0, sizeof(de));
1046         de.d_ino = ufs_rw32(node->inode->ino, needswap);
1047         de.d_type = IFTODT(node->type);
1048         de.d_namlen = (uint8_t)strlen(name);
1049         strcpy(de.d_name, name);
1050         reclen = DIRSIZ_SWAP(0, &de, needswap);
1051         de.d_reclen = ufs_rw16(reclen, needswap);
1052
1053         dp = (struct direct *)(dbuf->buf + dbuf->cur);
1054         llen = 0;
1055         if (dp != NULL)
1056                 llen = DIRSIZ_SWAP(0, dp, needswap);
1057
1058         if (debug & DEBUG_FS_MAKE_DIRBUF)
1059                 printf(
1060                     "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n"
1061                     "  ino %d type %d reclen %d namlen %d name %.30s\n",
1062                     dbuf->size, dbuf->cur, llen,
1063                     ufs_rw32(de.d_ino, needswap), de.d_type, reclen,
1064                     de.d_namlen, de.d_name);
1065
1066         if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) {
1067                 if (debug & DEBUG_FS_MAKE_DIRBUF)
1068                         printf("ffs_make_dirbuf: growing buf to %d\n",
1069                             dbuf->size + DIRBLKSIZ);
1070                 newbuf = erealloc(dbuf->buf, dbuf->size + DIRBLKSIZ);
1071                 dbuf->buf = newbuf;
1072                 dbuf->size += DIRBLKSIZ;
1073                 memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
1074                 dbuf->cur = dbuf->size - DIRBLKSIZ;
1075         } else if (dp) {                        /* shrink end of previous */
1076                 dp->d_reclen = ufs_rw16(llen,needswap);
1077                 dbuf->cur += llen;
1078         }
1079         dp = (struct direct *)(dbuf->buf + dbuf->cur);
1080         memcpy(dp, &de, reclen);
1081         dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap);
1082 }
1083
1084 /*
1085  * cribbed from sys/ufs/ffs/ffs_alloc.c
1086  */
1087 static void
1088 ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
1089 {
1090         char            *buf;
1091         struct ufs1_dinode *dp1;
1092         struct ufs2_dinode *dp2, *dip;
1093         struct cg       *cgp;
1094         struct fs       *fs;
1095         int             cg, cgino;
1096         uint32_t        i;
1097         daddr_t         d;
1098         char            sbbuf[FFS_MAXBSIZE];
1099         uint32_t        initediblk;
1100         ffs_opt_t       *ffs_opts = fsopts->fs_specific;
1101
1102         assert (dp != NULL);
1103         assert (ino > 0);
1104         assert (fsopts != NULL);
1105         assert (ffs_opts != NULL);
1106
1107         fs = (struct fs *)fsopts->superblock;
1108         cg = ino_to_cg(fs, ino);
1109         cgino = ino % fs->fs_ipg;
1110         if (debug & DEBUG_FS_WRITE_INODE)
1111                 printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n",
1112                     dp, ino, cg, cgino);
1113
1114         ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
1115             fsopts);
1116         cgp = (struct cg *)sbbuf;
1117         if (!cg_chkmagic_swap(cgp, fsopts->needswap))
1118                 errx(1, "ffs_write_inode: cg %d: bad magic number", cg);
1119
1120         assert (isclr(cg_inosused_swap(cgp, fsopts->needswap), cgino));
1121
1122         buf = emalloc(fs->fs_bsize);
1123         dp1 = (struct ufs1_dinode *)buf;
1124         dp2 = (struct ufs2_dinode *)buf;
1125
1126         if (fs->fs_cstotal.cs_nifree == 0)
1127                 errx(1, "ffs_write_inode: fs out of inodes for ino %u",
1128                     ino);
1129         if (fs->fs_cs(fs, cg).cs_nifree == 0)
1130                 errx(1,
1131                     "ffs_write_inode: cg %d out of inodes for ino %u",
1132                     cg, ino);
1133         setbit(cg_inosused_swap(cgp, fsopts->needswap), cgino);
1134         ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap);
1135         fs->fs_cstotal.cs_nifree--;
1136         fs->fs_cs(fs, cg).cs_nifree--;
1137         if (S_ISDIR(DIP(dp, mode))) {
1138                 ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap);
1139                 fs->fs_cstotal.cs_ndir++;
1140                 fs->fs_cs(fs, cg).cs_ndir++; 
1141         }
1142
1143         /*
1144          * Initialize inode blocks on the fly for UFS2.
1145          */
1146         initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap);
1147         while (ffs_opts->version == 2 && cgino + INOPB(fs) > initediblk &&
1148             initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) {
1149                 memset(buf, 0, fs->fs_bsize);
1150                 dip = (struct ufs2_dinode *)buf;
1151                 for (i = 0; i < INOPB(fs); i++) {
1152                         dip->di_gen = random();
1153                         dip++;
1154                 }
1155                 ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs,
1156                                   cg * fs->fs_ipg + initediblk)),
1157                     fs->fs_bsize, buf, fsopts);
1158                 initediblk += INOPB(fs);
1159                 cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap);
1160         }
1161
1162
1163         ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
1164             fsopts);
1165
1166                                         /* now write inode */
1167         d = fsbtodb(fs, ino_to_fsba(fs, ino));
1168         ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
1169         if (fsopts->needswap) {
1170                 if (ffs_opts->version == 1)
1171                         ffs_dinode1_swap(&dp->ffs1_din,
1172                             &dp1[ino_to_fsbo(fs, ino)]);
1173                 else
1174                         ffs_dinode2_swap(&dp->ffs2_din,
1175                             &dp2[ino_to_fsbo(fs, ino)]);
1176         } else {
1177                 if (ffs_opts->version == 1)
1178                         dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
1179                 else
1180                         dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;
1181         }
1182         ffs_wtfs(d, fs->fs_bsize, buf, fsopts);
1183         free(buf);
1184 }
1185
1186 void
1187 panic(const char *fmt, ...)
1188 {
1189         va_list ap;
1190
1191         va_start(ap, fmt);
1192         vwarnx(fmt, ap);
1193         va_end(ap);
1194         exit(1);
1195 }