1*da5362d5Sguenther /* $OpenBSD: ffs.c,v 1.39 2024/01/09 03:16:00 guenther Exp $ */
26163fc9cSnatano /* $NetBSD: ffs.c,v 1.66 2015/12/21 00:58:08 christos Exp $ */
36163fc9cSnatano
46163fc9cSnatano /*
56163fc9cSnatano * Copyright (c) 2001 Wasabi Systems, Inc.
66163fc9cSnatano * All rights reserved.
76163fc9cSnatano *
86163fc9cSnatano * Written by Luke Mewburn for Wasabi Systems, Inc.
96163fc9cSnatano *
106163fc9cSnatano * Redistribution and use in source and binary forms, with or without
116163fc9cSnatano * modification, are permitted provided that the following conditions
126163fc9cSnatano * are met:
136163fc9cSnatano * 1. Redistributions of source code must retain the above copyright
146163fc9cSnatano * notice, this list of conditions and the following disclaimer.
156163fc9cSnatano * 2. Redistributions in binary form must reproduce the above copyright
166163fc9cSnatano * notice, this list of conditions and the following disclaimer in the
176163fc9cSnatano * documentation and/or other materials provided with the distribution.
186163fc9cSnatano * 3. All advertising materials mentioning features or use of this software
196163fc9cSnatano * must display the following acknowledgement:
206163fc9cSnatano * This product includes software developed for the NetBSD Project by
216163fc9cSnatano * Wasabi Systems, Inc.
226163fc9cSnatano * 4. The name of Wasabi Systems, Inc. may not be used to endorse
236163fc9cSnatano * or promote products derived from this software without specific prior
246163fc9cSnatano * written permission.
256163fc9cSnatano *
266163fc9cSnatano * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
276163fc9cSnatano * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
286163fc9cSnatano * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
296163fc9cSnatano * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
306163fc9cSnatano * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
316163fc9cSnatano * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
326163fc9cSnatano * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
336163fc9cSnatano * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
346163fc9cSnatano * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
356163fc9cSnatano * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
366163fc9cSnatano * POSSIBILITY OF SUCH DAMAGE.
376163fc9cSnatano */
386163fc9cSnatano /*
396163fc9cSnatano * Copyright (c) 1982, 1986, 1989, 1993
406163fc9cSnatano * The Regents of the University of California. All rights reserved.
416163fc9cSnatano *
426163fc9cSnatano * Redistribution and use in source and binary forms, with or without
436163fc9cSnatano * modification, are permitted provided that the following conditions
446163fc9cSnatano * are met:
456163fc9cSnatano * 1. Redistributions of source code must retain the above copyright
466163fc9cSnatano * notice, this list of conditions and the following disclaimer.
476163fc9cSnatano * 2. Redistributions in binary form must reproduce the above copyright
486163fc9cSnatano * notice, this list of conditions and the following disclaimer in the
496163fc9cSnatano * documentation and/or other materials provided with the distribution.
506163fc9cSnatano * 3. Neither the name of the University nor the names of its contributors
516163fc9cSnatano * may be used to endorse or promote products derived from this software
526163fc9cSnatano * without specific prior written permission.
536163fc9cSnatano *
546163fc9cSnatano * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
556163fc9cSnatano * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
566163fc9cSnatano * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
576163fc9cSnatano * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
586163fc9cSnatano * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
596163fc9cSnatano * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
606163fc9cSnatano * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
616163fc9cSnatano * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
626163fc9cSnatano * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
636163fc9cSnatano * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
646163fc9cSnatano * SUCH DAMAGE.
656163fc9cSnatano *
666163fc9cSnatano * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
676163fc9cSnatano */
686163fc9cSnatano
694874b543Sderaadt #include <sys/param.h> /* roundup DEV_BSIZE */
70b7df7881Sderaadt #include <sys/types.h>
71eadd16bfSnatano #include <sys/disklabel.h>
726163fc9cSnatano
736163fc9cSnatano #include <assert.h>
746163fc9cSnatano #include <errno.h>
756163fc9cSnatano #include <fcntl.h>
766163fc9cSnatano #include <stdarg.h>
776163fc9cSnatano #include <stdio.h>
786163fc9cSnatano #include <stdint.h>
794874b543Sderaadt #include <limits.h>
806163fc9cSnatano #include <stdlib.h>
816163fc9cSnatano #include <string.h>
826163fc9cSnatano #include <unistd.h>
836163fc9cSnatano
846c4d9c1cSnatano #include <ufs/ufs/dinode.h>
856c4d9c1cSnatano #include <ufs/ufs/dir.h>
866c4d9c1cSnatano #include <ufs/ffs/fs.h>
876c4d9c1cSnatano
886c4d9c1cSnatano #include "ffs/ufs_inode.h"
896c4d9c1cSnatano #include "ffs/ffs_extern.h"
906c4d9c1cSnatano
916163fc9cSnatano #include "makefs.h"
926163fc9cSnatano #include "ffs.h"
936163fc9cSnatano #include "ffs/newfs_extern.h"
946163fc9cSnatano
956163fc9cSnatano #undef DIP
966163fc9cSnatano #define DIP(dp, field) \
976163fc9cSnatano ((ffs_opts->version == 1) ? \
986163fc9cSnatano (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
996163fc9cSnatano
1006163fc9cSnatano /*
1016163fc9cSnatano * Various file system defaults (cribbed from newfs(8)).
1026163fc9cSnatano */
10310c94a20Snatano #define DFL_FRAGSIZE 2048 /* fragment size */
10410c94a20Snatano #define DFL_BLKSIZE 16384 /* block size */
1056163fc9cSnatano #define DFL_SECSIZE 512 /* sector size */
1066163fc9cSnatano
1076163fc9cSnatano
1086163fc9cSnatano typedef struct {
1096163fc9cSnatano u_char *buf; /* buf for directory */
1106163fc9cSnatano doff_t size; /* full size of buf */
1116163fc9cSnatano doff_t cur; /* offset of current entry */
1126163fc9cSnatano } dirbuf_t;
1136163fc9cSnatano
1146163fc9cSnatano
1156163fc9cSnatano static int ffs_create_image(const char *, fsinfo_t *);
116b895f220Stedu static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *);
1176163fc9cSnatano static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *);
1186163fc9cSnatano static void ffs_size_dir(fsnode *, fsinfo_t *);
1196163fc9cSnatano static void ffs_validate(const char *, fsnode *, fsinfo_t *);
1206163fc9cSnatano static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *);
1216163fc9cSnatano static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *);
1226163fc9cSnatano static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *,
1236163fc9cSnatano fsnode *, fsinfo_t *);
1246163fc9cSnatano static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *,
1256163fc9cSnatano fsnode *, fsinfo_t *);
1266163fc9cSnatano
127fdb36351Skrw struct disklabel *ffs_makerdroot(const fsinfo_t *);
1286163fc9cSnatano
1296163fc9cSnatano
1308e544e80Sjsg /* publicly visible functions */
1316163fc9cSnatano void
ffs_prep_opts(fsinfo_t * fsopts)1326163fc9cSnatano ffs_prep_opts(fsinfo_t *fsopts)
1336163fc9cSnatano {
1346163fc9cSnatano ffs_opt_t *ffs_opts = ecalloc(1, sizeof(*ffs_opts));
1356163fc9cSnatano
1366163fc9cSnatano const option_t ffs_options[] = {
13740854474Snatano { "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, 1, INT_MAX },
13840854474Snatano { "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, 1, INT_MAX },
13940854474Snatano { "bsize", &ffs_opts->bsize, OPT_INT32, 1, INT_MAX },
14040854474Snatano { "density", &ffs_opts->density, OPT_INT32, 1, INT_MAX },
141eadd16bfSnatano { "disklabel", NULL, OPT_STRBUF, 0, 0 },
14240854474Snatano { "extent", &ffs_opts->maxbsize, OPT_INT32, 1, INT_MAX },
14340854474Snatano { "fsize", &ffs_opts->fsize, OPT_INT32, 1, INT_MAX },
14440854474Snatano { "label", ffs_opts->label, OPT_STRARRAY, 1, MAXVOLLEN },
14540854474Snatano { "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, 1, INT_MAX },
14640854474Snatano { "maxbpg", &ffs_opts->maxbpg, OPT_INT32, 1, INT_MAX },
14740854474Snatano { "minfree", &ffs_opts->minfree, OPT_INT32, 0, 99 },
14840854474Snatano { "optimization", NULL, OPT_STRBUF, 0, 0 },
149fdb36351Skrw { "rdroot", &ffs_opts->rdroot, OPT_INT32, 0, 1 },
15040854474Snatano { "version", &ffs_opts->version, OPT_INT32, 1, 2 },
1516163fc9cSnatano { .name = NULL }
1526163fc9cSnatano };
1536163fc9cSnatano
1546163fc9cSnatano ffs_opts->bsize = -1;
1556163fc9cSnatano ffs_opts->fsize = -1;
1566163fc9cSnatano ffs_opts->density = -1;
1570e3b68b4Snatano ffs_opts->minfree = MINFREE;
1581a82ed51Snatano ffs_opts->optimization = FS_OPTSPACE;
1596163fc9cSnatano ffs_opts->maxbpg = -1;
1600e3b68b4Snatano ffs_opts->avgfilesize = AVFILESIZ;
1610e3b68b4Snatano ffs_opts->avgfpdir = AFPDIR;
1626163fc9cSnatano ffs_opts->version = 1;
163fdb36351Skrw ffs_opts->rdroot = 0;
164eadd16bfSnatano ffs_opts->lp = NULL;
165ff15da3eSnatano ffs_opts->pp = NULL;
1666163fc9cSnatano
1676163fc9cSnatano fsopts->fs_specific = ffs_opts;
1686163fc9cSnatano fsopts->fs_options = copy_opts(ffs_options);
1696163fc9cSnatano }
1706163fc9cSnatano
1716163fc9cSnatano void
ffs_cleanup_opts(fsinfo_t * fsopts)1726163fc9cSnatano ffs_cleanup_opts(fsinfo_t *fsopts)
1736163fc9cSnatano {
1746163fc9cSnatano free(fsopts->fs_specific);
1756163fc9cSnatano free(fsopts->fs_options);
1766163fc9cSnatano }
1776163fc9cSnatano
1786163fc9cSnatano int
ffs_parse_opts(const char * option,fsinfo_t * fsopts)1796163fc9cSnatano ffs_parse_opts(const char *option, fsinfo_t *fsopts)
1806163fc9cSnatano {
1816163fc9cSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
1826163fc9cSnatano option_t *ffs_options = fsopts->fs_options;
1836163fc9cSnatano char buf[1024];
1846163fc9cSnatano
1856163fc9cSnatano int rv;
1866163fc9cSnatano
1876163fc9cSnatano assert(option != NULL);
1886163fc9cSnatano assert(fsopts != NULL);
1896163fc9cSnatano assert(ffs_opts != NULL);
1906163fc9cSnatano
1916163fc9cSnatano rv = set_option(ffs_options, option, buf, sizeof(buf));
1926163fc9cSnatano if (rv == -1)
1936163fc9cSnatano return 0;
1946163fc9cSnatano
1956163fc9cSnatano if (ffs_options[rv].name == NULL)
1966163fc9cSnatano abort();
1976163fc9cSnatano
198eadd16bfSnatano if (strcmp(ffs_options[rv].name, "disklabel") == 0) {
19966338d01Skrw struct disklabel *dp;
200eadd16bfSnatano
201eadd16bfSnatano dp = getdiskbyname(buf);
202eadd16bfSnatano if (dp == NULL)
203eadd16bfSnatano errx(1, "unknown disk type: %s", buf);
204eadd16bfSnatano
205eadd16bfSnatano ffs_opts->lp = emalloc(sizeof(struct disklabel));
206eadd16bfSnatano *ffs_opts->lp = *dp;
207eadd16bfSnatano } else if (strcmp(ffs_options[rv].name, "optimization") == 0) {
2086163fc9cSnatano if (strcmp(buf, "time") == 0) {
2096163fc9cSnatano ffs_opts->optimization = FS_OPTTIME;
2106163fc9cSnatano } else if (strcmp(buf, "space") == 0) {
2116163fc9cSnatano ffs_opts->optimization = FS_OPTSPACE;
2126163fc9cSnatano } else {
2136163fc9cSnatano warnx("Invalid optimization `%s'", buf);
2146163fc9cSnatano return 0;
2156163fc9cSnatano }
2166163fc9cSnatano }
2176163fc9cSnatano return 1;
2186163fc9cSnatano }
2196163fc9cSnatano
220fdb36351Skrw struct disklabel *
ffs_makerdroot(const fsinfo_t * fsopts)221fdb36351Skrw ffs_makerdroot(const fsinfo_t *fsopts)
222fdb36351Skrw {
223fdb36351Skrw const ffs_opt_t *ffs_opts = fsopts->fs_specific;
224fdb36351Skrw struct disklabel *lp;
225fdb36351Skrw struct partition *pp;
226fdb36351Skrw uint32_t rdsize, poffset;
227fdb36351Skrw const uint32_t sectorsize = fsopts->sectorsize;
228fdb36351Skrw const uint32_t fsize = ffs_opts->fsize;
229fdb36351Skrw const uint32_t bsize = ffs_opts->bsize;
230fdb36351Skrw
231fdb36351Skrw rdsize = (fsopts->size + sectorsize - 1) / sectorsize;
232fdb36351Skrw poffset = (fsopts->offset + sectorsize - 1) / sectorsize;
233fdb36351Skrw
234fdb36351Skrw lp = ecalloc(1, sizeof(struct disklabel));
235fdb36351Skrw
236fdb36351Skrw lp->d_version = 1;
237fdb36351Skrw lp->d_type = DTYPE_RDROOT;
238fdb36351Skrw strlcpy(lp->d_typename, "rdroot", sizeof(lp->d_typename));
239fdb36351Skrw lp->d_npartitions = RAW_PART + 1;
240fdb36351Skrw lp->d_secsize = sectorsize;
241fdb36351Skrw lp->d_ntracks = lp->d_ncylinders = 1;
242fdb36351Skrw lp->d_secpercyl = rdsize;
243fdb36351Skrw DL_SETDSIZE(lp, rdsize);
244fdb36351Skrw
245fdb36351Skrw pp = &lp->d_partitions[0]; /* a.k.a. 'a' */
246fdb36351Skrw pp->p_fstype = FS_BSDFFS;
247fdb36351Skrw pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, bsize / fsize);
248fdb36351Skrw DL_SETPOFFSET(pp, poffset);
249fdb36351Skrw DL_SETPSIZE(pp, rdsize - poffset);
250fdb36351Skrw
251fdb36351Skrw pp = &lp->d_partitions[RAW_PART]; /* a.k.a. 'c' */
252fdb36351Skrw DL_SETPOFFSET(pp, 0);
253fdb36351Skrw DL_SETPSIZE(pp, DL_GETDSIZE(lp));
254fdb36351Skrw
255fdb36351Skrw return lp;
256fdb36351Skrw }
2576163fc9cSnatano
2586163fc9cSnatano void
ffs_makefs(const char * image,const char * dir,fsnode * root,fsinfo_t * fsopts)2596163fc9cSnatano ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
2606163fc9cSnatano {
2616163fc9cSnatano struct fs *superblock;
262eadd16bfSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
2636163fc9cSnatano
2646163fc9cSnatano assert(image != NULL);
2656163fc9cSnatano assert(dir != NULL);
2666163fc9cSnatano assert(root != NULL);
2676163fc9cSnatano assert(fsopts != NULL);
2686163fc9cSnatano
2696163fc9cSnatano /* validate tree and options */
2706163fc9cSnatano ffs_validate(dir, root, fsopts);
2716163fc9cSnatano
2726163fc9cSnatano printf("Calculated size of `%s': %lld bytes, %lld inodes\n",
2736163fc9cSnatano image, (long long)fsopts->size, (long long)fsopts->inodes);
2746163fc9cSnatano
2756163fc9cSnatano /* create image */
2766163fc9cSnatano if (ffs_create_image(image, fsopts) == -1)
2776163fc9cSnatano errx(1, "Image file `%s' not created.", image);
2786163fc9cSnatano
2796c4d9c1cSnatano fsopts->curinode = ROOTINO;
2806163fc9cSnatano
2816163fc9cSnatano /* populate image */
2826163fc9cSnatano printf("Populating `%s'\n", image);
2836163fc9cSnatano if (! ffs_populate_dir(dir, root, fsopts))
2846163fc9cSnatano errx(1, "Image file `%s' not populated.", image);
2856163fc9cSnatano
2866163fc9cSnatano bcleanup();
2876163fc9cSnatano
2886163fc9cSnatano /* update various superblock parameters */
2896163fc9cSnatano superblock = fsopts->superblock;
2906163fc9cSnatano superblock->fs_fmod = 0;
2916c4d9c1cSnatano superblock->fs_ffs1_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir;
2926c4d9c1cSnatano superblock->fs_ffs1_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree;
2936c4d9c1cSnatano superblock->fs_ffs1_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree;
2946c4d9c1cSnatano superblock->fs_ffs1_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree;
2956163fc9cSnatano
2966163fc9cSnatano /* write out superblock; image is now complete */
2976163fc9cSnatano ffs_write_superblock(fsopts->superblock, fsopts);
298eadd16bfSnatano
299fdb36351Skrw if (ffs_opts->rdroot == 1) {
300fdb36351Skrw ffs_opts->lp = ffs_makerdroot(fsopts);
301fdb36351Skrw ffs_opts->pp = &ffs_opts->lp->d_partitions[0];
302fdb36351Skrw }
303fdb36351Skrw
304eadd16bfSnatano if (ffs_opts->lp != NULL) {
305eadd16bfSnatano struct disklabel *lp = ffs_opts->lp;
306eadd16bfSnatano uint16_t *p, *end, sum = 0;
307eadd16bfSnatano ssize_t n;
308ff15da3eSnatano uint32_t bpg;
309eadd16bfSnatano
310ff15da3eSnatano bpg = superblock->fs_fpg / superblock->fs_frag;
311ff15da3eSnatano while (bpg > UINT16_MAX)
312ff15da3eSnatano bpg >>= 1;
313ff15da3eSnatano ffs_opts->pp->p_cpg = bpg;
314eadd16bfSnatano
315eadd16bfSnatano lp->d_magic = DISKMAGIC;
316eadd16bfSnatano lp->d_magic2 = DISKMAGIC;
31735e8d567Snatano arc4random_buf(lp->d_uid, sizeof(lp->d_uid));
318eadd16bfSnatano lp->d_checksum = 0;
319eadd16bfSnatano
320eadd16bfSnatano p = (uint16_t *)lp;
321eadd16bfSnatano end = (uint16_t *)&lp->d_partitions[lp->d_npartitions];
322eadd16bfSnatano while (p < end)
323eadd16bfSnatano sum ^= *p++;
324eadd16bfSnatano lp->d_checksum = sum;
325eadd16bfSnatano
326eadd16bfSnatano n = pwrite(fsopts->fd, lp, sizeof(struct disklabel),
3278a42a32cSnatano fsopts->offset + LABELSECTOR * DEV_BSIZE + LABELOFFSET);
328eadd16bfSnatano if (n == -1)
329eadd16bfSnatano err(1, "failed to write disklabel");
330eadd16bfSnatano else if (n < sizeof(struct disklabel))
331eadd16bfSnatano errx(1, "failed to write disklabel: short write");
332eadd16bfSnatano }
333eadd16bfSnatano
3346163fc9cSnatano if (close(fsopts->fd) == -1)
3356163fc9cSnatano err(1, "Closing `%s'", image);
3366163fc9cSnatano fsopts->fd = -1;
3376163fc9cSnatano printf("Image `%s' complete\n", image);
3386163fc9cSnatano }
3396163fc9cSnatano
3406163fc9cSnatano /* end of public functions */
3416163fc9cSnatano
3426163fc9cSnatano
3436163fc9cSnatano static void
ffs_validate(const char * dir,fsnode * root,fsinfo_t * fsopts)3446163fc9cSnatano ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
3456163fc9cSnatano {
3466163fc9cSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
347ff15da3eSnatano struct disklabel *lp = ffs_opts->lp;
348ff15da3eSnatano struct partition *pp = NULL;
349ff15da3eSnatano int32_t ncg = 1;
350ff15da3eSnatano int i;
3516163fc9cSnatano
3526163fc9cSnatano assert(dir != NULL);
3536163fc9cSnatano assert(root != NULL);
3546163fc9cSnatano assert(fsopts != NULL);
3556163fc9cSnatano assert(ffs_opts != NULL);
3566163fc9cSnatano
357fdb36351Skrw if (lp != NULL && ffs_opts->rdroot == 1)
358fdb36351Skrw errx(1, "rdroot and disklabel are mutually exclusive");
359fdb36351Skrw
360ff15da3eSnatano if (lp != NULL) {
361ff15da3eSnatano for (i = 0; i < lp->d_npartitions; i++) {
362ff15da3eSnatano pp = &lp->d_partitions[i];
363ff15da3eSnatano if (pp->p_fstype == FS_BSDFFS &&
364ff15da3eSnatano pp->p_offset * lp->d_secsize == fsopts->offset) {
365ff15da3eSnatano break;
366ff15da3eSnatano }
367ff15da3eSnatano }
368ff15da3eSnatano if (i == lp->d_npartitions)
369ff15da3eSnatano errx(1, "no matching partition found in the disklabel");
370ff15da3eSnatano ffs_opts->pp = pp;
371ff15da3eSnatano
372ff15da3eSnatano if (pp->p_fragblock == 0)
373ff15da3eSnatano errx(1, "fragment size missing in disktab");
374ff15da3eSnatano if (fsopts->freeblocks != 0 || fsopts->freeblockpc != 0 ||
375ff15da3eSnatano fsopts->freefiles != 0 || fsopts->freefilepc != 0 ||
376ff15da3eSnatano fsopts->minsize != 0 || fsopts->maxsize != 0 ||
377ff15da3eSnatano fsopts->sectorsize != -1 || fsopts->size != 0)
378ff15da3eSnatano errx(1, "-bfMmSs and disklabel are mutually exclusive");
379ff15da3eSnatano if (ffs_opts->fsize != -1 || ffs_opts->bsize != -1)
380ff15da3eSnatano errx(1, "b/fsize and disklabel are mutually exclusive");
381ff15da3eSnatano
382ff15da3eSnatano fsopts->sectorsize = lp->d_secsize;
383ff15da3eSnatano fsopts->minsize = fsopts->maxsize =
384ff15da3eSnatano DL_GETPSIZE(pp) * lp->d_secsize;
385ff15da3eSnatano ffs_opts->fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
386ff15da3eSnatano ffs_opts->bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock);
387fdb36351Skrw } else if (ffs_opts->rdroot == 1) {
388fdb36351Skrw if (fsopts->freeblocks != 0 || fsopts->freeblockpc != 0 ||
389fdb36351Skrw fsopts->freefiles != 0 || fsopts->freefilepc != 0 ||
390fdb36351Skrw fsopts->offset != 0 || fsopts->sectorsize != -1 ||
391fdb36351Skrw fsopts->minsize != fsopts->maxsize)
392fdb36351Skrw errx(1, "rdroot and -bfMmOS are mutually exclusive");
393fdb36351Skrw if (fsopts->minsize == 0 || fsopts->maxsize == 0)
394fdb36351Skrw errx(1, "rdroot requires -s");
395fdb36351Skrw if (ffs_opts->minfree != 0)
396fdb36351Skrw errx(1, "rdroot requires minfree=0");
397fdb36351Skrw if (ffs_opts->fsize == -1 || ffs_opts->bsize == -1 ||
398fdb36351Skrw ffs_opts->density == -1)
399fdb36351Skrw errx(1, "rdroot requires bsize, fsize and density");
400fdb36351Skrw fsopts->sectorsize = DEV_BSIZE;
401ff15da3eSnatano }
402ff15da3eSnatano
4036163fc9cSnatano /* set FFS defaults */
4046163fc9cSnatano if (fsopts->sectorsize == -1)
4056163fc9cSnatano fsopts->sectorsize = DFL_SECSIZE;
4066163fc9cSnatano if (ffs_opts->fsize == -1)
4074874b543Sderaadt ffs_opts->fsize = MAXIMUM(DFL_FRAGSIZE, fsopts->sectorsize);
4086163fc9cSnatano if (ffs_opts->bsize == -1)
4094874b543Sderaadt ffs_opts->bsize = MINIMUM(DFL_BLKSIZE, 8 * ffs_opts->fsize);
4106163fc9cSnatano /* fsopts->density is set below */
4116163fc9cSnatano /* XXX ondisk32 */
4126163fc9cSnatano if (ffs_opts->maxbpg == -1)
4136163fc9cSnatano ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
4146163fc9cSnatano
4156163fc9cSnatano /* calculate size of tree */
4166163fc9cSnatano ffs_size_dir(root, fsopts);
4176c4d9c1cSnatano fsopts->inodes += ROOTINO; /* include first two inodes */
4186163fc9cSnatano
4196163fc9cSnatano /* add requested slop */
4206163fc9cSnatano fsopts->size += fsopts->freeblocks;
4216163fc9cSnatano fsopts->inodes += fsopts->freefiles;
4226163fc9cSnatano if (fsopts->freefilepc > 0)
4236163fc9cSnatano fsopts->inodes =
4246163fc9cSnatano fsopts->inodes * (100 + fsopts->freefilepc) / 100;
4256163fc9cSnatano if (fsopts->freeblockpc > 0)
4266163fc9cSnatano fsopts->size =
4276163fc9cSnatano fsopts->size * (100 + fsopts->freeblockpc) / 100;
4286163fc9cSnatano
4296163fc9cSnatano /* add space needed for superblocks */
4306163fc9cSnatano /*
4316163fc9cSnatano * The old SBOFF (SBLOCK_UFS1) is used here because makefs is
4326163fc9cSnatano * typically used for small filesystems where space matters.
4336163fc9cSnatano * XXX make this an option.
4346163fc9cSnatano */
4356163fc9cSnatano fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
4366163fc9cSnatano /* add space needed to store inodes, x3 for blockmaps, etc */
4376163fc9cSnatano if (ffs_opts->version == 1)
4386c4d9c1cSnatano fsopts->size += ncg * sizeof(struct ufs1_dinode) *
4396163fc9cSnatano roundup(fsopts->inodes / ncg,
4406c4d9c1cSnatano ffs_opts->bsize / sizeof(struct ufs1_dinode));
4416163fc9cSnatano else
4426c4d9c1cSnatano fsopts->size += ncg * sizeof(struct ufs2_dinode) *
4436163fc9cSnatano roundup(fsopts->inodes / ncg,
4446c4d9c1cSnatano ffs_opts->bsize / sizeof(struct ufs2_dinode));
4456163fc9cSnatano
4466163fc9cSnatano /* add minfree */
4476163fc9cSnatano if (ffs_opts->minfree > 0)
4486163fc9cSnatano fsopts->size =
4496163fc9cSnatano fsopts->size * (100 + ffs_opts->minfree) / 100;
4506163fc9cSnatano /*
4516163fc9cSnatano * XXX any other fs slop to add, such as csum's, bitmaps, etc ??
4526163fc9cSnatano */
4536163fc9cSnatano
4546163fc9cSnatano if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */
4556163fc9cSnatano fsopts->size = fsopts->minsize;
4566163fc9cSnatano
4576163fc9cSnatano /* round up to the next block */
4586163fc9cSnatano fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
4596163fc9cSnatano
4606163fc9cSnatano /* calculate density if necessary */
4616163fc9cSnatano if (ffs_opts->density == -1)
4626163fc9cSnatano ffs_opts->density = fsopts->size / fsopts->inodes + 1;
4636163fc9cSnatano
4646163fc9cSnatano /* now check calculated sizes vs requested sizes */
4656163fc9cSnatano if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
4666163fc9cSnatano errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
4676163fc9cSnatano dir, (long long)fsopts->size, (long long)fsopts->maxsize);
4686163fc9cSnatano }
4696163fc9cSnatano }
4706163fc9cSnatano
4716163fc9cSnatano
4726163fc9cSnatano static int
ffs_create_image(const char * image,fsinfo_t * fsopts)4736163fc9cSnatano ffs_create_image(const char *image, fsinfo_t *fsopts)
4746163fc9cSnatano {
4756163fc9cSnatano struct fs *fs;
4766163fc9cSnatano char *buf;
4776163fc9cSnatano int i, bufsize;
4786163fc9cSnatano off_t bufrem;
4796163fc9cSnatano time_t tstamp;
4806163fc9cSnatano int oflags = O_RDWR | O_CREAT;
4816163fc9cSnatano
4826163fc9cSnatano assert (image != NULL);
4836163fc9cSnatano assert (fsopts != NULL);
4846163fc9cSnatano
4856163fc9cSnatano /* create image */
4866163fc9cSnatano if (fsopts->offset == 0)
4876163fc9cSnatano oflags |= O_TRUNC;
4886163fc9cSnatano if ((fsopts->fd = open(image, oflags, 0666)) == -1) {
4896163fc9cSnatano warn("Can't open `%s' for writing", image);
4906163fc9cSnatano return (-1);
4916163fc9cSnatano }
4926163fc9cSnatano
4936163fc9cSnatano /* zero image */
4946163fc9cSnatano bufsize = 8192;
4956163fc9cSnatano bufrem = fsopts->size;
4966163fc9cSnatano
4976163fc9cSnatano if (fsopts->offset != 0)
4986163fc9cSnatano if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) {
4996163fc9cSnatano warn("can't seek");
5006163fc9cSnatano return -1;
5016163fc9cSnatano }
5026163fc9cSnatano
5036163fc9cSnatano if (bufrem > 0)
5046163fc9cSnatano buf = ecalloc(1, bufsize);
5056163fc9cSnatano while (bufrem > 0) {
5064874b543Sderaadt i = write(fsopts->fd, buf, MINIMUM(bufsize, bufrem));
5076163fc9cSnatano if (i == -1) {
5086163fc9cSnatano warn("zeroing image, %lld bytes to go",
5096163fc9cSnatano (long long)bufrem);
5106163fc9cSnatano free(buf);
5116163fc9cSnatano return (-1);
5126163fc9cSnatano }
5136163fc9cSnatano bufrem -= i;
5146163fc9cSnatano }
5156163fc9cSnatano free(buf);
5166163fc9cSnatano
5176163fc9cSnatano /* make the file system */
518bc67c994Snatano if (Tflag) {
519bc67c994Snatano tstamp = stampts;
520bc67c994Snatano srandom_deterministic(stampts);
521913395cbSnatano } else
5226163fc9cSnatano tstamp = start_time.tv_sec;
5236163fc9cSnatano
5246163fc9cSnatano fs = ffs_mkfs(image, fsopts, tstamp);
5256163fc9cSnatano fsopts->superblock = (void *)fs;
5266163fc9cSnatano
5276c4d9c1cSnatano if ((off_t)(fs->fs_cstotal.cs_nifree + ROOTINO) < fsopts->inodes) {
5286163fc9cSnatano warnx(
5296163fc9cSnatano "Image file `%s' has %lld free inodes; %lld are required.",
5306163fc9cSnatano image,
5316c4d9c1cSnatano (long long)(fs->fs_cstotal.cs_nifree + ROOTINO),
5326163fc9cSnatano (long long)fsopts->inodes);
5336163fc9cSnatano return (-1);
5346163fc9cSnatano }
5356163fc9cSnatano return (fsopts->fd);
5366163fc9cSnatano }
5376163fc9cSnatano
5386163fc9cSnatano
5396163fc9cSnatano static void
ffs_size_dir(fsnode * root,fsinfo_t * fsopts)5406163fc9cSnatano ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
5416163fc9cSnatano {
5426163fc9cSnatano struct direct tmpdir;
5436163fc9cSnatano fsnode * node;
5446163fc9cSnatano int curdirsize, this;
5456163fc9cSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
5466163fc9cSnatano
5476163fc9cSnatano /* node may be NULL (empty directory) */
5486163fc9cSnatano assert(fsopts != NULL);
5496163fc9cSnatano assert(ffs_opts != NULL);
5506163fc9cSnatano
5516163fc9cSnatano #define ADDDIRENT(e) do { \
5526163fc9cSnatano tmpdir.d_namlen = strlen((e)); \
553*da5362d5Sguenther this = DIRSIZ(&tmpdir); \
5546c4d9c1cSnatano if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ)) \
5556c4d9c1cSnatano curdirsize = roundup(curdirsize, DIRBLKSIZ); \
5566163fc9cSnatano curdirsize += this; \
5576163fc9cSnatano } while (0);
5586163fc9cSnatano
5596163fc9cSnatano /*
5606163fc9cSnatano * XXX this needs to take into account extra space consumed
5616163fc9cSnatano * by indirect blocks, etc.
5626163fc9cSnatano */
5636163fc9cSnatano #define ADDSIZE(x) do { \
5646163fc9cSnatano fsopts->size += roundup((x), ffs_opts->fsize); \
5656163fc9cSnatano } while (0);
5666163fc9cSnatano
5676163fc9cSnatano curdirsize = 0;
5686163fc9cSnatano for (node = root; node != NULL; node = node->next) {
5696163fc9cSnatano ADDDIRENT(node->name);
5706163fc9cSnatano if (node == root) { /* we're at "." */
5716163fc9cSnatano assert(strcmp(node->name, ".") == 0);
5726163fc9cSnatano ADDDIRENT("..");
5736163fc9cSnatano } else if ((node->inode->flags & FI_SIZED) == 0) {
5746163fc9cSnatano /* don't count duplicate names */
5756163fc9cSnatano node->inode->flags |= FI_SIZED;
5766163fc9cSnatano fsopts->inodes++;
5776163fc9cSnatano if (node->type == S_IFREG)
5786163fc9cSnatano ADDSIZE(node->inode->st.st_size);
5796163fc9cSnatano if (node->type == S_IFLNK) {
5806163fc9cSnatano size_t slen;
5816163fc9cSnatano
5826163fc9cSnatano slen = strlen(node->symlink) + 1;
5836163fc9cSnatano if (slen >= (ffs_opts->version == 1 ?
5846c4d9c1cSnatano MAXSYMLINKLEN_UFS1 :
5856c4d9c1cSnatano MAXSYMLINKLEN_UFS2))
5866163fc9cSnatano ADDSIZE(slen);
5876163fc9cSnatano }
5886163fc9cSnatano }
5896163fc9cSnatano if (node->type == S_IFDIR)
5906163fc9cSnatano ffs_size_dir(node->child, fsopts);
5916163fc9cSnatano }
5926163fc9cSnatano ADDSIZE(curdirsize);
5936163fc9cSnatano }
5946163fc9cSnatano
5956163fc9cSnatano static void *
ffs_build_dinode1(struct ufs1_dinode * dinp,dirbuf_t * dbufp,fsnode * cur,fsnode * root,fsinfo_t * fsopts)5966163fc9cSnatano ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
5976163fc9cSnatano fsnode *root, fsinfo_t *fsopts)
5986163fc9cSnatano {
5996163fc9cSnatano size_t slen;
6006163fc9cSnatano void *membuf;
6016163fc9cSnatano
6026163fc9cSnatano memset(dinp, 0, sizeof(*dinp));
6036163fc9cSnatano dinp->di_mode = cur->inode->st.st_mode;
6046163fc9cSnatano dinp->di_nlink = cur->inode->nlink;
6056163fc9cSnatano dinp->di_size = cur->inode->st.st_size;
6066163fc9cSnatano dinp->di_flags = cur->inode->st.st_flags;
6076163fc9cSnatano dinp->di_gen = cur->inode->st.st_gen;
6086163fc9cSnatano dinp->di_uid = cur->inode->st.st_uid;
6096163fc9cSnatano dinp->di_gid = cur->inode->st.st_gid;
6106163fc9cSnatano
611bc67c994Snatano dinp->di_atime = cur->inode->st.st_atime;
612bc67c994Snatano dinp->di_mtime = cur->inode->st.st_mtime;
613bc67c994Snatano dinp->di_ctime = cur->inode->st.st_ctime;
6146fa343acSguenther dinp->di_atimensec = cur->inode->st.st_atim.tv_nsec;
6156fa343acSguenther dinp->di_mtimensec = cur->inode->st.st_mtim.tv_nsec;
6166fa343acSguenther dinp->di_ctimensec = cur->inode->st.st_ctim.tv_nsec;
6176163fc9cSnatano /* not set: di_db, di_ib, di_blocks, di_spare */
6186163fc9cSnatano
6196163fc9cSnatano membuf = NULL;
6206163fc9cSnatano if (cur == root) { /* "."; write dirbuf */
6216163fc9cSnatano membuf = dbufp->buf;
6226163fc9cSnatano dinp->di_size = dbufp->size;
6236163fc9cSnatano } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
6246163fc9cSnatano dinp->di_size = 0; /* a device */
6257247f83aSnatano dinp->di_rdev = cur->inode->st.st_rdev;
6266163fc9cSnatano } else if (S_ISLNK(cur->type)) { /* symlink */
6276163fc9cSnatano slen = strlen(cur->symlink);
6286c4d9c1cSnatano if (slen < MAXSYMLINKLEN_UFS1) { /* short link */
6296163fc9cSnatano memcpy(dinp->di_db, cur->symlink, slen);
6306163fc9cSnatano } else
6316163fc9cSnatano membuf = cur->symlink;
6326163fc9cSnatano dinp->di_size = slen;
6336163fc9cSnatano }
6346163fc9cSnatano return membuf;
6356163fc9cSnatano }
6366163fc9cSnatano
6376163fc9cSnatano static void *
ffs_build_dinode2(struct ufs2_dinode * dinp,dirbuf_t * dbufp,fsnode * cur,fsnode * root,fsinfo_t * fsopts)6386163fc9cSnatano ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
6396163fc9cSnatano fsnode *root, fsinfo_t *fsopts)
6406163fc9cSnatano {
6416163fc9cSnatano size_t slen;
6426163fc9cSnatano void *membuf;
6436163fc9cSnatano
6446163fc9cSnatano memset(dinp, 0, sizeof(*dinp));
6456163fc9cSnatano dinp->di_mode = cur->inode->st.st_mode;
6466163fc9cSnatano dinp->di_nlink = cur->inode->nlink;
6476163fc9cSnatano dinp->di_size = cur->inode->st.st_size;
6486163fc9cSnatano dinp->di_flags = cur->inode->st.st_flags;
6496163fc9cSnatano dinp->di_gen = cur->inode->st.st_gen;
6506163fc9cSnatano dinp->di_uid = cur->inode->st.st_uid;
6516163fc9cSnatano dinp->di_gid = cur->inode->st.st_gid;
6526163fc9cSnatano
653bc67c994Snatano dinp->di_atime = cur->inode->st.st_atime;
654bc67c994Snatano dinp->di_mtime = cur->inode->st.st_mtime;
655bc67c994Snatano dinp->di_ctime = cur->inode->st.st_ctime;
6566fa343acSguenther dinp->di_atimensec = cur->inode->st.st_atim.tv_nsec;
6576fa343acSguenther dinp->di_mtimensec = cur->inode->st.st_mtim.tv_nsec;
6586fa343acSguenther dinp->di_ctimensec = cur->inode->st.st_ctim.tv_nsec;
6596163fc9cSnatano /* not set: di_db, di_ib, di_blocks, di_spare */
6606163fc9cSnatano
6616163fc9cSnatano membuf = NULL;
6626163fc9cSnatano if (cur == root) { /* "."; write dirbuf */
6636163fc9cSnatano membuf = dbufp->buf;
6646163fc9cSnatano dinp->di_size = dbufp->size;
6656163fc9cSnatano } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
6666163fc9cSnatano dinp->di_size = 0; /* a device */
6677247f83aSnatano dinp->di_rdev = cur->inode->st.st_rdev;
6686163fc9cSnatano } else if (S_ISLNK(cur->type)) { /* symlink */
6696163fc9cSnatano slen = strlen(cur->symlink);
6706c4d9c1cSnatano if (slen < MAXSYMLINKLEN_UFS2) { /* short link */
6716163fc9cSnatano memcpy(dinp->di_db, cur->symlink, slen);
6726163fc9cSnatano } else
6736163fc9cSnatano membuf = cur->symlink;
6746163fc9cSnatano dinp->di_size = slen;
6756163fc9cSnatano }
6766163fc9cSnatano return membuf;
6776163fc9cSnatano }
6786163fc9cSnatano
6796163fc9cSnatano static int
ffs_populate_dir(const char * dir,fsnode * root,fsinfo_t * fsopts)6806163fc9cSnatano ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
6816163fc9cSnatano {
6826163fc9cSnatano fsnode *cur;
6836163fc9cSnatano dirbuf_t dirbuf;
6846163fc9cSnatano union dinode din;
6856163fc9cSnatano void *membuf;
6864874b543Sderaadt char path[PATH_MAX + 1];
6876163fc9cSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
6886163fc9cSnatano
6896163fc9cSnatano assert(dir != NULL);
6906163fc9cSnatano assert(root != NULL);
6916163fc9cSnatano assert(fsopts != NULL);
6926163fc9cSnatano assert(ffs_opts != NULL);
6936163fc9cSnatano
6946163fc9cSnatano (void)memset(&dirbuf, 0, sizeof(dirbuf));
6956163fc9cSnatano
6966163fc9cSnatano /*
6976163fc9cSnatano * pass 1: allocate inode numbers, build directory `file'
6986163fc9cSnatano */
6996163fc9cSnatano for (cur = root; cur != NULL; cur = cur->next) {
7006163fc9cSnatano if ((cur->inode->flags & FI_ALLOCATED) == 0) {
7016163fc9cSnatano cur->inode->flags |= FI_ALLOCATED;
7026163fc9cSnatano if (cur == root && cur->parent != NULL)
7036163fc9cSnatano cur->inode->ino = cur->parent->inode->ino;
7046163fc9cSnatano else {
7056163fc9cSnatano cur->inode->ino = fsopts->curinode;
7066163fc9cSnatano fsopts->curinode++;
7076163fc9cSnatano }
7086163fc9cSnatano }
709b895f220Stedu ffs_make_dirbuf(&dirbuf, cur->name, cur);
7106163fc9cSnatano if (cur == root) { /* we're at "."; add ".." */
7116163fc9cSnatano ffs_make_dirbuf(&dirbuf, "..",
712b895f220Stedu cur->parent == NULL ? cur : cur->parent->first);
7136163fc9cSnatano root->inode->nlink++; /* count my parent's link */
7146163fc9cSnatano } else if (cur->child != NULL)
7156163fc9cSnatano root->inode->nlink++; /* count my child's link */
7166163fc9cSnatano
7176163fc9cSnatano /*
7186163fc9cSnatano * XXX possibly write file and long symlinks here,
7196163fc9cSnatano * ensuring that blocks get written before inodes?
7206163fc9cSnatano * otoh, this isn't a real filesystem, so who
7216163fc9cSnatano * cares about ordering? :-)
7226163fc9cSnatano */
7236163fc9cSnatano }
7246163fc9cSnatano
7256163fc9cSnatano /*
7266163fc9cSnatano * pass 2: write out dirbuf, then non-directories at this level
7276163fc9cSnatano */
7286163fc9cSnatano for (cur = root; cur != NULL; cur = cur->next) {
7296163fc9cSnatano if (cur->inode->flags & FI_WRITTEN)
7306163fc9cSnatano continue; /* skip hard-linked entries */
7316163fc9cSnatano cur->inode->flags |= FI_WRITTEN;
7326163fc9cSnatano
7336163fc9cSnatano if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root,
7346163fc9cSnatano cur->path, cur->name) >= sizeof(path))
7356163fc9cSnatano errx(1, "Pathname too long.");
7366163fc9cSnatano
7376163fc9cSnatano if (cur->child != NULL)
7386163fc9cSnatano continue; /* child creates own inode */
7396163fc9cSnatano
7406163fc9cSnatano /* build on-disk inode */
7416163fc9cSnatano if (ffs_opts->version == 1)
7426163fc9cSnatano membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
7436163fc9cSnatano root, fsopts);
7446163fc9cSnatano else
7456163fc9cSnatano membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur,
7466163fc9cSnatano root, fsopts);
7476163fc9cSnatano
7486163fc9cSnatano if (membuf != NULL) {
7496163fc9cSnatano ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
7506163fc9cSnatano } else if (S_ISREG(cur->type)) {
7516163fc9cSnatano ffs_write_file(&din, cur->inode->ino, path, fsopts);
7526163fc9cSnatano } else {
7536163fc9cSnatano assert (! S_ISDIR(cur->type));
7546163fc9cSnatano ffs_write_inode(&din, cur->inode->ino, fsopts);
7556163fc9cSnatano }
7566163fc9cSnatano }
7576163fc9cSnatano
7586163fc9cSnatano /*
7596163fc9cSnatano * pass 3: write out sub-directories
7606163fc9cSnatano */
7616163fc9cSnatano for (cur = root; cur != NULL; cur = cur->next) {
7626163fc9cSnatano if (cur->child == NULL)
7636163fc9cSnatano continue;
7646163fc9cSnatano if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir,
7656163fc9cSnatano cur->name) >= sizeof(path))
7666163fc9cSnatano errx(1, "Pathname too long.");
7676163fc9cSnatano if (! ffs_populate_dir(path, cur->child, fsopts))
7686163fc9cSnatano return (0);
7696163fc9cSnatano }
7706163fc9cSnatano
7716163fc9cSnatano /* cleanup */
7726163fc9cSnatano free(dirbuf.buf);
7736163fc9cSnatano return (1);
7746163fc9cSnatano }
7756163fc9cSnatano
7766163fc9cSnatano
7776163fc9cSnatano static void
ffs_write_file(union dinode * din,uint32_t ino,void * buf,fsinfo_t * fsopts)7786163fc9cSnatano ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
7796163fc9cSnatano {
7806163fc9cSnatano int isfile, ffd;
7816163fc9cSnatano char *fbuf, *p;
7826163fc9cSnatano off_t bufleft, chunk, offset;
7836163fc9cSnatano ssize_t nread;
7846163fc9cSnatano struct inode in;
7854af638d7Stedu struct mkfsbuf * bp;
7866163fc9cSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
7874af638d7Stedu struct mkfsvnode vp = { fsopts, NULL };
7886163fc9cSnatano
7896163fc9cSnatano assert (din != NULL);
7906163fc9cSnatano assert (buf != NULL);
7916163fc9cSnatano assert (fsopts != NULL);
7926163fc9cSnatano assert (ffs_opts != NULL);
7936163fc9cSnatano
7946163fc9cSnatano isfile = S_ISREG(DIP(din, mode));
7956163fc9cSnatano fbuf = NULL;
7966163fc9cSnatano ffd = -1;
7976163fc9cSnatano p = NULL;
7986163fc9cSnatano
7996163fc9cSnatano in.i_fs = (struct fs *)fsopts->superblock;
8006163fc9cSnatano in.i_devvp = &vp;
8016163fc9cSnatano
8026163fc9cSnatano in.i_number = ino;
8036163fc9cSnatano in.i_size = DIP(din, size);
8046163fc9cSnatano if (ffs_opts->version == 1)
8056163fc9cSnatano memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
8066163fc9cSnatano sizeof(in.i_din.ffs1_din));
8076163fc9cSnatano else
8086163fc9cSnatano memcpy(&in.i_din.ffs2_din, &din->ffs2_din,
8096163fc9cSnatano sizeof(in.i_din.ffs2_din));
8106163fc9cSnatano
8116163fc9cSnatano if (DIP(din, size) == 0)
8126163fc9cSnatano goto write_inode_and_leave; /* mmm, cheating */
8136163fc9cSnatano
8146163fc9cSnatano if (isfile) {
8156163fc9cSnatano fbuf = emalloc(ffs_opts->bsize);
816b7041c07Sderaadt if ((ffd = open((char *)buf, O_RDONLY)) == -1) {
8176163fc9cSnatano warn("Can't open `%s' for reading", (char *)buf);
8186163fc9cSnatano goto leave_ffs_write_file;
8196163fc9cSnatano }
8206163fc9cSnatano } else {
8216163fc9cSnatano p = buf;
8226163fc9cSnatano }
8236163fc9cSnatano
8246163fc9cSnatano chunk = 0;
8256163fc9cSnatano for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
8264874b543Sderaadt chunk = MINIMUM(bufleft, ffs_opts->bsize);
8276163fc9cSnatano if (!isfile)
8286163fc9cSnatano ;
8296163fc9cSnatano else if ((nread = read(ffd, fbuf, chunk)) == -1)
830944eabd5Snatano err(1, "Reading `%s', %lld bytes to go", (char *)buf,
831944eabd5Snatano (long long)bufleft);
8326163fc9cSnatano else if (nread != chunk)
833944eabd5Snatano errx(1, "Reading `%s', %lld bytes to go, "
8346163fc9cSnatano "read %zd bytes, expected %ju bytes, does "
8356163fc9cSnatano "metalog size= attribute mismatch source size?",
8366163fc9cSnatano (char *)buf, (long long)bufleft, nread,
8376163fc9cSnatano (uintmax_t)chunk);
8386163fc9cSnatano else
8396163fc9cSnatano p = fbuf;
8406163fc9cSnatano offset = DIP(din, size) - bufleft;
8416163fc9cSnatano /*
8426163fc9cSnatano * XXX if holey support is desired, do the check here
8436163fc9cSnatano *
8446163fc9cSnatano * XXX might need to write out last bit in fragroundup
8456163fc9cSnatano * sized chunk. however, ffs_balloc() handles this for us
8466163fc9cSnatano */
8476163fc9cSnatano errno = ffs_balloc(&in, offset, chunk, &bp);
8486163fc9cSnatano bad_ffs_write_file:
8496163fc9cSnatano if (errno != 0)
8506163fc9cSnatano err(1,
8516163fc9cSnatano "Writing inode %d (%s), bytes %lld + %lld",
8526163fc9cSnatano ino,
8536163fc9cSnatano isfile ? (char *)buf :
8546163fc9cSnatano inode_type(DIP(din, mode) & S_IFMT),
8556163fc9cSnatano (long long)offset, (long long)chunk);
8566163fc9cSnatano memcpy(bp->b_data, p, chunk);
8576163fc9cSnatano errno = bwrite(bp);
8586163fc9cSnatano if (errno != 0)
8596163fc9cSnatano goto bad_ffs_write_file;
8606163fc9cSnatano if (!isfile)
8616163fc9cSnatano p += chunk;
8626163fc9cSnatano }
8636163fc9cSnatano
8646163fc9cSnatano write_inode_and_leave:
8656163fc9cSnatano ffs_write_inode(&in.i_din, in.i_number, fsopts);
8666163fc9cSnatano
8676163fc9cSnatano leave_ffs_write_file:
8686163fc9cSnatano free(fbuf);
8696163fc9cSnatano if (ffd != -1)
8706163fc9cSnatano close(ffd);
8716163fc9cSnatano }
8726163fc9cSnatano
8736163fc9cSnatano
8746163fc9cSnatano static void
ffs_make_dirbuf(dirbuf_t * dbuf,const char * name,fsnode * node)875b895f220Stedu ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node)
8766163fc9cSnatano {
8776163fc9cSnatano struct direct de, *dp;
8787247f83aSnatano uint16_t llen;
8796163fc9cSnatano u_char *newbuf;
8806163fc9cSnatano
8816163fc9cSnatano assert (dbuf != NULL);
8826163fc9cSnatano assert (name != NULL);
8836163fc9cSnatano assert (node != NULL);
8846163fc9cSnatano /* create direct entry */
8856163fc9cSnatano (void)memset(&de, 0, sizeof(de));
8867247f83aSnatano de.d_ino = node->inode->ino;
8876163fc9cSnatano de.d_type = IFTODT(node->type);
8886163fc9cSnatano de.d_namlen = (uint8_t)strlen(name);
889d95291fdStedu strlcpy(de.d_name, name, sizeof de.d_name);
890*da5362d5Sguenther de.d_reclen = DIRSIZ(&de);
8916163fc9cSnatano
8926163fc9cSnatano dp = (struct direct *)(dbuf->buf + dbuf->cur);
8936163fc9cSnatano llen = 0;
8946163fc9cSnatano if (dp != NULL)
895*da5362d5Sguenther llen = DIRSIZ(dp);
8966163fc9cSnatano
8977247f83aSnatano if (de.d_reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) {
8986c4d9c1cSnatano newbuf = erealloc(dbuf->buf, dbuf->size + DIRBLKSIZ);
8996163fc9cSnatano dbuf->buf = newbuf;
9006c4d9c1cSnatano dbuf->size += DIRBLKSIZ;
9016c4d9c1cSnatano memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
9026c4d9c1cSnatano dbuf->cur = dbuf->size - DIRBLKSIZ;
9036163fc9cSnatano } else if (dp) { /* shrink end of previous */
9047247f83aSnatano dp->d_reclen = llen;
9056163fc9cSnatano dbuf->cur += llen;
9066163fc9cSnatano }
9076163fc9cSnatano dp = (struct direct *)(dbuf->buf + dbuf->cur);
9087247f83aSnatano memcpy(dp, &de, de.d_reclen);
9097247f83aSnatano dp->d_reclen = dbuf->size - dbuf->cur;
9106163fc9cSnatano }
9116163fc9cSnatano
9126163fc9cSnatano /*
9136163fc9cSnatano * cribbed from sys/ufs/ffs/ffs_alloc.c
9146163fc9cSnatano */
9156163fc9cSnatano static void
ffs_write_inode(union dinode * dp,uint32_t ino,const fsinfo_t * fsopts)9166163fc9cSnatano ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
9176163fc9cSnatano {
9186163fc9cSnatano char *buf;
9196163fc9cSnatano struct ufs1_dinode *dp1;
9206163fc9cSnatano struct ufs2_dinode *dp2, *dip;
9216163fc9cSnatano struct cg *cgp;
9226163fc9cSnatano struct fs *fs;
9236163fc9cSnatano int cg, cgino, i;
9246163fc9cSnatano daddr_t d;
9256163fc9cSnatano char sbbuf[FFS_MAXBSIZE];
9266163fc9cSnatano uint32_t initediblk;
9276163fc9cSnatano ffs_opt_t *ffs_opts = fsopts->fs_specific;
9286163fc9cSnatano
9296163fc9cSnatano assert (dp != NULL);
9306163fc9cSnatano assert (ino > 0);
9316163fc9cSnatano assert (fsopts != NULL);
9326163fc9cSnatano assert (ffs_opts != NULL);
9336163fc9cSnatano
9346163fc9cSnatano fs = (struct fs *)fsopts->superblock;
9356163fc9cSnatano cg = ino_to_cg(fs, ino);
9366163fc9cSnatano cgino = ino % fs->fs_ipg;
9376163fc9cSnatano
9386c4d9c1cSnatano ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
9396163fc9cSnatano fsopts);
9406163fc9cSnatano cgp = (struct cg *)sbbuf;
9416c4d9c1cSnatano if (!cg_chkmagic(cgp))
9426163fc9cSnatano errx(1, "ffs_write_inode: cg %d: bad magic number", cg);
9436163fc9cSnatano
9446c4d9c1cSnatano assert (isclr(cg_inosused(cgp), cgino));
9456163fc9cSnatano
9466163fc9cSnatano buf = emalloc(fs->fs_bsize);
9476163fc9cSnatano dp1 = (struct ufs1_dinode *)buf;
9486163fc9cSnatano dp2 = (struct ufs2_dinode *)buf;
9496163fc9cSnatano
9506163fc9cSnatano if (fs->fs_cstotal.cs_nifree == 0)
9516163fc9cSnatano errx(1, "ffs_write_inode: fs out of inodes for ino %u",
9526163fc9cSnatano ino);
9536163fc9cSnatano if (fs->fs_cs(fs, cg).cs_nifree == 0)
9546163fc9cSnatano errx(1,
9556163fc9cSnatano "ffs_write_inode: cg %d out of inodes for ino %u",
9566163fc9cSnatano cg, ino);
9576c4d9c1cSnatano setbit(cg_inosused(cgp), cgino);
95899a1e5aaStedu cgp->cg_cs.cs_nifree -= 1;
9596163fc9cSnatano fs->fs_cstotal.cs_nifree--;
9606163fc9cSnatano fs->fs_cs(fs, cg).cs_nifree--;
9616163fc9cSnatano if (S_ISDIR(DIP(dp, mode))) {
96299a1e5aaStedu cgp->cg_cs.cs_ndir += 1;
9636163fc9cSnatano fs->fs_cstotal.cs_ndir++;
9646163fc9cSnatano fs->fs_cs(fs, cg).cs_ndir++;
9656163fc9cSnatano }
9666163fc9cSnatano
9676163fc9cSnatano /*
9686163fc9cSnatano * Initialize inode blocks on the fly for UFS2.
9696163fc9cSnatano */
9707247f83aSnatano initediblk = cgp->cg_initediblk;
9716163fc9cSnatano if (ffs_opts->version == 2 &&
9726c4d9c1cSnatano (uint32_t)(cgino + INOPB(fs)) > initediblk &&
9737247f83aSnatano initediblk < cgp->cg_ffs2_niblk) {
9746163fc9cSnatano memset(buf, 0, fs->fs_bsize);
9756163fc9cSnatano dip = (struct ufs2_dinode *)buf;
9766c4d9c1cSnatano for (i = 0; i < INOPB(fs); i++) {
9776163fc9cSnatano dip->di_gen = random() / 2 + 1;
9786163fc9cSnatano dip++;
9796163fc9cSnatano }
9806c4d9c1cSnatano ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs,
9816163fc9cSnatano cg * fs->fs_ipg + initediblk)),
9826163fc9cSnatano fs->fs_bsize, buf, fsopts);
9836c4d9c1cSnatano initediblk += INOPB(fs);
9847247f83aSnatano cgp->cg_initediblk = initediblk;
9856163fc9cSnatano }
9866163fc9cSnatano
9876163fc9cSnatano
9886c4d9c1cSnatano ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
9896163fc9cSnatano fsopts);
9906163fc9cSnatano
9916163fc9cSnatano /* now write inode */
9926c4d9c1cSnatano d = fsbtodb(fs, ino_to_fsba(fs, ino));
9936163fc9cSnatano ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
9946163fc9cSnatano if (ffs_opts->version == 1)
9956163fc9cSnatano dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
9966163fc9cSnatano else
9976163fc9cSnatano dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;
9986163fc9cSnatano ffs_wtfs(d, fs->fs_bsize, buf, fsopts);
9996163fc9cSnatano free(buf);
10006163fc9cSnatano }
1001