xref: /dragonfly/usr.sbin/makefs/hammer2.c (revision 48a07aad)
12d60b848STomohiro Kusumi /*
22d60b848STomohiro Kusumi  * SPDX-License-Identifier: BSD-3-Clause
32d60b848STomohiro Kusumi  *
42d60b848STomohiro Kusumi  * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org>
52d60b848STomohiro Kusumi  * Copyright (c) 2011-2022 The DragonFly Project.  All rights reserved.
62d60b848STomohiro Kusumi  *
72d60b848STomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
82d60b848STomohiro Kusumi  * modification, are permitted provided that the following conditions
92d60b848STomohiro Kusumi  * are met:
102d60b848STomohiro Kusumi  *
112d60b848STomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
122d60b848STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
132d60b848STomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
142d60b848STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in
152d60b848STomohiro Kusumi  *    the documentation and/or other materials provided with the
162d60b848STomohiro Kusumi  *    distribution.
172d60b848STomohiro Kusumi  * 3. Neither the name of The DragonFly Project nor the names of its
182d60b848STomohiro Kusumi  *    contributors may be used to endorse or promote products derived
192d60b848STomohiro Kusumi  *    from this software without specific, prior written permission.
202d60b848STomohiro Kusumi  *
212d60b848STomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
222d60b848STomohiro Kusumi  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
232d60b848STomohiro Kusumi  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
242d60b848STomohiro Kusumi  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
252d60b848STomohiro Kusumi  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
262d60b848STomohiro Kusumi  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
272d60b848STomohiro Kusumi  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
282d60b848STomohiro Kusumi  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
292d60b848STomohiro Kusumi  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
302d60b848STomohiro Kusumi  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
312d60b848STomohiro Kusumi  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322d60b848STomohiro Kusumi  * SUCH DAMAGE.
332d60b848STomohiro Kusumi  */
342d60b848STomohiro Kusumi 
352d60b848STomohiro Kusumi #if HAVE_NBTOOL_CONFIG_H
362d60b848STomohiro Kusumi #include "nbtool_config.h"
372d60b848STomohiro Kusumi #endif
382d60b848STomohiro Kusumi 
392d60b848STomohiro Kusumi #include <sys/param.h>
402d60b848STomohiro Kusumi #include <sys/stat.h>
412d60b848STomohiro Kusumi #include <sys/sysctl.h>
422d60b848STomohiro Kusumi #include <sys/mman.h>
432d60b848STomohiro Kusumi 
442d60b848STomohiro Kusumi #include <stdio.h>
452d60b848STomohiro Kusumi #include <stdlib.h>
462d60b848STomohiro Kusumi #include <stdbool.h>
472d60b848STomohiro Kusumi #include <string.h>
482d60b848STomohiro Kusumi #include <unistd.h>
492d60b848STomohiro Kusumi #include <fcntl.h>
502d60b848STomohiro Kusumi #include <time.h>
512d60b848STomohiro Kusumi #include <err.h>
522d60b848STomohiro Kusumi #include <assert.h>
532d60b848STomohiro Kusumi #include <util.h>
542d60b848STomohiro Kusumi 
552d60b848STomohiro Kusumi #include "makefs.h"
562d60b848STomohiro Kusumi #include "hammer2.h"
572d60b848STomohiro Kusumi 
582d60b848STomohiro Kusumi #define APRINTF(X, ...)	\
592d60b848STomohiro Kusumi     printf("%s: " X, __func__, ## __VA_ARGS__)
602d60b848STomohiro Kusumi 
612d60b848STomohiro Kusumi static void hammer2_dump_fsinfo(fsinfo_t *);
622d60b848STomohiro Kusumi static int hammer2_create_image(const char *, fsinfo_t *);
632d60b848STomohiro Kusumi static int hammer2_populate_dir(struct vnode *, const char *, fsnode *,
642d60b848STomohiro Kusumi     fsnode *, fsinfo_t *, int);
652d60b848STomohiro Kusumi static void hammer2_validate(const char *, fsnode *, fsinfo_t *);
662d60b848STomohiro Kusumi static void hammer2_size_dir(fsnode *, fsinfo_t *);
672d60b848STomohiro Kusumi static int hammer2_write_file(struct vnode *, const char *, fsnode *);
682d60b848STomohiro Kusumi 
692d60b848STomohiro Kusumi void
702d60b848STomohiro Kusumi hammer2_prep_opts(fsinfo_t *fsopts)
712d60b848STomohiro Kusumi {
722d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = ecalloc(1, sizeof(*h2_opt));
732d60b848STomohiro Kusumi 	hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
742d60b848STomohiro Kusumi 
752d60b848STomohiro Kusumi 	const option_t hammer2_options[] = {
762d60b848STomohiro Kusumi 		/* newfs_hammer2(8) compatible options */
772d60b848STomohiro Kusumi 		{ 'b', "BootAreaSize", NULL, OPT_STRBUF, 0, 0, "boot area size" },
782d60b848STomohiro Kusumi 		{ 'r', "AuxAreaSize", NULL, OPT_STRBUF, 0, 0, "aux area size" },
792d60b848STomohiro Kusumi 		{ 'V', "Hammer2Version", NULL, OPT_STRBUF, 0, 0, "file system version" },
802d60b848STomohiro Kusumi 		{ 'L', "Label", NULL, OPT_STRBUF, 0, 0, "PFS label" },
812d60b848STomohiro Kusumi 		/* makefs(8) specific options */
822d60b848STomohiro Kusumi 		{ 'm', "MountLabel", NULL, OPT_STRBUF, 0, 0, "destination PFS label" },
832d60b848STomohiro Kusumi 		{ 'v', "NumVolhdr", &h2_opt->num_volhdr, OPT_INT32,
842d60b848STomohiro Kusumi 		    1, HAMMER2_NUM_VOLHDRS, "number of volume headers" },
852d60b848STomohiro Kusumi 		{ 'd', "Hammer2Debug", NULL, OPT_STRBUF, 0, 0, "debug tunable" },
862d60b848STomohiro Kusumi 		{ .name = NULL },
872d60b848STomohiro Kusumi 	};
882d60b848STomohiro Kusumi 
892d60b848STomohiro Kusumi 	hammer2_mkfs_init(opt);
902d60b848STomohiro Kusumi 
912d60b848STomohiro Kusumi 	/* make this tunable ? */
922d60b848STomohiro Kusumi 	assert(opt->CompType == HAMMER2_COMP_NEWFS_DEFAULT);
932d60b848STomohiro Kusumi 	assert(opt->CheckType == HAMMER2_CHECK_XXHASH64);
942d60b848STomohiro Kusumi 
952d60b848STomohiro Kusumi 	/* force debug mode for mkfs */
962d60b848STomohiro Kusumi 	opt->DebugOpt = 1;
972d60b848STomohiro Kusumi 
982d60b848STomohiro Kusumi 	fsopts->fs_specific = h2_opt;
992d60b848STomohiro Kusumi 	fsopts->fs_options = copy_opts(hammer2_options);
1002d60b848STomohiro Kusumi 	fsopts->sectorsize = DEV_BSIZE;
1012d60b848STomohiro Kusumi }
1022d60b848STomohiro Kusumi 
1032d60b848STomohiro Kusumi void
1042d60b848STomohiro Kusumi hammer2_cleanup_opts(fsinfo_t *fsopts)
1052d60b848STomohiro Kusumi {
1062d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
1072d60b848STomohiro Kusumi 	hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
1082d60b848STomohiro Kusumi 
1092d60b848STomohiro Kusumi 	hammer2_mkfs_cleanup(opt);
1102d60b848STomohiro Kusumi 
1112d60b848STomohiro Kusumi 	free(h2_opt);
1122d60b848STomohiro Kusumi 	free(fsopts->fs_options);
1132d60b848STomohiro Kusumi }
1142d60b848STomohiro Kusumi 
1152d60b848STomohiro Kusumi int
1162d60b848STomohiro Kusumi hammer2_parse_opts(const char *option, fsinfo_t *fsopts)
1172d60b848STomohiro Kusumi {
1182d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
1192d60b848STomohiro Kusumi 	hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
1202d60b848STomohiro Kusumi 
1212d60b848STomohiro Kusumi 	option_t *hammer2_options = fsopts->fs_options;
1222d60b848STomohiro Kusumi 	char buf[1024]; /* > HAMMER2_INODE_MAXNAME */
1232d60b848STomohiro Kusumi 	int i;
1242d60b848STomohiro Kusumi 
1252d60b848STomohiro Kusumi 	assert(option != NULL);
1262d60b848STomohiro Kusumi 	assert(fsopts != NULL);
1272d60b848STomohiro Kusumi 
1282d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_PARSE_OPTS)
1292d60b848STomohiro Kusumi 		APRINTF("got `%s'\n", option);
1302d60b848STomohiro Kusumi 
1312d60b848STomohiro Kusumi 	i = set_option(hammer2_options, option, buf, sizeof(buf));
1322d60b848STomohiro Kusumi 	if (i == -1)
1332d60b848STomohiro Kusumi 		return 0;
1342d60b848STomohiro Kusumi 
1352d60b848STomohiro Kusumi 	if (hammer2_options[i].name == NULL)
1362d60b848STomohiro Kusumi 		abort();
1372d60b848STomohiro Kusumi 
1382d60b848STomohiro Kusumi 	switch (hammer2_options[i].letter) {
1392d60b848STomohiro Kusumi 	case 'b':
1402d60b848STomohiro Kusumi 		opt->BootAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN,
1412d60b848STomohiro Kusumi 		    HAMMER2_BOOT_MAX_BYTES, 2);
1422d60b848STomohiro Kusumi 		break;
1432d60b848STomohiro Kusumi 	case 'r':
1442d60b848STomohiro Kusumi 		opt->AuxAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN,
1452d60b848STomohiro Kusumi 		    HAMMER2_AUX_MAX_BYTES, 2);
1462d60b848STomohiro Kusumi 		break;
1472d60b848STomohiro Kusumi 	case 'V':
1482d60b848STomohiro Kusumi 		opt->Hammer2Version = strtol(buf, NULL, 0);
1492d60b848STomohiro Kusumi 		if (opt->Hammer2Version < HAMMER2_VOL_VERSION_MIN ||
1502d60b848STomohiro Kusumi 		    opt->Hammer2Version >= HAMMER2_VOL_VERSION_WIP)
1512d60b848STomohiro Kusumi 			errx(1, "I don't understand how to format "
1522d60b848STomohiro Kusumi 			    "HAMMER2 version %d",
1532d60b848STomohiro Kusumi 			    opt->Hammer2Version);
1542d60b848STomohiro Kusumi 		break;
1552d60b848STomohiro Kusumi 	case 'L':
1562d60b848STomohiro Kusumi 		h2_opt->label_specified = 1;
1572d60b848STomohiro Kusumi 		if (strcasecmp(buf, "none") == 0)
1582d60b848STomohiro Kusumi 			break;
1592d60b848STomohiro Kusumi 		if (opt->NLabels >= MAXLABELS)
1602d60b848STomohiro Kusumi 			errx(1, "Limit of %d local labels", MAXLABELS - 1);
1612d60b848STomohiro Kusumi 		if (strlen(buf) == 0)
1622d60b848STomohiro Kusumi 			errx(1, "Volume label '%s' cannot be 0-length", buf);
1632d60b848STomohiro Kusumi 		if (strlen(buf) >= HAMMER2_INODE_MAXNAME)
1642d60b848STomohiro Kusumi 			errx(1, "Volume label '%s' is too long (%d chars max)",
1652d60b848STomohiro Kusumi 			    buf, HAMMER2_INODE_MAXNAME - 1);
1662d60b848STomohiro Kusumi 		opt->Label[opt->NLabels++] = strdup(buf);
1672d60b848STomohiro Kusumi 		break;
1682d60b848STomohiro Kusumi 	case 'm':
1692d60b848STomohiro Kusumi 		if (strlen(buf) == 0)
1702d60b848STomohiro Kusumi 			errx(1, "Volume label '%s' cannot be 0-length", buf);
1712d60b848STomohiro Kusumi 		if (strlen(buf) >= HAMMER2_INODE_MAXNAME)
1722d60b848STomohiro Kusumi 			errx(1, "Volume label '%s' is too long (%d chars max)",
1732d60b848STomohiro Kusumi 			    buf, HAMMER2_INODE_MAXNAME - 1);
1742d60b848STomohiro Kusumi 		strlcpy(h2_opt->mount_label, buf, sizeof(h2_opt->mount_label));
1752d60b848STomohiro Kusumi 		break;
1762d60b848STomohiro Kusumi 	case 'd':
1772d60b848STomohiro Kusumi 		hammer2_debug = strtoll(buf, NULL, 0);
1782d60b848STomohiro Kusumi 		break;
1792d60b848STomohiro Kusumi 	default:
1802d60b848STomohiro Kusumi 		break;
1812d60b848STomohiro Kusumi 	}
1822d60b848STomohiro Kusumi 
1832d60b848STomohiro Kusumi 	return 1;
1842d60b848STomohiro Kusumi }
1852d60b848STomohiro Kusumi 
1862d60b848STomohiro Kusumi void
1872d60b848STomohiro Kusumi hammer2_makefs(const char *image, const char *dir, fsnode *root,
1882d60b848STomohiro Kusumi     fsinfo_t *fsopts)
1892d60b848STomohiro Kusumi {
1902d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
1912d60b848STomohiro Kusumi 	struct mount mp;
1922d60b848STomohiro Kusumi 	struct hammer2_mount_info info;
1932d60b848STomohiro Kusumi 	struct vnode devvp, *vroot;
1942d60b848STomohiro Kusumi 	hammer2_inode_t *iroot;
1952d60b848STomohiro Kusumi 	struct timeval start;
1962d60b848STomohiro Kusumi 	int error;
1972d60b848STomohiro Kusumi 
1982d60b848STomohiro Kusumi 	assert(image != NULL);
1992d60b848STomohiro Kusumi 	assert(dir != NULL);
2002d60b848STomohiro Kusumi 	assert(root != NULL);
2012d60b848STomohiro Kusumi 	assert(fsopts != NULL);
2022d60b848STomohiro Kusumi 
2032d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_MAKEFS)
2042d60b848STomohiro Kusumi 		APRINTF("image \"%s\" directory \"%s\" root %p\n",
2052d60b848STomohiro Kusumi 		    image, dir, root);
2062d60b848STomohiro Kusumi 
2072d60b848STomohiro Kusumi 	/* validate tree and options */
2082d60b848STomohiro Kusumi 	TIMER_START(start);
2092d60b848STomohiro Kusumi 	hammer2_validate(dir, root, fsopts);
2102d60b848STomohiro Kusumi 	TIMER_RESULTS(start, "hammer2_validate");
2112d60b848STomohiro Kusumi 
2122d60b848STomohiro Kusumi 	/* create image */
2132d60b848STomohiro Kusumi 	TIMER_START(start);
2142d60b848STomohiro Kusumi 	if (hammer2_create_image(image, fsopts) == -1)
2152d60b848STomohiro Kusumi 		errx(1, "image file `%s' not created", image);
2162d60b848STomohiro Kusumi 	TIMER_RESULTS(start, "hammer2_create_image");
2172d60b848STomohiro Kusumi 
2182d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_MAKEFS)
2192d60b848STomohiro Kusumi 		putchar('\n');
2202d60b848STomohiro Kusumi 
2212d60b848STomohiro Kusumi 	/* vfs init */
2222d60b848STomohiro Kusumi 	error = hammer2_vfs_init();
2232d60b848STomohiro Kusumi 	if (error)
2242d60b848STomohiro Kusumi 		errx(1, "failed to vfs init, error %d", error);
2252d60b848STomohiro Kusumi 
2262d60b848STomohiro Kusumi 	/* mount image */
2272d60b848STomohiro Kusumi 	memset(&devvp, 0, sizeof(devvp));
2282d60b848STomohiro Kusumi 	devvp.fs = fsopts;
2292d60b848STomohiro Kusumi 	memset(&mp, 0, sizeof(mp));
2302d60b848STomohiro Kusumi 	memset(&info, 0, sizeof(info));
2312d60b848STomohiro Kusumi 	error = hammer2_vfs_mount(&devvp, &mp, h2_opt->mount_label, &info);
2322d60b848STomohiro Kusumi 	if (error)
2332d60b848STomohiro Kusumi 		errx(1, "failed to mount, error %d", error);
2342d60b848STomohiro Kusumi 	assert(mp.mnt_data);
2352d60b848STomohiro Kusumi 
2362d60b848STomohiro Kusumi 	/* get root vnode */
2372d60b848STomohiro Kusumi 	vroot = NULL;
2382d60b848STomohiro Kusumi 	error = hammer2_vfs_root(&mp, &vroot);
2392d60b848STomohiro Kusumi 	if (error)
2402d60b848STomohiro Kusumi 		errx(1, "failed to get root vnode, error %d", error);
2412d60b848STomohiro Kusumi 	assert(vroot);
2422d60b848STomohiro Kusumi 
2432d60b848STomohiro Kusumi 	iroot = VTOI(vroot);
2442d60b848STomohiro Kusumi 	assert(iroot);
2452d60b848STomohiro Kusumi 	printf("root inode inum %ld, mode 0%o, refs %d\n",
2462d60b848STomohiro Kusumi 	    iroot->meta.inum, iroot->meta.mode, iroot->refs);
2472d60b848STomohiro Kusumi 
2482d60b848STomohiro Kusumi 	/* populate image */
2492d60b848STomohiro Kusumi 	printf("populating `%s'\n", image);
2502d60b848STomohiro Kusumi 	TIMER_START(start);
2512d60b848STomohiro Kusumi 	if (hammer2_populate_dir(vroot, dir, root, root, fsopts, 0))
2522d60b848STomohiro Kusumi 		errx(1, "image file `%s' not populated", image);
2532d60b848STomohiro Kusumi 	TIMER_RESULTS(start, "hammer2_populate_dir");
2542d60b848STomohiro Kusumi 
2552d60b848STomohiro Kusumi 	/* unmount image */
2562d60b848STomohiro Kusumi 	error = hammer2_vfs_unmount(&mp, 0);
2572d60b848STomohiro Kusumi 	if (error)
2582d60b848STomohiro Kusumi 		errx(1, "failed to unmount, error %d", error);
2592d60b848STomohiro Kusumi 
2602d60b848STomohiro Kusumi 	/* check leaked resource */
2612d60b848STomohiro Kusumi 	if (vnode_count)
2622d60b848STomohiro Kusumi 		printf("XXX %ld vnode left\n", vnode_count);
2632d60b848STomohiro Kusumi 	if (hammer2_chain_allocs)
2642d60b848STomohiro Kusumi 		printf("XXX %ld chain left\n", hammer2_chain_allocs);
2652d60b848STomohiro Kusumi 	bcleanup();
2662d60b848STomohiro Kusumi 
2672d60b848STomohiro Kusumi 	/* vfs uninit */
2682d60b848STomohiro Kusumi 	error = hammer2_vfs_uninit();
2692d60b848STomohiro Kusumi 	if (error)
2702d60b848STomohiro Kusumi 		errx(1, "failed to vfs uninit, error %d", error);
2712d60b848STomohiro Kusumi 
2722d60b848STomohiro Kusumi 	if (close(fsopts->fd) == -1)
2732d60b848STomohiro Kusumi 		err(1, "closing `%s'", image);
2742d60b848STomohiro Kusumi 	fsopts->fd = -1;
2752d60b848STomohiro Kusumi 
2762d60b848STomohiro Kusumi 	printf("image `%s' complete\n", image);
2772d60b848STomohiro Kusumi }
2782d60b848STomohiro Kusumi 
2792d60b848STomohiro Kusumi /* end of public functions */
2802d60b848STomohiro Kusumi 
2812d60b848STomohiro Kusumi static hammer2_off_t
2822d60b848STomohiro Kusumi hammer2_image_size(fsinfo_t *fsopts)
2832d60b848STomohiro Kusumi {
2842d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
2852d60b848STomohiro Kusumi 	hammer2_off_t image_size, used_size = 0;
2862d60b848STomohiro Kusumi 	int num_level1, delta_num_level1;
2872d60b848STomohiro Kusumi 
2882d60b848STomohiro Kusumi 	/* use 4 volume headers by default */
2892d60b848STomohiro Kusumi 	num_level1 = h2_opt->num_volhdr * 2; /* default 4 x 2 */
2902d60b848STomohiro Kusumi 	assert(num_level1 != 0);
2912d60b848STomohiro Kusumi 	assert(num_level1 <= 8);
2922d60b848STomohiro Kusumi 
2932d60b848STomohiro Kusumi 	/* add 4MiB segment for each level1 */
2942d60b848STomohiro Kusumi 	used_size += HAMMER2_ZONE_SEG64 * num_level1;
2952d60b848STomohiro Kusumi 
2962d60b848STomohiro Kusumi 	/* add boot/aux area, but exact size unknown at this point */
2972d60b848STomohiro Kusumi 	used_size += HAMMER2_BOOT_NOM_BYTES + HAMMER2_AUX_NOM_BYTES;
2982d60b848STomohiro Kusumi 
2992d60b848STomohiro Kusumi 	/* add data size */
3002d60b848STomohiro Kusumi 	used_size += fsopts->size;
3012d60b848STomohiro Kusumi 
3022d60b848STomohiro Kusumi 	/* XXX add extra level1 for meta data and indirect blocks */
3032d60b848STomohiro Kusumi 	used_size += HAMMER2_FREEMAP_LEVEL1_SIZE;
3042d60b848STomohiro Kusumi 
3052d60b848STomohiro Kusumi 	/* XXX add extra level1 for safety */
3062d60b848STomohiro Kusumi 	if (used_size > HAMMER2_FREEMAP_LEVEL1_SIZE * 10)
3072d60b848STomohiro Kusumi 		used_size += HAMMER2_FREEMAP_LEVEL1_SIZE;
3082d60b848STomohiro Kusumi 
3092d60b848STomohiro Kusumi 	/* use 8GiB image size by default */
3102d60b848STomohiro Kusumi 	image_size = HAMMER2_FREEMAP_LEVEL1_SIZE * num_level1;
3112d60b848STomohiro Kusumi 	printf("trying default image size %s\n", sizetostr(image_size));
3122d60b848STomohiro Kusumi 
3132d60b848STomohiro Kusumi 	/* adjust if image size isn't large enough */
3142d60b848STomohiro Kusumi 	if (used_size > image_size) {
3152d60b848STomohiro Kusumi 		/* determine extra level1 needed */
3162d60b848STomohiro Kusumi 		delta_num_level1 = howmany(used_size - image_size,
3172d60b848STomohiro Kusumi 		    HAMMER2_FREEMAP_LEVEL1_SIZE);
3182d60b848STomohiro Kusumi 
3192d60b848STomohiro Kusumi 		/* adjust used size with 4MiB segment for each extra level1 */
3202d60b848STomohiro Kusumi 		used_size += HAMMER2_ZONE_SEG64 * delta_num_level1;
3212d60b848STomohiro Kusumi 
3222d60b848STomohiro Kusumi 		/* adjust image size with extra level1 */
3232d60b848STomohiro Kusumi 		image_size += HAMMER2_FREEMAP_LEVEL1_SIZE * delta_num_level1;
3242d60b848STomohiro Kusumi 		printf("trying adjusted image size %s\n",
3252d60b848STomohiro Kusumi 		    sizetostr(image_size));
3262d60b848STomohiro Kusumi 
3272d60b848STomohiro Kusumi 		if (used_size > image_size)
3282d60b848STomohiro Kusumi 			errx(1, "invalid used_size %ld > image_size %ld",
3292d60b848STomohiro Kusumi 			    used_size, image_size);
3302d60b848STomohiro Kusumi 	}
3312d60b848STomohiro Kusumi 
3322d60b848STomohiro Kusumi 	return image_size;
3332d60b848STomohiro Kusumi }
3342d60b848STomohiro Kusumi 
3352d60b848STomohiro Kusumi static const char *
3362d60b848STomohiro Kusumi hammer2_label_name(int label_type)
3372d60b848STomohiro Kusumi {
3382d60b848STomohiro Kusumi 	switch (label_type) {
3392d60b848STomohiro Kusumi 	case HAMMER2_LABEL_NONE:
3402d60b848STomohiro Kusumi 		return "NONE";
3412d60b848STomohiro Kusumi 	case HAMMER2_LABEL_BOOT:
3422d60b848STomohiro Kusumi 		return "BOOT";
3432d60b848STomohiro Kusumi 	case HAMMER2_LABEL_ROOT:
3442d60b848STomohiro Kusumi 		return "ROOT";
3452d60b848STomohiro Kusumi 	case HAMMER2_LABEL_DATA:
3462d60b848STomohiro Kusumi 		return "DATA";
3472d60b848STomohiro Kusumi 	default:
3482d60b848STomohiro Kusumi 		assert(0);
3492d60b848STomohiro Kusumi 	}
3502d60b848STomohiro Kusumi 	return NULL;
3512d60b848STomohiro Kusumi }
3522d60b848STomohiro Kusumi 
3532d60b848STomohiro Kusumi static void
3542d60b848STomohiro Kusumi hammer2_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
3552d60b848STomohiro Kusumi {
3562d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
3572d60b848STomohiro Kusumi 	hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
3582d60b848STomohiro Kusumi 	hammer2_off_t image_size, minsize, maxsize;
3592d60b848STomohiro Kusumi 	const char *s;
3602d60b848STomohiro Kusumi 
3612d60b848STomohiro Kusumi 	assert(dir != NULL);
3622d60b848STomohiro Kusumi 	assert(root != NULL);
3632d60b848STomohiro Kusumi 	assert(fsopts != NULL);
3642d60b848STomohiro Kusumi 
3652d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_VALIDATE) {
3662d60b848STomohiro Kusumi 		APRINTF("before defaults set:\n");
3672d60b848STomohiro Kusumi 		hammer2_dump_fsinfo(fsopts);
3682d60b848STomohiro Kusumi 	}
3692d60b848STomohiro Kusumi 
3702d60b848STomohiro Kusumi 	/* makefs only supports "DATA" for default PFS label */
3712d60b848STomohiro Kusumi 	if (!h2_opt->label_specified) {
3722d60b848STomohiro Kusumi 		opt->DefaultLabelType = HAMMER2_LABEL_DATA;
3732d60b848STomohiro Kusumi 		s = hammer2_label_name(opt->DefaultLabelType);
3742d60b848STomohiro Kusumi 		printf("using default label \"%s\"\n", s);
3752d60b848STomohiro Kusumi 	}
3762d60b848STomohiro Kusumi 
3772d60b848STomohiro Kusumi 	/* set default mount PFS label */
3782d60b848STomohiro Kusumi 	if (!strcmp(h2_opt->mount_label, "")) {
3792d60b848STomohiro Kusumi 		s = hammer2_label_name(HAMMER2_LABEL_DATA);
3802d60b848STomohiro Kusumi 		strlcpy(h2_opt->mount_label, s, sizeof(h2_opt->mount_label));
3812d60b848STomohiro Kusumi 		printf("using default mount label \"%s\"\n", s);
3822d60b848STomohiro Kusumi 	}
3832d60b848STomohiro Kusumi 
3842d60b848STomohiro Kusumi 	/* set default number of volume headers */
3852d60b848STomohiro Kusumi 	if (!h2_opt->num_volhdr) {
3862d60b848STomohiro Kusumi 		h2_opt->num_volhdr = HAMMER2_NUM_VOLHDRS;
3872d60b848STomohiro Kusumi 		printf("using default %d volume headers\n", h2_opt->num_volhdr);
3882d60b848STomohiro Kusumi 	}
3892d60b848STomohiro Kusumi 
3902d60b848STomohiro Kusumi 	/* calculate data size */
3912d60b848STomohiro Kusumi 	if (fsopts->size != 0)
3922d60b848STomohiro Kusumi 		fsopts->size = 0; /* shouldn't reach here to begin with */
3932d60b848STomohiro Kusumi 	hammer2_size_dir(root, fsopts);
3942d60b848STomohiro Kusumi 	printf("estimated data size %s from %lld inode\n",
3952d60b848STomohiro Kusumi 	    sizetostr(fsopts->size), (long long)fsopts->inodes);
3962d60b848STomohiro Kusumi 
3972d60b848STomohiro Kusumi 	/* determine image size from data size */
3982d60b848STomohiro Kusumi 	image_size = hammer2_image_size(fsopts);
3992d60b848STomohiro Kusumi 	assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0);
4002d60b848STomohiro Kusumi 
4012d60b848STomohiro Kusumi 	minsize = roundup(fsopts->minsize, HAMMER2_FREEMAP_LEVEL1_SIZE);
4022d60b848STomohiro Kusumi 	maxsize = roundup(fsopts->maxsize, HAMMER2_FREEMAP_LEVEL1_SIZE);
4032d60b848STomohiro Kusumi 	if (image_size < minsize)
4042d60b848STomohiro Kusumi 		image_size = minsize;
4052d60b848STomohiro Kusumi 	else if (maxsize > 0 && image_size > maxsize)
4062d60b848STomohiro Kusumi 		errx(1, "`%s' size of %ld is larger than the maxsize of %ld",
4072d60b848STomohiro Kusumi 		    dir, image_size, maxsize);
4082d60b848STomohiro Kusumi 
4092d60b848STomohiro Kusumi 	assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0);
4102d60b848STomohiro Kusumi 	h2_opt->image_size = image_size;
4112d60b848STomohiro Kusumi 	printf("using %s image size\n", sizetostr(h2_opt->image_size));
4122d60b848STomohiro Kusumi 
4132d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_VALIDATE) {
4142d60b848STomohiro Kusumi 		APRINTF("after defaults set:\n");
4152d60b848STomohiro Kusumi 		hammer2_dump_fsinfo(fsopts);
4162d60b848STomohiro Kusumi 	}
4172d60b848STomohiro Kusumi }
4182d60b848STomohiro Kusumi 
4192d60b848STomohiro Kusumi static void
4202d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsinfo_t *fsopts)
4212d60b848STomohiro Kusumi {
4222d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
4232d60b848STomohiro Kusumi 	hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
4242d60b848STomohiro Kusumi 	int i;
4252d60b848STomohiro Kusumi 	char *s;
4262d60b848STomohiro Kusumi 
4272d60b848STomohiro Kusumi 	assert(fsopts != NULL);
4282d60b848STomohiro Kusumi 
4292d60b848STomohiro Kusumi 	APRINTF("fsinfo_t at %p\n", fsopts);
4302d60b848STomohiro Kusumi 
4312d60b848STomohiro Kusumi 	printf("\tinodes %lld\n", (long long)fsopts->inodes);
4322d60b848STomohiro Kusumi 	printf("\tsize %lld, minsize %lld, maxsize %lld\n",
4332d60b848STomohiro Kusumi 	    (long long)fsopts->size,
4342d60b848STomohiro Kusumi 	    (long long)fsopts->minsize,
4352d60b848STomohiro Kusumi 	    (long long)fsopts->maxsize);
4362d60b848STomohiro Kusumi 
4372d60b848STomohiro Kusumi 	printf("\thammer2_debug 0x%x\n", hammer2_debug);
4382d60b848STomohiro Kusumi 
4392d60b848STomohiro Kusumi 	printf("\tlabel_specified %d\n", h2_opt->label_specified);
4402d60b848STomohiro Kusumi 	printf("\tmount_label \"%s\"\n", h2_opt->mount_label);
4412d60b848STomohiro Kusumi 	printf("\tnum_volhdr %d\n", h2_opt->num_volhdr);
4422d60b848STomohiro Kusumi 	printf("\timage_size 0x%lx\n", h2_opt->image_size);
4432d60b848STomohiro Kusumi 
4442d60b848STomohiro Kusumi 	printf("\tHammer2Version %d\n", opt->Hammer2Version);
4452d60b848STomohiro Kusumi 	printf("\tBootAreaSize 0x%jx\n", opt->BootAreaSize);
4462d60b848STomohiro Kusumi 	printf("\tAuxAreaSize 0x%jx\n", opt->AuxAreaSize);
4472d60b848STomohiro Kusumi 	printf("\tNLabels %d\n", opt->NLabels);
4482d60b848STomohiro Kusumi 	printf("\tCompType %d\n", opt->CompType);
4492d60b848STomohiro Kusumi 	printf("\tCheckType %d\n", opt->CheckType);
4502d60b848STomohiro Kusumi 	printf("\tDefaultLabelType %d\n", opt->DefaultLabelType);
4512d60b848STomohiro Kusumi 	printf("\tDebugOpt %d\n", opt->DebugOpt);
4522d60b848STomohiro Kusumi 
4532d60b848STomohiro Kusumi 	s = NULL;
4542d60b848STomohiro Kusumi 	hammer2_uuid_to_str(&opt->Hammer2_FSType, &s);
4552d60b848STomohiro Kusumi 	printf("\tHammer2_FSType \"%s\"\n", s);
4562d60b848STomohiro Kusumi 	s = NULL;
4572d60b848STomohiro Kusumi 	hammer2_uuid_to_str(&opt->Hammer2_VolFSID, &s);
4582d60b848STomohiro Kusumi 	printf("\tHammer2_VolFSID \"%s\"\n", s);
4592d60b848STomohiro Kusumi 	s = NULL;
4602d60b848STomohiro Kusumi 	hammer2_uuid_to_str(&opt->Hammer2_SupCLID, &s);
4612d60b848STomohiro Kusumi 	printf("\tHammer2_SupCLID \"%s\"\n", s);
4622d60b848STomohiro Kusumi 	s = NULL;
4632d60b848STomohiro Kusumi 	hammer2_uuid_to_str(&opt->Hammer2_SupFSID, &s);
4642d60b848STomohiro Kusumi 	printf("\tHammer2_SupFSID \"%s\"\n", s);
4652d60b848STomohiro Kusumi 
4662d60b848STomohiro Kusumi 	for (i = 0; i < opt->NLabels; i++) {
4672d60b848STomohiro Kusumi 		printf("\tLabel[%d] \"%s\"\n", i, opt->Label[i]);
4682d60b848STomohiro Kusumi 		s = NULL;
4692d60b848STomohiro Kusumi 		hammer2_uuid_to_str(&opt->Hammer2_PfsCLID[i], &s);
4702d60b848STomohiro Kusumi 		printf("\t Hammer2_PfsCLID[%d] \"%s\"\n", i, s);
4712d60b848STomohiro Kusumi 		s = NULL;
4722d60b848STomohiro Kusumi 		hammer2_uuid_to_str(&opt->Hammer2_PfsFSID[i], &s);
4732d60b848STomohiro Kusumi 		printf("\t Hammer2_PfsFSID[%d] \"%s\"\n", i, s);
4742d60b848STomohiro Kusumi 	}
4752d60b848STomohiro Kusumi 
4762d60b848STomohiro Kusumi 	free(s);
4772d60b848STomohiro Kusumi }
4782d60b848STomohiro Kusumi 
4792d60b848STomohiro Kusumi static int
4802d60b848STomohiro Kusumi hammer2_create_image(const char *image, fsinfo_t *fsopts)
4812d60b848STomohiro Kusumi {
4822d60b848STomohiro Kusumi 	hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
4832d60b848STomohiro Kusumi 	hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
4842d60b848STomohiro Kusumi 	char *av[] = { (char *)image, }; /* XXX support multi-volumes */
4852d60b848STomohiro Kusumi 	char *buf;
4862d60b848STomohiro Kusumi 	int i, bufsize, oflags;
4872d60b848STomohiro Kusumi 	off_t bufrem;
4882d60b848STomohiro Kusumi 
4892d60b848STomohiro Kusumi 	assert(image != NULL);
4902d60b848STomohiro Kusumi 	assert(fsopts != NULL);
4912d60b848STomohiro Kusumi 
4922d60b848STomohiro Kusumi 	/* create image */
4932d60b848STomohiro Kusumi 	oflags = O_RDWR | O_CREAT;
4942d60b848STomohiro Kusumi 	if (fsopts->offset == 0)
4952d60b848STomohiro Kusumi 		oflags |= O_TRUNC;
4962d60b848STomohiro Kusumi 	if ((fsopts->fd = open(image, oflags, 0666)) == -1) {
4972d60b848STomohiro Kusumi 		warn("can't open `%s' for writing", image);
4982d60b848STomohiro Kusumi 		return -1;
4992d60b848STomohiro Kusumi 	}
5002d60b848STomohiro Kusumi 
5012d60b848STomohiro Kusumi 	/* zero image */
5022d60b848STomohiro Kusumi 	bufsize = HAMMER2_PBUFSIZE;
5032d60b848STomohiro Kusumi 	bufrem = h2_opt->image_size;
5042d60b848STomohiro Kusumi 	if (fsopts->sparse) {
5052d60b848STomohiro Kusumi 		if (ftruncate(fsopts->fd, bufrem) == -1) {
5062d60b848STomohiro Kusumi 			warn("sparse option disabled");
5072d60b848STomohiro Kusumi 			fsopts->sparse = 0;
5082d60b848STomohiro Kusumi 		}
5092d60b848STomohiro Kusumi 	}
5102d60b848STomohiro Kusumi 	if (fsopts->sparse) {
5112d60b848STomohiro Kusumi 		/* File truncated at bufrem. Remaining is 0 */
5122d60b848STomohiro Kusumi 		bufrem = 0;
5132d60b848STomohiro Kusumi 		buf = NULL;
5142d60b848STomohiro Kusumi 	} else {
5152d60b848STomohiro Kusumi 		if (debug & DEBUG_FS_CREATE_IMAGE)
5162d60b848STomohiro Kusumi 			APRINTF("zero-ing image `%s', %lld sectors, "
5172d60b848STomohiro Kusumi 			    "using %d byte chunks\n",
5182d60b848STomohiro Kusumi 			    image, (long long)bufrem, bufsize);
5192d60b848STomohiro Kusumi 		buf = ecalloc(1, bufsize);
5202d60b848STomohiro Kusumi 	}
5212d60b848STomohiro Kusumi 
5222d60b848STomohiro Kusumi 	if (fsopts->offset != 0) {
5232d60b848STomohiro Kusumi 		if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) {
5242d60b848STomohiro Kusumi 			warn("can't seek");
5252d60b848STomohiro Kusumi 			free(buf);
5262d60b848STomohiro Kusumi 			return -1;
5272d60b848STomohiro Kusumi 		}
5282d60b848STomohiro Kusumi 	}
5292d60b848STomohiro Kusumi 
5302d60b848STomohiro Kusumi 	while (bufrem > 0) {
5312d60b848STomohiro Kusumi 		i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
5322d60b848STomohiro Kusumi 		if (i == -1) {
5332d60b848STomohiro Kusumi 			warn("zeroing image, %lld bytes to go",
5342d60b848STomohiro Kusumi 			    (long long)bufrem);
5352d60b848STomohiro Kusumi 			free(buf);
5362d60b848STomohiro Kusumi 			return -1;
5372d60b848STomohiro Kusumi 		}
5382d60b848STomohiro Kusumi 		bufrem -= i;
5392d60b848STomohiro Kusumi 	}
5402d60b848STomohiro Kusumi 	if (buf)
5412d60b848STomohiro Kusumi 		free(buf);
5422d60b848STomohiro Kusumi 
5432d60b848STomohiro Kusumi 	/* make the file system */
5442d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_CREATE_IMAGE)
5452d60b848STomohiro Kusumi 		APRINTF("calling mkfs(\"%s\", ...)\n", image);
5462d60b848STomohiro Kusumi 	hammer2_mkfs(1, av, opt); /* success if returned */
5472d60b848STomohiro Kusumi 
5482d60b848STomohiro Kusumi 	return fsopts->fd;
5492d60b848STomohiro Kusumi }
5502d60b848STomohiro Kusumi 
5512d60b848STomohiro Kusumi static off_t
5522d60b848STomohiro Kusumi hammer2_phys_size(off_t size)
5532d60b848STomohiro Kusumi {
5542d60b848STomohiro Kusumi 	off_t radix_size, phys_size = 0;
5552d60b848STomohiro Kusumi 	int i;
5562d60b848STomohiro Kusumi 
5572d60b848STomohiro Kusumi 	if (size > HAMMER2_PBUFSIZE) {
5582d60b848STomohiro Kusumi 		phys_size += rounddown(size, HAMMER2_PBUFSIZE);
5592d60b848STomohiro Kusumi 		size = size % HAMMER2_PBUFSIZE;
5602d60b848STomohiro Kusumi 	}
5612d60b848STomohiro Kusumi 
5622d60b848STomohiro Kusumi 	for (i = HAMMER2_RADIX_MIN; i <= HAMMER2_RADIX_MAX; i++) {
5632d60b848STomohiro Kusumi 		radix_size = 1UL << i;
5642d60b848STomohiro Kusumi 		if (radix_size >= size) {
5652d60b848STomohiro Kusumi 			phys_size += radix_size;
5662d60b848STomohiro Kusumi 			break;
5672d60b848STomohiro Kusumi 		}
5682d60b848STomohiro Kusumi 	}
5692d60b848STomohiro Kusumi 
5702d60b848STomohiro Kusumi 	return phys_size;
5712d60b848STomohiro Kusumi }
5722d60b848STomohiro Kusumi 
5732d60b848STomohiro Kusumi /* calculate data size */
5742d60b848STomohiro Kusumi static void
5752d60b848STomohiro Kusumi hammer2_size_dir(fsnode *root, fsinfo_t *fsopts)
5762d60b848STomohiro Kusumi {
5772d60b848STomohiro Kusumi 	fsnode *node;
5782d60b848STomohiro Kusumi 	int curdirsize;
5792d60b848STomohiro Kusumi 
5802d60b848STomohiro Kusumi 	assert(fsopts != NULL);
5812d60b848STomohiro Kusumi 
5822d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_SIZE_DIR)
5832d60b848STomohiro Kusumi 		APRINTF("entry: bytes %lld inodes %lld\n",
5842d60b848STomohiro Kusumi 		    (long long)fsopts->size, (long long)fsopts->inodes);
5852d60b848STomohiro Kusumi 
5862d60b848STomohiro Kusumi 	curdirsize = 0;
5872d60b848STomohiro Kusumi 	for (node = root; node != NULL; node = node->next) {
5882d60b848STomohiro Kusumi 		if (node == root) { /* we're at "." */
5892d60b848STomohiro Kusumi 			assert(strcmp(node->name, ".") == 0);
5902d60b848STomohiro Kusumi 		} else if ((node->inode->flags & FI_SIZED) == 0) {
5912d60b848STomohiro Kusumi 			/* don't count duplicate names */
5922d60b848STomohiro Kusumi 			node->inode->flags |= FI_SIZED;
5932d60b848STomohiro Kusumi 			if (debug & DEBUG_FS_SIZE_DIR_NODE)
5942d60b848STomohiro Kusumi 				APRINTF("`%s' size %lld\n",
5952d60b848STomohiro Kusumi 				    node->name,
5962d60b848STomohiro Kusumi 				    (long long)node->inode->st.st_size);
5972d60b848STomohiro Kusumi 			fsopts->inodes++;
5982d60b848STomohiro Kusumi 			fsopts->size += sizeof(hammer2_inode_data_t);
5992d60b848STomohiro Kusumi 			if (node->type == S_IFREG) {
6002d60b848STomohiro Kusumi 				size_t st_size = node->inode->st.st_size;
6012d60b848STomohiro Kusumi 				if (st_size > HAMMER2_EMBEDDED_BYTES)
6022d60b848STomohiro Kusumi 					fsopts->size += hammer2_phys_size(st_size);
6032d60b848STomohiro Kusumi 			} else if (node->type == S_IFLNK) {
6042d60b848STomohiro Kusumi 				size_t nlen = strlen(node->symlink);
6052d60b848STomohiro Kusumi 				if (nlen > HAMMER2_EMBEDDED_BYTES)
6062d60b848STomohiro Kusumi 					fsopts->size += hammer2_phys_size(nlen);
6072d60b848STomohiro Kusumi 			}
6082d60b848STomohiro Kusumi 		}
6092d60b848STomohiro Kusumi 		if (node->type == S_IFDIR)
6102d60b848STomohiro Kusumi 			hammer2_size_dir(node->child, fsopts);
6112d60b848STomohiro Kusumi 	}
6122d60b848STomohiro Kusumi 
6132d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_SIZE_DIR)
6142d60b848STomohiro Kusumi 		APRINTF("exit: size %lld inodes %lld\n",
6152d60b848STomohiro Kusumi 		    (long long)fsopts->size, (long long)fsopts->inodes);
6162d60b848STomohiro Kusumi }
6172d60b848STomohiro Kusumi 
6182d60b848STomohiro Kusumi static void
6192d60b848STomohiro Kusumi hammer2_print(const struct vnode *dvp, const struct vnode *vp,
6202d60b848STomohiro Kusumi     const fsnode *node, int depth, const char *msg)
6212d60b848STomohiro Kusumi {
6222d60b848STomohiro Kusumi 	if (debug & DEBUG_FS_POPULATE) {
6232d60b848STomohiro Kusumi 		if (1) {
6242d60b848STomohiro Kusumi 			int indent = depth * 2;
6252d60b848STomohiro Kusumi 			char *type;
6262d60b848STomohiro Kusumi 			if (S_ISDIR(node->type))
6272d60b848STomohiro Kusumi 				type = "dir";
6282d60b848STomohiro Kusumi 			else if (S_ISREG(node->type))
6292d60b848STomohiro Kusumi 				type = "reg";
6302d60b848STomohiro Kusumi 			else if (S_ISLNK(node->type))
6312d60b848STomohiro Kusumi 				type = "lnk";
6324d8112c5STomohiro Kusumi 			else if (S_ISFIFO(node->type))
6334d8112c5STomohiro Kusumi 				type = "fifo";
6342d60b848STomohiro Kusumi 			else
6352d60b848STomohiro Kusumi 				type = "???";
6362d60b848STomohiro Kusumi 			printf("%*.*s", indent, indent, "");
6372d60b848STomohiro Kusumi 			printf("dvp=%p/%d vp=%p/%d \"%s\" %s %s\n",
6382d60b848STomohiro Kusumi 			    dvp, dvp ? VTOI(dvp)->refs : 0,
6392d60b848STomohiro Kusumi 			    vp, vp ? VTOI(vp)->refs : 0,
6402d60b848STomohiro Kusumi 			    node->name, type, msg);
6412d60b848STomohiro Kusumi 		} else {
6422d60b848STomohiro Kusumi 			char type;
6432d60b848STomohiro Kusumi 			if (S_ISDIR(node->type))
6442d60b848STomohiro Kusumi 				type = 'd';
6452d60b848STomohiro Kusumi 			else if (S_ISREG(node->type))
6462d60b848STomohiro Kusumi 				type = 'r';
6472d60b848STomohiro Kusumi 			else if (S_ISLNK(node->type))
6482d60b848STomohiro Kusumi 				type = 'l';
6494d8112c5STomohiro Kusumi 			else if (S_ISFIFO(node->type))
6504d8112c5STomohiro Kusumi 				type = 'f';
6512d60b848STomohiro Kusumi 			else
6522d60b848STomohiro Kusumi 				type = '?';
6532d60b848STomohiro Kusumi 			printf("%c", type);
6542d60b848STomohiro Kusumi 			fflush(stdout);
6552d60b848STomohiro Kusumi 		}
6562d60b848STomohiro Kusumi 	}
6572d60b848STomohiro Kusumi }
6582d60b848STomohiro Kusumi 
6592d60b848STomohiro Kusumi static int
6602d60b848STomohiro Kusumi hammer2_populate_dir(struct vnode *dvp, const char *dir, fsnode *root,
6612d60b848STomohiro Kusumi     fsnode *parent, fsinfo_t *fsopts, int depth)
6622d60b848STomohiro Kusumi {
6632d60b848STomohiro Kusumi 	fsnode *cur;
6642d60b848STomohiro Kusumi 	struct vnode *vp;
6652d60b848STomohiro Kusumi 	struct stat st;
6662d60b848STomohiro Kusumi 	char f[MAXPATHLEN];
6672d60b848STomohiro Kusumi 	const char *path;
668213ebac1STomohiro Kusumi 	int hardlink;
6692d60b848STomohiro Kusumi 	int error;
6702d60b848STomohiro Kusumi 
6712d60b848STomohiro Kusumi 	assert(dvp != NULL);
6722d60b848STomohiro Kusumi 	assert(dir != NULL);
6732d60b848STomohiro Kusumi 	assert(root != NULL);
6742d60b848STomohiro Kusumi 	assert(parent != NULL);
6752d60b848STomohiro Kusumi 	assert(fsopts != NULL);
6762d60b848STomohiro Kusumi 
6772d60b848STomohiro Kusumi 	/* assert root directory */
6782d60b848STomohiro Kusumi 	assert(S_ISDIR(root->type));
6792d60b848STomohiro Kusumi 	assert(!strcmp(root->name, "."));
6802d60b848STomohiro Kusumi 	assert(!root->child);
6812d60b848STomohiro Kusumi 	assert(!root->parent || root->parent->child == root);
6822d60b848STomohiro Kusumi 
6832d60b848STomohiro Kusumi 	hammer2_print(dvp, NULL, root, depth, "enter");
6842d60b848STomohiro Kusumi 	if (stat(dir, &st) == -1)
6852d60b848STomohiro Kusumi 		err(1, "no such path %s", dir);
6862d60b848STomohiro Kusumi 	if (!S_ISDIR(st.st_mode))
6872d60b848STomohiro Kusumi 		errx(1, "no such dir %s", dir);
6882d60b848STomohiro Kusumi 
6892d60b848STomohiro Kusumi 	for (cur = root->next; cur != NULL; cur = cur->next) {
6902d60b848STomohiro Kusumi 		/* construct source path */
6912d60b848STomohiro Kusumi 		if (cur->contents) {
6922d60b848STomohiro Kusumi 			path = cur->contents;
6932d60b848STomohiro Kusumi 		} else {
6942d60b848STomohiro Kusumi 			if (S_ISDIR(cur->type)) {
6952d60b848STomohiro Kusumi 				/* this should be same as root/path/name */
6962d60b848STomohiro Kusumi 				if (snprintf(f, sizeof(f), "%s/%s",
6972d60b848STomohiro Kusumi 				    dir, cur->name) >= (int)sizeof(f))
6982d60b848STomohiro Kusumi 					errx(1, "pathname too long");
6992d60b848STomohiro Kusumi 			} else {
7002d60b848STomohiro Kusumi 				if (snprintf(f, sizeof(f), "%s/%s/%s",
7012d60b848STomohiro Kusumi 				    cur->root, cur->path, cur->name) >= (int)sizeof(f))
7022d60b848STomohiro Kusumi 					errx(1, "pathname too long");
7032d60b848STomohiro Kusumi 			}
7042d60b848STomohiro Kusumi 			path = f;
7052d60b848STomohiro Kusumi 		}
7062d60b848STomohiro Kusumi 		if (stat(path, &st) == -1)
7072d60b848STomohiro Kusumi 			err(1, "no such file %s", f);
7082d60b848STomohiro Kusumi 
7092d60b848STomohiro Kusumi 		/* update node state */
7102d60b848STomohiro Kusumi 		if ((cur->inode->flags & FI_ALLOCATED) == 0) {
7112d60b848STomohiro Kusumi 			cur->inode->flags |= FI_ALLOCATED;
7122d60b848STomohiro Kusumi 			if (cur != root)
7132d60b848STomohiro Kusumi 				cur->parent = parent;
7142d60b848STomohiro Kusumi 		}
7152d60b848STomohiro Kusumi 
716213ebac1STomohiro Kusumi 		/* detect hardlink */
717213ebac1STomohiro Kusumi 		if (cur->inode->flags & FI_WRITTEN) {
718213ebac1STomohiro Kusumi 			assert(!S_ISDIR(cur->type));
719213ebac1STomohiro Kusumi 			hardlink = 1;
720213ebac1STomohiro Kusumi 		} else {
721213ebac1STomohiro Kusumi 			hardlink = 0;
722213ebac1STomohiro Kusumi 		}
7232d60b848STomohiro Kusumi 		cur->inode->flags |= FI_WRITTEN;
7242d60b848STomohiro Kusumi 
7252d60b848STomohiro Kusumi 		/* make sure it doesn't exist yet */
7262d60b848STomohiro Kusumi 		vp = NULL;
7272d60b848STomohiro Kusumi 		error = hammer2_nresolve(dvp, &vp, cur->name,
7282d60b848STomohiro Kusumi 		    strlen(cur->name));
7292d60b848STomohiro Kusumi 		if (!error)
7302d60b848STomohiro Kusumi 			errx(1, "hammer2_nresolve(\"%s\") already exists",
7312d60b848STomohiro Kusumi 			    cur->name);
7322d60b848STomohiro Kusumi 		hammer2_print(dvp, vp, cur, depth, "nresolve");
7332d60b848STomohiro Kusumi 
7342d60b848STomohiro Kusumi 		/* if directory, mkdir and recurse */
7352d60b848STomohiro Kusumi 		if (S_ISDIR(cur->type)) {
7362d60b848STomohiro Kusumi 			assert(cur->child);
7372d60b848STomohiro Kusumi 
7382d60b848STomohiro Kusumi 			vp = NULL;
7392d60b848STomohiro Kusumi 			error = hammer2_nmkdir(dvp, &vp, cur->name,
7402d60b848STomohiro Kusumi 			    strlen(cur->name));
7412d60b848STomohiro Kusumi 			if (error)
7422d60b848STomohiro Kusumi 				errx(1, "hammer2_nmkdir(\"%s\") failed: %s",
7432d60b848STomohiro Kusumi 				    cur->name, strerror(error));
7442d60b848STomohiro Kusumi 			assert(vp);
7452d60b848STomohiro Kusumi 			hammer2_print(dvp, vp, cur, depth, "nmkdir");
7462d60b848STomohiro Kusumi 
7472d60b848STomohiro Kusumi 			error = hammer2_populate_dir(vp, path, cur->child, cur,
7482d60b848STomohiro Kusumi 			    fsopts, depth + 1);
7492d60b848STomohiro Kusumi 			if (error)
7502d60b848STomohiro Kusumi 				errx(1, "failed to populate %s: %s",
7512d60b848STomohiro Kusumi 				    path, strerror(error));
752213ebac1STomohiro Kusumi 			cur->inode->priv = vp;
7532d60b848STomohiro Kusumi 			continue;
7542d60b848STomohiro Kusumi 		}
7552d60b848STomohiro Kusumi 
7562d60b848STomohiro Kusumi 		/* if regular file, creat and write its data */
757213ebac1STomohiro Kusumi 		if (S_ISREG(cur->type) && !hardlink) {
7582d60b848STomohiro Kusumi 			assert(cur->child == NULL);
7592d60b848STomohiro Kusumi 
7602d60b848STomohiro Kusumi 			vp = NULL;
7612d60b848STomohiro Kusumi 			error = hammer2_ncreate(dvp, &vp, cur->name,
7622d60b848STomohiro Kusumi 			    strlen(cur->name));
7632d60b848STomohiro Kusumi 			if (error)
7642d60b848STomohiro Kusumi 				errx(1, "hammer2_ncreate(\"%s\") failed: %s",
7652d60b848STomohiro Kusumi 				    cur->name, strerror(error));
7662d60b848STomohiro Kusumi 			assert(vp);
7672d60b848STomohiro Kusumi 			hammer2_print(dvp, vp, cur, depth, "ncreate");
7682d60b848STomohiro Kusumi 
7692d60b848STomohiro Kusumi 			error = hammer2_write_file(vp, path, cur);
7702d60b848STomohiro Kusumi 			if (error)
7712d60b848STomohiro Kusumi 				errx(1, "hammer2_write_file(\"%s\") failed: %s",
7722d60b848STomohiro Kusumi 				    path, strerror(error));
773213ebac1STomohiro Kusumi 			cur->inode->priv = vp;
774213ebac1STomohiro Kusumi 			continue;
775213ebac1STomohiro Kusumi 		}
776213ebac1STomohiro Kusumi 
7772d60b848STomohiro Kusumi 		/* if symlink, create a symlink against target */
7782d60b848STomohiro Kusumi 		if (S_ISLNK(cur->type)) {
7792d60b848STomohiro Kusumi 			assert(cur->child == NULL);
7802d60b848STomohiro Kusumi 
7812d60b848STomohiro Kusumi 			vp = NULL;
7822d60b848STomohiro Kusumi 			error = hammer2_nsymlink(dvp, &vp, cur->name,
7832d60b848STomohiro Kusumi 			    strlen(cur->name), cur->symlink);
7842d60b848STomohiro Kusumi 			if (error)
7852d60b848STomohiro Kusumi 				errx(1, "hammer2_nsymlink(\"%s\") failed: %s",
7862d60b848STomohiro Kusumi 				    cur->name, strerror(error));
7872d60b848STomohiro Kusumi 			assert(vp);
7882d60b848STomohiro Kusumi 			hammer2_print(dvp, vp, cur, depth, "nsymlink");
789213ebac1STomohiro Kusumi 			cur->inode->priv = vp;
7902d60b848STomohiro Kusumi 			continue;
7912d60b848STomohiro Kusumi 		}
7922d60b848STomohiro Kusumi 
7934d8112c5STomohiro Kusumi 		/* if fifo, create a fifo */
794*48a07aadSTomohiro Kusumi 		if (S_ISFIFO(cur->type) && !hardlink) {
7954d8112c5STomohiro Kusumi 			assert(cur->child == NULL);
7964d8112c5STomohiro Kusumi 
7974d8112c5STomohiro Kusumi 			vp = NULL;
7984d8112c5STomohiro Kusumi 			error = hammer2_nmknod(dvp, &vp, cur->name,
7994d8112c5STomohiro Kusumi 			    strlen(cur->name), VFIFO);
8004d8112c5STomohiro Kusumi 			if (error)
8014d8112c5STomohiro Kusumi 				errx(1, "hammer2_nmknod(\"%s\") failed: %s",
8024d8112c5STomohiro Kusumi 				    cur->name, strerror(error));
8034d8112c5STomohiro Kusumi 			assert(vp);
8044d8112c5STomohiro Kusumi 			hammer2_print(dvp, vp, cur, depth, "nmknod");
805213ebac1STomohiro Kusumi 			cur->inode->priv = vp;
8064d8112c5STomohiro Kusumi 			continue;
8074d8112c5STomohiro Kusumi 		}
8084d8112c5STomohiro Kusumi 
809*48a07aadSTomohiro Kusumi 		/* if hardlink, creat a hardlink */
810*48a07aadSTomohiro Kusumi 		if ((S_ISREG(cur->type) || S_ISFIFO(cur->type)) && hardlink) {
811*48a07aadSTomohiro Kusumi 			char buf[64];
812*48a07aadSTomohiro Kusumi 			assert(cur->child == NULL);
813*48a07aadSTomohiro Kusumi 
814*48a07aadSTomohiro Kusumi 			/* source vnode must not be NULL */
815*48a07aadSTomohiro Kusumi 			vp = cur->inode->priv;
816*48a07aadSTomohiro Kusumi 			assert(vp);
817*48a07aadSTomohiro Kusumi 			/* currently these conditions must be true */
818*48a07aadSTomohiro Kusumi 			assert(vp->v_data);
819*48a07aadSTomohiro Kusumi 			assert(vp->v_type == VREG || vp->v_type == VFIFO);
820*48a07aadSTomohiro Kusumi 			assert(vp->v_logical);
821*48a07aadSTomohiro Kusumi 			assert(!vp->v_vflushed);
822*48a07aadSTomohiro Kusumi 			assert(vp->v_malloced);
823*48a07aadSTomohiro Kusumi 			assert(VTOI(vp)->refs > 0);
824*48a07aadSTomohiro Kusumi 
825*48a07aadSTomohiro Kusumi 			error = hammer2_nlink(dvp, vp, cur->name,
826*48a07aadSTomohiro Kusumi 			    strlen(cur->name));
827*48a07aadSTomohiro Kusumi 			if (error)
828*48a07aadSTomohiro Kusumi 				errx(1, "hammer2_nlink(\"%s\") failed: %s",
829*48a07aadSTomohiro Kusumi 				    cur->name, strerror(error));
830*48a07aadSTomohiro Kusumi 			snprintf(buf, sizeof(buf), "nlink=%ld",
831*48a07aadSTomohiro Kusumi 			    VTOI(vp)->meta.nlinks);
832*48a07aadSTomohiro Kusumi 			hammer2_print(dvp, vp, cur, depth, buf);
833*48a07aadSTomohiro Kusumi 			continue;
834*48a07aadSTomohiro Kusumi 		}
835*48a07aadSTomohiro Kusumi 
8362d60b848STomohiro Kusumi 		/* other types are unsupported */
8372d60b848STomohiro Kusumi 		printf("ignore %s 0%o\n", path, cur->type);
8382d60b848STomohiro Kusumi 	}
8392d60b848STomohiro Kusumi 
8402d60b848STomohiro Kusumi 	return 0;
8412d60b848STomohiro Kusumi }
8422d60b848STomohiro Kusumi 
8432d60b848STomohiro Kusumi static int
8442d60b848STomohiro Kusumi hammer2_write_file(struct vnode *vp, const char *path, fsnode *node)
8452d60b848STomohiro Kusumi {
8462d60b848STomohiro Kusumi 	struct stat *st = &node->inode->st;
8472d60b848STomohiro Kusumi 	size_t nsize, bufsize;
8482d60b848STomohiro Kusumi 	off_t offset;
8492d60b848STomohiro Kusumi 	int fd, error;
8502d60b848STomohiro Kusumi 	char *p;
8512d60b848STomohiro Kusumi 
8522d60b848STomohiro Kusumi 	nsize = st->st_size;
8532d60b848STomohiro Kusumi 	if (nsize == 0)
8542d60b848STomohiro Kusumi 		return 0;
8552d60b848STomohiro Kusumi 	/* check nsize vs maximum file size */
8562d60b848STomohiro Kusumi 
8572d60b848STomohiro Kusumi 	fd = open(path, O_RDONLY);
8582d60b848STomohiro Kusumi 	if (fd < 0)
8592d60b848STomohiro Kusumi 		err(1, "failed to open %s", path);
8602d60b848STomohiro Kusumi 
8612d60b848STomohiro Kusumi 	p = mmap(0, nsize, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
8622d60b848STomohiro Kusumi 	if (p == MAP_FAILED)
8632d60b848STomohiro Kusumi 		err(1, "failed to mmap %s", path);
8642d60b848STomohiro Kusumi 	close(fd);
8652d60b848STomohiro Kusumi 
8662d60b848STomohiro Kusumi 	for (offset = 0; offset < nsize; ) {
8672d60b848STomohiro Kusumi 		bufsize = MIN(nsize - offset, HAMMER2_PBUFSIZE);
8682d60b848STomohiro Kusumi 		assert(bufsize <= HAMMER2_PBUFSIZE);
8692d60b848STomohiro Kusumi 		error = hammer2_write(vp, p + offset, bufsize, offset);
8702d60b848STomohiro Kusumi 		if (error)
8712d60b848STomohiro Kusumi 			errx(1, "failed to write to %s vnode: %s",
8722d60b848STomohiro Kusumi 			    path, strerror(error));
8732d60b848STomohiro Kusumi 		offset += bufsize;
8742d60b848STomohiro Kusumi 		if (bufsize == HAMMER2_PBUFSIZE)
8752d60b848STomohiro Kusumi 			assert((offset & (HAMMER2_PBUFSIZE - 1)) == 0);
8762d60b848STomohiro Kusumi 	}
8772d60b848STomohiro Kusumi 	munmap(p, nsize);
8782d60b848STomohiro Kusumi 
8792d60b848STomohiro Kusumi 	return 0;
8802d60b848STomohiro Kusumi }
881