1*2d60b848STomohiro Kusumi /* 2*2d60b848STomohiro Kusumi * SPDX-License-Identifier: BSD-3-Clause 3*2d60b848STomohiro Kusumi * 4*2d60b848STomohiro Kusumi * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org> 5*2d60b848STomohiro Kusumi * Copyright (c) 2011-2022 The DragonFly Project. All rights reserved. 6*2d60b848STomohiro Kusumi * 7*2d60b848STomohiro Kusumi * Redistribution and use in source and binary forms, with or without 8*2d60b848STomohiro Kusumi * modification, are permitted provided that the following conditions 9*2d60b848STomohiro Kusumi * are met: 10*2d60b848STomohiro Kusumi * 11*2d60b848STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 12*2d60b848STomohiro Kusumi * notice, this list of conditions and the following disclaimer. 13*2d60b848STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 14*2d60b848STomohiro Kusumi * notice, this list of conditions and the following disclaimer in 15*2d60b848STomohiro Kusumi * the documentation and/or other materials provided with the 16*2d60b848STomohiro Kusumi * distribution. 17*2d60b848STomohiro Kusumi * 3. Neither the name of The DragonFly Project nor the names of its 18*2d60b848STomohiro Kusumi * contributors may be used to endorse or promote products derived 19*2d60b848STomohiro Kusumi * from this software without specific, prior written permission. 20*2d60b848STomohiro Kusumi * 21*2d60b848STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*2d60b848STomohiro Kusumi * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*2d60b848STomohiro Kusumi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24*2d60b848STomohiro Kusumi * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25*2d60b848STomohiro Kusumi * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26*2d60b848STomohiro Kusumi * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27*2d60b848STomohiro Kusumi * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28*2d60b848STomohiro Kusumi * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29*2d60b848STomohiro Kusumi * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30*2d60b848STomohiro Kusumi * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31*2d60b848STomohiro Kusumi * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*2d60b848STomohiro Kusumi * SUCH DAMAGE. 33*2d60b848STomohiro Kusumi */ 34*2d60b848STomohiro Kusumi 35*2d60b848STomohiro Kusumi #if HAVE_NBTOOL_CONFIG_H 36*2d60b848STomohiro Kusumi #include "nbtool_config.h" 37*2d60b848STomohiro Kusumi #endif 38*2d60b848STomohiro Kusumi 39*2d60b848STomohiro Kusumi #include <sys/param.h> 40*2d60b848STomohiro Kusumi #include <sys/stat.h> 41*2d60b848STomohiro Kusumi #include <sys/sysctl.h> 42*2d60b848STomohiro Kusumi #include <sys/mman.h> 43*2d60b848STomohiro Kusumi 44*2d60b848STomohiro Kusumi #include <stdio.h> 45*2d60b848STomohiro Kusumi #include <stdlib.h> 46*2d60b848STomohiro Kusumi #include <stdbool.h> 47*2d60b848STomohiro Kusumi #include <string.h> 48*2d60b848STomohiro Kusumi #include <unistd.h> 49*2d60b848STomohiro Kusumi #include <fcntl.h> 50*2d60b848STomohiro Kusumi #include <time.h> 51*2d60b848STomohiro Kusumi #include <err.h> 52*2d60b848STomohiro Kusumi #include <assert.h> 53*2d60b848STomohiro Kusumi #include <util.h> 54*2d60b848STomohiro Kusumi 55*2d60b848STomohiro Kusumi #include "makefs.h" 56*2d60b848STomohiro Kusumi #include "hammer2.h" 57*2d60b848STomohiro Kusumi 58*2d60b848STomohiro Kusumi #define APRINTF(X, ...) \ 59*2d60b848STomohiro Kusumi printf("%s: " X, __func__, ## __VA_ARGS__) 60*2d60b848STomohiro Kusumi 61*2d60b848STomohiro Kusumi static void hammer2_dump_fsinfo(fsinfo_t *); 62*2d60b848STomohiro Kusumi static int hammer2_create_image(const char *, fsinfo_t *); 63*2d60b848STomohiro Kusumi static int hammer2_populate_dir(struct vnode *, const char *, fsnode *, 64*2d60b848STomohiro Kusumi fsnode *, fsinfo_t *, int); 65*2d60b848STomohiro Kusumi static void hammer2_validate(const char *, fsnode *, fsinfo_t *); 66*2d60b848STomohiro Kusumi static void hammer2_size_dir(fsnode *, fsinfo_t *); 67*2d60b848STomohiro Kusumi static int hammer2_write_file(struct vnode *, const char *, fsnode *); 68*2d60b848STomohiro Kusumi 69*2d60b848STomohiro Kusumi void 70*2d60b848STomohiro Kusumi hammer2_prep_opts(fsinfo_t *fsopts) 71*2d60b848STomohiro Kusumi { 72*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = ecalloc(1, sizeof(*h2_opt)); 73*2d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 74*2d60b848STomohiro Kusumi 75*2d60b848STomohiro Kusumi const option_t hammer2_options[] = { 76*2d60b848STomohiro Kusumi /* newfs_hammer2(8) compatible options */ 77*2d60b848STomohiro Kusumi { 'b', "BootAreaSize", NULL, OPT_STRBUF, 0, 0, "boot area size" }, 78*2d60b848STomohiro Kusumi { 'r', "AuxAreaSize", NULL, OPT_STRBUF, 0, 0, "aux area size" }, 79*2d60b848STomohiro Kusumi { 'V', "Hammer2Version", NULL, OPT_STRBUF, 0, 0, "file system version" }, 80*2d60b848STomohiro Kusumi { 'L', "Label", NULL, OPT_STRBUF, 0, 0, "PFS label" }, 81*2d60b848STomohiro Kusumi /* makefs(8) specific options */ 82*2d60b848STomohiro Kusumi { 'm', "MountLabel", NULL, OPT_STRBUF, 0, 0, "destination PFS label" }, 83*2d60b848STomohiro Kusumi { 'v', "NumVolhdr", &h2_opt->num_volhdr, OPT_INT32, 84*2d60b848STomohiro Kusumi 1, HAMMER2_NUM_VOLHDRS, "number of volume headers" }, 85*2d60b848STomohiro Kusumi { 'd', "Hammer2Debug", NULL, OPT_STRBUF, 0, 0, "debug tunable" }, 86*2d60b848STomohiro Kusumi { .name = NULL }, 87*2d60b848STomohiro Kusumi }; 88*2d60b848STomohiro Kusumi 89*2d60b848STomohiro Kusumi hammer2_mkfs_init(opt); 90*2d60b848STomohiro Kusumi 91*2d60b848STomohiro Kusumi /* make this tunable ? */ 92*2d60b848STomohiro Kusumi assert(opt->CompType == HAMMER2_COMP_NEWFS_DEFAULT); 93*2d60b848STomohiro Kusumi assert(opt->CheckType == HAMMER2_CHECK_XXHASH64); 94*2d60b848STomohiro Kusumi 95*2d60b848STomohiro Kusumi /* force debug mode for mkfs */ 96*2d60b848STomohiro Kusumi opt->DebugOpt = 1; 97*2d60b848STomohiro Kusumi 98*2d60b848STomohiro Kusumi fsopts->fs_specific = h2_opt; 99*2d60b848STomohiro Kusumi fsopts->fs_options = copy_opts(hammer2_options); 100*2d60b848STomohiro Kusumi fsopts->sectorsize = DEV_BSIZE; 101*2d60b848STomohiro Kusumi } 102*2d60b848STomohiro Kusumi 103*2d60b848STomohiro Kusumi void 104*2d60b848STomohiro Kusumi hammer2_cleanup_opts(fsinfo_t *fsopts) 105*2d60b848STomohiro Kusumi { 106*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 107*2d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 108*2d60b848STomohiro Kusumi 109*2d60b848STomohiro Kusumi hammer2_mkfs_cleanup(opt); 110*2d60b848STomohiro Kusumi 111*2d60b848STomohiro Kusumi free(h2_opt); 112*2d60b848STomohiro Kusumi free(fsopts->fs_options); 113*2d60b848STomohiro Kusumi } 114*2d60b848STomohiro Kusumi 115*2d60b848STomohiro Kusumi int 116*2d60b848STomohiro Kusumi hammer2_parse_opts(const char *option, fsinfo_t *fsopts) 117*2d60b848STomohiro Kusumi { 118*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 119*2d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 120*2d60b848STomohiro Kusumi 121*2d60b848STomohiro Kusumi option_t *hammer2_options = fsopts->fs_options; 122*2d60b848STomohiro Kusumi char buf[1024]; /* > HAMMER2_INODE_MAXNAME */ 123*2d60b848STomohiro Kusumi int i; 124*2d60b848STomohiro Kusumi 125*2d60b848STomohiro Kusumi assert(option != NULL); 126*2d60b848STomohiro Kusumi assert(fsopts != NULL); 127*2d60b848STomohiro Kusumi 128*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_PARSE_OPTS) 129*2d60b848STomohiro Kusumi APRINTF("got `%s'\n", option); 130*2d60b848STomohiro Kusumi 131*2d60b848STomohiro Kusumi i = set_option(hammer2_options, option, buf, sizeof(buf)); 132*2d60b848STomohiro Kusumi if (i == -1) 133*2d60b848STomohiro Kusumi return 0; 134*2d60b848STomohiro Kusumi 135*2d60b848STomohiro Kusumi if (hammer2_options[i].name == NULL) 136*2d60b848STomohiro Kusumi abort(); 137*2d60b848STomohiro Kusumi 138*2d60b848STomohiro Kusumi switch (hammer2_options[i].letter) { 139*2d60b848STomohiro Kusumi case 'b': 140*2d60b848STomohiro Kusumi opt->BootAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN, 141*2d60b848STomohiro Kusumi HAMMER2_BOOT_MAX_BYTES, 2); 142*2d60b848STomohiro Kusumi break; 143*2d60b848STomohiro Kusumi case 'r': 144*2d60b848STomohiro Kusumi opt->AuxAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN, 145*2d60b848STomohiro Kusumi HAMMER2_AUX_MAX_BYTES, 2); 146*2d60b848STomohiro Kusumi break; 147*2d60b848STomohiro Kusumi case 'V': 148*2d60b848STomohiro Kusumi opt->Hammer2Version = strtol(buf, NULL, 0); 149*2d60b848STomohiro Kusumi if (opt->Hammer2Version < HAMMER2_VOL_VERSION_MIN || 150*2d60b848STomohiro Kusumi opt->Hammer2Version >= HAMMER2_VOL_VERSION_WIP) 151*2d60b848STomohiro Kusumi errx(1, "I don't understand how to format " 152*2d60b848STomohiro Kusumi "HAMMER2 version %d", 153*2d60b848STomohiro Kusumi opt->Hammer2Version); 154*2d60b848STomohiro Kusumi break; 155*2d60b848STomohiro Kusumi case 'L': 156*2d60b848STomohiro Kusumi h2_opt->label_specified = 1; 157*2d60b848STomohiro Kusumi if (strcasecmp(buf, "none") == 0) 158*2d60b848STomohiro Kusumi break; 159*2d60b848STomohiro Kusumi if (opt->NLabels >= MAXLABELS) 160*2d60b848STomohiro Kusumi errx(1, "Limit of %d local labels", MAXLABELS - 1); 161*2d60b848STomohiro Kusumi if (strlen(buf) == 0) 162*2d60b848STomohiro Kusumi errx(1, "Volume label '%s' cannot be 0-length", buf); 163*2d60b848STomohiro Kusumi if (strlen(buf) >= HAMMER2_INODE_MAXNAME) 164*2d60b848STomohiro Kusumi errx(1, "Volume label '%s' is too long (%d chars max)", 165*2d60b848STomohiro Kusumi buf, HAMMER2_INODE_MAXNAME - 1); 166*2d60b848STomohiro Kusumi opt->Label[opt->NLabels++] = strdup(buf); 167*2d60b848STomohiro Kusumi break; 168*2d60b848STomohiro Kusumi case 'm': 169*2d60b848STomohiro Kusumi if (strlen(buf) == 0) 170*2d60b848STomohiro Kusumi errx(1, "Volume label '%s' cannot be 0-length", buf); 171*2d60b848STomohiro Kusumi if (strlen(buf) >= HAMMER2_INODE_MAXNAME) 172*2d60b848STomohiro Kusumi errx(1, "Volume label '%s' is too long (%d chars max)", 173*2d60b848STomohiro Kusumi buf, HAMMER2_INODE_MAXNAME - 1); 174*2d60b848STomohiro Kusumi strlcpy(h2_opt->mount_label, buf, sizeof(h2_opt->mount_label)); 175*2d60b848STomohiro Kusumi break; 176*2d60b848STomohiro Kusumi case 'd': 177*2d60b848STomohiro Kusumi hammer2_debug = strtoll(buf, NULL, 0); 178*2d60b848STomohiro Kusumi break; 179*2d60b848STomohiro Kusumi default: 180*2d60b848STomohiro Kusumi break; 181*2d60b848STomohiro Kusumi } 182*2d60b848STomohiro Kusumi 183*2d60b848STomohiro Kusumi return 1; 184*2d60b848STomohiro Kusumi } 185*2d60b848STomohiro Kusumi 186*2d60b848STomohiro Kusumi void 187*2d60b848STomohiro Kusumi hammer2_makefs(const char *image, const char *dir, fsnode *root, 188*2d60b848STomohiro Kusumi fsinfo_t *fsopts) 189*2d60b848STomohiro Kusumi { 190*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 191*2d60b848STomohiro Kusumi struct mount mp; 192*2d60b848STomohiro Kusumi struct hammer2_mount_info info; 193*2d60b848STomohiro Kusumi struct vnode devvp, *vroot; 194*2d60b848STomohiro Kusumi hammer2_inode_t *iroot; 195*2d60b848STomohiro Kusumi struct timeval start; 196*2d60b848STomohiro Kusumi int error; 197*2d60b848STomohiro Kusumi 198*2d60b848STomohiro Kusumi assert(image != NULL); 199*2d60b848STomohiro Kusumi assert(dir != NULL); 200*2d60b848STomohiro Kusumi assert(root != NULL); 201*2d60b848STomohiro Kusumi assert(fsopts != NULL); 202*2d60b848STomohiro Kusumi 203*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_MAKEFS) 204*2d60b848STomohiro Kusumi APRINTF("image \"%s\" directory \"%s\" root %p\n", 205*2d60b848STomohiro Kusumi image, dir, root); 206*2d60b848STomohiro Kusumi 207*2d60b848STomohiro Kusumi /* validate tree and options */ 208*2d60b848STomohiro Kusumi TIMER_START(start); 209*2d60b848STomohiro Kusumi hammer2_validate(dir, root, fsopts); 210*2d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_validate"); 211*2d60b848STomohiro Kusumi 212*2d60b848STomohiro Kusumi /* create image */ 213*2d60b848STomohiro Kusumi TIMER_START(start); 214*2d60b848STomohiro Kusumi if (hammer2_create_image(image, fsopts) == -1) 215*2d60b848STomohiro Kusumi errx(1, "image file `%s' not created", image); 216*2d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_create_image"); 217*2d60b848STomohiro Kusumi 218*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_MAKEFS) 219*2d60b848STomohiro Kusumi putchar('\n'); 220*2d60b848STomohiro Kusumi 221*2d60b848STomohiro Kusumi /* vfs init */ 222*2d60b848STomohiro Kusumi error = hammer2_vfs_init(); 223*2d60b848STomohiro Kusumi if (error) 224*2d60b848STomohiro Kusumi errx(1, "failed to vfs init, error %d", error); 225*2d60b848STomohiro Kusumi 226*2d60b848STomohiro Kusumi /* mount image */ 227*2d60b848STomohiro Kusumi memset(&devvp, 0, sizeof(devvp)); 228*2d60b848STomohiro Kusumi devvp.fs = fsopts; 229*2d60b848STomohiro Kusumi memset(&mp, 0, sizeof(mp)); 230*2d60b848STomohiro Kusumi memset(&info, 0, sizeof(info)); 231*2d60b848STomohiro Kusumi error = hammer2_vfs_mount(&devvp, &mp, h2_opt->mount_label, &info); 232*2d60b848STomohiro Kusumi if (error) 233*2d60b848STomohiro Kusumi errx(1, "failed to mount, error %d", error); 234*2d60b848STomohiro Kusumi assert(mp.mnt_data); 235*2d60b848STomohiro Kusumi 236*2d60b848STomohiro Kusumi /* get root vnode */ 237*2d60b848STomohiro Kusumi vroot = NULL; 238*2d60b848STomohiro Kusumi error = hammer2_vfs_root(&mp, &vroot); 239*2d60b848STomohiro Kusumi if (error) 240*2d60b848STomohiro Kusumi errx(1, "failed to get root vnode, error %d", error); 241*2d60b848STomohiro Kusumi assert(vroot); 242*2d60b848STomohiro Kusumi 243*2d60b848STomohiro Kusumi iroot = VTOI(vroot); 244*2d60b848STomohiro Kusumi assert(iroot); 245*2d60b848STomohiro Kusumi printf("root inode inum %ld, mode 0%o, refs %d\n", 246*2d60b848STomohiro Kusumi iroot->meta.inum, iroot->meta.mode, iroot->refs); 247*2d60b848STomohiro Kusumi 248*2d60b848STomohiro Kusumi /* populate image */ 249*2d60b848STomohiro Kusumi printf("populating `%s'\n", image); 250*2d60b848STomohiro Kusumi TIMER_START(start); 251*2d60b848STomohiro Kusumi if (hammer2_populate_dir(vroot, dir, root, root, fsopts, 0)) 252*2d60b848STomohiro Kusumi errx(1, "image file `%s' not populated", image); 253*2d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_populate_dir"); 254*2d60b848STomohiro Kusumi 255*2d60b848STomohiro Kusumi /* unmount image */ 256*2d60b848STomohiro Kusumi error = hammer2_vfs_unmount(&mp, 0); 257*2d60b848STomohiro Kusumi if (error) 258*2d60b848STomohiro Kusumi errx(1, "failed to unmount, error %d", error); 259*2d60b848STomohiro Kusumi 260*2d60b848STomohiro Kusumi /* check leaked resource */ 261*2d60b848STomohiro Kusumi if (vnode_count) 262*2d60b848STomohiro Kusumi printf("XXX %ld vnode left\n", vnode_count); 263*2d60b848STomohiro Kusumi if (hammer2_chain_allocs) 264*2d60b848STomohiro Kusumi printf("XXX %ld chain left\n", hammer2_chain_allocs); 265*2d60b848STomohiro Kusumi bcleanup(); 266*2d60b848STomohiro Kusumi 267*2d60b848STomohiro Kusumi /* vfs uninit */ 268*2d60b848STomohiro Kusumi error = hammer2_vfs_uninit(); 269*2d60b848STomohiro Kusumi if (error) 270*2d60b848STomohiro Kusumi errx(1, "failed to vfs uninit, error %d", error); 271*2d60b848STomohiro Kusumi 272*2d60b848STomohiro Kusumi if (close(fsopts->fd) == -1) 273*2d60b848STomohiro Kusumi err(1, "closing `%s'", image); 274*2d60b848STomohiro Kusumi fsopts->fd = -1; 275*2d60b848STomohiro Kusumi 276*2d60b848STomohiro Kusumi printf("image `%s' complete\n", image); 277*2d60b848STomohiro Kusumi } 278*2d60b848STomohiro Kusumi 279*2d60b848STomohiro Kusumi /* end of public functions */ 280*2d60b848STomohiro Kusumi 281*2d60b848STomohiro Kusumi static hammer2_off_t 282*2d60b848STomohiro Kusumi hammer2_image_size(fsinfo_t *fsopts) 283*2d60b848STomohiro Kusumi { 284*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 285*2d60b848STomohiro Kusumi hammer2_off_t image_size, used_size = 0; 286*2d60b848STomohiro Kusumi int num_level1, delta_num_level1; 287*2d60b848STomohiro Kusumi 288*2d60b848STomohiro Kusumi /* use 4 volume headers by default */ 289*2d60b848STomohiro Kusumi num_level1 = h2_opt->num_volhdr * 2; /* default 4 x 2 */ 290*2d60b848STomohiro Kusumi assert(num_level1 != 0); 291*2d60b848STomohiro Kusumi assert(num_level1 <= 8); 292*2d60b848STomohiro Kusumi 293*2d60b848STomohiro Kusumi /* add 4MiB segment for each level1 */ 294*2d60b848STomohiro Kusumi used_size += HAMMER2_ZONE_SEG64 * num_level1; 295*2d60b848STomohiro Kusumi 296*2d60b848STomohiro Kusumi /* add boot/aux area, but exact size unknown at this point */ 297*2d60b848STomohiro Kusumi used_size += HAMMER2_BOOT_NOM_BYTES + HAMMER2_AUX_NOM_BYTES; 298*2d60b848STomohiro Kusumi 299*2d60b848STomohiro Kusumi /* add data size */ 300*2d60b848STomohiro Kusumi used_size += fsopts->size; 301*2d60b848STomohiro Kusumi 302*2d60b848STomohiro Kusumi /* XXX add extra level1 for meta data and indirect blocks */ 303*2d60b848STomohiro Kusumi used_size += HAMMER2_FREEMAP_LEVEL1_SIZE; 304*2d60b848STomohiro Kusumi 305*2d60b848STomohiro Kusumi /* XXX add extra level1 for safety */ 306*2d60b848STomohiro Kusumi if (used_size > HAMMER2_FREEMAP_LEVEL1_SIZE * 10) 307*2d60b848STomohiro Kusumi used_size += HAMMER2_FREEMAP_LEVEL1_SIZE; 308*2d60b848STomohiro Kusumi 309*2d60b848STomohiro Kusumi /* use 8GiB image size by default */ 310*2d60b848STomohiro Kusumi image_size = HAMMER2_FREEMAP_LEVEL1_SIZE * num_level1; 311*2d60b848STomohiro Kusumi printf("trying default image size %s\n", sizetostr(image_size)); 312*2d60b848STomohiro Kusumi 313*2d60b848STomohiro Kusumi /* adjust if image size isn't large enough */ 314*2d60b848STomohiro Kusumi if (used_size > image_size) { 315*2d60b848STomohiro Kusumi /* determine extra level1 needed */ 316*2d60b848STomohiro Kusumi delta_num_level1 = howmany(used_size - image_size, 317*2d60b848STomohiro Kusumi HAMMER2_FREEMAP_LEVEL1_SIZE); 318*2d60b848STomohiro Kusumi 319*2d60b848STomohiro Kusumi /* adjust used size with 4MiB segment for each extra level1 */ 320*2d60b848STomohiro Kusumi used_size += HAMMER2_ZONE_SEG64 * delta_num_level1; 321*2d60b848STomohiro Kusumi 322*2d60b848STomohiro Kusumi /* adjust image size with extra level1 */ 323*2d60b848STomohiro Kusumi image_size += HAMMER2_FREEMAP_LEVEL1_SIZE * delta_num_level1; 324*2d60b848STomohiro Kusumi printf("trying adjusted image size %s\n", 325*2d60b848STomohiro Kusumi sizetostr(image_size)); 326*2d60b848STomohiro Kusumi 327*2d60b848STomohiro Kusumi if (used_size > image_size) 328*2d60b848STomohiro Kusumi errx(1, "invalid used_size %ld > image_size %ld", 329*2d60b848STomohiro Kusumi used_size, image_size); 330*2d60b848STomohiro Kusumi } 331*2d60b848STomohiro Kusumi 332*2d60b848STomohiro Kusumi return image_size; 333*2d60b848STomohiro Kusumi } 334*2d60b848STomohiro Kusumi 335*2d60b848STomohiro Kusumi static const char * 336*2d60b848STomohiro Kusumi hammer2_label_name(int label_type) 337*2d60b848STomohiro Kusumi { 338*2d60b848STomohiro Kusumi switch (label_type) { 339*2d60b848STomohiro Kusumi case HAMMER2_LABEL_NONE: 340*2d60b848STomohiro Kusumi return "NONE"; 341*2d60b848STomohiro Kusumi case HAMMER2_LABEL_BOOT: 342*2d60b848STomohiro Kusumi return "BOOT"; 343*2d60b848STomohiro Kusumi case HAMMER2_LABEL_ROOT: 344*2d60b848STomohiro Kusumi return "ROOT"; 345*2d60b848STomohiro Kusumi case HAMMER2_LABEL_DATA: 346*2d60b848STomohiro Kusumi return "DATA"; 347*2d60b848STomohiro Kusumi default: 348*2d60b848STomohiro Kusumi assert(0); 349*2d60b848STomohiro Kusumi } 350*2d60b848STomohiro Kusumi return NULL; 351*2d60b848STomohiro Kusumi } 352*2d60b848STomohiro Kusumi 353*2d60b848STomohiro Kusumi static void 354*2d60b848STomohiro Kusumi hammer2_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) 355*2d60b848STomohiro Kusumi { 356*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 357*2d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 358*2d60b848STomohiro Kusumi hammer2_off_t image_size, minsize, maxsize; 359*2d60b848STomohiro Kusumi const char *s; 360*2d60b848STomohiro Kusumi 361*2d60b848STomohiro Kusumi assert(dir != NULL); 362*2d60b848STomohiro Kusumi assert(root != NULL); 363*2d60b848STomohiro Kusumi assert(fsopts != NULL); 364*2d60b848STomohiro Kusumi 365*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_VALIDATE) { 366*2d60b848STomohiro Kusumi APRINTF("before defaults set:\n"); 367*2d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsopts); 368*2d60b848STomohiro Kusumi } 369*2d60b848STomohiro Kusumi 370*2d60b848STomohiro Kusumi /* makefs only supports "DATA" for default PFS label */ 371*2d60b848STomohiro Kusumi if (!h2_opt->label_specified) { 372*2d60b848STomohiro Kusumi opt->DefaultLabelType = HAMMER2_LABEL_DATA; 373*2d60b848STomohiro Kusumi s = hammer2_label_name(opt->DefaultLabelType); 374*2d60b848STomohiro Kusumi printf("using default label \"%s\"\n", s); 375*2d60b848STomohiro Kusumi } 376*2d60b848STomohiro Kusumi 377*2d60b848STomohiro Kusumi /* set default mount PFS label */ 378*2d60b848STomohiro Kusumi if (!strcmp(h2_opt->mount_label, "")) { 379*2d60b848STomohiro Kusumi s = hammer2_label_name(HAMMER2_LABEL_DATA); 380*2d60b848STomohiro Kusumi strlcpy(h2_opt->mount_label, s, sizeof(h2_opt->mount_label)); 381*2d60b848STomohiro Kusumi printf("using default mount label \"%s\"\n", s); 382*2d60b848STomohiro Kusumi } 383*2d60b848STomohiro Kusumi 384*2d60b848STomohiro Kusumi /* set default number of volume headers */ 385*2d60b848STomohiro Kusumi if (!h2_opt->num_volhdr) { 386*2d60b848STomohiro Kusumi h2_opt->num_volhdr = HAMMER2_NUM_VOLHDRS; 387*2d60b848STomohiro Kusumi printf("using default %d volume headers\n", h2_opt->num_volhdr); 388*2d60b848STomohiro Kusumi } 389*2d60b848STomohiro Kusumi 390*2d60b848STomohiro Kusumi /* calculate data size */ 391*2d60b848STomohiro Kusumi if (fsopts->size != 0) 392*2d60b848STomohiro Kusumi fsopts->size = 0; /* shouldn't reach here to begin with */ 393*2d60b848STomohiro Kusumi hammer2_size_dir(root, fsopts); 394*2d60b848STomohiro Kusumi printf("estimated data size %s from %lld inode\n", 395*2d60b848STomohiro Kusumi sizetostr(fsopts->size), (long long)fsopts->inodes); 396*2d60b848STomohiro Kusumi 397*2d60b848STomohiro Kusumi /* determine image size from data size */ 398*2d60b848STomohiro Kusumi image_size = hammer2_image_size(fsopts); 399*2d60b848STomohiro Kusumi assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0); 400*2d60b848STomohiro Kusumi 401*2d60b848STomohiro Kusumi minsize = roundup(fsopts->minsize, HAMMER2_FREEMAP_LEVEL1_SIZE); 402*2d60b848STomohiro Kusumi maxsize = roundup(fsopts->maxsize, HAMMER2_FREEMAP_LEVEL1_SIZE); 403*2d60b848STomohiro Kusumi if (image_size < minsize) 404*2d60b848STomohiro Kusumi image_size = minsize; 405*2d60b848STomohiro Kusumi else if (maxsize > 0 && image_size > maxsize) 406*2d60b848STomohiro Kusumi errx(1, "`%s' size of %ld is larger than the maxsize of %ld", 407*2d60b848STomohiro Kusumi dir, image_size, maxsize); 408*2d60b848STomohiro Kusumi 409*2d60b848STomohiro Kusumi assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0); 410*2d60b848STomohiro Kusumi h2_opt->image_size = image_size; 411*2d60b848STomohiro Kusumi printf("using %s image size\n", sizetostr(h2_opt->image_size)); 412*2d60b848STomohiro Kusumi 413*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_VALIDATE) { 414*2d60b848STomohiro Kusumi APRINTF("after defaults set:\n"); 415*2d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsopts); 416*2d60b848STomohiro Kusumi } 417*2d60b848STomohiro Kusumi } 418*2d60b848STomohiro Kusumi 419*2d60b848STomohiro Kusumi static void 420*2d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsinfo_t *fsopts) 421*2d60b848STomohiro Kusumi { 422*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 423*2d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 424*2d60b848STomohiro Kusumi int i; 425*2d60b848STomohiro Kusumi char *s; 426*2d60b848STomohiro Kusumi 427*2d60b848STomohiro Kusumi assert(fsopts != NULL); 428*2d60b848STomohiro Kusumi 429*2d60b848STomohiro Kusumi APRINTF("fsinfo_t at %p\n", fsopts); 430*2d60b848STomohiro Kusumi 431*2d60b848STomohiro Kusumi printf("\tinodes %lld\n", (long long)fsopts->inodes); 432*2d60b848STomohiro Kusumi printf("\tsize %lld, minsize %lld, maxsize %lld\n", 433*2d60b848STomohiro Kusumi (long long)fsopts->size, 434*2d60b848STomohiro Kusumi (long long)fsopts->minsize, 435*2d60b848STomohiro Kusumi (long long)fsopts->maxsize); 436*2d60b848STomohiro Kusumi 437*2d60b848STomohiro Kusumi printf("\thammer2_debug 0x%x\n", hammer2_debug); 438*2d60b848STomohiro Kusumi 439*2d60b848STomohiro Kusumi printf("\tlabel_specified %d\n", h2_opt->label_specified); 440*2d60b848STomohiro Kusumi printf("\tmount_label \"%s\"\n", h2_opt->mount_label); 441*2d60b848STomohiro Kusumi printf("\tnum_volhdr %d\n", h2_opt->num_volhdr); 442*2d60b848STomohiro Kusumi printf("\timage_size 0x%lx\n", h2_opt->image_size); 443*2d60b848STomohiro Kusumi 444*2d60b848STomohiro Kusumi printf("\tHammer2Version %d\n", opt->Hammer2Version); 445*2d60b848STomohiro Kusumi printf("\tBootAreaSize 0x%jx\n", opt->BootAreaSize); 446*2d60b848STomohiro Kusumi printf("\tAuxAreaSize 0x%jx\n", opt->AuxAreaSize); 447*2d60b848STomohiro Kusumi printf("\tNLabels %d\n", opt->NLabels); 448*2d60b848STomohiro Kusumi printf("\tCompType %d\n", opt->CompType); 449*2d60b848STomohiro Kusumi printf("\tCheckType %d\n", opt->CheckType); 450*2d60b848STomohiro Kusumi printf("\tDefaultLabelType %d\n", opt->DefaultLabelType); 451*2d60b848STomohiro Kusumi printf("\tDebugOpt %d\n", opt->DebugOpt); 452*2d60b848STomohiro Kusumi 453*2d60b848STomohiro Kusumi s = NULL; 454*2d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_FSType, &s); 455*2d60b848STomohiro Kusumi printf("\tHammer2_FSType \"%s\"\n", s); 456*2d60b848STomohiro Kusumi s = NULL; 457*2d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_VolFSID, &s); 458*2d60b848STomohiro Kusumi printf("\tHammer2_VolFSID \"%s\"\n", s); 459*2d60b848STomohiro Kusumi s = NULL; 460*2d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_SupCLID, &s); 461*2d60b848STomohiro Kusumi printf("\tHammer2_SupCLID \"%s\"\n", s); 462*2d60b848STomohiro Kusumi s = NULL; 463*2d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_SupFSID, &s); 464*2d60b848STomohiro Kusumi printf("\tHammer2_SupFSID \"%s\"\n", s); 465*2d60b848STomohiro Kusumi 466*2d60b848STomohiro Kusumi for (i = 0; i < opt->NLabels; i++) { 467*2d60b848STomohiro Kusumi printf("\tLabel[%d] \"%s\"\n", i, opt->Label[i]); 468*2d60b848STomohiro Kusumi s = NULL; 469*2d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_PfsCLID[i], &s); 470*2d60b848STomohiro Kusumi printf("\t Hammer2_PfsCLID[%d] \"%s\"\n", i, s); 471*2d60b848STomohiro Kusumi s = NULL; 472*2d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_PfsFSID[i], &s); 473*2d60b848STomohiro Kusumi printf("\t Hammer2_PfsFSID[%d] \"%s\"\n", i, s); 474*2d60b848STomohiro Kusumi } 475*2d60b848STomohiro Kusumi 476*2d60b848STomohiro Kusumi free(s); 477*2d60b848STomohiro Kusumi } 478*2d60b848STomohiro Kusumi 479*2d60b848STomohiro Kusumi static int 480*2d60b848STomohiro Kusumi hammer2_create_image(const char *image, fsinfo_t *fsopts) 481*2d60b848STomohiro Kusumi { 482*2d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 483*2d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 484*2d60b848STomohiro Kusumi char *av[] = { (char *)image, }; /* XXX support multi-volumes */ 485*2d60b848STomohiro Kusumi char *buf; 486*2d60b848STomohiro Kusumi int i, bufsize, oflags; 487*2d60b848STomohiro Kusumi off_t bufrem; 488*2d60b848STomohiro Kusumi 489*2d60b848STomohiro Kusumi assert(image != NULL); 490*2d60b848STomohiro Kusumi assert(fsopts != NULL); 491*2d60b848STomohiro Kusumi 492*2d60b848STomohiro Kusumi /* create image */ 493*2d60b848STomohiro Kusumi oflags = O_RDWR | O_CREAT; 494*2d60b848STomohiro Kusumi if (fsopts->offset == 0) 495*2d60b848STomohiro Kusumi oflags |= O_TRUNC; 496*2d60b848STomohiro Kusumi if ((fsopts->fd = open(image, oflags, 0666)) == -1) { 497*2d60b848STomohiro Kusumi warn("can't open `%s' for writing", image); 498*2d60b848STomohiro Kusumi return -1; 499*2d60b848STomohiro Kusumi } 500*2d60b848STomohiro Kusumi 501*2d60b848STomohiro Kusumi /* zero image */ 502*2d60b848STomohiro Kusumi bufsize = HAMMER2_PBUFSIZE; 503*2d60b848STomohiro Kusumi bufrem = h2_opt->image_size; 504*2d60b848STomohiro Kusumi if (fsopts->sparse) { 505*2d60b848STomohiro Kusumi if (ftruncate(fsopts->fd, bufrem) == -1) { 506*2d60b848STomohiro Kusumi warn("sparse option disabled"); 507*2d60b848STomohiro Kusumi fsopts->sparse = 0; 508*2d60b848STomohiro Kusumi } 509*2d60b848STomohiro Kusumi } 510*2d60b848STomohiro Kusumi if (fsopts->sparse) { 511*2d60b848STomohiro Kusumi /* File truncated at bufrem. Remaining is 0 */ 512*2d60b848STomohiro Kusumi bufrem = 0; 513*2d60b848STomohiro Kusumi buf = NULL; 514*2d60b848STomohiro Kusumi } else { 515*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_CREATE_IMAGE) 516*2d60b848STomohiro Kusumi APRINTF("zero-ing image `%s', %lld sectors, " 517*2d60b848STomohiro Kusumi "using %d byte chunks\n", 518*2d60b848STomohiro Kusumi image, (long long)bufrem, bufsize); 519*2d60b848STomohiro Kusumi buf = ecalloc(1, bufsize); 520*2d60b848STomohiro Kusumi } 521*2d60b848STomohiro Kusumi 522*2d60b848STomohiro Kusumi if (fsopts->offset != 0) { 523*2d60b848STomohiro Kusumi if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) { 524*2d60b848STomohiro Kusumi warn("can't seek"); 525*2d60b848STomohiro Kusumi free(buf); 526*2d60b848STomohiro Kusumi return -1; 527*2d60b848STomohiro Kusumi } 528*2d60b848STomohiro Kusumi } 529*2d60b848STomohiro Kusumi 530*2d60b848STomohiro Kusumi while (bufrem > 0) { 531*2d60b848STomohiro Kusumi i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); 532*2d60b848STomohiro Kusumi if (i == -1) { 533*2d60b848STomohiro Kusumi warn("zeroing image, %lld bytes to go", 534*2d60b848STomohiro Kusumi (long long)bufrem); 535*2d60b848STomohiro Kusumi free(buf); 536*2d60b848STomohiro Kusumi return -1; 537*2d60b848STomohiro Kusumi } 538*2d60b848STomohiro Kusumi bufrem -= i; 539*2d60b848STomohiro Kusumi } 540*2d60b848STomohiro Kusumi if (buf) 541*2d60b848STomohiro Kusumi free(buf); 542*2d60b848STomohiro Kusumi 543*2d60b848STomohiro Kusumi /* make the file system */ 544*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_CREATE_IMAGE) 545*2d60b848STomohiro Kusumi APRINTF("calling mkfs(\"%s\", ...)\n", image); 546*2d60b848STomohiro Kusumi hammer2_mkfs(1, av, opt); /* success if returned */ 547*2d60b848STomohiro Kusumi 548*2d60b848STomohiro Kusumi return fsopts->fd; 549*2d60b848STomohiro Kusumi } 550*2d60b848STomohiro Kusumi 551*2d60b848STomohiro Kusumi static off_t 552*2d60b848STomohiro Kusumi hammer2_phys_size(off_t size) 553*2d60b848STomohiro Kusumi { 554*2d60b848STomohiro Kusumi off_t radix_size, phys_size = 0; 555*2d60b848STomohiro Kusumi int i; 556*2d60b848STomohiro Kusumi 557*2d60b848STomohiro Kusumi if (size > HAMMER2_PBUFSIZE) { 558*2d60b848STomohiro Kusumi phys_size += rounddown(size, HAMMER2_PBUFSIZE); 559*2d60b848STomohiro Kusumi size = size % HAMMER2_PBUFSIZE; 560*2d60b848STomohiro Kusumi } 561*2d60b848STomohiro Kusumi 562*2d60b848STomohiro Kusumi for (i = HAMMER2_RADIX_MIN; i <= HAMMER2_RADIX_MAX; i++) { 563*2d60b848STomohiro Kusumi radix_size = 1UL << i; 564*2d60b848STomohiro Kusumi if (radix_size >= size) { 565*2d60b848STomohiro Kusumi phys_size += radix_size; 566*2d60b848STomohiro Kusumi break; 567*2d60b848STomohiro Kusumi } 568*2d60b848STomohiro Kusumi } 569*2d60b848STomohiro Kusumi 570*2d60b848STomohiro Kusumi return phys_size; 571*2d60b848STomohiro Kusumi } 572*2d60b848STomohiro Kusumi 573*2d60b848STomohiro Kusumi /* calculate data size */ 574*2d60b848STomohiro Kusumi static void 575*2d60b848STomohiro Kusumi hammer2_size_dir(fsnode *root, fsinfo_t *fsopts) 576*2d60b848STomohiro Kusumi { 577*2d60b848STomohiro Kusumi fsnode *node; 578*2d60b848STomohiro Kusumi int curdirsize; 579*2d60b848STomohiro Kusumi 580*2d60b848STomohiro Kusumi assert(fsopts != NULL); 581*2d60b848STomohiro Kusumi 582*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR) 583*2d60b848STomohiro Kusumi APRINTF("entry: bytes %lld inodes %lld\n", 584*2d60b848STomohiro Kusumi (long long)fsopts->size, (long long)fsopts->inodes); 585*2d60b848STomohiro Kusumi 586*2d60b848STomohiro Kusumi curdirsize = 0; 587*2d60b848STomohiro Kusumi for (node = root; node != NULL; node = node->next) { 588*2d60b848STomohiro Kusumi if (node == root) { /* we're at "." */ 589*2d60b848STomohiro Kusumi assert(strcmp(node->name, ".") == 0); 590*2d60b848STomohiro Kusumi } else if ((node->inode->flags & FI_SIZED) == 0) { 591*2d60b848STomohiro Kusumi /* don't count duplicate names */ 592*2d60b848STomohiro Kusumi node->inode->flags |= FI_SIZED; 593*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR_NODE) 594*2d60b848STomohiro Kusumi APRINTF("`%s' size %lld\n", 595*2d60b848STomohiro Kusumi node->name, 596*2d60b848STomohiro Kusumi (long long)node->inode->st.st_size); 597*2d60b848STomohiro Kusumi fsopts->inodes++; 598*2d60b848STomohiro Kusumi fsopts->size += sizeof(hammer2_inode_data_t); 599*2d60b848STomohiro Kusumi if (node->type == S_IFREG) { 600*2d60b848STomohiro Kusumi size_t st_size = node->inode->st.st_size; 601*2d60b848STomohiro Kusumi if (st_size > HAMMER2_EMBEDDED_BYTES) 602*2d60b848STomohiro Kusumi fsopts->size += hammer2_phys_size(st_size); 603*2d60b848STomohiro Kusumi } else if (node->type == S_IFLNK) { 604*2d60b848STomohiro Kusumi size_t nlen = strlen(node->symlink); 605*2d60b848STomohiro Kusumi if (nlen > HAMMER2_EMBEDDED_BYTES) 606*2d60b848STomohiro Kusumi fsopts->size += hammer2_phys_size(nlen); 607*2d60b848STomohiro Kusumi } 608*2d60b848STomohiro Kusumi } 609*2d60b848STomohiro Kusumi if (node->type == S_IFDIR) 610*2d60b848STomohiro Kusumi hammer2_size_dir(node->child, fsopts); 611*2d60b848STomohiro Kusumi } 612*2d60b848STomohiro Kusumi 613*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR) 614*2d60b848STomohiro Kusumi APRINTF("exit: size %lld inodes %lld\n", 615*2d60b848STomohiro Kusumi (long long)fsopts->size, (long long)fsopts->inodes); 616*2d60b848STomohiro Kusumi } 617*2d60b848STomohiro Kusumi 618*2d60b848STomohiro Kusumi static void 619*2d60b848STomohiro Kusumi hammer2_print(const struct vnode *dvp, const struct vnode *vp, 620*2d60b848STomohiro Kusumi const fsnode *node, int depth, const char *msg) 621*2d60b848STomohiro Kusumi { 622*2d60b848STomohiro Kusumi if (debug & DEBUG_FS_POPULATE) { 623*2d60b848STomohiro Kusumi if (1) { 624*2d60b848STomohiro Kusumi int indent = depth * 2; 625*2d60b848STomohiro Kusumi char *type; 626*2d60b848STomohiro Kusumi if (S_ISDIR(node->type)) 627*2d60b848STomohiro Kusumi type = "dir"; 628*2d60b848STomohiro Kusumi else if (S_ISREG(node->type)) 629*2d60b848STomohiro Kusumi type = "reg"; 630*2d60b848STomohiro Kusumi else if (S_ISLNK(node->type)) 631*2d60b848STomohiro Kusumi type = "lnk"; 632*2d60b848STomohiro Kusumi else 633*2d60b848STomohiro Kusumi type = "???"; 634*2d60b848STomohiro Kusumi printf("%*.*s", indent, indent, ""); 635*2d60b848STomohiro Kusumi printf("dvp=%p/%d vp=%p/%d \"%s\" %s %s\n", 636*2d60b848STomohiro Kusumi dvp, dvp ? VTOI(dvp)->refs : 0, 637*2d60b848STomohiro Kusumi vp, vp ? VTOI(vp)->refs : 0, 638*2d60b848STomohiro Kusumi node->name, type, msg); 639*2d60b848STomohiro Kusumi } else { 640*2d60b848STomohiro Kusumi char type; 641*2d60b848STomohiro Kusumi if (S_ISDIR(node->type)) 642*2d60b848STomohiro Kusumi type = 'd'; 643*2d60b848STomohiro Kusumi else if (S_ISREG(node->type)) 644*2d60b848STomohiro Kusumi type = 'r'; 645*2d60b848STomohiro Kusumi else if (S_ISLNK(node->type)) 646*2d60b848STomohiro Kusumi type = 'l'; 647*2d60b848STomohiro Kusumi else 648*2d60b848STomohiro Kusumi type = '?'; 649*2d60b848STomohiro Kusumi printf("%c", type); 650*2d60b848STomohiro Kusumi fflush(stdout); 651*2d60b848STomohiro Kusumi } 652*2d60b848STomohiro Kusumi } 653*2d60b848STomohiro Kusumi } 654*2d60b848STomohiro Kusumi 655*2d60b848STomohiro Kusumi static int 656*2d60b848STomohiro Kusumi hammer2_populate_dir(struct vnode *dvp, const char *dir, fsnode *root, 657*2d60b848STomohiro Kusumi fsnode *parent, fsinfo_t *fsopts, int depth) 658*2d60b848STomohiro Kusumi { 659*2d60b848STomohiro Kusumi fsnode *cur; 660*2d60b848STomohiro Kusumi struct vnode *vp; 661*2d60b848STomohiro Kusumi struct stat st; 662*2d60b848STomohiro Kusumi char f[MAXPATHLEN]; 663*2d60b848STomohiro Kusumi const char *path; 664*2d60b848STomohiro Kusumi int error; 665*2d60b848STomohiro Kusumi 666*2d60b848STomohiro Kusumi assert(dvp != NULL); 667*2d60b848STomohiro Kusumi assert(dir != NULL); 668*2d60b848STomohiro Kusumi assert(root != NULL); 669*2d60b848STomohiro Kusumi assert(parent != NULL); 670*2d60b848STomohiro Kusumi assert(fsopts != NULL); 671*2d60b848STomohiro Kusumi 672*2d60b848STomohiro Kusumi /* assert root directory */ 673*2d60b848STomohiro Kusumi assert(S_ISDIR(root->type)); 674*2d60b848STomohiro Kusumi assert(!strcmp(root->name, ".")); 675*2d60b848STomohiro Kusumi assert(!root->child); 676*2d60b848STomohiro Kusumi assert(!root->parent || root->parent->child == root); 677*2d60b848STomohiro Kusumi 678*2d60b848STomohiro Kusumi hammer2_print(dvp, NULL, root, depth, "enter"); 679*2d60b848STomohiro Kusumi if (stat(dir, &st) == -1) 680*2d60b848STomohiro Kusumi err(1, "no such path %s", dir); 681*2d60b848STomohiro Kusumi if (!S_ISDIR(st.st_mode)) 682*2d60b848STomohiro Kusumi errx(1, "no such dir %s", dir); 683*2d60b848STomohiro Kusumi 684*2d60b848STomohiro Kusumi for (cur = root->next; cur != NULL; cur = cur->next) { 685*2d60b848STomohiro Kusumi /* construct source path */ 686*2d60b848STomohiro Kusumi if (cur->contents) { 687*2d60b848STomohiro Kusumi path = cur->contents; 688*2d60b848STomohiro Kusumi } else { 689*2d60b848STomohiro Kusumi if (S_ISDIR(cur->type)) { 690*2d60b848STomohiro Kusumi /* this should be same as root/path/name */ 691*2d60b848STomohiro Kusumi if (snprintf(f, sizeof(f), "%s/%s", 692*2d60b848STomohiro Kusumi dir, cur->name) >= (int)sizeof(f)) 693*2d60b848STomohiro Kusumi errx(1, "pathname too long"); 694*2d60b848STomohiro Kusumi } else { 695*2d60b848STomohiro Kusumi if (snprintf(f, sizeof(f), "%s/%s/%s", 696*2d60b848STomohiro Kusumi cur->root, cur->path, cur->name) >= (int)sizeof(f)) 697*2d60b848STomohiro Kusumi errx(1, "pathname too long"); 698*2d60b848STomohiro Kusumi } 699*2d60b848STomohiro Kusumi path = f; 700*2d60b848STomohiro Kusumi } 701*2d60b848STomohiro Kusumi if (stat(path, &st) == -1) 702*2d60b848STomohiro Kusumi err(1, "no such file %s", f); 703*2d60b848STomohiro Kusumi 704*2d60b848STomohiro Kusumi /* update node state */ 705*2d60b848STomohiro Kusumi if ((cur->inode->flags & FI_ALLOCATED) == 0) { 706*2d60b848STomohiro Kusumi cur->inode->flags |= FI_ALLOCATED; 707*2d60b848STomohiro Kusumi if (cur != root) 708*2d60b848STomohiro Kusumi cur->parent = parent; 709*2d60b848STomohiro Kusumi } 710*2d60b848STomohiro Kusumi 711*2d60b848STomohiro Kusumi if (cur->inode->flags & FI_WRITTEN) 712*2d60b848STomohiro Kusumi continue; /* hard link */ 713*2d60b848STomohiro Kusumi cur->inode->flags |= FI_WRITTEN; 714*2d60b848STomohiro Kusumi 715*2d60b848STomohiro Kusumi /* make sure it doesn't exist yet */ 716*2d60b848STomohiro Kusumi vp = NULL; 717*2d60b848STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, cur->name, 718*2d60b848STomohiro Kusumi strlen(cur->name)); 719*2d60b848STomohiro Kusumi if (!error) 720*2d60b848STomohiro Kusumi errx(1, "hammer2_nresolve(\"%s\") already exists", 721*2d60b848STomohiro Kusumi cur->name); 722*2d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nresolve"); 723*2d60b848STomohiro Kusumi 724*2d60b848STomohiro Kusumi /* if directory, mkdir and recurse */ 725*2d60b848STomohiro Kusumi if (S_ISDIR(cur->type)) { 726*2d60b848STomohiro Kusumi assert(cur->child); 727*2d60b848STomohiro Kusumi 728*2d60b848STomohiro Kusumi vp = NULL; 729*2d60b848STomohiro Kusumi error = hammer2_nmkdir(dvp, &vp, cur->name, 730*2d60b848STomohiro Kusumi strlen(cur->name)); 731*2d60b848STomohiro Kusumi if (error) 732*2d60b848STomohiro Kusumi errx(1, "hammer2_nmkdir(\"%s\") failed: %s", 733*2d60b848STomohiro Kusumi cur->name, strerror(error)); 734*2d60b848STomohiro Kusumi assert(vp); 735*2d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nmkdir"); 736*2d60b848STomohiro Kusumi 737*2d60b848STomohiro Kusumi error = hammer2_populate_dir(vp, path, cur->child, cur, 738*2d60b848STomohiro Kusumi fsopts, depth + 1); 739*2d60b848STomohiro Kusumi if (error) 740*2d60b848STomohiro Kusumi errx(1, "failed to populate %s: %s", 741*2d60b848STomohiro Kusumi path, strerror(error)); 742*2d60b848STomohiro Kusumi continue; 743*2d60b848STomohiro Kusumi } 744*2d60b848STomohiro Kusumi 745*2d60b848STomohiro Kusumi /* if regular file, creat and write its data */ 746*2d60b848STomohiro Kusumi if (S_ISREG(cur->type)) { 747*2d60b848STomohiro Kusumi assert(cur->child == NULL); 748*2d60b848STomohiro Kusumi 749*2d60b848STomohiro Kusumi vp = NULL; 750*2d60b848STomohiro Kusumi error = hammer2_ncreate(dvp, &vp, cur->name, 751*2d60b848STomohiro Kusumi strlen(cur->name)); 752*2d60b848STomohiro Kusumi if (error) 753*2d60b848STomohiro Kusumi errx(1, "hammer2_ncreate(\"%s\") failed: %s", 754*2d60b848STomohiro Kusumi cur->name, strerror(error)); 755*2d60b848STomohiro Kusumi assert(vp); 756*2d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "ncreate"); 757*2d60b848STomohiro Kusumi 758*2d60b848STomohiro Kusumi error = hammer2_write_file(vp, path, cur); 759*2d60b848STomohiro Kusumi if (error) 760*2d60b848STomohiro Kusumi errx(1, "hammer2_write_file(\"%s\") failed: %s", 761*2d60b848STomohiro Kusumi path, strerror(error)); 762*2d60b848STomohiro Kusumi continue; 763*2d60b848STomohiro Kusumi } 764*2d60b848STomohiro Kusumi 765*2d60b848STomohiro Kusumi /* if symlink, create a symlink against target */ 766*2d60b848STomohiro Kusumi if (S_ISLNK(cur->type)) { 767*2d60b848STomohiro Kusumi assert(cur->child == NULL); 768*2d60b848STomohiro Kusumi 769*2d60b848STomohiro Kusumi vp = NULL; 770*2d60b848STomohiro Kusumi error = hammer2_nsymlink(dvp, &vp, cur->name, 771*2d60b848STomohiro Kusumi strlen(cur->name), cur->symlink); 772*2d60b848STomohiro Kusumi if (error) 773*2d60b848STomohiro Kusumi errx(1, "hammer2_nsymlink(\"%s\") failed: %s", 774*2d60b848STomohiro Kusumi cur->name, strerror(error)); 775*2d60b848STomohiro Kusumi assert(vp); 776*2d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nsymlink"); 777*2d60b848STomohiro Kusumi continue; 778*2d60b848STomohiro Kusumi } 779*2d60b848STomohiro Kusumi 780*2d60b848STomohiro Kusumi /* other types are unsupported */ 781*2d60b848STomohiro Kusumi printf("ignore %s 0%o\n", path, cur->type); 782*2d60b848STomohiro Kusumi } 783*2d60b848STomohiro Kusumi 784*2d60b848STomohiro Kusumi return 0; 785*2d60b848STomohiro Kusumi } 786*2d60b848STomohiro Kusumi 787*2d60b848STomohiro Kusumi static int 788*2d60b848STomohiro Kusumi hammer2_write_file(struct vnode *vp, const char *path, fsnode *node) 789*2d60b848STomohiro Kusumi { 790*2d60b848STomohiro Kusumi struct stat *st = &node->inode->st; 791*2d60b848STomohiro Kusumi size_t nsize, bufsize; 792*2d60b848STomohiro Kusumi off_t offset; 793*2d60b848STomohiro Kusumi int fd, error; 794*2d60b848STomohiro Kusumi char *p; 795*2d60b848STomohiro Kusumi 796*2d60b848STomohiro Kusumi nsize = st->st_size; 797*2d60b848STomohiro Kusumi if (nsize == 0) 798*2d60b848STomohiro Kusumi return 0; 799*2d60b848STomohiro Kusumi /* check nsize vs maximum file size */ 800*2d60b848STomohiro Kusumi 801*2d60b848STomohiro Kusumi fd = open(path, O_RDONLY); 802*2d60b848STomohiro Kusumi if (fd < 0) 803*2d60b848STomohiro Kusumi err(1, "failed to open %s", path); 804*2d60b848STomohiro Kusumi 805*2d60b848STomohiro Kusumi p = mmap(0, nsize, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 806*2d60b848STomohiro Kusumi if (p == MAP_FAILED) 807*2d60b848STomohiro Kusumi err(1, "failed to mmap %s", path); 808*2d60b848STomohiro Kusumi close(fd); 809*2d60b848STomohiro Kusumi 810*2d60b848STomohiro Kusumi for (offset = 0; offset < nsize; ) { 811*2d60b848STomohiro Kusumi bufsize = MIN(nsize - offset, HAMMER2_PBUFSIZE); 812*2d60b848STomohiro Kusumi assert(bufsize <= HAMMER2_PBUFSIZE); 813*2d60b848STomohiro Kusumi error = hammer2_write(vp, p + offset, bufsize, offset); 814*2d60b848STomohiro Kusumi if (error) 815*2d60b848STomohiro Kusumi errx(1, "failed to write to %s vnode: %s", 816*2d60b848STomohiro Kusumi path, strerror(error)); 817*2d60b848STomohiro Kusumi offset += bufsize; 818*2d60b848STomohiro Kusumi if (bufsize == HAMMER2_PBUFSIZE) 819*2d60b848STomohiro Kusumi assert((offset & (HAMMER2_PBUFSIZE - 1)) == 0); 820*2d60b848STomohiro Kusumi } 821*2d60b848STomohiro Kusumi munmap(p, nsize); 822*2d60b848STomohiro Kusumi 823*2d60b848STomohiro Kusumi return 0; 824*2d60b848STomohiro Kusumi } 825