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>
436da97f51STomohiro Kusumi #include <sys/time.h>
445e8b0eb7STomohiro Kusumi #include <sys/dirent.h>
452d60b848STomohiro Kusumi
462d60b848STomohiro Kusumi #include <stdio.h>
472d60b848STomohiro Kusumi #include <stdlib.h>
482d60b848STomohiro Kusumi #include <stdbool.h>
492d60b848STomohiro Kusumi #include <string.h>
50465e1141STomohiro Kusumi #include <ctype.h>
512d60b848STomohiro Kusumi #include <unistd.h>
522d60b848STomohiro Kusumi #include <fcntl.h>
532d60b848STomohiro Kusumi #include <time.h>
542d60b848STomohiro Kusumi #include <err.h>
552d60b848STomohiro Kusumi #include <assert.h>
562d60b848STomohiro Kusumi #include <util.h>
572d60b848STomohiro Kusumi
582d60b848STomohiro Kusumi #include "makefs.h"
592d60b848STomohiro Kusumi #include "hammer2.h"
602d60b848STomohiro Kusumi
612d60b848STomohiro Kusumi #define APRINTF(X, ...) \
622d60b848STomohiro Kusumi printf("%s: " X, __func__, ## __VA_ARGS__)
632d60b848STomohiro Kusumi
643999233bSTomohiro Kusumi static void hammer2_parse_pfs_opts(const char *, fsinfo_t *);
65f804c425STomohiro Kusumi static void hammer2_parse_inode_opts(const char *, fsinfo_t *);
662d60b848STomohiro Kusumi static void hammer2_dump_fsinfo(fsinfo_t *);
672d60b848STomohiro Kusumi static int hammer2_create_image(const char *, fsinfo_t *);
686bcbb706STomohiro Kusumi static int hammer2_populate_dir(struct m_vnode *, const char *, fsnode *,
692d60b848STomohiro Kusumi fsnode *, fsinfo_t *, int);
702d60b848STomohiro Kusumi static void hammer2_validate(const char *, fsnode *, fsinfo_t *);
712d60b848STomohiro Kusumi static void hammer2_size_dir(fsnode *, fsinfo_t *);
726bcbb706STomohiro Kusumi static int hammer2_write_file(struct m_vnode *, const char *, fsnode *);
73f72350acSTomohiro Kusumi static int hammer2_version_get(struct m_vnode *);
749a149651STomohiro Kusumi static int hammer2_pfs_get(struct m_vnode *);
759a149651STomohiro Kusumi static int hammer2_pfs_lookup(struct m_vnode *, const char *);
769a149651STomohiro Kusumi static int hammer2_pfs_create(struct m_vnode *, const char *);
779a149651STomohiro Kusumi static int hammer2_pfs_delete(struct m_vnode *, const char *);
789a149651STomohiro Kusumi static int hammer2_pfs_snapshot(struct m_vnode *, const char *, const char *);
79465e1141STomohiro Kusumi static int hammer2_inode_getx(struct m_vnode *, const char *);
80465e1141STomohiro Kusumi static int hammer2_inode_setcheck(struct m_vnode *, const char *);
81465e1141STomohiro Kusumi static int hammer2_inode_setcomp(struct m_vnode *, const char *);
823999233bSTomohiro Kusumi static int hammer2_bulkfree(struct m_vnode *);
833999233bSTomohiro Kusumi static int hammer2_destroy_path(struct m_vnode *, const char *);
843999233bSTomohiro Kusumi static int hammer2_destroy_inum(struct m_vnode *, hammer2_tid_t);
853999233bSTomohiro Kusumi static int hammer2_growfs(struct m_vnode *, hammer2_off_t);
862d0322dbSTomohiro Kusumi struct hammer2_linkq;
872d0322dbSTomohiro Kusumi static int hammer2_readx_handle(struct m_vnode *, const char *, const char *,
882d0322dbSTomohiro Kusumi struct hammer2_linkq *);
89fc4148feSTomohiro Kusumi static int hammer2_readx(struct m_vnode *, const char *, const char *);
906857f034STomohiro Kusumi static void unittest_trim_slash(void);
912d60b848STomohiro Kusumi
92ddd1d3d1STomohiro Kusumi fsnode *hammer2_curnode;
93ddd1d3d1STomohiro Kusumi
942d60b848STomohiro Kusumi void
hammer2_prep_opts(fsinfo_t * fsopts)952d60b848STomohiro Kusumi hammer2_prep_opts(fsinfo_t *fsopts)
962d60b848STomohiro Kusumi {
972d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = ecalloc(1, sizeof(*h2_opt));
982d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
992d60b848STomohiro Kusumi
1002d60b848STomohiro Kusumi const option_t hammer2_options[] = {
1012d60b848STomohiro Kusumi /* newfs_hammer2(8) compatible options */
1022d60b848STomohiro Kusumi { 'b', "BootAreaSize", NULL, OPT_STRBUF, 0, 0, "boot area size" },
1032d60b848STomohiro Kusumi { 'r', "AuxAreaSize", NULL, OPT_STRBUF, 0, 0, "aux area size" },
1042d60b848STomohiro Kusumi { 'V', "Hammer2Version", NULL, OPT_STRBUF, 0, 0, "file system version" },
1052d60b848STomohiro Kusumi { 'L', "Label", NULL, OPT_STRBUF, 0, 0, "PFS label" },
1062d60b848STomohiro Kusumi /* makefs(8) specific options */
1072d60b848STomohiro Kusumi { 'm', "MountLabel", NULL, OPT_STRBUF, 0, 0, "destination PFS label" },
1082d60b848STomohiro Kusumi { 'v', "NumVolhdr", &h2_opt->num_volhdr, OPT_INT32,
1092d60b848STomohiro Kusumi 1, HAMMER2_NUM_VOLHDRS, "number of volume headers" },
11060e242c5STomohiro Kusumi { 'c', "CompressionType", NULL, OPT_STRBUF, 0, 0, "compression type" },
11160e242c5STomohiro Kusumi { 'C', "CheckType", NULL, OPT_STRBUF, 0, 0, "check type" },
1122d60b848STomohiro Kusumi { 'd', "Hammer2Debug", NULL, OPT_STRBUF, 0, 0, "debug tunable" },
11348ed4577STomohiro Kusumi { 'E', "EmergencyMode", &h2_opt->emergency_mode, OPT_BOOL, 0, 0,
11448ed4577STomohiro Kusumi "emergency mode" },
1153999233bSTomohiro Kusumi { 'P', "PFS", NULL, OPT_STRBUF, 0, 0, "offline PFS" },
116f804c425STomohiro Kusumi { 'I', "Inode", NULL, OPT_STRBUF, 0, 0, "offline inode" },
1179a149651STomohiro Kusumi { 'B', "Bulkfree", NULL, OPT_STRBUF, 0, 0, "offline bulkfree" },
118917508cdSTomohiro Kusumi { 'D', "Destroy", NULL, OPT_STRBUF, 0, 0, "offline destroy" },
1199a149651STomohiro Kusumi { 'G', "Growfs", NULL, OPT_STRBUF, 0, 0, "offline growfs" },
120fc4148feSTomohiro Kusumi { 'R', "Read", NULL, OPT_STRBUF, 0, 0, "offline read" },
1212d60b848STomohiro Kusumi { .name = NULL },
1222d60b848STomohiro Kusumi };
1232d60b848STomohiro Kusumi
1242d60b848STomohiro Kusumi hammer2_mkfs_init(opt);
1252d60b848STomohiro Kusumi
126a071436bSTomohiro Kusumi assert(opt->CompType == HAMMER2_COMP_DEFAULT);
1279046282cSTomohiro Kusumi assert(opt->CheckType == HAMMER2_CHECK_DEFAULT);
1282d60b848STomohiro Kusumi
1292d60b848STomohiro Kusumi /* force debug mode for mkfs */
1302d60b848STomohiro Kusumi opt->DebugOpt = 1;
1312d60b848STomohiro Kusumi
1322d60b848STomohiro Kusumi fsopts->fs_specific = h2_opt;
1332d60b848STomohiro Kusumi fsopts->fs_options = copy_opts(hammer2_options);
1342d60b848STomohiro Kusumi fsopts->sectorsize = DEV_BSIZE;
1352d60b848STomohiro Kusumi }
1362d60b848STomohiro Kusumi
1372d60b848STomohiro Kusumi void
hammer2_cleanup_opts(fsinfo_t * fsopts)1382d60b848STomohiro Kusumi hammer2_cleanup_opts(fsinfo_t *fsopts)
1392d60b848STomohiro Kusumi {
1402d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
1412d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
1422d60b848STomohiro Kusumi
1432d60b848STomohiro Kusumi hammer2_mkfs_cleanup(opt);
1442d60b848STomohiro Kusumi
1452d60b848STomohiro Kusumi free(h2_opt);
1462d60b848STomohiro Kusumi free(fsopts->fs_options);
1472d60b848STomohiro Kusumi }
1482d60b848STomohiro Kusumi
1492d60b848STomohiro Kusumi int
hammer2_parse_opts(const char * option,fsinfo_t * fsopts)1502d60b848STomohiro Kusumi hammer2_parse_opts(const char *option, fsinfo_t *fsopts)
1512d60b848STomohiro Kusumi {
1522d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
1532d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
1542d60b848STomohiro Kusumi
1552d60b848STomohiro Kusumi option_t *hammer2_options = fsopts->fs_options;
1562d60b848STomohiro Kusumi char buf[1024]; /* > HAMMER2_INODE_MAXNAME */
1572d60b848STomohiro Kusumi int i;
1582d60b848STomohiro Kusumi
1592d60b848STomohiro Kusumi assert(option != NULL);
1602d60b848STomohiro Kusumi assert(fsopts != NULL);
1612d60b848STomohiro Kusumi
1622d60b848STomohiro Kusumi if (debug & DEBUG_FS_PARSE_OPTS)
1632d60b848STomohiro Kusumi APRINTF("got `%s'\n", option);
1642d60b848STomohiro Kusumi
1652d60b848STomohiro Kusumi i = set_option(hammer2_options, option, buf, sizeof(buf));
1662d60b848STomohiro Kusumi if (i == -1)
1672d60b848STomohiro Kusumi return 0;
1682d60b848STomohiro Kusumi
1692d60b848STomohiro Kusumi if (hammer2_options[i].name == NULL)
1702d60b848STomohiro Kusumi abort();
1712d60b848STomohiro Kusumi
1722d60b848STomohiro Kusumi switch (hammer2_options[i].letter) {
1732d60b848STomohiro Kusumi case 'b':
1742d60b848STomohiro Kusumi opt->BootAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN,
1752d60b848STomohiro Kusumi HAMMER2_BOOT_MAX_BYTES, 2);
1762d60b848STomohiro Kusumi break;
1772d60b848STomohiro Kusumi case 'r':
1782d60b848STomohiro Kusumi opt->AuxAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN,
1792d60b848STomohiro Kusumi HAMMER2_AUX_MAX_BYTES, 2);
1802d60b848STomohiro Kusumi break;
1812d60b848STomohiro Kusumi case 'V':
182f72350acSTomohiro Kusumi if (strlen(buf) == 0) {
183f72350acSTomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_VERSION_GET;
184f72350acSTomohiro Kusumi } else {
1852d60b848STomohiro Kusumi opt->Hammer2Version = strtol(buf, NULL, 0);
1862d60b848STomohiro Kusumi if (opt->Hammer2Version < HAMMER2_VOL_VERSION_MIN ||
1872d60b848STomohiro Kusumi opt->Hammer2Version >= HAMMER2_VOL_VERSION_WIP)
1882d60b848STomohiro Kusumi errx(1, "I don't understand how to format "
1892d60b848STomohiro Kusumi "HAMMER2 version %d",
1902d60b848STomohiro Kusumi opt->Hammer2Version);
191f72350acSTomohiro Kusumi }
1922d60b848STomohiro Kusumi break;
1932d60b848STomohiro Kusumi case 'L':
1942d60b848STomohiro Kusumi h2_opt->label_specified = 1;
1952d60b848STomohiro Kusumi if (strcasecmp(buf, "none") == 0)
1962d60b848STomohiro Kusumi break;
1972d60b848STomohiro Kusumi if (opt->NLabels >= MAXLABELS)
1982d60b848STomohiro Kusumi errx(1, "Limit of %d local labels", MAXLABELS - 1);
1992d60b848STomohiro Kusumi if (strlen(buf) == 0)
2002d60b848STomohiro Kusumi errx(1, "Volume label '%s' cannot be 0-length", buf);
2012d60b848STomohiro Kusumi if (strlen(buf) >= HAMMER2_INODE_MAXNAME)
2022d60b848STomohiro Kusumi errx(1, "Volume label '%s' is too long (%d chars max)",
2032d60b848STomohiro Kusumi buf, HAMMER2_INODE_MAXNAME - 1);
2042d60b848STomohiro Kusumi opt->Label[opt->NLabels++] = strdup(buf);
2052d60b848STomohiro Kusumi break;
2062d60b848STomohiro Kusumi case 'm':
2072d60b848STomohiro Kusumi if (strlen(buf) == 0)
2082d60b848STomohiro Kusumi errx(1, "Volume label '%s' cannot be 0-length", buf);
2092d60b848STomohiro Kusumi if (strlen(buf) >= HAMMER2_INODE_MAXNAME)
2102d60b848STomohiro Kusumi errx(1, "Volume label '%s' is too long (%d chars max)",
2112d60b848STomohiro Kusumi buf, HAMMER2_INODE_MAXNAME - 1);
2122d60b848STomohiro Kusumi strlcpy(h2_opt->mount_label, buf, sizeof(h2_opt->mount_label));
2132d60b848STomohiro Kusumi break;
21460e242c5STomohiro Kusumi case 'c':
21560e242c5STomohiro Kusumi if (strlen(buf) == 0)
21660e242c5STomohiro Kusumi errx(1, "Compression type '%s' cannot be 0-length", buf);
21760e242c5STomohiro Kusumi if (strcasecmp(buf, "none") == 0)
21860e242c5STomohiro Kusumi opt->CompType = HAMMER2_COMP_NONE;
21960e242c5STomohiro Kusumi else if (strcasecmp(buf, "autozero") == 0)
22060e242c5STomohiro Kusumi opt->CompType = HAMMER2_COMP_AUTOZERO;
22160e242c5STomohiro Kusumi else if (strcasecmp(buf, "lz4") == 0)
22260e242c5STomohiro Kusumi opt->CompType = HAMMER2_COMP_LZ4;
22360e242c5STomohiro Kusumi else if (strcasecmp(buf, "zlib") == 0)
22460e242c5STomohiro Kusumi opt->CompType = HAMMER2_COMP_ZLIB;
22560e242c5STomohiro Kusumi else
22660e242c5STomohiro Kusumi errx(1, "Invalid compression type '%s'", buf);
22760e242c5STomohiro Kusumi break;
22860e242c5STomohiro Kusumi case 'C':
22960e242c5STomohiro Kusumi if (strlen(buf) == 0)
23060e242c5STomohiro Kusumi errx(1, "Check type '%s' cannot be 0-length", buf);
23160e242c5STomohiro Kusumi if (strcasecmp(buf, "none") == 0)
23260e242c5STomohiro Kusumi opt->CheckType = HAMMER2_CHECK_NONE;
23360e242c5STomohiro Kusumi else if (strcasecmp(buf, "disabled") == 0)
23460e242c5STomohiro Kusumi opt->CheckType = HAMMER2_CHECK_DISABLED;
23560e242c5STomohiro Kusumi else if (strcasecmp(buf, "iscsi32") == 0)
23660e242c5STomohiro Kusumi opt->CheckType = HAMMER2_CHECK_ISCSI32;
23760e242c5STomohiro Kusumi else if (strcasecmp(buf, "xxhash64") == 0)
23860e242c5STomohiro Kusumi opt->CheckType = HAMMER2_CHECK_XXHASH64;
23960e242c5STomohiro Kusumi else if (strcasecmp(buf, "sha192") == 0)
24060e242c5STomohiro Kusumi opt->CheckType = HAMMER2_CHECK_SHA192;
24160e242c5STomohiro Kusumi else if (strcasecmp(buf, "freemap") == 0)
24260e242c5STomohiro Kusumi opt->CheckType = HAMMER2_CHECK_FREEMAP;
24360e242c5STomohiro Kusumi else
24460e242c5STomohiro Kusumi errx(1, "Invalid check type '%s'", buf);
24560e242c5STomohiro Kusumi break;
2462d60b848STomohiro Kusumi case 'd':
2472d60b848STomohiro Kusumi hammer2_debug = strtoll(buf, NULL, 0);
2482d60b848STomohiro Kusumi break;
2493999233bSTomohiro Kusumi case 'P':
2503999233bSTomohiro Kusumi if (strlen(buf) == 0)
2513999233bSTomohiro Kusumi errx(1, "PFS argument '%s' cannot be 0-length", buf);
2523999233bSTomohiro Kusumi hammer2_parse_pfs_opts(buf, fsopts);
2533999233bSTomohiro Kusumi break;
254f804c425STomohiro Kusumi case 'I':
255f804c425STomohiro Kusumi if (strlen(buf) == 0)
256f804c425STomohiro Kusumi errx(1, "Inode argument '%s' cannot be 0-length", buf);
257f804c425STomohiro Kusumi hammer2_parse_inode_opts(buf, fsopts);
258f804c425STomohiro Kusumi break;
2599a149651STomohiro Kusumi case 'B':
2609a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_BULKFREE_SCAN;
2619a149651STomohiro Kusumi break;
262917508cdSTomohiro Kusumi case 'D':
2639a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_DESTROY;
264b4807901STomohiro Kusumi if (strlen(buf) == 0)
265b4807901STomohiro Kusumi errx(1, "Destroy argument '%s' cannot be 0-length", buf);
266917508cdSTomohiro Kusumi if (buf[0] == '/') {
2676857f034STomohiro Kusumi strlcpy(h2_opt->destroy_path, buf,
268917508cdSTomohiro Kusumi sizeof(h2_opt->destroy_path));
269b4807901STomohiro Kusumi } else if (strncmp(buf, "0x", 2) == 0 ||
270917508cdSTomohiro Kusumi (buf[0] >= '0' && buf[0] <= '9')) {
271917508cdSTomohiro Kusumi h2_opt->destroy_inum = strtoull(buf, NULL, 0);
272917508cdSTomohiro Kusumi if (errno)
273917508cdSTomohiro Kusumi err(1, "strtoull");
274917508cdSTomohiro Kusumi } else {
275917508cdSTomohiro Kusumi errx(1, "Invalid destroy argument %s", buf);
276917508cdSTomohiro Kusumi }
277917508cdSTomohiro Kusumi break;
2789a149651STomohiro Kusumi case 'G':
2799a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_GROWFS;
2809a149651STomohiro Kusumi break;
281fc4148feSTomohiro Kusumi case 'R':
282fc4148feSTomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_READ;
283fc4148feSTomohiro Kusumi if (strlen(buf) == 0)
284fc4148feSTomohiro Kusumi errx(1, "Read argument '%s' cannot be 0-length", buf);
285fc4148feSTomohiro Kusumi strlcpy(h2_opt->read_path, buf, sizeof(h2_opt->read_path));
286fc4148feSTomohiro Kusumi break;
2872d60b848STomohiro Kusumi default:
2882d60b848STomohiro Kusumi break;
2892d60b848STomohiro Kusumi }
2902d60b848STomohiro Kusumi
2916857f034STomohiro Kusumi if (hammer2_debug && h2_opt->ioctl_cmd)
2926857f034STomohiro Kusumi unittest_trim_slash();
2936857f034STomohiro Kusumi
2942d60b848STomohiro Kusumi return 1;
2952d60b848STomohiro Kusumi }
2962d60b848STomohiro Kusumi
2972d60b848STomohiro Kusumi void
hammer2_makefs(const char * image,const char * dir,fsnode * root,fsinfo_t * fsopts)2982d60b848STomohiro Kusumi hammer2_makefs(const char *image, const char *dir, fsnode *root,
2992d60b848STomohiro Kusumi fsinfo_t *fsopts)
3002d60b848STomohiro Kusumi {
3012d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
3022d60b848STomohiro Kusumi struct mount mp;
3032d60b848STomohiro Kusumi struct hammer2_mount_info info;
3046bcbb706STomohiro Kusumi struct m_vnode devvp, *vroot;
3052d60b848STomohiro Kusumi hammer2_inode_t *iroot;
3062d60b848STomohiro Kusumi struct timeval start;
3072d60b848STomohiro Kusumi int error;
3082d60b848STomohiro Kusumi
30970e962f7STomohiro Kusumi /* ioctl commands could have NULL dir / root */
3102d60b848STomohiro Kusumi assert(image != NULL);
3112d60b848STomohiro Kusumi assert(fsopts != NULL);
3122d60b848STomohiro Kusumi
3132d60b848STomohiro Kusumi if (debug & DEBUG_FS_MAKEFS)
3142d60b848STomohiro Kusumi APRINTF("image \"%s\" directory \"%s\" root %p\n",
3152d60b848STomohiro Kusumi image, dir, root);
3162d60b848STomohiro Kusumi
3172d60b848STomohiro Kusumi /* validate tree and options */
3182d60b848STomohiro Kusumi TIMER_START(start);
3192d60b848STomohiro Kusumi hammer2_validate(dir, root, fsopts);
3202d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_validate");
3212d60b848STomohiro Kusumi
3229a149651STomohiro Kusumi if (h2_opt->ioctl_cmd) {
323b4807901STomohiro Kusumi /* open existing image */
324b4807901STomohiro Kusumi fsopts->fd = open(image, O_RDWR);
325b4807901STomohiro Kusumi if (fsopts->fd < 0)
326b4807901STomohiro Kusumi err(1, "failed to open `%s'", image);
327b4807901STomohiro Kusumi } else {
3282d60b848STomohiro Kusumi /* create image */
3292d60b848STomohiro Kusumi TIMER_START(start);
3302d60b848STomohiro Kusumi if (hammer2_create_image(image, fsopts) == -1)
3312d60b848STomohiro Kusumi errx(1, "image file `%s' not created", image);
3322d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_create_image");
333a63188c8STomohiro Kusumi }
334a63188c8STomohiro Kusumi assert(fsopts->fd > 0);
3352d60b848STomohiro Kusumi
3362d60b848STomohiro Kusumi if (debug & DEBUG_FS_MAKEFS)
3372d60b848STomohiro Kusumi putchar('\n');
3382d60b848STomohiro Kusumi
3392d60b848STomohiro Kusumi /* vfs init */
3402d60b848STomohiro Kusumi error = hammer2_vfs_init();
3412d60b848STomohiro Kusumi if (error)
3422d60b848STomohiro Kusumi errx(1, "failed to vfs init, error %d", error);
3432d60b848STomohiro Kusumi
3442d60b848STomohiro Kusumi /* mount image */
3452d60b848STomohiro Kusumi memset(&devvp, 0, sizeof(devvp));
3462d60b848STomohiro Kusumi devvp.fs = fsopts;
3472d60b848STomohiro Kusumi memset(&mp, 0, sizeof(mp));
3482d60b848STomohiro Kusumi memset(&info, 0, sizeof(info));
3492d60b848STomohiro Kusumi error = hammer2_vfs_mount(&devvp, &mp, h2_opt->mount_label, &info);
3502d60b848STomohiro Kusumi if (error)
3512d60b848STomohiro Kusumi errx(1, "failed to mount, error %d", error);
3522d60b848STomohiro Kusumi assert(mp.mnt_data);
3532d60b848STomohiro Kusumi
3542d60b848STomohiro Kusumi /* get root vnode */
3552d60b848STomohiro Kusumi vroot = NULL;
3562d60b848STomohiro Kusumi error = hammer2_vfs_root(&mp, &vroot);
3572d60b848STomohiro Kusumi if (error)
3582d60b848STomohiro Kusumi errx(1, "failed to get root vnode, error %d", error);
3592d60b848STomohiro Kusumi assert(vroot);
3602d60b848STomohiro Kusumi
3612d60b848STomohiro Kusumi iroot = VTOI(vroot);
3622d60b848STomohiro Kusumi assert(iroot);
363f8a1147cSTomohiro Kusumi printf("root inode inum %lld, mode 0%o, refs %d\n",
364f8a1147cSTomohiro Kusumi (long long)iroot->meta.inum, iroot->meta.mode, iroot->refs);
3652d60b848STomohiro Kusumi
36648ed4577STomohiro Kusumi if (h2_opt->emergency_mode)
36748ed4577STomohiro Kusumi hammer2_ioctl_emerg_mode(iroot, 1);
36848ed4577STomohiro Kusumi
3699a149651STomohiro Kusumi switch (h2_opt->ioctl_cmd) {
370f72350acSTomohiro Kusumi case HAMMER2IOC_VERSION_GET:
371f72350acSTomohiro Kusumi printf("version get `%s'\n", image);
372f72350acSTomohiro Kusumi TIMER_START(start);
373f72350acSTomohiro Kusumi error = hammer2_version_get(vroot);
374f72350acSTomohiro Kusumi if (error)
375f72350acSTomohiro Kusumi errx(1, "version get `%s' failed '%s'", image,
376f72350acSTomohiro Kusumi strerror(error));
377f72350acSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_version_get");
378f72350acSTomohiro Kusumi break;
3799a149651STomohiro Kusumi case HAMMER2IOC_PFS_GET:
3803999233bSTomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image);
3813999233bSTomohiro Kusumi TIMER_START(start);
3829a149651STomohiro Kusumi error = hammer2_pfs_get(vroot);
3839a149651STomohiro Kusumi if (error)
3849a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name,
3859a149651STomohiro Kusumi image, strerror(error));
3869a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_get");
3879a149651STomohiro Kusumi break;
3889a149651STomohiro Kusumi case HAMMER2IOC_PFS_LOOKUP:
3899a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image);
3909a149651STomohiro Kusumi TIMER_START(start);
3919a149651STomohiro Kusumi error = hammer2_pfs_lookup(vroot, h2_opt->pfs_name);
3929a149651STomohiro Kusumi if (error)
3939a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name,
3949a149651STomohiro Kusumi image, strerror(error));
3959a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_lookup");
3969a149651STomohiro Kusumi break;
3979a149651STomohiro Kusumi case HAMMER2IOC_PFS_CREATE:
3989a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image);
3999a149651STomohiro Kusumi TIMER_START(start);
4009a149651STomohiro Kusumi error = hammer2_pfs_create(vroot, h2_opt->pfs_name);
4019a149651STomohiro Kusumi if (error)
4029a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name,
4039a149651STomohiro Kusumi image, strerror(error));
4049a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_create");
4059a149651STomohiro Kusumi break;
4069a149651STomohiro Kusumi case HAMMER2IOC_PFS_DELETE:
4079a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image);
4089a149651STomohiro Kusumi TIMER_START(start);
4099a149651STomohiro Kusumi error = hammer2_pfs_delete(vroot, h2_opt->pfs_name);
4109a149651STomohiro Kusumi if (error)
4119a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name,
4129a149651STomohiro Kusumi image, strerror(error));
4139a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_delete");
4149a149651STomohiro Kusumi break;
4159a149651STomohiro Kusumi case HAMMER2IOC_PFS_SNAPSHOT:
4169a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image);
4179a149651STomohiro Kusumi TIMER_START(start);
4189a149651STomohiro Kusumi error = hammer2_pfs_snapshot(vroot, h2_opt->pfs_name,
41906d1ac82STomohiro Kusumi h2_opt->mount_label);
42006d1ac82STomohiro Kusumi if (error)
42106d1ac82STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name,
42206d1ac82STomohiro Kusumi image, strerror(error));
4239a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_snapshot");
4249a149651STomohiro Kusumi break;
425f804c425STomohiro Kusumi case HAMMER2IOC_INODE_GET:
426465e1141STomohiro Kusumi printf("inode %s `%s'\n", h2_opt->inode_cmd_name, image);
427f804c425STomohiro Kusumi TIMER_START(start);
428f804c425STomohiro Kusumi error = hammer2_inode_getx(vroot, h2_opt->inode_path);
429f804c425STomohiro Kusumi if (error)
430465e1141STomohiro Kusumi errx(1, "inode %s `%s' failed '%s'",
431465e1141STomohiro Kusumi h2_opt->inode_cmd_name, image, strerror(error));
432f804c425STomohiro Kusumi TIMER_RESULTS(start, "hammer2_inode_getx");
433f804c425STomohiro Kusumi break;
434465e1141STomohiro Kusumi case HAMMER2IOC_INODE_SET:
435465e1141STomohiro Kusumi printf("inode %s `%s'\n", h2_opt->inode_cmd_name, image);
436465e1141STomohiro Kusumi TIMER_START(start);
437465e1141STomohiro Kusumi if (!strcmp(h2_opt->inode_cmd_name, "setcheck")) {
438465e1141STomohiro Kusumi error = hammer2_inode_setcheck(vroot,
439465e1141STomohiro Kusumi h2_opt->inode_path);
440465e1141STomohiro Kusumi if (error)
441465e1141STomohiro Kusumi errx(1, "inode %s `%s' failed '%s'",
442465e1141STomohiro Kusumi h2_opt->inode_cmd_name, image,
443465e1141STomohiro Kusumi strerror(error));
444465e1141STomohiro Kusumi } else if (!strcmp(h2_opt->inode_cmd_name, "setcomp")) {
445465e1141STomohiro Kusumi error = hammer2_inode_setcomp(vroot,
446465e1141STomohiro Kusumi h2_opt->inode_path);
447465e1141STomohiro Kusumi if (error)
448465e1141STomohiro Kusumi errx(1, "inode %s `%s' failed '%s'",
449465e1141STomohiro Kusumi h2_opt->inode_cmd_name, image,
450465e1141STomohiro Kusumi strerror(error));
451465e1141STomohiro Kusumi } else {
452465e1141STomohiro Kusumi assert(0);
453465e1141STomohiro Kusumi }
454465e1141STomohiro Kusumi TIMER_RESULTS(start, "hammer2_inode_setx");
455465e1141STomohiro Kusumi break;
4569a149651STomohiro Kusumi case HAMMER2IOC_BULKFREE_SCAN:
457a63188c8STomohiro Kusumi printf("bulkfree `%s'\n", image);
458a63188c8STomohiro Kusumi TIMER_START(start);
45906d1ac82STomohiro Kusumi error = hammer2_bulkfree(vroot);
46006d1ac82STomohiro Kusumi if (error)
46106d1ac82STomohiro Kusumi errx(1, "bulkfree `%s' failed '%s'", image,
46206d1ac82STomohiro Kusumi strerror(error));
463a63188c8STomohiro Kusumi TIMER_RESULTS(start, "hammer2_bulkfree");
4649a149651STomohiro Kusumi break;
4659a149651STomohiro Kusumi case HAMMER2IOC_DESTROY:
466917508cdSTomohiro Kusumi TIMER_START(start);
467917508cdSTomohiro Kusumi if (strlen(h2_opt->destroy_path)) {
468917508cdSTomohiro Kusumi printf("destroy `%s' in `%s'\n",
469917508cdSTomohiro Kusumi h2_opt->destroy_path, image);
47006d1ac82STomohiro Kusumi error = hammer2_destroy_path(vroot,
47106d1ac82STomohiro Kusumi h2_opt->destroy_path);
47206d1ac82STomohiro Kusumi if (error)
47306d1ac82STomohiro Kusumi errx(1, "destroy `%s' in `%s' failed '%s'",
47406d1ac82STomohiro Kusumi h2_opt->destroy_path, image,
47506d1ac82STomohiro Kusumi strerror(error));
476917508cdSTomohiro Kusumi } else {
477917508cdSTomohiro Kusumi printf("destroy %lld in `%s'\n",
478917508cdSTomohiro Kusumi (long long)h2_opt->destroy_inum, image);
47906d1ac82STomohiro Kusumi error = hammer2_destroy_inum(vroot,
48006d1ac82STomohiro Kusumi h2_opt->destroy_inum);
48106d1ac82STomohiro Kusumi if (error)
48206d1ac82STomohiro Kusumi errx(1, "destroy %lld in `%s' failed '%s'",
48306d1ac82STomohiro Kusumi (long long)h2_opt->destroy_inum, image,
48406d1ac82STomohiro Kusumi strerror(error));
485917508cdSTomohiro Kusumi }
486917508cdSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_destroy");
4879a149651STomohiro Kusumi break;
4889a149651STomohiro Kusumi case HAMMER2IOC_GROWFS:
489afa5234bSTomohiro Kusumi printf("growfs `%s'\n", image);
490afa5234bSTomohiro Kusumi TIMER_START(start);
49106d1ac82STomohiro Kusumi error = hammer2_growfs(vroot, h2_opt->image_size);
49206d1ac82STomohiro Kusumi if (error)
49306d1ac82STomohiro Kusumi errx(1, "growfs `%s' failed '%s'", image,
49406d1ac82STomohiro Kusumi strerror(error));
495afa5234bSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_growfs");
4969a149651STomohiro Kusumi break;
497fc4148feSTomohiro Kusumi case HAMMER2IOC_READ:
498fc4148feSTomohiro Kusumi printf("read `%s'\n", image);
499fc4148feSTomohiro Kusumi TIMER_START(start);
500fc4148feSTomohiro Kusumi error = hammer2_readx(vroot, dir, h2_opt->read_path);
501fc4148feSTomohiro Kusumi if (error)
502fc4148feSTomohiro Kusumi errx(1, "read `%s' failed '%s'", image,
503fc4148feSTomohiro Kusumi strerror(error));
504fc4148feSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_readx");
505fc4148feSTomohiro Kusumi break;
5069a149651STomohiro Kusumi default:
507b4807901STomohiro Kusumi printf("populating `%s'\n", image);
508b4807901STomohiro Kusumi TIMER_START(start);
509b4807901STomohiro Kusumi if (hammer2_populate_dir(vroot, dir, root, root, fsopts, 0))
510b4807901STomohiro Kusumi errx(1, "image file `%s' not populated", image);
511b4807901STomohiro Kusumi TIMER_RESULTS(start, "hammer2_populate_dir");
5129a149651STomohiro Kusumi break;
513a63188c8STomohiro Kusumi }
5142d60b848STomohiro Kusumi
5152d60b848STomohiro Kusumi /* unmount image */
5162d60b848STomohiro Kusumi error = hammer2_vfs_unmount(&mp, 0);
5172d60b848STomohiro Kusumi if (error)
5182d60b848STomohiro Kusumi errx(1, "failed to unmount, error %d", error);
5192d60b848STomohiro Kusumi
5202d60b848STomohiro Kusumi /* check leaked resource */
5212d60b848STomohiro Kusumi if (vnode_count)
522f8a1147cSTomohiro Kusumi printf("XXX %lld vnode left\n", (long long)vnode_count);
5232d60b848STomohiro Kusumi if (hammer2_chain_allocs)
5242d60b848STomohiro Kusumi printf("XXX %ld chain left\n", hammer2_chain_allocs);
5252d60b848STomohiro Kusumi bcleanup();
5262d60b848STomohiro Kusumi
5272d60b848STomohiro Kusumi /* vfs uninit */
5282d60b848STomohiro Kusumi error = hammer2_vfs_uninit();
5292d60b848STomohiro Kusumi if (error)
5302d60b848STomohiro Kusumi errx(1, "failed to vfs uninit, error %d", error);
5312d60b848STomohiro Kusumi
5322d60b848STomohiro Kusumi if (close(fsopts->fd) == -1)
5332d60b848STomohiro Kusumi err(1, "closing `%s'", image);
5342d60b848STomohiro Kusumi fsopts->fd = -1;
5352d60b848STomohiro Kusumi
5362d60b848STomohiro Kusumi printf("image `%s' complete\n", image);
5372d60b848STomohiro Kusumi }
5382d60b848STomohiro Kusumi
5392d60b848STomohiro Kusumi /* end of public functions */
5402d60b848STomohiro Kusumi
5413999233bSTomohiro Kusumi static void
hammer2_parse_pfs_opts(const char * buf,fsinfo_t * fsopts)5423999233bSTomohiro Kusumi hammer2_parse_pfs_opts(const char *buf, fsinfo_t *fsopts)
5433999233bSTomohiro Kusumi {
5443999233bSTomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
5453999233bSTomohiro Kusumi char *o, *p;
5463999233bSTomohiro Kusumi size_t n;
5473999233bSTomohiro Kusumi
5483999233bSTomohiro Kusumi o = p = strdup(buf);
5493999233bSTomohiro Kusumi p = strchr(p, ':');
5503999233bSTomohiro Kusumi if (p != NULL) {
5513999233bSTomohiro Kusumi *p++ = 0;
5523999233bSTomohiro Kusumi n = strlen(p);
5533999233bSTomohiro Kusumi } else {
5543999233bSTomohiro Kusumi n = 0;
5553999233bSTomohiro Kusumi }
5563999233bSTomohiro Kusumi
5573999233bSTomohiro Kusumi if (!strcmp(o, "get") || !strcmp(o, "list")) {
5589a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_GET;
5593999233bSTomohiro Kusumi } else if (!strcmp(o, "lookup")) {
5603999233bSTomohiro Kusumi if (n == 0 || n > NAME_MAX)
5613999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p);
5629a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_LOOKUP;
5633999233bSTomohiro Kusumi } else if (!strcmp(o, "create")) {
5643999233bSTomohiro Kusumi if (n == 0 || n > NAME_MAX)
5653999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p);
5669a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_CREATE;
5673999233bSTomohiro Kusumi } else if (!strcmp(o, "delete")) {
5683999233bSTomohiro Kusumi if (n == 0 || n > NAME_MAX)
5693999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p);
5709a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_DELETE;
5713999233bSTomohiro Kusumi } else if (!strcmp(o, "snapshot")) {
5723999233bSTomohiro Kusumi if (n > NAME_MAX)
5733999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p);
5749a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_SNAPSHOT;
5753999233bSTomohiro Kusumi } else {
5763999233bSTomohiro Kusumi errx(1, "invalid PFS command \"%s\"", o);
5773999233bSTomohiro Kusumi }
5783999233bSTomohiro Kusumi
5793999233bSTomohiro Kusumi strlcpy(h2_opt->pfs_cmd_name, o, sizeof(h2_opt->pfs_cmd_name));
5803999233bSTomohiro Kusumi if (n > 0)
5813999233bSTomohiro Kusumi strlcpy(h2_opt->pfs_name, p, sizeof(h2_opt->pfs_name));
5823999233bSTomohiro Kusumi
5833999233bSTomohiro Kusumi free(o);
5843999233bSTomohiro Kusumi }
5853999233bSTomohiro Kusumi
586f804c425STomohiro Kusumi static void
hammer2_parse_inode_opts(const char * buf,fsinfo_t * fsopts)587f804c425STomohiro Kusumi hammer2_parse_inode_opts(const char *buf, fsinfo_t *fsopts)
588f804c425STomohiro Kusumi {
589f804c425STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
590f804c425STomohiro Kusumi char *o, *p;
591f804c425STomohiro Kusumi size_t n;
592f804c425STomohiro Kusumi
593f804c425STomohiro Kusumi o = p = strdup(buf);
594f804c425STomohiro Kusumi p = strchr(p, ':');
595f804c425STomohiro Kusumi if (p != NULL) {
596f804c425STomohiro Kusumi *p++ = 0;
597f804c425STomohiro Kusumi n = strlen(p);
598f804c425STomohiro Kusumi } else {
599f804c425STomohiro Kusumi n = 0;
600f804c425STomohiro Kusumi }
601f804c425STomohiro Kusumi
602f804c425STomohiro Kusumi if (!strcmp(o, "get")) {
603f804c425STomohiro Kusumi if (n == 0 || n > PATH_MAX)
604f804c425STomohiro Kusumi errx(1, "invalid file path \"%s\"", p);
605f804c425STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_INODE_GET;
606465e1141STomohiro Kusumi } else if (!strcmp(o, "setcheck")) {
607465e1141STomohiro Kusumi if (n == 0 || n > PATH_MAX - 10)
608465e1141STomohiro Kusumi errx(1, "invalid argument \"%s\"", p);
609465e1141STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_INODE_SET;
610465e1141STomohiro Kusumi } else if (!strcmp(o, "setcomp")) {
611465e1141STomohiro Kusumi if (n == 0 || n > PATH_MAX - 10)
612465e1141STomohiro Kusumi errx(1, "invalid argument \"%s\"", p);
613465e1141STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_INODE_SET;
614f804c425STomohiro Kusumi } else {
615f804c425STomohiro Kusumi errx(1, "invalid inode command \"%s\"", o);
616f804c425STomohiro Kusumi }
617f804c425STomohiro Kusumi
618465e1141STomohiro Kusumi strlcpy(h2_opt->inode_cmd_name, o, sizeof(h2_opt->inode_cmd_name));
6196857f034STomohiro Kusumi if (n > 0)
620f804c425STomohiro Kusumi strlcpy(h2_opt->inode_path, p, sizeof(h2_opt->inode_path));
621f804c425STomohiro Kusumi
622f804c425STomohiro Kusumi free(o);
623f804c425STomohiro Kusumi }
624f804c425STomohiro Kusumi
6252d60b848STomohiro Kusumi static hammer2_off_t
hammer2_image_size(fsinfo_t * fsopts)6262d60b848STomohiro Kusumi hammer2_image_size(fsinfo_t *fsopts)
6272d60b848STomohiro Kusumi {
6282d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
6292d60b848STomohiro Kusumi hammer2_off_t image_size, used_size = 0;
6302d60b848STomohiro Kusumi int num_level1, delta_num_level1;
6312d60b848STomohiro Kusumi
6322d60b848STomohiro Kusumi /* use 4 volume headers by default */
6332d60b848STomohiro Kusumi num_level1 = h2_opt->num_volhdr * 2; /* default 4 x 2 */
6342d60b848STomohiro Kusumi assert(num_level1 != 0);
6352d60b848STomohiro Kusumi assert(num_level1 <= 8);
6362d60b848STomohiro Kusumi
6372d60b848STomohiro Kusumi /* add 4MiB segment for each level1 */
6382d60b848STomohiro Kusumi used_size += HAMMER2_ZONE_SEG64 * num_level1;
6392d60b848STomohiro Kusumi
6402d60b848STomohiro Kusumi /* add boot/aux area, but exact size unknown at this point */
6412d60b848STomohiro Kusumi used_size += HAMMER2_BOOT_NOM_BYTES + HAMMER2_AUX_NOM_BYTES;
6422d60b848STomohiro Kusumi
6432d60b848STomohiro Kusumi /* add data size */
6442d60b848STomohiro Kusumi used_size += fsopts->size;
6452d60b848STomohiro Kusumi
6462d60b848STomohiro Kusumi /* XXX add extra level1 for meta data and indirect blocks */
6472d60b848STomohiro Kusumi used_size += HAMMER2_FREEMAP_LEVEL1_SIZE;
6482d60b848STomohiro Kusumi
6492d60b848STomohiro Kusumi /* XXX add extra level1 for safety */
6502d60b848STomohiro Kusumi if (used_size > HAMMER2_FREEMAP_LEVEL1_SIZE * 10)
6512d60b848STomohiro Kusumi used_size += HAMMER2_FREEMAP_LEVEL1_SIZE;
6522d60b848STomohiro Kusumi
6532d60b848STomohiro Kusumi /* use 8GiB image size by default */
6542d60b848STomohiro Kusumi image_size = HAMMER2_FREEMAP_LEVEL1_SIZE * num_level1;
6552d60b848STomohiro Kusumi printf("trying default image size %s\n", sizetostr(image_size));
6562d60b848STomohiro Kusumi
6572d60b848STomohiro Kusumi /* adjust if image size isn't large enough */
6582d60b848STomohiro Kusumi if (used_size > image_size) {
6592d60b848STomohiro Kusumi /* determine extra level1 needed */
6602d60b848STomohiro Kusumi delta_num_level1 = howmany(used_size - image_size,
6612d60b848STomohiro Kusumi HAMMER2_FREEMAP_LEVEL1_SIZE);
6622d60b848STomohiro Kusumi
6632d60b848STomohiro Kusumi /* adjust used size with 4MiB segment for each extra level1 */
6642d60b848STomohiro Kusumi used_size += HAMMER2_ZONE_SEG64 * delta_num_level1;
6652d60b848STomohiro Kusumi
6662d60b848STomohiro Kusumi /* adjust image size with extra level1 */
6672d60b848STomohiro Kusumi image_size += HAMMER2_FREEMAP_LEVEL1_SIZE * delta_num_level1;
6682d60b848STomohiro Kusumi printf("trying adjusted image size %s\n",
6692d60b848STomohiro Kusumi sizetostr(image_size));
6702d60b848STomohiro Kusumi
6712d60b848STomohiro Kusumi if (used_size > image_size)
672f8a1147cSTomohiro Kusumi errx(1, "invalid used_size %lld > image_size %lld",
673f8a1147cSTomohiro Kusumi (long long)used_size, (long long)image_size);
6742d60b848STomohiro Kusumi }
6752d60b848STomohiro Kusumi
6762d60b848STomohiro Kusumi return image_size;
6772d60b848STomohiro Kusumi }
6782d60b848STomohiro Kusumi
6792d60b848STomohiro Kusumi static const char *
hammer2_label_name(int label_type)6802d60b848STomohiro Kusumi hammer2_label_name(int label_type)
6812d60b848STomohiro Kusumi {
6822d60b848STomohiro Kusumi switch (label_type) {
6832d60b848STomohiro Kusumi case HAMMER2_LABEL_NONE:
6842d60b848STomohiro Kusumi return "NONE";
6852d60b848STomohiro Kusumi case HAMMER2_LABEL_BOOT:
6862d60b848STomohiro Kusumi return "BOOT";
6872d60b848STomohiro Kusumi case HAMMER2_LABEL_ROOT:
6882d60b848STomohiro Kusumi return "ROOT";
6892d60b848STomohiro Kusumi case HAMMER2_LABEL_DATA:
6902d60b848STomohiro Kusumi return "DATA";
6912d60b848STomohiro Kusumi default:
6922d60b848STomohiro Kusumi assert(0);
6932d60b848STomohiro Kusumi }
6942d60b848STomohiro Kusumi return NULL;
6952d60b848STomohiro Kusumi }
6962d60b848STomohiro Kusumi
6972d60b848STomohiro Kusumi static void
hammer2_validate(const char * dir,fsnode * root,fsinfo_t * fsopts)6982d60b848STomohiro Kusumi hammer2_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
6992d60b848STomohiro Kusumi {
7002d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
7012d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
702afa5234bSTomohiro Kusumi hammer2_off_t image_size = 0, minsize, maxsize;
7032d60b848STomohiro Kusumi const char *s;
7042d60b848STomohiro Kusumi
70570e962f7STomohiro Kusumi /* ioctl commands could have NULL dir / root */
7062d60b848STomohiro Kusumi assert(fsopts != NULL);
7072d60b848STomohiro Kusumi
7082d60b848STomohiro Kusumi if (debug & DEBUG_FS_VALIDATE) {
7092d60b848STomohiro Kusumi APRINTF("before defaults set:\n");
7102d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsopts);
7112d60b848STomohiro Kusumi }
7122d60b848STomohiro Kusumi
7132d60b848STomohiro Kusumi /* makefs only supports "DATA" for default PFS label */
7142d60b848STomohiro Kusumi if (!h2_opt->label_specified) {
7152d60b848STomohiro Kusumi opt->DefaultLabelType = HAMMER2_LABEL_DATA;
7162d60b848STomohiro Kusumi s = hammer2_label_name(opt->DefaultLabelType);
7172d60b848STomohiro Kusumi printf("using default label \"%s\"\n", s);
7182d60b848STomohiro Kusumi }
7192d60b848STomohiro Kusumi
7202d60b848STomohiro Kusumi /* set default mount PFS label */
7212d60b848STomohiro Kusumi if (!strcmp(h2_opt->mount_label, "")) {
7222d60b848STomohiro Kusumi s = hammer2_label_name(HAMMER2_LABEL_DATA);
7232d60b848STomohiro Kusumi strlcpy(h2_opt->mount_label, s, sizeof(h2_opt->mount_label));
7242d60b848STomohiro Kusumi printf("using default mount label \"%s\"\n", s);
7252d60b848STomohiro Kusumi }
7262d60b848STomohiro Kusumi
7272d60b848STomohiro Kusumi /* set default number of volume headers */
7282d60b848STomohiro Kusumi if (!h2_opt->num_volhdr) {
7292d60b848STomohiro Kusumi h2_opt->num_volhdr = HAMMER2_NUM_VOLHDRS;
7302d60b848STomohiro Kusumi printf("using default %d volume headers\n", h2_opt->num_volhdr);
7312d60b848STomohiro Kusumi }
7322d60b848STomohiro Kusumi
733917508cdSTomohiro Kusumi /* done if ioctl commands */
7349a149651STomohiro Kusumi if (h2_opt->ioctl_cmd) {
7359a149651STomohiro Kusumi if (h2_opt->ioctl_cmd == HAMMER2IOC_GROWFS)
736afa5234bSTomohiro Kusumi goto ignore_size_dir;
7379a149651STomohiro Kusumi else
7389a149651STomohiro Kusumi goto done;
7399a149651STomohiro Kusumi }
740a63188c8STomohiro Kusumi
7412d60b848STomohiro Kusumi /* calculate data size */
7422d60b848STomohiro Kusumi if (fsopts->size != 0)
7432d60b848STomohiro Kusumi fsopts->size = 0; /* shouldn't reach here to begin with */
744a63188c8STomohiro Kusumi if (root == NULL)
745a63188c8STomohiro Kusumi errx(1, "fsnode tree not constructed");
7462d60b848STomohiro Kusumi hammer2_size_dir(root, fsopts);
7472d60b848STomohiro Kusumi printf("estimated data size %s from %lld inode\n",
7482d60b848STomohiro Kusumi sizetostr(fsopts->size), (long long)fsopts->inodes);
7492d60b848STomohiro Kusumi
7502d60b848STomohiro Kusumi /* determine image size from data size */
7512d60b848STomohiro Kusumi image_size = hammer2_image_size(fsopts);
7522d60b848STomohiro Kusumi assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0);
753afa5234bSTomohiro Kusumi ignore_size_dir:
7542d60b848STomohiro Kusumi minsize = roundup(fsopts->minsize, HAMMER2_FREEMAP_LEVEL1_SIZE);
7552d60b848STomohiro Kusumi maxsize = roundup(fsopts->maxsize, HAMMER2_FREEMAP_LEVEL1_SIZE);
7562d60b848STomohiro Kusumi if (image_size < minsize)
7572d60b848STomohiro Kusumi image_size = minsize;
7582d60b848STomohiro Kusumi else if (maxsize > 0 && image_size > maxsize)
759f8a1147cSTomohiro Kusumi errx(1, "`%s' size of %lld is larger than the maxsize of %lld",
760f8a1147cSTomohiro Kusumi dir, (long long)image_size, (long long)maxsize);
7612d60b848STomohiro Kusumi
7622d60b848STomohiro Kusumi assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0);
7632d60b848STomohiro Kusumi h2_opt->image_size = image_size;
7642d60b848STomohiro Kusumi printf("using %s image size\n", sizetostr(h2_opt->image_size));
765a63188c8STomohiro Kusumi done:
7662d60b848STomohiro Kusumi if (debug & DEBUG_FS_VALIDATE) {
7672d60b848STomohiro Kusumi APRINTF("after defaults set:\n");
7682d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsopts);
7692d60b848STomohiro Kusumi }
7702d60b848STomohiro Kusumi }
7712d60b848STomohiro Kusumi
7722d60b848STomohiro Kusumi static void
hammer2_dump_fsinfo(fsinfo_t * fsopts)7732d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsinfo_t *fsopts)
7742d60b848STomohiro Kusumi {
7752d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
7762d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
7772d60b848STomohiro Kusumi int i;
7782d60b848STomohiro Kusumi char *s;
7792d60b848STomohiro Kusumi
7802d60b848STomohiro Kusumi assert(fsopts != NULL);
7812d60b848STomohiro Kusumi
7822d60b848STomohiro Kusumi APRINTF("fsinfo_t at %p\n", fsopts);
7832d60b848STomohiro Kusumi
7842d60b848STomohiro Kusumi printf("\tinodes %lld\n", (long long)fsopts->inodes);
7852d60b848STomohiro Kusumi printf("\tsize %lld, minsize %lld, maxsize %lld\n",
7862d60b848STomohiro Kusumi (long long)fsopts->size,
7872d60b848STomohiro Kusumi (long long)fsopts->minsize,
7882d60b848STomohiro Kusumi (long long)fsopts->maxsize);
7892d60b848STomohiro Kusumi
7902d60b848STomohiro Kusumi printf("\thammer2_debug 0x%x\n", hammer2_debug);
7912d60b848STomohiro Kusumi
7922d60b848STomohiro Kusumi printf("\tlabel_specified %d\n", h2_opt->label_specified);
7932d60b848STomohiro Kusumi printf("\tmount_label \"%s\"\n", h2_opt->mount_label);
7942d60b848STomohiro Kusumi printf("\tnum_volhdr %d\n", h2_opt->num_volhdr);
7959a149651STomohiro Kusumi printf("\tioctl_cmd %ld\n", h2_opt->ioctl_cmd);
79648ed4577STomohiro Kusumi printf("\temergency_mode %d\n", h2_opt->emergency_mode);
7973999233bSTomohiro Kusumi printf("\tpfs_cmd_name \"%s\"\n", h2_opt->pfs_cmd_name);
7983999233bSTomohiro Kusumi printf("\tpfs_name \"%s\"\n", h2_opt->pfs_name);
799465e1141STomohiro Kusumi printf("\tinode_cmd_name \"%s\"\n", h2_opt->inode_cmd_name);
800f804c425STomohiro Kusumi printf("\tinode_path \"%s\"\n", h2_opt->inode_path);
801917508cdSTomohiro Kusumi printf("\tdestroy_path \"%s\"\n", h2_opt->destroy_path);
802917508cdSTomohiro Kusumi printf("\tdestroy_inum %lld\n", (long long)h2_opt->destroy_inum);
8035e8b0eb7STomohiro Kusumi printf("\tread_path \"%s\"\n", h2_opt->read_path);
804f8a1147cSTomohiro Kusumi printf("\timage_size 0x%llx\n", (long long)h2_opt->image_size);
8052d60b848STomohiro Kusumi
8062d60b848STomohiro Kusumi printf("\tHammer2Version %d\n", opt->Hammer2Version);
8072d60b848STomohiro Kusumi printf("\tBootAreaSize 0x%jx\n", opt->BootAreaSize);
8082d60b848STomohiro Kusumi printf("\tAuxAreaSize 0x%jx\n", opt->AuxAreaSize);
8092d60b848STomohiro Kusumi printf("\tNLabels %d\n", opt->NLabels);
8102d60b848STomohiro Kusumi printf("\tCompType %d\n", opt->CompType);
8112d60b848STomohiro Kusumi printf("\tCheckType %d\n", opt->CheckType);
8122d60b848STomohiro Kusumi printf("\tDefaultLabelType %d\n", opt->DefaultLabelType);
8132d60b848STomohiro Kusumi printf("\tDebugOpt %d\n", opt->DebugOpt);
8142d60b848STomohiro Kusumi
8152d60b848STomohiro Kusumi s = NULL;
8162d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_FSType, &s);
8172d60b848STomohiro Kusumi printf("\tHammer2_FSType \"%s\"\n", s);
8182d60b848STomohiro Kusumi s = NULL;
8192d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_VolFSID, &s);
8202d60b848STomohiro Kusumi printf("\tHammer2_VolFSID \"%s\"\n", s);
8212d60b848STomohiro Kusumi s = NULL;
8222d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_SupCLID, &s);
8232d60b848STomohiro Kusumi printf("\tHammer2_SupCLID \"%s\"\n", s);
8242d60b848STomohiro Kusumi s = NULL;
8252d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_SupFSID, &s);
8262d60b848STomohiro Kusumi printf("\tHammer2_SupFSID \"%s\"\n", s);
8272d60b848STomohiro Kusumi
8282d60b848STomohiro Kusumi for (i = 0; i < opt->NLabels; i++) {
8292d60b848STomohiro Kusumi printf("\tLabel[%d] \"%s\"\n", i, opt->Label[i]);
8302d60b848STomohiro Kusumi s = NULL;
8312d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_PfsCLID[i], &s);
8322d60b848STomohiro Kusumi printf("\t Hammer2_PfsCLID[%d] \"%s\"\n", i, s);
8332d60b848STomohiro Kusumi s = NULL;
8342d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_PfsFSID[i], &s);
8352d60b848STomohiro Kusumi printf("\t Hammer2_PfsFSID[%d] \"%s\"\n", i, s);
8362d60b848STomohiro Kusumi }
8372d60b848STomohiro Kusumi
8382d60b848STomohiro Kusumi free(s);
8392d60b848STomohiro Kusumi }
8402d60b848STomohiro Kusumi
8412d60b848STomohiro Kusumi static int
hammer2_setup_blkdev(const char * image,fsinfo_t * fsopts)842*764bf12eSTomohiro Kusumi hammer2_setup_blkdev(const char *image, fsinfo_t *fsopts)
843*764bf12eSTomohiro Kusumi {
844*764bf12eSTomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
845*764bf12eSTomohiro Kusumi hammer2_off_t size;
846*764bf12eSTomohiro Kusumi
847*764bf12eSTomohiro Kusumi if ((fsopts->fd = open(image, O_RDWR)) == -1) {
848*764bf12eSTomohiro Kusumi warn("can't open `%s' for writing", image);
849*764bf12eSTomohiro Kusumi return -1;
850*764bf12eSTomohiro Kusumi }
851*764bf12eSTomohiro Kusumi
852*764bf12eSTomohiro Kusumi size = check_volume(fsopts->fd);
853*764bf12eSTomohiro Kusumi if (h2_opt->image_size > size) {
854*764bf12eSTomohiro Kusumi warnx("image size %lld exceeds %s size %lld",
855*764bf12eSTomohiro Kusumi (long long)h2_opt->image_size, image, (long long)size);
856*764bf12eSTomohiro Kusumi return -1;
857*764bf12eSTomohiro Kusumi }
858*764bf12eSTomohiro Kusumi
859*764bf12eSTomohiro Kusumi return 0;
860*764bf12eSTomohiro Kusumi }
861*764bf12eSTomohiro Kusumi
862*764bf12eSTomohiro Kusumi static int
hammer2_create_image(const char * image,fsinfo_t * fsopts)8632d60b848STomohiro Kusumi hammer2_create_image(const char *image, fsinfo_t *fsopts)
8642d60b848STomohiro Kusumi {
8652d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific;
8662d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options;
8672d60b848STomohiro Kusumi char *av[] = { (char *)image, }; /* XXX support multi-volumes */
8682d60b848STomohiro Kusumi char *buf;
8692d60b848STomohiro Kusumi int i, bufsize, oflags;
8702d60b848STomohiro Kusumi off_t bufrem;
871*764bf12eSTomohiro Kusumi struct stat st;
8722d60b848STomohiro Kusumi
8732d60b848STomohiro Kusumi assert(image != NULL);
8742d60b848STomohiro Kusumi assert(fsopts != NULL);
8752d60b848STomohiro Kusumi
876*764bf12eSTomohiro Kusumi /* check if image is blk or chr */
877*764bf12eSTomohiro Kusumi if (stat(image, &st) == 0) {
878*764bf12eSTomohiro Kusumi if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
879*764bf12eSTomohiro Kusumi if (hammer2_setup_blkdev(image, fsopts))
880*764bf12eSTomohiro Kusumi return -1;
881*764bf12eSTomohiro Kusumi goto done;
882*764bf12eSTomohiro Kusumi }
883*764bf12eSTomohiro Kusumi }
884*764bf12eSTomohiro Kusumi
8852d60b848STomohiro Kusumi /* create image */
8862d60b848STomohiro Kusumi oflags = O_RDWR | O_CREAT;
8872d60b848STomohiro Kusumi if (fsopts->offset == 0)
8882d60b848STomohiro Kusumi oflags |= O_TRUNC;
8892d60b848STomohiro Kusumi if ((fsopts->fd = open(image, oflags, 0666)) == -1) {
8902d60b848STomohiro Kusumi warn("can't open `%s' for writing", image);
8912d60b848STomohiro Kusumi return -1;
8922d60b848STomohiro Kusumi }
8932d60b848STomohiro Kusumi
8942d60b848STomohiro Kusumi /* zero image */
8952d60b848STomohiro Kusumi bufsize = HAMMER2_PBUFSIZE;
8962d60b848STomohiro Kusumi bufrem = h2_opt->image_size;
8972d60b848STomohiro Kusumi if (fsopts->sparse) {
8982d60b848STomohiro Kusumi if (ftruncate(fsopts->fd, bufrem) == -1) {
8992d60b848STomohiro Kusumi warn("sparse option disabled");
9002d60b848STomohiro Kusumi fsopts->sparse = 0;
9012d60b848STomohiro Kusumi }
9022d60b848STomohiro Kusumi }
9032d60b848STomohiro Kusumi if (fsopts->sparse) {
9042d60b848STomohiro Kusumi /* File truncated at bufrem. Remaining is 0 */
9052d60b848STomohiro Kusumi bufrem = 0;
9062d60b848STomohiro Kusumi buf = NULL;
9072d60b848STomohiro Kusumi } else {
9082d60b848STomohiro Kusumi if (debug & DEBUG_FS_CREATE_IMAGE)
9092d60b848STomohiro Kusumi APRINTF("zero-ing image `%s', %lld sectors, "
9102d60b848STomohiro Kusumi "using %d byte chunks\n",
9112d60b848STomohiro Kusumi image, (long long)bufrem, bufsize);
9122d60b848STomohiro Kusumi buf = ecalloc(1, bufsize);
9132d60b848STomohiro Kusumi }
9142d60b848STomohiro Kusumi
9152d60b848STomohiro Kusumi if (fsopts->offset != 0) {
9162d60b848STomohiro Kusumi if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) {
9172d60b848STomohiro Kusumi warn("can't seek");
9182d60b848STomohiro Kusumi free(buf);
9192d60b848STomohiro Kusumi return -1;
9202d60b848STomohiro Kusumi }
9212d60b848STomohiro Kusumi }
9222d60b848STomohiro Kusumi
9232d60b848STomohiro Kusumi while (bufrem > 0) {
9242d60b848STomohiro Kusumi i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
9252d60b848STomohiro Kusumi if (i == -1) {
9262d60b848STomohiro Kusumi warn("zeroing image, %lld bytes to go",
9272d60b848STomohiro Kusumi (long long)bufrem);
9282d60b848STomohiro Kusumi free(buf);
9292d60b848STomohiro Kusumi return -1;
9302d60b848STomohiro Kusumi }
9312d60b848STomohiro Kusumi bufrem -= i;
9322d60b848STomohiro Kusumi }
9332d60b848STomohiro Kusumi if (buf)
9342d60b848STomohiro Kusumi free(buf);
935*764bf12eSTomohiro Kusumi done:
9362d60b848STomohiro Kusumi /* make the file system */
9372d60b848STomohiro Kusumi if (debug & DEBUG_FS_CREATE_IMAGE)
9382d60b848STomohiro Kusumi APRINTF("calling mkfs(\"%s\", ...)\n", image);
9392d60b848STomohiro Kusumi hammer2_mkfs(1, av, opt); /* success if returned */
9402d60b848STomohiro Kusumi
9412d60b848STomohiro Kusumi return fsopts->fd;
9422d60b848STomohiro Kusumi }
9432d60b848STomohiro Kusumi
9442d60b848STomohiro Kusumi static off_t
hammer2_phys_size(off_t size)9452d60b848STomohiro Kusumi hammer2_phys_size(off_t size)
9462d60b848STomohiro Kusumi {
9472d60b848STomohiro Kusumi off_t radix_size, phys_size = 0;
9482d60b848STomohiro Kusumi int i;
9492d60b848STomohiro Kusumi
9502d60b848STomohiro Kusumi if (size > HAMMER2_PBUFSIZE) {
9512d60b848STomohiro Kusumi phys_size += rounddown(size, HAMMER2_PBUFSIZE);
9522d60b848STomohiro Kusumi size = size % HAMMER2_PBUFSIZE;
9532d60b848STomohiro Kusumi }
9542d60b848STomohiro Kusumi
9552d60b848STomohiro Kusumi for (i = HAMMER2_RADIX_MIN; i <= HAMMER2_RADIX_MAX; i++) {
9562d60b848STomohiro Kusumi radix_size = 1UL << i;
9572d60b848STomohiro Kusumi if (radix_size >= size) {
9582d60b848STomohiro Kusumi phys_size += radix_size;
9592d60b848STomohiro Kusumi break;
9602d60b848STomohiro Kusumi }
9612d60b848STomohiro Kusumi }
9622d60b848STomohiro Kusumi
9632d60b848STomohiro Kusumi return phys_size;
9642d60b848STomohiro Kusumi }
9652d60b848STomohiro Kusumi
9662d60b848STomohiro Kusumi /* calculate data size */
9672d60b848STomohiro Kusumi static void
hammer2_size_dir(fsnode * root,fsinfo_t * fsopts)9682d60b848STomohiro Kusumi hammer2_size_dir(fsnode *root, fsinfo_t *fsopts)
9692d60b848STomohiro Kusumi {
9702d60b848STomohiro Kusumi fsnode *node;
9712d60b848STomohiro Kusumi
9722d60b848STomohiro Kusumi assert(fsopts != NULL);
9732d60b848STomohiro Kusumi
9742d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR)
9752d60b848STomohiro Kusumi APRINTF("entry: bytes %lld inodes %lld\n",
9762d60b848STomohiro Kusumi (long long)fsopts->size, (long long)fsopts->inodes);
9772d60b848STomohiro Kusumi
9782d60b848STomohiro Kusumi for (node = root; node != NULL; node = node->next) {
9792d60b848STomohiro Kusumi if (node == root) { /* we're at "." */
9802d60b848STomohiro Kusumi assert(strcmp(node->name, ".") == 0);
9812d60b848STomohiro Kusumi } else if ((node->inode->flags & FI_SIZED) == 0) {
9822d60b848STomohiro Kusumi /* don't count duplicate names */
9832d60b848STomohiro Kusumi node->inode->flags |= FI_SIZED;
9842d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR_NODE)
9852d60b848STomohiro Kusumi APRINTF("`%s' size %lld\n",
9862d60b848STomohiro Kusumi node->name,
9872d60b848STomohiro Kusumi (long long)node->inode->st.st_size);
9882d60b848STomohiro Kusumi fsopts->inodes++;
9892d60b848STomohiro Kusumi fsopts->size += sizeof(hammer2_inode_data_t);
9902d60b848STomohiro Kusumi if (node->type == S_IFREG) {
9912d60b848STomohiro Kusumi size_t st_size = node->inode->st.st_size;
9922d60b848STomohiro Kusumi if (st_size > HAMMER2_EMBEDDED_BYTES)
9932d60b848STomohiro Kusumi fsopts->size += hammer2_phys_size(st_size);
9942d60b848STomohiro Kusumi } else if (node->type == S_IFLNK) {
9952d60b848STomohiro Kusumi size_t nlen = strlen(node->symlink);
9962d60b848STomohiro Kusumi if (nlen > HAMMER2_EMBEDDED_BYTES)
9972d60b848STomohiro Kusumi fsopts->size += hammer2_phys_size(nlen);
9982d60b848STomohiro Kusumi }
9992d60b848STomohiro Kusumi }
10002d60b848STomohiro Kusumi if (node->type == S_IFDIR)
10012d60b848STomohiro Kusumi hammer2_size_dir(node->child, fsopts);
10022d60b848STomohiro Kusumi }
10032d60b848STomohiro Kusumi
10042d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR)
10052d60b848STomohiro Kusumi APRINTF("exit: size %lld inodes %lld\n",
10062d60b848STomohiro Kusumi (long long)fsopts->size, (long long)fsopts->inodes);
10072d60b848STomohiro Kusumi }
10082d60b848STomohiro Kusumi
10092d60b848STomohiro Kusumi static void
hammer2_print(const struct m_vnode * dvp,const struct m_vnode * vp,const fsnode * node,int depth,const char * msg)10106bcbb706STomohiro Kusumi hammer2_print(const struct m_vnode *dvp, const struct m_vnode *vp,
10112d60b848STomohiro Kusumi const fsnode *node, int depth, const char *msg)
10122d60b848STomohiro Kusumi {
10132d60b848STomohiro Kusumi if (debug & DEBUG_FS_POPULATE) {
10142d60b848STomohiro Kusumi if (1) {
10152d60b848STomohiro Kusumi int indent = depth * 2;
10162d60b848STomohiro Kusumi char *type;
10172d60b848STomohiro Kusumi if (S_ISDIR(node->type))
10182d60b848STomohiro Kusumi type = "dir";
10192d60b848STomohiro Kusumi else if (S_ISREG(node->type))
10202d60b848STomohiro Kusumi type = "reg";
10212d60b848STomohiro Kusumi else if (S_ISLNK(node->type))
10222d60b848STomohiro Kusumi type = "lnk";
10234d8112c5STomohiro Kusumi else if (S_ISFIFO(node->type))
10244d8112c5STomohiro Kusumi type = "fifo";
10252d60b848STomohiro Kusumi else
10262d60b848STomohiro Kusumi type = "???";
10272d60b848STomohiro Kusumi printf("%*.*s", indent, indent, "");
10282d60b848STomohiro Kusumi printf("dvp=%p/%d vp=%p/%d \"%s\" %s %s\n",
10292d60b848STomohiro Kusumi dvp, dvp ? VTOI(dvp)->refs : 0,
10302d60b848STomohiro Kusumi vp, vp ? VTOI(vp)->refs : 0,
10312d60b848STomohiro Kusumi node->name, type, msg);
10322d60b848STomohiro Kusumi } else {
10332d60b848STomohiro Kusumi char type;
10342d60b848STomohiro Kusumi if (S_ISDIR(node->type))
10352d60b848STomohiro Kusumi type = 'd';
10362d60b848STomohiro Kusumi else if (S_ISREG(node->type))
10372d60b848STomohiro Kusumi type = 'r';
10382d60b848STomohiro Kusumi else if (S_ISLNK(node->type))
10392d60b848STomohiro Kusumi type = 'l';
10404d8112c5STomohiro Kusumi else if (S_ISFIFO(node->type))
10414d8112c5STomohiro Kusumi type = 'f';
10422d60b848STomohiro Kusumi else
10432d60b848STomohiro Kusumi type = '?';
10442d60b848STomohiro Kusumi printf("%c", type);
10452d60b848STomohiro Kusumi fflush(stdout);
10462d60b848STomohiro Kusumi }
10472d60b848STomohiro Kusumi }
10482d60b848STomohiro Kusumi }
10492d60b848STomohiro Kusumi
10502d60b848STomohiro Kusumi static int
hammer2_populate_dir(struct m_vnode * dvp,const char * dir,fsnode * root,fsnode * parent,fsinfo_t * fsopts,int depth)10516bcbb706STomohiro Kusumi hammer2_populate_dir(struct m_vnode *dvp, const char *dir, fsnode *root,
10522d60b848STomohiro Kusumi fsnode *parent, fsinfo_t *fsopts, int depth)
10532d60b848STomohiro Kusumi {
10542d60b848STomohiro Kusumi fsnode *cur;
10556bcbb706STomohiro Kusumi struct m_vnode *vp;
10562d60b848STomohiro Kusumi struct stat st;
10572d60b848STomohiro Kusumi char f[MAXPATHLEN];
10582d60b848STomohiro Kusumi const char *path;
1059213ebac1STomohiro Kusumi int hardlink;
10602d60b848STomohiro Kusumi int error;
10612d60b848STomohiro Kusumi
10622d60b848STomohiro Kusumi assert(dvp != NULL);
10632d60b848STomohiro Kusumi assert(dir != NULL);
10642d60b848STomohiro Kusumi assert(root != NULL);
10652d60b848STomohiro Kusumi assert(parent != NULL);
10662d60b848STomohiro Kusumi assert(fsopts != NULL);
10672d60b848STomohiro Kusumi
10682d60b848STomohiro Kusumi /* assert root directory */
10692d60b848STomohiro Kusumi assert(S_ISDIR(root->type));
10702d60b848STomohiro Kusumi assert(!strcmp(root->name, "."));
10712d60b848STomohiro Kusumi assert(!root->child);
10722d60b848STomohiro Kusumi assert(!root->parent || root->parent->child == root);
10732d60b848STomohiro Kusumi
10742d60b848STomohiro Kusumi hammer2_print(dvp, NULL, root, depth, "enter");
10752d60b848STomohiro Kusumi if (stat(dir, &st) == -1)
10762d60b848STomohiro Kusumi err(1, "no such path %s", dir);
10772d60b848STomohiro Kusumi if (!S_ISDIR(st.st_mode))
10782d60b848STomohiro Kusumi errx(1, "no such dir %s", dir);
10792d60b848STomohiro Kusumi
10802d60b848STomohiro Kusumi for (cur = root->next; cur != NULL; cur = cur->next) {
1081ddd1d3d1STomohiro Kusumi /* global variable for HAMMER2 vnops */
1082ddd1d3d1STomohiro Kusumi hammer2_curnode = cur;
1083ddd1d3d1STomohiro Kusumi
10842d60b848STomohiro Kusumi /* construct source path */
10852d60b848STomohiro Kusumi if (cur->contents) {
10862d60b848STomohiro Kusumi path = cur->contents;
10872d60b848STomohiro Kusumi } else {
10882d60b848STomohiro Kusumi if (snprintf(f, sizeof(f), "%s/%s/%s",
10892d60b848STomohiro Kusumi cur->root, cur->path, cur->name) >= (int)sizeof(f))
1090d5e693f1STomohiro Kusumi errx(1, "path %s too long", f);
10912d60b848STomohiro Kusumi path = f;
10922d60b848STomohiro Kusumi }
10932de31a7dSTomohiro Kusumi if (S_ISLNK(cur->type)) {
10942de31a7dSTomohiro Kusumi if (lstat(path, &st) == -1)
10952de31a7dSTomohiro Kusumi err(1, "no such symlink %s", path);
10962de31a7dSTomohiro Kusumi } else {
10972d60b848STomohiro Kusumi if (stat(path, &st) == -1)
10982de31a7dSTomohiro Kusumi err(1, "no such path %s", path);
10992de31a7dSTomohiro Kusumi }
11002d60b848STomohiro Kusumi
11012d60b848STomohiro Kusumi /* update node state */
11022d60b848STomohiro Kusumi if ((cur->inode->flags & FI_ALLOCATED) == 0) {
11032d60b848STomohiro Kusumi cur->inode->flags |= FI_ALLOCATED;
11042d60b848STomohiro Kusumi if (cur != root)
11052d60b848STomohiro Kusumi cur->parent = parent;
11062d60b848STomohiro Kusumi }
11072d60b848STomohiro Kusumi
1108213ebac1STomohiro Kusumi /* detect hardlink */
1109213ebac1STomohiro Kusumi if (cur->inode->flags & FI_WRITTEN) {
1110213ebac1STomohiro Kusumi assert(!S_ISDIR(cur->type));
1111213ebac1STomohiro Kusumi hardlink = 1;
1112213ebac1STomohiro Kusumi } else {
1113213ebac1STomohiro Kusumi hardlink = 0;
1114213ebac1STomohiro Kusumi }
11152d60b848STomohiro Kusumi cur->inode->flags |= FI_WRITTEN;
11162d60b848STomohiro Kusumi
11172d60b848STomohiro Kusumi /* make sure it doesn't exist yet */
11182d60b848STomohiro Kusumi vp = NULL;
11192d60b848STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, cur->name,
11202d60b848STomohiro Kusumi strlen(cur->name));
11212d60b848STomohiro Kusumi if (!error)
11222d60b848STomohiro Kusumi errx(1, "hammer2_nresolve(\"%s\") already exists",
11232d60b848STomohiro Kusumi cur->name);
11242d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nresolve");
11252d60b848STomohiro Kusumi
11262d60b848STomohiro Kusumi /* if directory, mkdir and recurse */
11272d60b848STomohiro Kusumi if (S_ISDIR(cur->type)) {
11282d60b848STomohiro Kusumi assert(cur->child);
11292d60b848STomohiro Kusumi
11302d60b848STomohiro Kusumi vp = NULL;
11312d60b848STomohiro Kusumi error = hammer2_nmkdir(dvp, &vp, cur->name,
11328f9d1da1STomohiro Kusumi strlen(cur->name), cur->inode->st.st_mode);
11332d60b848STomohiro Kusumi if (error)
11342d60b848STomohiro Kusumi errx(1, "hammer2_nmkdir(\"%s\") failed: %s",
11352d60b848STomohiro Kusumi cur->name, strerror(error));
11362d60b848STomohiro Kusumi assert(vp);
11372d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nmkdir");
11382d60b848STomohiro Kusumi
11392d60b848STomohiro Kusumi error = hammer2_populate_dir(vp, path, cur->child, cur,
11402d60b848STomohiro Kusumi fsopts, depth + 1);
11412d60b848STomohiro Kusumi if (error)
11422d60b848STomohiro Kusumi errx(1, "failed to populate %s: %s",
11432d60b848STomohiro Kusumi path, strerror(error));
11443bffb051STomohiro Kusumi cur->inode->param = vp;
11452d60b848STomohiro Kusumi continue;
11462d60b848STomohiro Kusumi }
11472d60b848STomohiro Kusumi
11482d60b848STomohiro Kusumi /* if regular file, creat and write its data */
1149213ebac1STomohiro Kusumi if (S_ISREG(cur->type) && !hardlink) {
11502d60b848STomohiro Kusumi assert(cur->child == NULL);
11512d60b848STomohiro Kusumi
11522d60b848STomohiro Kusumi vp = NULL;
11532d60b848STomohiro Kusumi error = hammer2_ncreate(dvp, &vp, cur->name,
11548f9d1da1STomohiro Kusumi strlen(cur->name), cur->inode->st.st_mode);
11552d60b848STomohiro Kusumi if (error)
11562d60b848STomohiro Kusumi errx(1, "hammer2_ncreate(\"%s\") failed: %s",
11572d60b848STomohiro Kusumi cur->name, strerror(error));
11582d60b848STomohiro Kusumi assert(vp);
11592d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "ncreate");
11602d60b848STomohiro Kusumi
11612d60b848STomohiro Kusumi error = hammer2_write_file(vp, path, cur);
11622d60b848STomohiro Kusumi if (error)
11632d60b848STomohiro Kusumi errx(1, "hammer2_write_file(\"%s\") failed: %s",
11642d60b848STomohiro Kusumi path, strerror(error));
11653bffb051STomohiro Kusumi cur->inode->param = vp;
1166213ebac1STomohiro Kusumi continue;
1167213ebac1STomohiro Kusumi }
1168213ebac1STomohiro Kusumi
11692d60b848STomohiro Kusumi /* if symlink, create a symlink against target */
11702d60b848STomohiro Kusumi if (S_ISLNK(cur->type)) {
11712d60b848STomohiro Kusumi assert(cur->child == NULL);
11722d60b848STomohiro Kusumi
11732d60b848STomohiro Kusumi vp = NULL;
11742d60b848STomohiro Kusumi error = hammer2_nsymlink(dvp, &vp, cur->name,
11758f9d1da1STomohiro Kusumi strlen(cur->name), cur->symlink,
11768f9d1da1STomohiro Kusumi cur->inode->st.st_mode);
11772d60b848STomohiro Kusumi if (error)
11782d60b848STomohiro Kusumi errx(1, "hammer2_nsymlink(\"%s\") failed: %s",
11792d60b848STomohiro Kusumi cur->name, strerror(error));
11802d60b848STomohiro Kusumi assert(vp);
11812d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nsymlink");
11823bffb051STomohiro Kusumi cur->inode->param = vp;
11832d60b848STomohiro Kusumi continue;
11842d60b848STomohiro Kusumi }
11852d60b848STomohiro Kusumi
11864d8112c5STomohiro Kusumi /* if fifo, create a fifo */
118748a07aadSTomohiro Kusumi if (S_ISFIFO(cur->type) && !hardlink) {
11884d8112c5STomohiro Kusumi assert(cur->child == NULL);
11894d8112c5STomohiro Kusumi
11904d8112c5STomohiro Kusumi vp = NULL;
11914d8112c5STomohiro Kusumi error = hammer2_nmknod(dvp, &vp, cur->name,
11928f9d1da1STomohiro Kusumi strlen(cur->name), VFIFO, cur->inode->st.st_mode);
11934d8112c5STomohiro Kusumi if (error)
11944d8112c5STomohiro Kusumi errx(1, "hammer2_nmknod(\"%s\") failed: %s",
11954d8112c5STomohiro Kusumi cur->name, strerror(error));
11964d8112c5STomohiro Kusumi assert(vp);
11974d8112c5STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nmknod");
11983bffb051STomohiro Kusumi cur->inode->param = vp;
11994d8112c5STomohiro Kusumi continue;
12004d8112c5STomohiro Kusumi }
12014d8112c5STomohiro Kusumi
120248a07aadSTomohiro Kusumi /* if hardlink, creat a hardlink */
120348a07aadSTomohiro Kusumi if ((S_ISREG(cur->type) || S_ISFIFO(cur->type)) && hardlink) {
120448a07aadSTomohiro Kusumi char buf[64];
120548a07aadSTomohiro Kusumi assert(cur->child == NULL);
120648a07aadSTomohiro Kusumi
120748a07aadSTomohiro Kusumi /* source vnode must not be NULL */
12083bffb051STomohiro Kusumi vp = cur->inode->param;
120948a07aadSTomohiro Kusumi assert(vp);
121048a07aadSTomohiro Kusumi /* currently these conditions must be true */
121148a07aadSTomohiro Kusumi assert(vp->v_data);
121248a07aadSTomohiro Kusumi assert(vp->v_type == VREG || vp->v_type == VFIFO);
121348a07aadSTomohiro Kusumi assert(vp->v_logical);
121448a07aadSTomohiro Kusumi assert(!vp->v_vflushed);
121548a07aadSTomohiro Kusumi assert(vp->v_malloced);
121648a07aadSTomohiro Kusumi assert(VTOI(vp)->refs > 0);
121748a07aadSTomohiro Kusumi
121848a07aadSTomohiro Kusumi error = hammer2_nlink(dvp, vp, cur->name,
121948a07aadSTomohiro Kusumi strlen(cur->name));
122048a07aadSTomohiro Kusumi if (error)
122148a07aadSTomohiro Kusumi errx(1, "hammer2_nlink(\"%s\") failed: %s",
122248a07aadSTomohiro Kusumi cur->name, strerror(error));
1223f8a1147cSTomohiro Kusumi snprintf(buf, sizeof(buf), "nlink=%lld",
1224f8a1147cSTomohiro Kusumi (long long)VTOI(vp)->meta.nlinks);
122548a07aadSTomohiro Kusumi hammer2_print(dvp, vp, cur, depth, buf);
122648a07aadSTomohiro Kusumi continue;
122748a07aadSTomohiro Kusumi }
122848a07aadSTomohiro Kusumi
12292d60b848STomohiro Kusumi /* other types are unsupported */
12302d60b848STomohiro Kusumi printf("ignore %s 0%o\n", path, cur->type);
12312d60b848STomohiro Kusumi }
12322d60b848STomohiro Kusumi
12332d60b848STomohiro Kusumi return 0;
12342d60b848STomohiro Kusumi }
12352d60b848STomohiro Kusumi
12362d60b848STomohiro Kusumi static int
hammer2_write_file(struct m_vnode * vp,const char * path,fsnode * node)12376bcbb706STomohiro Kusumi hammer2_write_file(struct m_vnode *vp, const char *path, fsnode *node)
12382d60b848STomohiro Kusumi {
12392d60b848STomohiro Kusumi struct stat *st = &node->inode->st;
12402d60b848STomohiro Kusumi size_t nsize, bufsize;
12412d60b848STomohiro Kusumi off_t offset;
12422d60b848STomohiro Kusumi int fd, error;
12432d60b848STomohiro Kusumi char *p;
12442d60b848STomohiro Kusumi
12452d60b848STomohiro Kusumi nsize = st->st_size;
12462d60b848STomohiro Kusumi if (nsize == 0)
12472d60b848STomohiro Kusumi return 0;
12482d60b848STomohiro Kusumi /* check nsize vs maximum file size */
12492d60b848STomohiro Kusumi
12502d60b848STomohiro Kusumi fd = open(path, O_RDONLY);
12512d60b848STomohiro Kusumi if (fd < 0)
12522d60b848STomohiro Kusumi err(1, "failed to open %s", path);
12532d60b848STomohiro Kusumi
12542d60b848STomohiro Kusumi p = mmap(0, nsize, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
12552d60b848STomohiro Kusumi if (p == MAP_FAILED)
12562d60b848STomohiro Kusumi err(1, "failed to mmap %s", path);
12572d60b848STomohiro Kusumi close(fd);
12582d60b848STomohiro Kusumi
12592d60b848STomohiro Kusumi for (offset = 0; offset < nsize; ) {
12602d60b848STomohiro Kusumi bufsize = MIN(nsize - offset, HAMMER2_PBUFSIZE);
12612d60b848STomohiro Kusumi assert(bufsize <= HAMMER2_PBUFSIZE);
12622d60b848STomohiro Kusumi error = hammer2_write(vp, p + offset, bufsize, offset);
12632d60b848STomohiro Kusumi if (error)
12642d60b848STomohiro Kusumi errx(1, "failed to write to %s vnode: %s",
12652d60b848STomohiro Kusumi path, strerror(error));
12662d60b848STomohiro Kusumi offset += bufsize;
12672d60b848STomohiro Kusumi if (bufsize == HAMMER2_PBUFSIZE)
12682d60b848STomohiro Kusumi assert((offset & (HAMMER2_PBUFSIZE - 1)) == 0);
12692d60b848STomohiro Kusumi }
12702d60b848STomohiro Kusumi munmap(p, nsize);
12712d60b848STomohiro Kusumi
12722d60b848STomohiro Kusumi return 0;
12732d60b848STomohiro Kusumi }
1274a63188c8STomohiro Kusumi
1275f72350acSTomohiro Kusumi static int
trim_char(char * p,char c)12766857f034STomohiro Kusumi trim_char(char *p, char c)
12776857f034STomohiro Kusumi {
12786857f034STomohiro Kusumi char *o, tmp[PATH_MAX];
1279bca6a9a0STomohiro Kusumi bool prev_was_c;
12806857f034STomohiro Kusumi size_t n;
12816857f034STomohiro Kusumi int i;
12826857f034STomohiro Kusumi
128393bffd46STomohiro Kusumi assert(p);
128493bffd46STomohiro Kusumi /* nothing to do */
128593bffd46STomohiro Kusumi if (strlen(p) == 0)
128693bffd46STomohiro Kusumi return 0;
128793bffd46STomohiro Kusumi
12886857f034STomohiro Kusumi strlcpy(tmp, p, sizeof(tmp));
12896857f034STomohiro Kusumi if (strncmp(tmp, p, sizeof(tmp)))
12906857f034STomohiro Kusumi return ENOSPC;
12916857f034STomohiro Kusumi
12926857f034STomohiro Kusumi /* trim consecutive */
1293bca6a9a0STomohiro Kusumi prev_was_c = false;
12946857f034STomohiro Kusumi o = p;
12956857f034STomohiro Kusumi n = strlen(p);
12966857f034STomohiro Kusumi
12976857f034STomohiro Kusumi for (i = 0; i < n; i++) {
12986857f034STomohiro Kusumi if (tmp[i] == c) {
1299bca6a9a0STomohiro Kusumi if (!prev_was_c)
13006857f034STomohiro Kusumi *p++ = tmp[i];
1301bca6a9a0STomohiro Kusumi prev_was_c = true;
13026857f034STomohiro Kusumi } else {
13036857f034STomohiro Kusumi *p++ = tmp[i];
1304bca6a9a0STomohiro Kusumi prev_was_c = false;
13056857f034STomohiro Kusumi }
13066857f034STomohiro Kusumi }
13076857f034STomohiro Kusumi *p = 0;
13086857f034STomohiro Kusumi assert(strlen(p) <= strlen(tmp));
13096857f034STomohiro Kusumi
13106857f034STomohiro Kusumi /* assert no consecutive */
1311bca6a9a0STomohiro Kusumi prev_was_c = false;
13126857f034STomohiro Kusumi p = o;
13136857f034STomohiro Kusumi n = strlen(p);
13146857f034STomohiro Kusumi
13156857f034STomohiro Kusumi for (i = 0; i < n; i++) {
13166857f034STomohiro Kusumi if (p[i] == c) {
1317bca6a9a0STomohiro Kusumi assert(!prev_was_c);
1318bca6a9a0STomohiro Kusumi prev_was_c = true;
13196857f034STomohiro Kusumi } else {
1320bca6a9a0STomohiro Kusumi prev_was_c = false;
13216857f034STomohiro Kusumi }
13226857f034STomohiro Kusumi }
13236857f034STomohiro Kusumi
13246857f034STomohiro Kusumi /* trim leading */
13256857f034STomohiro Kusumi if (*p == c)
13266857f034STomohiro Kusumi memmove(p, p + 1, strlen(p + 1) + 1);
13276857f034STomohiro Kusumi assert(*p != '/');
13286857f034STomohiro Kusumi
13296857f034STomohiro Kusumi /* trim trailing */
13306857f034STomohiro Kusumi p += strlen(p);
13316857f034STomohiro Kusumi p--;
13326857f034STomohiro Kusumi if (*p == c)
13336857f034STomohiro Kusumi *p = 0;
13346857f034STomohiro Kusumi assert(p[strlen(p) - 1] != '/');
13356857f034STomohiro Kusumi
13366857f034STomohiro Kusumi return 0;
13376857f034STomohiro Kusumi }
13386857f034STomohiro Kusumi
13396857f034STomohiro Kusumi static int
trim_slash(char * p)13406857f034STomohiro Kusumi trim_slash(char *p)
13416857f034STomohiro Kusumi {
13426857f034STomohiro Kusumi return trim_char(p, '/');
13436857f034STomohiro Kusumi }
13446857f034STomohiro Kusumi
134589a3eb16STomohiro Kusumi static bool
is_supported_link(const char * s)134689a3eb16STomohiro Kusumi is_supported_link(const char *s)
134789a3eb16STomohiro Kusumi {
134889a3eb16STomohiro Kusumi /* absolute path can't be supported */
134989a3eb16STomohiro Kusumi if (strlen(s) >= 1 && strncmp(s, "/", 1) == 0)
135089a3eb16STomohiro Kusumi return false;
135189a3eb16STomohiro Kusumi
135289a3eb16STomohiro Kusumi /* XXX ".." is currently unsupported */
135389a3eb16STomohiro Kusumi if (strlen(s) >= 3 && strncmp(s, "../", 3) == 0)
135489a3eb16STomohiro Kusumi return false;
135589a3eb16STomohiro Kusumi
135689a3eb16STomohiro Kusumi return true;
135789a3eb16STomohiro Kusumi }
135889a3eb16STomohiro Kusumi
13596857f034STomohiro Kusumi static int
hammer2_version_get(struct m_vnode * vp)1360f72350acSTomohiro Kusumi hammer2_version_get(struct m_vnode *vp)
1361f72350acSTomohiro Kusumi {
1362f72350acSTomohiro Kusumi hammer2_dev_t *hmp;
1363f72350acSTomohiro Kusumi
1364f72350acSTomohiro Kusumi hmp = VTOI(vp)->pmp->pfs_hmps[0];
1365f72350acSTomohiro Kusumi if (hmp == NULL)
1366f72350acSTomohiro Kusumi return EINVAL;
1367f72350acSTomohiro Kusumi
1368f72350acSTomohiro Kusumi printf("version: %d\n", hmp->voldata.version);
1369f72350acSTomohiro Kusumi
1370f72350acSTomohiro Kusumi return 0;
1371f72350acSTomohiro Kusumi }
1372f72350acSTomohiro Kusumi
13733999233bSTomohiro Kusumi struct pfs_entry {
13743999233bSTomohiro Kusumi TAILQ_ENTRY(pfs_entry) entry;
13753999233bSTomohiro Kusumi char name[NAME_MAX+1];
13763999233bSTomohiro Kusumi char s[NAME_MAX+1];
13773999233bSTomohiro Kusumi };
13783999233bSTomohiro Kusumi
13793999233bSTomohiro Kusumi static int
hammer2_pfs_get(struct m_vnode * vp)13803999233bSTomohiro Kusumi hammer2_pfs_get(struct m_vnode *vp)
13813999233bSTomohiro Kusumi {
13823999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs;
13833999233bSTomohiro Kusumi TAILQ_HEAD(, pfs_entry) head;
13843999233bSTomohiro Kusumi struct pfs_entry *p, *e;
13853999233bSTomohiro Kusumi char *pfs_id_str;
13863999233bSTomohiro Kusumi const char *type_str;
13873999233bSTomohiro Kusumi int error;
13883999233bSTomohiro Kusumi
13893999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs));
13903999233bSTomohiro Kusumi TAILQ_INIT(&head);
13913999233bSTomohiro Kusumi
13923999233bSTomohiro Kusumi while ((pfs.name_key = pfs.name_next) != (hammer2_key_t)-1) {
13933999233bSTomohiro Kusumi error = hammer2_ioctl_pfs_get(VTOI(vp), &pfs);
13943999233bSTomohiro Kusumi if (error)
13953999233bSTomohiro Kusumi return error;
13963999233bSTomohiro Kusumi
13973999233bSTomohiro Kusumi pfs_id_str = NULL;
13983999233bSTomohiro Kusumi hammer2_uuid_to_str(&pfs.pfs_clid, &pfs_id_str);
13993999233bSTomohiro Kusumi
14003999233bSTomohiro Kusumi if (pfs.pfs_type == HAMMER2_PFSTYPE_MASTER) {
14013999233bSTomohiro Kusumi if (pfs.pfs_subtype == HAMMER2_PFSSUBTYPE_NONE)
14023999233bSTomohiro Kusumi type_str = "MASTER";
14033999233bSTomohiro Kusumi else
14043999233bSTomohiro Kusumi type_str = hammer2_pfssubtype_to_str(
14053999233bSTomohiro Kusumi pfs.pfs_subtype);
14063999233bSTomohiro Kusumi } else {
14073999233bSTomohiro Kusumi type_str = hammer2_pfstype_to_str(pfs.pfs_type);
14083999233bSTomohiro Kusumi }
140906d1ac82STomohiro Kusumi e = ecalloc(1, sizeof(*e));
14103999233bSTomohiro Kusumi snprintf(e->name, sizeof(e->name), "%s", pfs.name);
14113999233bSTomohiro Kusumi snprintf(e->s, sizeof(e->s), "%-11s %s", type_str, pfs_id_str);
14123999233bSTomohiro Kusumi free(pfs_id_str);
14133999233bSTomohiro Kusumi
14143999233bSTomohiro Kusumi p = TAILQ_FIRST(&head);
14153999233bSTomohiro Kusumi while (p) {
14163999233bSTomohiro Kusumi if (strcmp(e->name, p->name) <= 0) {
14173999233bSTomohiro Kusumi TAILQ_INSERT_BEFORE(p, e, entry);
14183999233bSTomohiro Kusumi break;
14193999233bSTomohiro Kusumi }
14203999233bSTomohiro Kusumi p = TAILQ_NEXT(p, entry);
14213999233bSTomohiro Kusumi }
14223999233bSTomohiro Kusumi if (!p)
14233999233bSTomohiro Kusumi TAILQ_INSERT_TAIL(&head, e, entry);
14243999233bSTomohiro Kusumi }
14253999233bSTomohiro Kusumi
14263999233bSTomohiro Kusumi printf("Type "
14273999233bSTomohiro Kusumi "ClusterId (pfs_clid) "
14283999233bSTomohiro Kusumi "Label\n");
14293999233bSTomohiro Kusumi while ((p = TAILQ_FIRST(&head)) != NULL) {
14303999233bSTomohiro Kusumi printf("%s %s\n", p->s, p->name);
14313999233bSTomohiro Kusumi TAILQ_REMOVE(&head, p, entry);
14323999233bSTomohiro Kusumi free(p);
14333999233bSTomohiro Kusumi }
14343999233bSTomohiro Kusumi
14353999233bSTomohiro Kusumi return 0;
14363999233bSTomohiro Kusumi }
14373999233bSTomohiro Kusumi
14383999233bSTomohiro Kusumi static int
hammer2_pfs_lookup(struct m_vnode * vp,const char * pfs_name)14393999233bSTomohiro Kusumi hammer2_pfs_lookup(struct m_vnode *vp, const char *pfs_name)
14403999233bSTomohiro Kusumi {
14413999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs;
14423999233bSTomohiro Kusumi char *pfs_id_str;
14433999233bSTomohiro Kusumi int error;
14443999233bSTomohiro Kusumi
14453999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs));
14463999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name));
14473999233bSTomohiro Kusumi
14483999233bSTomohiro Kusumi error = hammer2_ioctl_pfs_lookup(VTOI(vp), &pfs);
14493999233bSTomohiro Kusumi if (error == 0) {
14503999233bSTomohiro Kusumi printf("name: %s\n", pfs.name);
14513999233bSTomohiro Kusumi printf("type: %s\n", hammer2_pfstype_to_str(pfs.pfs_type));
14523999233bSTomohiro Kusumi printf("subtype: %s\n",
14533999233bSTomohiro Kusumi hammer2_pfssubtype_to_str(pfs.pfs_subtype));
14543999233bSTomohiro Kusumi
14553999233bSTomohiro Kusumi pfs_id_str = NULL;
14563999233bSTomohiro Kusumi hammer2_uuid_to_str(&pfs.pfs_fsid, &pfs_id_str);
14573999233bSTomohiro Kusumi printf("fsid: %s\n", pfs_id_str);
14583999233bSTomohiro Kusumi free(pfs_id_str);
14593999233bSTomohiro Kusumi
14603999233bSTomohiro Kusumi pfs_id_str = NULL;
14613999233bSTomohiro Kusumi hammer2_uuid_to_str(&pfs.pfs_clid, &pfs_id_str);
14623999233bSTomohiro Kusumi printf("clid: %s\n", pfs_id_str);
14633999233bSTomohiro Kusumi free(pfs_id_str);
14643999233bSTomohiro Kusumi }
14653999233bSTomohiro Kusumi
14663999233bSTomohiro Kusumi return error;
14673999233bSTomohiro Kusumi }
14683999233bSTomohiro Kusumi
14693999233bSTomohiro Kusumi static int
hammer2_pfs_create(struct m_vnode * vp,const char * pfs_name)14703999233bSTomohiro Kusumi hammer2_pfs_create(struct m_vnode *vp, const char *pfs_name)
14713999233bSTomohiro Kusumi {
14723999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs;
14733999233bSTomohiro Kusumi int error;
14743999233bSTomohiro Kusumi
14753999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs));
14763999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name));
14773999233bSTomohiro Kusumi pfs.pfs_type = HAMMER2_PFSTYPE_MASTER;
14783999233bSTomohiro Kusumi uuid_create(&pfs.pfs_clid, NULL);
14793999233bSTomohiro Kusumi uuid_create(&pfs.pfs_fsid, NULL);
14803999233bSTomohiro Kusumi
14813999233bSTomohiro Kusumi error = hammer2_ioctl_pfs_create(VTOI(vp), &pfs);
14823999233bSTomohiro Kusumi if (error == EEXIST)
14833999233bSTomohiro Kusumi fprintf(stderr,
14843999233bSTomohiro Kusumi "NOTE: Typically the same name is "
14853999233bSTomohiro Kusumi "used for cluster elements on "
14863999233bSTomohiro Kusumi "different mounts,\n"
14873999233bSTomohiro Kusumi " but cluster elements on the "
14883999233bSTomohiro Kusumi "same mount require unique names.\n"
14893999233bSTomohiro Kusumi "hammer2: pfs_create(%s): already present\n",
14903999233bSTomohiro Kusumi pfs_name);
14913999233bSTomohiro Kusumi
14923999233bSTomohiro Kusumi return error;
14933999233bSTomohiro Kusumi }
14943999233bSTomohiro Kusumi
14953999233bSTomohiro Kusumi static int
hammer2_pfs_delete(struct m_vnode * vp,const char * pfs_name)14963999233bSTomohiro Kusumi hammer2_pfs_delete(struct m_vnode *vp, const char *pfs_name)
14973999233bSTomohiro Kusumi {
14983999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs;
14993999233bSTomohiro Kusumi
15003999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs));
15013999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name));
15023999233bSTomohiro Kusumi
15033999233bSTomohiro Kusumi return hammer2_ioctl_pfs_delete(VTOI(vp), &pfs);
15043999233bSTomohiro Kusumi }
15053999233bSTomohiro Kusumi
15063999233bSTomohiro Kusumi static int
hammer2_pfs_snapshot(struct m_vnode * vp,const char * pfs_name,const char * mount_label)15073999233bSTomohiro Kusumi hammer2_pfs_snapshot(struct m_vnode *vp, const char *pfs_name,
15083999233bSTomohiro Kusumi const char *mount_label)
15093999233bSTomohiro Kusumi {
15103999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs;
15113999233bSTomohiro Kusumi struct tm *tp;
15123999233bSTomohiro Kusumi time_t t;
15133999233bSTomohiro Kusumi
15143999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs));
15153999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name));
15163999233bSTomohiro Kusumi
15173999233bSTomohiro Kusumi if (strlen(pfs.name) == 0) {
15183999233bSTomohiro Kusumi time(&t);
15193999233bSTomohiro Kusumi tp = localtime(&t);
15203999233bSTomohiro Kusumi snprintf(pfs.name, sizeof(pfs.name),
15213999233bSTomohiro Kusumi "%s.%04d%02d%02d.%02d%02d%02d",
15223999233bSTomohiro Kusumi mount_label,
15233999233bSTomohiro Kusumi tp->tm_year + 1900,
15243999233bSTomohiro Kusumi tp->tm_mon + 1,
15253999233bSTomohiro Kusumi tp->tm_mday,
15263999233bSTomohiro Kusumi tp->tm_hour,
15273999233bSTomohiro Kusumi tp->tm_min,
15283999233bSTomohiro Kusumi tp->tm_sec);
15293999233bSTomohiro Kusumi }
15303999233bSTomohiro Kusumi
15313999233bSTomohiro Kusumi return hammer2_ioctl_pfs_snapshot(VTOI(vp), &pfs);
15323999233bSTomohiro Kusumi }
15333999233bSTomohiro Kusumi
15343999233bSTomohiro Kusumi static int
hammer2_inode_getx(struct m_vnode * dvp,const char * f)1535f804c425STomohiro Kusumi hammer2_inode_getx(struct m_vnode *dvp, const char *f)
1536f804c425STomohiro Kusumi {
1537f804c425STomohiro Kusumi hammer2_ioc_inode_t inode;
1538f804c425STomohiro Kusumi hammer2_inode_t *ip;
1539f804c425STomohiro Kusumi hammer2_inode_meta_t *meta;
1540f804c425STomohiro Kusumi struct m_vnode *vp;
1541f804c425STomohiro Kusumi char *o, *p, *name, *str = NULL;
154289a3eb16STomohiro Kusumi char tmp[PATH_MAX];
1543f804c425STomohiro Kusumi int error;
1544f804c425STomohiro Kusumi uuid_t uuid;
1545f804c425STomohiro Kusumi
1546f804c425STomohiro Kusumi assert(strlen(f) > 0);
15476857f034STomohiro Kusumi o = p = name = strdup(f);
1548f804c425STomohiro Kusumi
15496857f034STomohiro Kusumi error = trim_slash(p);
15506857f034STomohiro Kusumi if (error)
15516857f034STomohiro Kusumi return error;
15525e8b0eb7STomohiro Kusumi if (strlen(p) == 0) {
15535e8b0eb7STomohiro Kusumi vp = dvp;
15545e8b0eb7STomohiro Kusumi goto start_ioctl;
15555e8b0eb7STomohiro Kusumi }
1556f804c425STomohiro Kusumi
1557f804c425STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) {
1558f804c425STomohiro Kusumi *p++ = 0; /* NULL terminate name */
155989a3eb16STomohiro Kusumi if (!strcmp(name, ".")) {
156089a3eb16STomohiro Kusumi name = p;
156189a3eb16STomohiro Kusumi continue;
156289a3eb16STomohiro Kusumi }
1563f804c425STomohiro Kusumi vp = NULL;
1564f804c425STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1565f804c425STomohiro Kusumi if (error)
1566f804c425STomohiro Kusumi return error;
1567f804c425STomohiro Kusumi
1568f804c425STomohiro Kusumi ip = VTOI(vp);
156989a3eb16STomohiro Kusumi switch (ip->meta.type) {
157089a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_DIRECTORY:
157189a3eb16STomohiro Kusumi break;
157289a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_SOFTLINK:
157389a3eb16STomohiro Kusumi bzero(tmp, sizeof(tmp));
157489a3eb16STomohiro Kusumi error = hammer2_readlink(vp, tmp, sizeof(tmp));
157589a3eb16STomohiro Kusumi if (error)
157689a3eb16STomohiro Kusumi return error;
157789a3eb16STomohiro Kusumi if (!is_supported_link(tmp))
157889a3eb16STomohiro Kusumi return EINVAL;
157989a3eb16STomohiro Kusumi strlcat(tmp, "/", sizeof(tmp));
158089a3eb16STomohiro Kusumi strlcat(tmp, p, sizeof(tmp));
158189a3eb16STomohiro Kusumi error = trim_slash(tmp);
158289a3eb16STomohiro Kusumi if (error)
158389a3eb16STomohiro Kusumi return error;
158489a3eb16STomohiro Kusumi p = name = tmp;
158589a3eb16STomohiro Kusumi continue;
158689a3eb16STomohiro Kusumi default:
158789a3eb16STomohiro Kusumi return EINVAL;
158889a3eb16STomohiro Kusumi }
1589f804c425STomohiro Kusumi
1590f804c425STomohiro Kusumi dvp = vp;
1591f804c425STomohiro Kusumi name = p;
1592f804c425STomohiro Kusumi }
1593f804c425STomohiro Kusumi
1594f804c425STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1595f804c425STomohiro Kusumi if (error)
1596f804c425STomohiro Kusumi return error;
15975e8b0eb7STomohiro Kusumi start_ioctl:
1598f804c425STomohiro Kusumi bzero(&inode, sizeof(inode));
1599f804c425STomohiro Kusumi error = hammer2_ioctl_inode_get(VTOI(vp), &inode);
1600f804c425STomohiro Kusumi if (error)
1601f804c425STomohiro Kusumi return error;
1602f804c425STomohiro Kusumi
1603f804c425STomohiro Kusumi meta = &inode.ip_data.meta;
1604f804c425STomohiro Kusumi printf("--------------------\n");
1605f804c425STomohiro Kusumi printf("flags = 0x%x\n", inode.flags);
1606f804c425STomohiro Kusumi printf("data_count = %ju\n", (uintmax_t)inode.data_count);
1607f804c425STomohiro Kusumi printf("inode_count = %ju\n", (uintmax_t)inode.inode_count);
1608f804c425STomohiro Kusumi printf("--------------------\n");
1609f804c425STomohiro Kusumi printf("version = %u\n", meta->version);
1610f804c425STomohiro Kusumi printf("pfs_subtype = %u (%s)\n", meta->pfs_subtype,
1611f804c425STomohiro Kusumi hammer2_pfssubtype_to_str(meta->pfs_subtype));
1612f804c425STomohiro Kusumi printf("uflags = 0x%x\n", (unsigned int)meta->uflags);
1613f804c425STomohiro Kusumi printf("rmajor = %u\n", meta->rmajor);
1614f804c425STomohiro Kusumi printf("rminor = %u\n", meta->rminor);
1615f804c425STomohiro Kusumi printf("ctime = %s\n", hammer2_time64_to_str(meta->ctime, &str));
1616f804c425STomohiro Kusumi printf("mtime = %s\n", hammer2_time64_to_str(meta->mtime, &str));
1617f804c425STomohiro Kusumi printf("atime = %s\n", hammer2_time64_to_str(meta->atime, &str));
1618f804c425STomohiro Kusumi printf("btime = %s\n", hammer2_time64_to_str(meta->btime, &str));
1619f804c425STomohiro Kusumi uuid = meta->uid;
1620f804c425STomohiro Kusumi printf("uid = %s\n", hammer2_uuid_to_str(&uuid, &str));
1621f804c425STomohiro Kusumi uuid = meta->gid;
1622f804c425STomohiro Kusumi printf("gid = %s\n", hammer2_uuid_to_str(&uuid, &str));
1623f804c425STomohiro Kusumi printf("type = %u (%s)\n", meta->type,
1624f804c425STomohiro Kusumi hammer2_iptype_to_str(meta->type));
1625f804c425STomohiro Kusumi printf("op_flags = 0x%x\n", meta->op_flags);
1626f804c425STomohiro Kusumi printf("cap_flags = 0x%x\n", meta->cap_flags);
1627f804c425STomohiro Kusumi printf("mode = 0%o\n", meta->mode);
1628f804c425STomohiro Kusumi printf("inum = 0x%jx\n", (uintmax_t)meta->inum);
1629f804c425STomohiro Kusumi printf("size = %ju\n", (uintmax_t)meta->size);
1630f804c425STomohiro Kusumi printf("nlinks = %ju\n", (uintmax_t)meta->nlinks);
1631f804c425STomohiro Kusumi printf("iparent = 0x%jx\n", (uintmax_t)meta->iparent);
1632f804c425STomohiro Kusumi printf("name_key = 0x%jx\n", (uintmax_t)meta->name_key);
1633f804c425STomohiro Kusumi printf("name_len = %u\n", meta->name_len);
1634f804c425STomohiro Kusumi printf("ncopies = %u\n", meta->ncopies);
163593bffd46STomohiro Kusumi printf("comp_algo = 0x%jx\n", (uintmax_t)meta->comp_algo);
1636f804c425STomohiro Kusumi printf("target_type = %u\n", meta->target_type);
1637f804c425STomohiro Kusumi printf("check_algo = %u\n", meta->check_algo);
1638f804c425STomohiro Kusumi printf("pfs_nmasters = %u\n", meta->pfs_nmasters);
1639f804c425STomohiro Kusumi printf("pfs_type = %u (%s)\n", meta->pfs_type,
1640f804c425STomohiro Kusumi hammer2_pfstype_to_str(meta->pfs_type));
1641f804c425STomohiro Kusumi printf("pfs_inum = 0x%jx\n", (uintmax_t)meta->pfs_inum);
1642f804c425STomohiro Kusumi uuid = meta->pfs_clid;
1643f804c425STomohiro Kusumi printf("pfs_clid = %s\n", hammer2_uuid_to_str(&uuid, &str));
1644f804c425STomohiro Kusumi uuid = meta->pfs_fsid;
1645f804c425STomohiro Kusumi printf("pfs_fsid = %s\n", hammer2_uuid_to_str(&uuid, &str));
1646f804c425STomohiro Kusumi printf("data_quota = 0x%jx\n", (uintmax_t)meta->data_quota);
1647f804c425STomohiro Kusumi printf("inode_quota = 0x%jx\n", (uintmax_t)meta->inode_quota);
1648f804c425STomohiro Kusumi printf("pfs_lsnap_tid = 0x%jx\n", (uintmax_t)meta->pfs_lsnap_tid);
1649f804c425STomohiro Kusumi printf("decrypt_check = 0x%jx\n", (uintmax_t)meta->decrypt_check);
1650f804c425STomohiro Kusumi printf("--------------------\n");
1651f804c425STomohiro Kusumi
1652f804c425STomohiro Kusumi free(o);
1653f804c425STomohiro Kusumi
1654f804c425STomohiro Kusumi return error;
1655f804c425STomohiro Kusumi }
1656f804c425STomohiro Kusumi
1657f804c425STomohiro Kusumi static int
hammer2_inode_setcheck(struct m_vnode * dvp,const char * f)1658465e1141STomohiro Kusumi hammer2_inode_setcheck(struct m_vnode *dvp, const char *f)
1659465e1141STomohiro Kusumi {
1660465e1141STomohiro Kusumi hammer2_ioc_inode_t inode;
1661465e1141STomohiro Kusumi hammer2_inode_t *ip;
1662465e1141STomohiro Kusumi struct m_vnode *vp;
1663465e1141STomohiro Kusumi char *o, *p, *name, *check_algo_str;
166489a3eb16STomohiro Kusumi char tmp[PATH_MAX];
1665465e1141STomohiro Kusumi const char *checks[] = { "none", "disabled", "crc32", "xxhash64",
1666465e1141STomohiro Kusumi "sha192", };
1667465e1141STomohiro Kusumi int check_algo_idx, error;
1668465e1141STomohiro Kusumi uint8_t check_algo;
1669465e1141STomohiro Kusumi
1670465e1141STomohiro Kusumi assert(strlen(f) > 0);
1671465e1141STomohiro Kusumi o = p = strdup(f);
1672465e1141STomohiro Kusumi
1673465e1141STomohiro Kusumi p = strrchr(p, ':');
1674465e1141STomohiro Kusumi if (p == NULL)
1675465e1141STomohiro Kusumi return EINVAL;
1676465e1141STomohiro Kusumi
1677465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate path */
1678465e1141STomohiro Kusumi check_algo_str = p;
1679465e1141STomohiro Kusumi name = p = o;
1680465e1141STomohiro Kusumi
168193bffd46STomohiro Kusumi /* fail if already empty before trim */
168293bffd46STomohiro Kusumi if (strlen(p) == 0)
168393bffd46STomohiro Kusumi return EINVAL;
168493bffd46STomohiro Kusumi
16856857f034STomohiro Kusumi error = trim_slash(p);
16866857f034STomohiro Kusumi if (error)
16876857f034STomohiro Kusumi return error;
168893bffd46STomohiro Kusumi if (strlen(check_algo_str) == 0)
1689465e1141STomohiro Kusumi return EINVAL;
1690465e1141STomohiro Kusumi
1691465e1141STomohiro Kusumi /* convert check_algo_str to check_algo_idx */
16926857f034STomohiro Kusumi check_algo_idx = nitems(checks);
1693465e1141STomohiro Kusumi while (--check_algo_idx >= 0)
1694465e1141STomohiro Kusumi if (strcasecmp(check_algo_str, checks[check_algo_idx]) == 0)
1695465e1141STomohiro Kusumi break;
1696465e1141STomohiro Kusumi if (check_algo_idx < 0) {
1697465e1141STomohiro Kusumi if (strcasecmp(check_algo_str, "default") == 0) {
1698465e1141STomohiro Kusumi check_algo_str = "xxhash64";
1699465e1141STomohiro Kusumi check_algo_idx = HAMMER2_CHECK_XXHASH64;
1700465e1141STomohiro Kusumi } else if (strcasecmp(check_algo_str, "disabled") == 0) {
1701465e1141STomohiro Kusumi check_algo_str = "disabled";
1702465e1141STomohiro Kusumi check_algo_idx = HAMMER2_CHECK_DISABLED;
1703465e1141STomohiro Kusumi } else {
1704465e1141STomohiro Kusumi printf("invalid check_algo_str: %s\n", check_algo_str);
1705465e1141STomohiro Kusumi return EINVAL;
1706465e1141STomohiro Kusumi }
1707465e1141STomohiro Kusumi }
1708465e1141STomohiro Kusumi check_algo = HAMMER2_ENC_ALGO(check_algo_idx);
1709465e1141STomohiro Kusumi printf("change %s to algo %d (%s)\n", p, check_algo, check_algo_str);
1710465e1141STomohiro Kusumi
171193bffd46STomohiro Kusumi if (strlen(p) == 0) {
171293bffd46STomohiro Kusumi vp = dvp;
171393bffd46STomohiro Kusumi goto start_ioctl;
171493bffd46STomohiro Kusumi }
171593bffd46STomohiro Kusumi
1716465e1141STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) {
1717465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate name */
171889a3eb16STomohiro Kusumi if (!strcmp(name, ".")) {
171989a3eb16STomohiro Kusumi name = p;
172089a3eb16STomohiro Kusumi continue;
172189a3eb16STomohiro Kusumi }
1722465e1141STomohiro Kusumi vp = NULL;
1723465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1724465e1141STomohiro Kusumi if (error)
1725465e1141STomohiro Kusumi return error;
1726465e1141STomohiro Kusumi
1727465e1141STomohiro Kusumi ip = VTOI(vp);
172889a3eb16STomohiro Kusumi switch (ip->meta.type) {
172989a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_DIRECTORY:
173089a3eb16STomohiro Kusumi break;
173189a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_SOFTLINK:
173289a3eb16STomohiro Kusumi bzero(tmp, sizeof(tmp));
173389a3eb16STomohiro Kusumi error = hammer2_readlink(vp, tmp, sizeof(tmp));
173489a3eb16STomohiro Kusumi if (error)
173589a3eb16STomohiro Kusumi return error;
173689a3eb16STomohiro Kusumi if (!is_supported_link(tmp))
173789a3eb16STomohiro Kusumi return EINVAL;
173889a3eb16STomohiro Kusumi strlcat(tmp, "/", sizeof(tmp));
173989a3eb16STomohiro Kusumi strlcat(tmp, p, sizeof(tmp));
174089a3eb16STomohiro Kusumi error = trim_slash(tmp);
174189a3eb16STomohiro Kusumi if (error)
174289a3eb16STomohiro Kusumi return error;
174389a3eb16STomohiro Kusumi p = name = tmp;
174489a3eb16STomohiro Kusumi continue;
174589a3eb16STomohiro Kusumi default:
174689a3eb16STomohiro Kusumi return EINVAL;
174789a3eb16STomohiro Kusumi }
1748465e1141STomohiro Kusumi
1749465e1141STomohiro Kusumi dvp = vp;
1750465e1141STomohiro Kusumi name = p;
1751465e1141STomohiro Kusumi }
1752465e1141STomohiro Kusumi
1753465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1754465e1141STomohiro Kusumi if (error)
1755465e1141STomohiro Kusumi return error;
175693bffd46STomohiro Kusumi start_ioctl:
1757465e1141STomohiro Kusumi ip = VTOI(vp);
1758465e1141STomohiro Kusumi
1759465e1141STomohiro Kusumi bzero(&inode, sizeof(inode));
1760465e1141STomohiro Kusumi error = hammer2_ioctl_inode_get(ip, &inode);
1761465e1141STomohiro Kusumi if (error)
1762465e1141STomohiro Kusumi return error;
1763465e1141STomohiro Kusumi
1764465e1141STomohiro Kusumi inode.flags |= HAMMER2IOC_INODE_FLAG_CHECK;
1765465e1141STomohiro Kusumi inode.ip_data.meta.check_algo = check_algo;
1766465e1141STomohiro Kusumi error = hammer2_ioctl_inode_set(ip, &inode);
1767465e1141STomohiro Kusumi if (error)
1768465e1141STomohiro Kusumi return error;
1769465e1141STomohiro Kusumi
1770465e1141STomohiro Kusumi free(o);
1771465e1141STomohiro Kusumi
1772465e1141STomohiro Kusumi return error;
1773465e1141STomohiro Kusumi }
1774465e1141STomohiro Kusumi
1775465e1141STomohiro Kusumi static int
hammer2_inode_setcomp(struct m_vnode * dvp,const char * f)1776465e1141STomohiro Kusumi hammer2_inode_setcomp(struct m_vnode *dvp, const char *f)
1777465e1141STomohiro Kusumi {
1778465e1141STomohiro Kusumi hammer2_ioc_inode_t inode;
1779465e1141STomohiro Kusumi hammer2_inode_t *ip;
1780465e1141STomohiro Kusumi struct m_vnode *vp;
1781465e1141STomohiro Kusumi char *o, *p, *name, *comp_algo_str, *comp_level_str;
178289a3eb16STomohiro Kusumi char tmp[PATH_MAX];
1783465e1141STomohiro Kusumi const char *comps[] = { "none", "autozero", "lz4", "zlib", };
1784465e1141STomohiro Kusumi int comp_algo_idx, comp_level_idx, error;
1785465e1141STomohiro Kusumi uint8_t comp_algo, comp_level;
1786465e1141STomohiro Kusumi
1787465e1141STomohiro Kusumi assert(strlen(f) > 0);
1788465e1141STomohiro Kusumi o = p = strdup(f);
1789465e1141STomohiro Kusumi
1790465e1141STomohiro Kusumi p = strrchr(p, ':');
1791465e1141STomohiro Kusumi if (p == NULL)
1792465e1141STomohiro Kusumi return EINVAL;
1793465e1141STomohiro Kusumi
1794465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate comp_algo_str */
1795465e1141STomohiro Kusumi comp_level_str = p;
1796465e1141STomohiro Kusumi p = o;
1797465e1141STomohiro Kusumi
1798465e1141STomohiro Kusumi p = strrchr(p, ':');
1799465e1141STomohiro Kusumi if (p == NULL) {
1800465e1141STomohiro Kusumi /* comp_level_str not specified */
1801465e1141STomohiro Kusumi comp_algo_str = comp_level_str;
1802465e1141STomohiro Kusumi comp_level_str = NULL;
1803465e1141STomohiro Kusumi } else {
1804465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate path */
1805465e1141STomohiro Kusumi comp_algo_str = p;
1806465e1141STomohiro Kusumi }
1807465e1141STomohiro Kusumi name = p = o;
1808465e1141STomohiro Kusumi
180993bffd46STomohiro Kusumi /* fail if already empty before trim */
181093bffd46STomohiro Kusumi if (strlen(p) == 0)
181193bffd46STomohiro Kusumi return EINVAL;
181293bffd46STomohiro Kusumi
18136857f034STomohiro Kusumi error = trim_slash(p);
18146857f034STomohiro Kusumi if (error)
18156857f034STomohiro Kusumi return error;
181693bffd46STomohiro Kusumi if (strlen(comp_algo_str) == 0)
1817465e1141STomohiro Kusumi return EINVAL;
1818465e1141STomohiro Kusumi
1819465e1141STomohiro Kusumi /* convert comp_algo_str to comp_algo_idx */
18206857f034STomohiro Kusumi comp_algo_idx = nitems(comps);
1821465e1141STomohiro Kusumi while (--comp_algo_idx >= 0)
1822465e1141STomohiro Kusumi if (strcasecmp(comp_algo_str, comps[comp_algo_idx]) == 0)
1823465e1141STomohiro Kusumi break;
1824465e1141STomohiro Kusumi if (comp_algo_idx < 0) {
1825465e1141STomohiro Kusumi if (strcasecmp(comp_algo_str, "default") == 0) {
1826465e1141STomohiro Kusumi comp_algo_str = "lz4";
1827465e1141STomohiro Kusumi comp_algo_idx = HAMMER2_COMP_LZ4;
1828465e1141STomohiro Kusumi } else if (strcasecmp(comp_algo_str, "disabled") == 0) {
1829465e1141STomohiro Kusumi comp_algo_str = "autozero";
1830465e1141STomohiro Kusumi comp_algo_idx = HAMMER2_COMP_AUTOZERO;
1831465e1141STomohiro Kusumi } else {
1832465e1141STomohiro Kusumi printf("invalid comp_algo_str: %s\n", comp_algo_str);
1833465e1141STomohiro Kusumi return EINVAL;
1834465e1141STomohiro Kusumi }
1835465e1141STomohiro Kusumi }
1836465e1141STomohiro Kusumi comp_algo = HAMMER2_ENC_ALGO(comp_algo_idx);
1837465e1141STomohiro Kusumi
1838465e1141STomohiro Kusumi /* convert comp_level_str to comp_level_idx */
1839465e1141STomohiro Kusumi if (comp_level_str == NULL) {
1840465e1141STomohiro Kusumi comp_level_idx = 0;
1841bca6a9a0STomohiro Kusumi } else if (isdigit((int)comp_level_str[0])) {
1842465e1141STomohiro Kusumi comp_level_idx = strtol(comp_level_str, NULL, 0);
1843465e1141STomohiro Kusumi } else if (strcasecmp(comp_level_str, "default") == 0) {
1844465e1141STomohiro Kusumi comp_level_idx = 0;
1845465e1141STomohiro Kusumi } else {
1846465e1141STomohiro Kusumi printf("invalid comp_level_str: %s\n", comp_level_str);
1847465e1141STomohiro Kusumi return EINVAL;
1848465e1141STomohiro Kusumi }
1849465e1141STomohiro Kusumi if (comp_level_idx) {
1850465e1141STomohiro Kusumi switch (comp_algo) {
1851465e1141STomohiro Kusumi case HAMMER2_COMP_ZLIB:
1852465e1141STomohiro Kusumi if (comp_level_idx < 6 || comp_level_idx > 9) {
1853465e1141STomohiro Kusumi printf("unsupported comp_level %d for %s\n",
1854465e1141STomohiro Kusumi comp_level_idx, comp_algo_str);
1855465e1141STomohiro Kusumi return EINVAL;
1856465e1141STomohiro Kusumi }
1857465e1141STomohiro Kusumi break;
1858465e1141STomohiro Kusumi default:
1859465e1141STomohiro Kusumi printf("unsupported comp_level %d for %s\n",
1860465e1141STomohiro Kusumi comp_level_idx, comp_algo_str);
1861465e1141STomohiro Kusumi return EINVAL;
1862465e1141STomohiro Kusumi }
1863465e1141STomohiro Kusumi }
1864465e1141STomohiro Kusumi comp_level = HAMMER2_ENC_LEVEL(comp_level_idx);
1865465e1141STomohiro Kusumi printf("change %s to algo %d (%s) level %d\n",
1866465e1141STomohiro Kusumi p, comp_algo, comp_algo_str, comp_level_idx);
1867465e1141STomohiro Kusumi
186893bffd46STomohiro Kusumi if (strlen(p) == 0) {
186993bffd46STomohiro Kusumi vp = dvp;
187093bffd46STomohiro Kusumi goto start_ioctl;
187193bffd46STomohiro Kusumi }
187293bffd46STomohiro Kusumi
1873465e1141STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) {
1874465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate name */
187589a3eb16STomohiro Kusumi if (!strcmp(name, ".")) {
187689a3eb16STomohiro Kusumi name = p;
187789a3eb16STomohiro Kusumi continue;
187889a3eb16STomohiro Kusumi }
1879465e1141STomohiro Kusumi vp = NULL;
1880465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1881465e1141STomohiro Kusumi if (error)
1882465e1141STomohiro Kusumi return error;
1883465e1141STomohiro Kusumi
1884465e1141STomohiro Kusumi ip = VTOI(vp);
188589a3eb16STomohiro Kusumi switch (ip->meta.type) {
188689a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_DIRECTORY:
188789a3eb16STomohiro Kusumi break;
188889a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_SOFTLINK:
188989a3eb16STomohiro Kusumi bzero(tmp, sizeof(tmp));
189089a3eb16STomohiro Kusumi error = hammer2_readlink(vp, tmp, sizeof(tmp));
189189a3eb16STomohiro Kusumi if (error)
189289a3eb16STomohiro Kusumi return error;
189389a3eb16STomohiro Kusumi if (!is_supported_link(tmp))
189489a3eb16STomohiro Kusumi return EINVAL;
189589a3eb16STomohiro Kusumi strlcat(tmp, "/", sizeof(tmp));
189689a3eb16STomohiro Kusumi strlcat(tmp, p, sizeof(tmp));
189789a3eb16STomohiro Kusumi error = trim_slash(tmp);
189889a3eb16STomohiro Kusumi if (error)
189989a3eb16STomohiro Kusumi return error;
190089a3eb16STomohiro Kusumi p = name = tmp;
190189a3eb16STomohiro Kusumi continue;
190289a3eb16STomohiro Kusumi default:
190389a3eb16STomohiro Kusumi return EINVAL;
190489a3eb16STomohiro Kusumi }
1905465e1141STomohiro Kusumi
1906465e1141STomohiro Kusumi dvp = vp;
1907465e1141STomohiro Kusumi name = p;
1908465e1141STomohiro Kusumi }
1909465e1141STomohiro Kusumi
1910465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1911465e1141STomohiro Kusumi if (error)
1912465e1141STomohiro Kusumi return error;
191393bffd46STomohiro Kusumi start_ioctl:
1914465e1141STomohiro Kusumi ip = VTOI(vp);
1915465e1141STomohiro Kusumi
1916465e1141STomohiro Kusumi bzero(&inode, sizeof(inode));
1917465e1141STomohiro Kusumi error = hammer2_ioctl_inode_get(ip, &inode);
1918465e1141STomohiro Kusumi if (error)
1919465e1141STomohiro Kusumi return error;
1920465e1141STomohiro Kusumi
1921465e1141STomohiro Kusumi inode.flags |= HAMMER2IOC_INODE_FLAG_COMP;
1922465e1141STomohiro Kusumi inode.ip_data.meta.comp_algo = comp_algo | comp_level;
1923465e1141STomohiro Kusumi error = hammer2_ioctl_inode_set(ip, &inode);
1924465e1141STomohiro Kusumi if (error)
1925465e1141STomohiro Kusumi return error;
1926465e1141STomohiro Kusumi
1927465e1141STomohiro Kusumi free(o);
1928465e1141STomohiro Kusumi
1929465e1141STomohiro Kusumi return error;
1930465e1141STomohiro Kusumi }
1931465e1141STomohiro Kusumi
1932465e1141STomohiro Kusumi static int
hammer2_bulkfree(struct m_vnode * vp)1933a63188c8STomohiro Kusumi hammer2_bulkfree(struct m_vnode *vp)
1934a63188c8STomohiro Kusumi {
1935a63188c8STomohiro Kusumi hammer2_ioc_bulkfree_t bfi;
1936a63188c8STomohiro Kusumi size_t usermem;
1937a63188c8STomohiro Kusumi size_t usermem_size = sizeof(usermem);
1938a63188c8STomohiro Kusumi
1939a63188c8STomohiro Kusumi bzero(&bfi, sizeof(bfi));
1940a63188c8STomohiro Kusumi usermem = 0;
1941a63188c8STomohiro Kusumi if (sysctlbyname("hw.usermem", &usermem, &usermem_size, NULL, 0) == 0)
1942a63188c8STomohiro Kusumi bfi.size = usermem / 16;
1943a63188c8STomohiro Kusumi else
1944a63188c8STomohiro Kusumi bfi.size = 0;
1945a63188c8STomohiro Kusumi if (bfi.size < 8192 * 1024)
1946a63188c8STomohiro Kusumi bfi.size = 8192 * 1024;
1947a63188c8STomohiro Kusumi
1948a63188c8STomohiro Kusumi return hammer2_ioctl_bulkfree_scan(VTOI(vp), &bfi);
1949a63188c8STomohiro Kusumi }
1950afa5234bSTomohiro Kusumi
1951afa5234bSTomohiro Kusumi static int
hammer2_destroy_path(struct m_vnode * dvp,const char * f)1952ac97ce60STomohiro Kusumi hammer2_destroy_path(struct m_vnode *dvp, const char *f)
1953917508cdSTomohiro Kusumi {
1954917508cdSTomohiro Kusumi hammer2_ioc_destroy_t destroy;
1955ac97ce60STomohiro Kusumi hammer2_inode_t *ip;
1956ac97ce60STomohiro Kusumi struct m_vnode *vp;
1957ac97ce60STomohiro Kusumi char *o, *p, *name;
195889a3eb16STomohiro Kusumi char tmp[PATH_MAX];
1959b4807901STomohiro Kusumi int error;
1960917508cdSTomohiro Kusumi
196106d1ac82STomohiro Kusumi assert(strlen(f) > 0);
19626857f034STomohiro Kusumi o = p = name = strdup(f);
1963ac97ce60STomohiro Kusumi
19646857f034STomohiro Kusumi error = trim_slash(p);
19656857f034STomohiro Kusumi if (error)
19666857f034STomohiro Kusumi return error;
1967ac97ce60STomohiro Kusumi if (strlen(p) == 0)
1968ac97ce60STomohiro Kusumi return EINVAL;
1969ac97ce60STomohiro Kusumi
1970ac97ce60STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) {
1971ac97ce60STomohiro Kusumi *p++ = 0; /* NULL terminate name */
197289a3eb16STomohiro Kusumi if (!strcmp(name, ".")) {
197389a3eb16STomohiro Kusumi name = p;
197489a3eb16STomohiro Kusumi continue;
197589a3eb16STomohiro Kusumi }
1976ac97ce60STomohiro Kusumi vp = NULL;
1977ac97ce60STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
1978ac97ce60STomohiro Kusumi if (error)
1979ac97ce60STomohiro Kusumi return error;
1980ac97ce60STomohiro Kusumi
1981ac97ce60STomohiro Kusumi ip = VTOI(vp);
198289a3eb16STomohiro Kusumi switch (ip->meta.type) {
198389a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_DIRECTORY:
198489a3eb16STomohiro Kusumi break;
198589a3eb16STomohiro Kusumi case HAMMER2_OBJTYPE_SOFTLINK:
198689a3eb16STomohiro Kusumi bzero(tmp, sizeof(tmp));
198789a3eb16STomohiro Kusumi error = hammer2_readlink(vp, tmp, sizeof(tmp));
198889a3eb16STomohiro Kusumi if (error)
198989a3eb16STomohiro Kusumi return error;
199089a3eb16STomohiro Kusumi if (!is_supported_link(tmp))
199189a3eb16STomohiro Kusumi return EINVAL;
199289a3eb16STomohiro Kusumi strlcat(tmp, "/", sizeof(tmp));
199389a3eb16STomohiro Kusumi strlcat(tmp, p, sizeof(tmp));
199489a3eb16STomohiro Kusumi error = trim_slash(tmp);
199589a3eb16STomohiro Kusumi if (error)
199689a3eb16STomohiro Kusumi return error;
199789a3eb16STomohiro Kusumi p = name = tmp;
199889a3eb16STomohiro Kusumi continue;
199989a3eb16STomohiro Kusumi default:
200089a3eb16STomohiro Kusumi return EINVAL;
200189a3eb16STomohiro Kusumi }
2002ac97ce60STomohiro Kusumi
2003ac97ce60STomohiro Kusumi dvp = vp;
2004ac97ce60STomohiro Kusumi name = p;
2005ac97ce60STomohiro Kusumi }
2006ac97ce60STomohiro Kusumi
2007ba024da8STomohiro Kusumi /* XXX When does (or why does not) ioctl modify this inode ? */
2008ba024da8STomohiro Kusumi hammer2_inode_modify(VTOI(dvp));
2009ba024da8STomohiro Kusumi
2010917508cdSTomohiro Kusumi bzero(&destroy, sizeof(destroy));
2011917508cdSTomohiro Kusumi destroy.cmd = HAMMER2_DELETE_FILE;
2012ac97ce60STomohiro Kusumi snprintf(destroy.path, sizeof(destroy.path), "%s", name);
2013917508cdSTomohiro Kusumi
2014917508cdSTomohiro Kusumi printf("%s\t", f);
2015917508cdSTomohiro Kusumi fflush(stdout);
2016917508cdSTomohiro Kusumi
2017ac97ce60STomohiro Kusumi error = hammer2_ioctl_destroy(VTOI(dvp), &destroy);
2018917508cdSTomohiro Kusumi if (error)
2019917508cdSTomohiro Kusumi printf("%s\n", strerror(error));
2020917508cdSTomohiro Kusumi else
2021917508cdSTomohiro Kusumi printf("ok\n");
2022ac97ce60STomohiro Kusumi free(o);
2023917508cdSTomohiro Kusumi
2024917508cdSTomohiro Kusumi return error;
2025917508cdSTomohiro Kusumi }
2026917508cdSTomohiro Kusumi
2027917508cdSTomohiro Kusumi static int
hammer2_destroy_inum(struct m_vnode * vp,hammer2_tid_t inum)2028917508cdSTomohiro Kusumi hammer2_destroy_inum(struct m_vnode *vp, hammer2_tid_t inum)
2029917508cdSTomohiro Kusumi {
2030917508cdSTomohiro Kusumi hammer2_ioc_destroy_t destroy;
2031b4807901STomohiro Kusumi int error;
2032917508cdSTomohiro Kusumi
2033917508cdSTomohiro Kusumi bzero(&destroy, sizeof(destroy));
2034917508cdSTomohiro Kusumi destroy.cmd = HAMMER2_DELETE_INUM;
2035917508cdSTomohiro Kusumi destroy.inum = inum;
2036917508cdSTomohiro Kusumi
2037917508cdSTomohiro Kusumi printf("%jd\t", (intmax_t)destroy.inum);
2038917508cdSTomohiro Kusumi fflush(stdout);
2039917508cdSTomohiro Kusumi
2040917508cdSTomohiro Kusumi error = hammer2_ioctl_destroy(VTOI(vp), &destroy);
2041917508cdSTomohiro Kusumi if (error)
2042917508cdSTomohiro Kusumi printf("%s\n", strerror(error));
2043917508cdSTomohiro Kusumi else
2044917508cdSTomohiro Kusumi printf("ok\n");
2045917508cdSTomohiro Kusumi
2046917508cdSTomohiro Kusumi return error;
2047917508cdSTomohiro Kusumi }
2048917508cdSTomohiro Kusumi
2049917508cdSTomohiro Kusumi static int
hammer2_growfs(struct m_vnode * vp,hammer2_off_t size)2050afa5234bSTomohiro Kusumi hammer2_growfs(struct m_vnode *vp, hammer2_off_t size)
2051afa5234bSTomohiro Kusumi {
2052afa5234bSTomohiro Kusumi hammer2_ioc_growfs_t growfs;
2053afa5234bSTomohiro Kusumi int error;
2054afa5234bSTomohiro Kusumi
2055afa5234bSTomohiro Kusumi bzero(&growfs, sizeof(growfs));
2056afa5234bSTomohiro Kusumi growfs.size = size;
2057afa5234bSTomohiro Kusumi
2058afa5234bSTomohiro Kusumi error = hammer2_ioctl_growfs(VTOI(vp), &growfs, NULL);
2059afa5234bSTomohiro Kusumi if (!error) {
2060afa5234bSTomohiro Kusumi if (growfs.modified)
2061afa5234bSTomohiro Kusumi printf("grown to %016jx\n", (intmax_t)growfs.size);
2062afa5234bSTomohiro Kusumi else
2063afa5234bSTomohiro Kusumi printf("no size change - %016jx\n",
2064afa5234bSTomohiro Kusumi (intmax_t)growfs.size);
2065afa5234bSTomohiro Kusumi }
2066afa5234bSTomohiro Kusumi
2067afa5234bSTomohiro Kusumi return error;
2068afa5234bSTomohiro Kusumi }
20696857f034STomohiro Kusumi
20702d0322dbSTomohiro Kusumi struct hammer2_link {
20712d0322dbSTomohiro Kusumi TAILQ_ENTRY(hammer2_link) entry;
20722d0322dbSTomohiro Kusumi hammer2_tid_t inum;
20732d0322dbSTomohiro Kusumi uint64_t nlinks;
20742d0322dbSTomohiro Kusumi char path[PATH_MAX];
20752d0322dbSTomohiro Kusumi };
20762d0322dbSTomohiro Kusumi
20772d0322dbSTomohiro Kusumi TAILQ_HEAD(hammer2_linkq, hammer2_link);
20782d0322dbSTomohiro Kusumi
20792d0322dbSTomohiro Kusumi static void
hammer2_linkq_init(struct hammer2_linkq * linkq)20802d0322dbSTomohiro Kusumi hammer2_linkq_init(struct hammer2_linkq *linkq)
20812d0322dbSTomohiro Kusumi {
20822d0322dbSTomohiro Kusumi TAILQ_INIT(linkq);
20832d0322dbSTomohiro Kusumi }
20842d0322dbSTomohiro Kusumi
20852d0322dbSTomohiro Kusumi static void
hammer2_linkq_cleanup(struct hammer2_linkq * linkq,bool is_root)20862db6f39cSTomohiro Kusumi hammer2_linkq_cleanup(struct hammer2_linkq *linkq, bool is_root)
20872d0322dbSTomohiro Kusumi {
20882d0322dbSTomohiro Kusumi struct hammer2_link *e;
20892d0322dbSTomohiro Kusumi int count = 0;
20902d0322dbSTomohiro Kusumi
20912d0322dbSTomohiro Kusumi /*
20922db6f39cSTomohiro Kusumi * If is_root is true, linkq must be empty, or link count is broken.
20932d0322dbSTomohiro Kusumi * Note that if an image was made by makefs, hardlinks in the source
20942db6f39cSTomohiro Kusumi * directory became hardlinks in the image only if >1 links existed under
20952d0322dbSTomohiro Kusumi * that directory, as makefs doesn't determine hardlink via link count.
20962d0322dbSTomohiro Kusumi */
20972d0322dbSTomohiro Kusumi while ((e = TAILQ_FIRST(linkq)) != NULL) {
20982d0322dbSTomohiro Kusumi count++;
20992d0322dbSTomohiro Kusumi TAILQ_REMOVE(linkq, e, entry);
21002d0322dbSTomohiro Kusumi free(e);
21012d0322dbSTomohiro Kusumi }
21022d0322dbSTomohiro Kusumi assert(TAILQ_EMPTY(linkq));
21032d0322dbSTomohiro Kusumi
21042db6f39cSTomohiro Kusumi if (count && is_root)
21052d0322dbSTomohiro Kusumi errx(1, "%d link entries remained", count);
21062d0322dbSTomohiro Kusumi }
21072d0322dbSTomohiro Kusumi
21082d0322dbSTomohiro Kusumi static void
hammer2_linkq_add(struct hammer2_linkq * linkq,hammer2_tid_t inum,uint64_t nlinks,const char * path)21092d0322dbSTomohiro Kusumi hammer2_linkq_add(struct hammer2_linkq *linkq, hammer2_tid_t inum,
21102d0322dbSTomohiro Kusumi uint64_t nlinks, const char *path)
21112d0322dbSTomohiro Kusumi {
21122d0322dbSTomohiro Kusumi struct hammer2_link *e;
21132d0322dbSTomohiro Kusumi int count = 0;
21142d0322dbSTomohiro Kusumi
21152d0322dbSTomohiro Kusumi e = ecalloc(1, sizeof(*e));
21162d0322dbSTomohiro Kusumi e->inum = inum;
21172d0322dbSTomohiro Kusumi e->nlinks = nlinks;
21182d0322dbSTomohiro Kusumi strlcpy(e->path, path, sizeof(e->path));
21192d0322dbSTomohiro Kusumi TAILQ_INSERT_TAIL(linkq, e, entry);
21202d0322dbSTomohiro Kusumi
21212d0322dbSTomohiro Kusumi TAILQ_FOREACH(e, linkq, entry)
21222d0322dbSTomohiro Kusumi if (e->inum == inum)
21232d0322dbSTomohiro Kusumi count++;
21242d0322dbSTomohiro Kusumi if (count > 1)
21252d0322dbSTomohiro Kusumi errx(1, "%d link entries exist for inum %jd",
21262d0322dbSTomohiro Kusumi count, (intmax_t)inum);
21272d0322dbSTomohiro Kusumi }
21282d0322dbSTomohiro Kusumi
21292d0322dbSTomohiro Kusumi static void
hammer2_linkq_del(struct hammer2_linkq * linkq,hammer2_tid_t inum)21302d0322dbSTomohiro Kusumi hammer2_linkq_del(struct hammer2_linkq *linkq, hammer2_tid_t inum)
21312d0322dbSTomohiro Kusumi {
21322d0322dbSTomohiro Kusumi struct hammer2_link *e, *next;
21332d0322dbSTomohiro Kusumi
21342d0322dbSTomohiro Kusumi TAILQ_FOREACH_MUTABLE(e, linkq, entry, next)
21352d0322dbSTomohiro Kusumi if (e->inum == inum) {
21362d0322dbSTomohiro Kusumi e->nlinks--;
21372d0322dbSTomohiro Kusumi if (e->nlinks == 1) {
21382d0322dbSTomohiro Kusumi TAILQ_REMOVE(linkq, e, entry);
21392d0322dbSTomohiro Kusumi free(e);
21402d0322dbSTomohiro Kusumi }
21412d0322dbSTomohiro Kusumi }
21422d0322dbSTomohiro Kusumi }
21432d0322dbSTomohiro Kusumi
21446da97f51STomohiro Kusumi static void
hammer2_utimes(struct m_vnode * vp,const char * f)21456da97f51STomohiro Kusumi hammer2_utimes(struct m_vnode *vp, const char *f)
21466da97f51STomohiro Kusumi {
21476da97f51STomohiro Kusumi hammer2_inode_t *ip = VTOI(vp);
21486da97f51STomohiro Kusumi struct timeval tv[2];
21496da97f51STomohiro Kusumi
21506da97f51STomohiro Kusumi hammer2_time_to_timeval(ip->meta.atime, &tv[0]);
21516da97f51STomohiro Kusumi hammer2_time_to_timeval(ip->meta.mtime, &tv[1]);
21526da97f51STomohiro Kusumi
21536da97f51STomohiro Kusumi utimes(f, tv); /* ignore failure */
21546da97f51STomohiro Kusumi }
21556da97f51STomohiro Kusumi
2156fc4148feSTomohiro Kusumi static int
hammer2_readx_directory(struct m_vnode * dvp,const char * dir,const char * name,struct hammer2_linkq * linkq)21572d0322dbSTomohiro Kusumi hammer2_readx_directory(struct m_vnode *dvp, const char *dir, const char *name,
21582d0322dbSTomohiro Kusumi struct hammer2_linkq *linkq)
21595e8b0eb7STomohiro Kusumi {
21605e8b0eb7STomohiro Kusumi struct m_vnode *vp;
21615e8b0eb7STomohiro Kusumi struct dirent *dp;
21625e8b0eb7STomohiro Kusumi struct stat st;
21635e8b0eb7STomohiro Kusumi char *buf, tmp[PATH_MAX];
21645e8b0eb7STomohiro Kusumi off_t offset = 0;
21655e8b0eb7STomohiro Kusumi int ndirent = 0;
21665e8b0eb7STomohiro Kusumi int eofflag = 0;
21675e8b0eb7STomohiro Kusumi int i, error;
21685e8b0eb7STomohiro Kusumi
21695e8b0eb7STomohiro Kusumi snprintf(tmp, sizeof(tmp), "%s/%s", dir, name);
21705e8b0eb7STomohiro Kusumi if (stat(tmp, &st) == -1 && mkdir(tmp, 0666) == -1)
21715e8b0eb7STomohiro Kusumi err(1, "failed to mkdir %s", tmp);
21725e8b0eb7STomohiro Kusumi
21732db6f39cSTomohiro Kusumi buf = ecalloc(1, HAMMER2_PBUFSIZE);
21745e8b0eb7STomohiro Kusumi
21755e8b0eb7STomohiro Kusumi while (!eofflag) {
21765e8b0eb7STomohiro Kusumi error = hammer2_readdir(dvp, buf, HAMMER2_PBUFSIZE, &offset,
21775e8b0eb7STomohiro Kusumi &ndirent, &eofflag);
21785e8b0eb7STomohiro Kusumi if (error)
21795e8b0eb7STomohiro Kusumi errx(1, "failed to readdir");
21805e8b0eb7STomohiro Kusumi dp = (void *)buf;
21815e8b0eb7STomohiro Kusumi
21825e8b0eb7STomohiro Kusumi for (i = 0; i < ndirent; i++) {
21835e8b0eb7STomohiro Kusumi if (strcmp(dp->d_name, ".") &&
21845e8b0eb7STomohiro Kusumi strcmp(dp->d_name, "..")) {
21855e8b0eb7STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, dp->d_name,
21865e8b0eb7STomohiro Kusumi strlen(dp->d_name));
21875e8b0eb7STomohiro Kusumi if (error)
21885e8b0eb7STomohiro Kusumi return error;
21895e8b0eb7STomohiro Kusumi error = hammer2_readx_handle(vp, tmp,
21902d0322dbSTomohiro Kusumi dp->d_name, linkq);
21915e8b0eb7STomohiro Kusumi if (error)
21925e8b0eb7STomohiro Kusumi return error;
21935e8b0eb7STomohiro Kusumi }
21945e8b0eb7STomohiro Kusumi dp = (void *)((char *)dp +
21955e8b0eb7STomohiro Kusumi _DIRENT_RECLEN(dp->d_namlen));
21965e8b0eb7STomohiro Kusumi }
21975e8b0eb7STomohiro Kusumi }
21985e8b0eb7STomohiro Kusumi
21995e8b0eb7STomohiro Kusumi free(buf);
22006da97f51STomohiro Kusumi hammer2_utimes(dvp, tmp);
22015e8b0eb7STomohiro Kusumi
22025e8b0eb7STomohiro Kusumi return 0;
22035e8b0eb7STomohiro Kusumi }
22045e8b0eb7STomohiro Kusumi
22055e8b0eb7STomohiro Kusumi static int
hammer2_readx_link(struct m_vnode * vp,const char * src,const char * lnk,struct hammer2_linkq * linkq)22062d0322dbSTomohiro Kusumi hammer2_readx_link(struct m_vnode *vp, const char *src, const char *lnk,
22072d0322dbSTomohiro Kusumi struct hammer2_linkq *linkq)
22085e8b0eb7STomohiro Kusumi {
22095e8b0eb7STomohiro Kusumi hammer2_inode_t *ip = VTOI(vp);
22102d0322dbSTomohiro Kusumi struct stat st;
22112d0322dbSTomohiro Kusumi int error;
22122d0322dbSTomohiro Kusumi
22132d0322dbSTomohiro Kusumi if (!stat(lnk, &st)) {
22142d0322dbSTomohiro Kusumi error = unlink(lnk);
22152d0322dbSTomohiro Kusumi if (error)
22162d0322dbSTomohiro Kusumi return error;
22172d0322dbSTomohiro Kusumi }
22182d0322dbSTomohiro Kusumi
22192d0322dbSTomohiro Kusumi error = link(src, lnk);
22202d0322dbSTomohiro Kusumi if (error)
22212d0322dbSTomohiro Kusumi return error;
22222d0322dbSTomohiro Kusumi
22232d0322dbSTomohiro Kusumi hammer2_linkq_del(linkq, ip->meta.inum);
22242d0322dbSTomohiro Kusumi
22252d0322dbSTomohiro Kusumi return 0;
22262d0322dbSTomohiro Kusumi }
22272d0322dbSTomohiro Kusumi
22282d0322dbSTomohiro Kusumi static int
hammer2_readx_regfile(struct m_vnode * vp,const char * dir,const char * name,struct hammer2_linkq * linkq)22292d0322dbSTomohiro Kusumi hammer2_readx_regfile(struct m_vnode *vp, const char *dir, const char *name,
22302d0322dbSTomohiro Kusumi struct hammer2_linkq *linkq)
22312d0322dbSTomohiro Kusumi {
22322d0322dbSTomohiro Kusumi hammer2_inode_t *ip = VTOI(vp);
22332d0322dbSTomohiro Kusumi struct hammer2_link *e;
22345e8b0eb7STomohiro Kusumi char *buf, out[PATH_MAX];
22355e8b0eb7STomohiro Kusumi size_t resid, n;
22365e8b0eb7STomohiro Kusumi off_t offset;
22375e8b0eb7STomohiro Kusumi int fd, error;
22382d0322dbSTomohiro Kusumi bool found = false;
22395e8b0eb7STomohiro Kusumi
22405e8b0eb7STomohiro Kusumi snprintf(out, sizeof(out), "%s/%s", dir, name);
22412d0322dbSTomohiro Kusumi
22422d0322dbSTomohiro Kusumi if (ip->meta.nlinks > 1) {
22432d0322dbSTomohiro Kusumi TAILQ_FOREACH(e, linkq, entry)
22442d0322dbSTomohiro Kusumi if (e->inum == ip->meta.inum) {
22452d0322dbSTomohiro Kusumi found = true;
22462d0322dbSTomohiro Kusumi error = hammer2_readx_link(vp, e->path, out,
22472d0322dbSTomohiro Kusumi linkq);
22482d0322dbSTomohiro Kusumi if (error == 0)
22492d0322dbSTomohiro Kusumi return 0;
22502d0322dbSTomohiro Kusumi /* ignore failure */
22512d0322dbSTomohiro Kusumi }
22522d0322dbSTomohiro Kusumi if (!found)
22532d0322dbSTomohiro Kusumi hammer2_linkq_add(linkq, ip->meta.inum, ip->meta.nlinks,
22542d0322dbSTomohiro Kusumi out);
22552d0322dbSTomohiro Kusumi }
22562d0322dbSTomohiro Kusumi
22575e8b0eb7STomohiro Kusumi fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666);
22585e8b0eb7STomohiro Kusumi if (fd == -1)
22595e8b0eb7STomohiro Kusumi err(1, "failed to create %s", out);
22605e8b0eb7STomohiro Kusumi
22612db6f39cSTomohiro Kusumi buf = ecalloc(1, HAMMER2_PBUFSIZE);
22625e8b0eb7STomohiro Kusumi resid = ip->meta.size;
22635e8b0eb7STomohiro Kusumi offset = 0;
22645e8b0eb7STomohiro Kusumi
22655e8b0eb7STomohiro Kusumi while (resid > 0) {
22665e8b0eb7STomohiro Kusumi bzero(buf, HAMMER2_PBUFSIZE);
22675e8b0eb7STomohiro Kusumi error = hammer2_read(vp, buf, HAMMER2_PBUFSIZE, offset);
22685e8b0eb7STomohiro Kusumi if (error)
22695e8b0eb7STomohiro Kusumi errx(1, "failed to read from %s", name);
22705e8b0eb7STomohiro Kusumi
22715e8b0eb7STomohiro Kusumi n = resid >= HAMMER2_PBUFSIZE ? HAMMER2_PBUFSIZE : resid;
22725e8b0eb7STomohiro Kusumi error = write(fd, buf, n);
22735e8b0eb7STomohiro Kusumi if (error == -1)
22745e8b0eb7STomohiro Kusumi err(1, "failed to write to %s", out);
22755e8b0eb7STomohiro Kusumi else if (error != n)
22765e8b0eb7STomohiro Kusumi return EINVAL;
22775e8b0eb7STomohiro Kusumi
22785e8b0eb7STomohiro Kusumi resid -= n;
22795e8b0eb7STomohiro Kusumi offset += HAMMER2_PBUFSIZE;
22805e8b0eb7STomohiro Kusumi }
22815e8b0eb7STomohiro Kusumi fsync(fd);
22825e8b0eb7STomohiro Kusumi close(fd);
22835e8b0eb7STomohiro Kusumi
22845e8b0eb7STomohiro Kusumi free(buf);
22856da97f51STomohiro Kusumi hammer2_utimes(vp, out);
22865e8b0eb7STomohiro Kusumi
22875e8b0eb7STomohiro Kusumi return 0;
22885e8b0eb7STomohiro Kusumi }
22895e8b0eb7STomohiro Kusumi
22905e8b0eb7STomohiro Kusumi static int
hammer2_readx_handle(struct m_vnode * vp,const char * dir,const char * name,struct hammer2_linkq * linkq)22912d0322dbSTomohiro Kusumi hammer2_readx_handle(struct m_vnode *vp, const char *dir, const char *name,
22922d0322dbSTomohiro Kusumi struct hammer2_linkq *linkq)
22935e8b0eb7STomohiro Kusumi {
22945e8b0eb7STomohiro Kusumi hammer2_inode_t *ip = VTOI(vp);
22955e8b0eb7STomohiro Kusumi
22965e8b0eb7STomohiro Kusumi switch (ip->meta.type) {
22975e8b0eb7STomohiro Kusumi case HAMMER2_OBJTYPE_DIRECTORY:
22982d0322dbSTomohiro Kusumi return hammer2_readx_directory(vp, dir, name, linkq);
22995e8b0eb7STomohiro Kusumi case HAMMER2_OBJTYPE_REGFILE:
23002d0322dbSTomohiro Kusumi return hammer2_readx_regfile(vp, dir, name, linkq);
23015e8b0eb7STomohiro Kusumi default:
23025e8b0eb7STomohiro Kusumi /* XXX */
23035e8b0eb7STomohiro Kusumi printf("ignore inode %jd %s \"%s\"\n",
23045e8b0eb7STomohiro Kusumi (intmax_t)ip->meta.inum,
23055e8b0eb7STomohiro Kusumi hammer2_iptype_to_str(ip->meta.type),
23065e8b0eb7STomohiro Kusumi name);
23075e8b0eb7STomohiro Kusumi return 0;
23085e8b0eb7STomohiro Kusumi }
23095e8b0eb7STomohiro Kusumi return EINVAL;
23105e8b0eb7STomohiro Kusumi }
23115e8b0eb7STomohiro Kusumi
23125e8b0eb7STomohiro Kusumi static int
hammer2_readx(struct m_vnode * dvp,const char * dir,const char * f)2313fc4148feSTomohiro Kusumi hammer2_readx(struct m_vnode *dvp, const char *dir, const char *f)
2314fc4148feSTomohiro Kusumi {
2315fc4148feSTomohiro Kusumi hammer2_inode_t *ip;
23162d0322dbSTomohiro Kusumi struct hammer2_linkq linkq;
23172db6f39cSTomohiro Kusumi struct m_vnode *vp, *ovp = dvp;
23185e8b0eb7STomohiro Kusumi char *o, *p, *name;
23195e8b0eb7STomohiro Kusumi char tmp[PATH_MAX];
23205e8b0eb7STomohiro Kusumi int error;
2321fc4148feSTomohiro Kusumi
2322fc4148feSTomohiro Kusumi if (dir == NULL)
2323fc4148feSTomohiro Kusumi return EINVAL;
2324fc4148feSTomohiro Kusumi
2325fc4148feSTomohiro Kusumi assert(strlen(f) > 0);
2326fc4148feSTomohiro Kusumi o = p = name = strdup(f);
2327fc4148feSTomohiro Kusumi
2328fc4148feSTomohiro Kusumi error = trim_slash(p);
2329fc4148feSTomohiro Kusumi if (error)
2330fc4148feSTomohiro Kusumi return error;
23315e8b0eb7STomohiro Kusumi if (strlen(p) == 0) {
23325e8b0eb7STomohiro Kusumi vp = dvp;
23332db6f39cSTomohiro Kusumi goto start_read;
23345e8b0eb7STomohiro Kusumi }
2335fc4148feSTomohiro Kusumi
2336fc4148feSTomohiro Kusumi while ((p = strchr(p, '/')) != NULL) {
2337fc4148feSTomohiro Kusumi *p++ = 0; /* NULL terminate name */
2338fc4148feSTomohiro Kusumi if (!strcmp(name, ".")) {
2339fc4148feSTomohiro Kusumi name = p;
2340fc4148feSTomohiro Kusumi continue;
2341fc4148feSTomohiro Kusumi }
2342fc4148feSTomohiro Kusumi vp = NULL;
2343fc4148feSTomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
2344fc4148feSTomohiro Kusumi if (error)
2345fc4148feSTomohiro Kusumi return error;
2346fc4148feSTomohiro Kusumi
2347fc4148feSTomohiro Kusumi ip = VTOI(vp);
2348fc4148feSTomohiro Kusumi switch (ip->meta.type) {
2349fc4148feSTomohiro Kusumi case HAMMER2_OBJTYPE_DIRECTORY:
2350fc4148feSTomohiro Kusumi break;
2351fc4148feSTomohiro Kusumi case HAMMER2_OBJTYPE_SOFTLINK:
2352fc4148feSTomohiro Kusumi bzero(tmp, sizeof(tmp));
2353fc4148feSTomohiro Kusumi error = hammer2_readlink(vp, tmp, sizeof(tmp));
2354fc4148feSTomohiro Kusumi if (error)
2355fc4148feSTomohiro Kusumi return error;
2356fc4148feSTomohiro Kusumi if (!is_supported_link(tmp))
2357fc4148feSTomohiro Kusumi return EINVAL;
2358fc4148feSTomohiro Kusumi strlcat(tmp, "/", sizeof(tmp));
2359fc4148feSTomohiro Kusumi strlcat(tmp, p, sizeof(tmp));
2360fc4148feSTomohiro Kusumi error = trim_slash(tmp);
2361fc4148feSTomohiro Kusumi if (error)
2362fc4148feSTomohiro Kusumi return error;
2363fc4148feSTomohiro Kusumi p = name = tmp;
2364fc4148feSTomohiro Kusumi continue;
2365fc4148feSTomohiro Kusumi default:
2366fc4148feSTomohiro Kusumi return EINVAL;
2367fc4148feSTomohiro Kusumi }
2368fc4148feSTomohiro Kusumi
2369fc4148feSTomohiro Kusumi dvp = vp;
2370fc4148feSTomohiro Kusumi name = p;
2371fc4148feSTomohiro Kusumi }
2372fc4148feSTomohiro Kusumi
2373fc4148feSTomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name));
2374fc4148feSTomohiro Kusumi if (error)
2375fc4148feSTomohiro Kusumi return error;
23762db6f39cSTomohiro Kusumi start_read:
23772d0322dbSTomohiro Kusumi hammer2_linkq_init(&linkq);
23782d0322dbSTomohiro Kusumi error = hammer2_readx_handle(vp, dir, name, &linkq);
23792db6f39cSTomohiro Kusumi hammer2_linkq_cleanup(&linkq, vp == ovp);
2380fc4148feSTomohiro Kusumi if (error)
23815e8b0eb7STomohiro Kusumi return error;
2382fc4148feSTomohiro Kusumi
2383fc4148feSTomohiro Kusumi free(o);
2384fc4148feSTomohiro Kusumi
2385fc4148feSTomohiro Kusumi return 0;
2386fc4148feSTomohiro Kusumi }
2387fc4148feSTomohiro Kusumi
23886857f034STomohiro Kusumi static void
assert_trim_slash(const char * input,const char * expected)23896857f034STomohiro Kusumi assert_trim_slash(const char *input, const char *expected)
23906857f034STomohiro Kusumi {
23916857f034STomohiro Kusumi char tmp[PATH_MAX];
23926857f034STomohiro Kusumi int error;
23936857f034STomohiro Kusumi
23946857f034STomohiro Kusumi strlcpy(tmp, input, sizeof(tmp));
23956857f034STomohiro Kusumi error = trim_slash(tmp);
23966857f034STomohiro Kusumi if (error)
23976857f034STomohiro Kusumi errx(1, "input \"%s\" error %d", input, error);
23986857f034STomohiro Kusumi
23996857f034STomohiro Kusumi if (strncmp(tmp, expected, sizeof(tmp)))
24006857f034STomohiro Kusumi errx(1, "input \"%s\" result \"%s\" vs expected \"%s\"",
24016857f034STomohiro Kusumi input, tmp, expected);
24026857f034STomohiro Kusumi }
24036857f034STomohiro Kusumi
24046857f034STomohiro Kusumi static void
unittest_trim_slash(void)24056857f034STomohiro Kusumi unittest_trim_slash(void)
24066857f034STomohiro Kusumi {
24076857f034STomohiro Kusumi assert_trim_slash("", "");
24086857f034STomohiro Kusumi assert_trim_slash("/", "");
24096857f034STomohiro Kusumi assert_trim_slash("//", "");
24106857f034STomohiro Kusumi assert_trim_slash("///", "");
24116857f034STomohiro Kusumi
24126857f034STomohiro Kusumi assert_trim_slash("makefs", "makefs");
24136857f034STomohiro Kusumi assert_trim_slash("/makefs", "makefs");
24146857f034STomohiro Kusumi assert_trim_slash("//makefs", "makefs");
24156857f034STomohiro Kusumi assert_trim_slash("makefs/", "makefs");
24166857f034STomohiro Kusumi assert_trim_slash("makefs//", "makefs");
24176857f034STomohiro Kusumi assert_trim_slash("/makefs/", "makefs");
24186857f034STomohiro Kusumi assert_trim_slash("//makefs//", "makefs");
24196857f034STomohiro Kusumi
24206857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2", "sys/vfs/hammer2");
24216857f034STomohiro Kusumi assert_trim_slash("/sys/vfs/hammer2", "sys/vfs/hammer2");
24226857f034STomohiro Kusumi assert_trim_slash("//sys/vfs/hammer2", "sys/vfs/hammer2");
24236857f034STomohiro Kusumi assert_trim_slash("///sys/vfs/hammer2", "sys/vfs/hammer2");
24246857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2/", "sys/vfs/hammer2");
24256857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2//", "sys/vfs/hammer2");
24266857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2///", "sys/vfs/hammer2");
24276857f034STomohiro Kusumi assert_trim_slash("/sys/vfs/hammer2/", "sys/vfs/hammer2");
24286857f034STomohiro Kusumi assert_trim_slash("//sys//vfs//hammer2//", "sys/vfs/hammer2");
24296857f034STomohiro Kusumi assert_trim_slash("///sys///vfs///hammer2///", "sys/vfs/hammer2");
24306857f034STomohiro Kusumi
2431bca6a9a0STomohiro Kusumi APRINTF("success\n");
24326857f034STomohiro Kusumi }
2433