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