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