xref: /openbsd-src/usr.sbin/makefs/ffs.c (revision da5362d567d5bc29ee9e27984ebc5dd0bad1b0e2)
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