2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org>
5 * Copyright (c) 2011-2022 The DragonFly Project. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
39 #include <sys/param.h>
41 #include <sys/sysctl.h>
58 #define APRINTF(X, ...) \
59 printf("%s: " X, __func__, ## __VA_ARGS__)
61 static void hammer2_dump_fsinfo(fsinfo_t
*);
62 static int hammer2_create_image(const char *, fsinfo_t
*);
63 static int hammer2_populate_dir(struct m_vnode
*, const char *, fsnode
*,
64 fsnode
*, fsinfo_t
*, int);
65 static void hammer2_validate(const char *, fsnode
*, fsinfo_t
*);
66 static void hammer2_size_dir(fsnode
*, fsinfo_t
*);
67 static int hammer2_write_file(struct m_vnode
*, const char *, fsnode
*);
69 fsnode
*hammer2_curnode
;
72 hammer2_prep_opts(fsinfo_t
*fsopts
)
74 hammer2_makefs_options_t
*h2_opt
= ecalloc(1, sizeof(*h2_opt
));
75 hammer2_mkfs_options_t
*opt
= &h2_opt
->mkfs_options
;
77 const option_t hammer2_options
[] = {
78 /* newfs_hammer2(8) compatible options */
79 { 'b', "BootAreaSize", NULL
, OPT_STRBUF
, 0, 0, "boot area size" },
80 { 'r', "AuxAreaSize", NULL
, OPT_STRBUF
, 0, 0, "aux area size" },
81 { 'V', "Hammer2Version", NULL
, OPT_STRBUF
, 0, 0, "file system version" },
82 { 'L', "Label", NULL
, OPT_STRBUF
, 0, 0, "PFS label" },
83 /* makefs(8) specific options */
84 { 'm', "MountLabel", NULL
, OPT_STRBUF
, 0, 0, "destination PFS label" },
85 { 'v', "NumVolhdr", &h2_opt
->num_volhdr
, OPT_INT32
,
86 1, HAMMER2_NUM_VOLHDRS
, "number of volume headers" },
87 { 'd', "Hammer2Debug", NULL
, OPT_STRBUF
, 0, 0, "debug tunable" },
91 hammer2_mkfs_init(opt
);
93 /* make this tunable ? */
94 assert(opt
->CompType
== HAMMER2_COMP_NEWFS_DEFAULT
);
95 assert(opt
->CheckType
== HAMMER2_CHECK_XXHASH64
);
97 /* force debug mode for mkfs */
100 fsopts
->fs_specific
= h2_opt
;
101 fsopts
->fs_options
= copy_opts(hammer2_options
);
102 fsopts
->sectorsize
= DEV_BSIZE
;
106 hammer2_cleanup_opts(fsinfo_t
*fsopts
)
108 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
109 hammer2_mkfs_options_t
*opt
= &h2_opt
->mkfs_options
;
111 hammer2_mkfs_cleanup(opt
);
114 free(fsopts
->fs_options
);
118 hammer2_parse_opts(const char *option
, fsinfo_t
*fsopts
)
120 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
121 hammer2_mkfs_options_t
*opt
= &h2_opt
->mkfs_options
;
123 option_t
*hammer2_options
= fsopts
->fs_options
;
124 char buf
[1024]; /* > HAMMER2_INODE_MAXNAME */
127 assert(option
!= NULL
);
128 assert(fsopts
!= NULL
);
130 if (debug
& DEBUG_FS_PARSE_OPTS
)
131 APRINTF("got `%s'\n", option
);
133 i
= set_option(hammer2_options
, option
, buf
, sizeof(buf
));
137 if (hammer2_options
[i
].name
== NULL
)
140 switch (hammer2_options
[i
].letter
) {
142 opt
->BootAreaSize
= getsize(buf
, HAMMER2_NEWFS_ALIGN
,
143 HAMMER2_BOOT_MAX_BYTES
, 2);
146 opt
->AuxAreaSize
= getsize(buf
, HAMMER2_NEWFS_ALIGN
,
147 HAMMER2_AUX_MAX_BYTES
, 2);
150 opt
->Hammer2Version
= strtol(buf
, NULL
, 0);
151 if (opt
->Hammer2Version
< HAMMER2_VOL_VERSION_MIN
||
152 opt
->Hammer2Version
>= HAMMER2_VOL_VERSION_WIP
)
153 errx(1, "I don't understand how to format "
154 "HAMMER2 version %d",
155 opt
->Hammer2Version
);
158 h2_opt
->label_specified
= 1;
159 if (strcasecmp(buf
, "none") == 0)
161 if (opt
->NLabels
>= MAXLABELS
)
162 errx(1, "Limit of %d local labels", MAXLABELS
- 1);
163 if (strlen(buf
) == 0)
164 errx(1, "Volume label '%s' cannot be 0-length", buf
);
165 if (strlen(buf
) >= HAMMER2_INODE_MAXNAME
)
166 errx(1, "Volume label '%s' is too long (%d chars max)",
167 buf
, HAMMER2_INODE_MAXNAME
- 1);
168 opt
->Label
[opt
->NLabels
++] = strdup(buf
);
171 if (strlen(buf
) == 0)
172 errx(1, "Volume label '%s' cannot be 0-length", buf
);
173 if (strlen(buf
) >= HAMMER2_INODE_MAXNAME
)
174 errx(1, "Volume label '%s' is too long (%d chars max)",
175 buf
, HAMMER2_INODE_MAXNAME
- 1);
176 strlcpy(h2_opt
->mount_label
, buf
, sizeof(h2_opt
->mount_label
));
179 hammer2_debug
= strtoll(buf
, NULL
, 0);
189 hammer2_makefs(const char *image
, const char *dir
, fsnode
*root
,
192 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
194 struct hammer2_mount_info info
;
195 struct m_vnode devvp
, *vroot
;
196 hammer2_inode_t
*iroot
;
197 struct timeval start
;
200 assert(image
!= NULL
);
202 assert(root
!= NULL
);
203 assert(fsopts
!= NULL
);
205 if (debug
& DEBUG_FS_MAKEFS
)
206 APRINTF("image \"%s\" directory \"%s\" root %p\n",
209 /* validate tree and options */
211 hammer2_validate(dir
, root
, fsopts
);
212 TIMER_RESULTS(start
, "hammer2_validate");
216 if (hammer2_create_image(image
, fsopts
) == -1)
217 errx(1, "image file `%s' not created", image
);
218 TIMER_RESULTS(start
, "hammer2_create_image");
220 if (debug
& DEBUG_FS_MAKEFS
)
224 error
= hammer2_vfs_init();
226 errx(1, "failed to vfs init, error %d", error
);
229 memset(&devvp
, 0, sizeof(devvp
));
231 memset(&mp
, 0, sizeof(mp
));
232 memset(&info
, 0, sizeof(info
));
233 error
= hammer2_vfs_mount(&devvp
, &mp
, h2_opt
->mount_label
, &info
);
235 errx(1, "failed to mount, error %d", error
);
240 error
= hammer2_vfs_root(&mp
, &vroot
);
242 errx(1, "failed to get root vnode, error %d", error
);
247 printf("root inode inum %lld, mode 0%o, refs %d\n",
248 (long long)iroot
->meta
.inum
, iroot
->meta
.mode
, iroot
->refs
);
251 printf("populating `%s'\n", image
);
253 if (hammer2_populate_dir(vroot
, dir
, root
, root
, fsopts
, 0))
254 errx(1, "image file `%s' not populated", image
);
255 TIMER_RESULTS(start
, "hammer2_populate_dir");
258 error
= hammer2_vfs_unmount(&mp
, 0);
260 errx(1, "failed to unmount, error %d", error
);
262 /* check leaked resource */
264 printf("XXX %lld vnode left\n", (long long)vnode_count
);
265 if (hammer2_chain_allocs
)
266 printf("XXX %ld chain left\n", hammer2_chain_allocs
);
270 error
= hammer2_vfs_uninit();
272 errx(1, "failed to vfs uninit, error %d", error
);
274 if (close(fsopts
->fd
) == -1)
275 err(1, "closing `%s'", image
);
278 printf("image `%s' complete\n", image
);
281 /* end of public functions */
284 hammer2_image_size(fsinfo_t
*fsopts
)
286 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
287 hammer2_off_t image_size
, used_size
= 0;
288 int num_level1
, delta_num_level1
;
290 /* use 4 volume headers by default */
291 num_level1
= h2_opt
->num_volhdr
* 2; /* default 4 x 2 */
292 assert(num_level1
!= 0);
293 assert(num_level1
<= 8);
295 /* add 4MiB segment for each level1 */
296 used_size
+= HAMMER2_ZONE_SEG64
* num_level1
;
298 /* add boot/aux area, but exact size unknown at this point */
299 used_size
+= HAMMER2_BOOT_NOM_BYTES
+ HAMMER2_AUX_NOM_BYTES
;
302 used_size
+= fsopts
->size
;
304 /* XXX add extra level1 for meta data and indirect blocks */
305 used_size
+= HAMMER2_FREEMAP_LEVEL1_SIZE
;
307 /* XXX add extra level1 for safety */
308 if (used_size
> HAMMER2_FREEMAP_LEVEL1_SIZE
* 10)
309 used_size
+= HAMMER2_FREEMAP_LEVEL1_SIZE
;
311 /* use 8GiB image size by default */
312 image_size
= HAMMER2_FREEMAP_LEVEL1_SIZE
* num_level1
;
313 printf("trying default image size %s\n", sizetostr(image_size
));
315 /* adjust if image size isn't large enough */
316 if (used_size
> image_size
) {
317 /* determine extra level1 needed */
318 delta_num_level1
= howmany(used_size
- image_size
,
319 HAMMER2_FREEMAP_LEVEL1_SIZE
);
321 /* adjust used size with 4MiB segment for each extra level1 */
322 used_size
+= HAMMER2_ZONE_SEG64
* delta_num_level1
;
324 /* adjust image size with extra level1 */
325 image_size
+= HAMMER2_FREEMAP_LEVEL1_SIZE
* delta_num_level1
;
326 printf("trying adjusted image size %s\n",
327 sizetostr(image_size
));
329 if (used_size
> image_size
)
330 errx(1, "invalid used_size %lld > image_size %lld",
331 (long long)used_size
, (long long)image_size
);
338 hammer2_label_name(int label_type
)
340 switch (label_type
) {
341 case HAMMER2_LABEL_NONE
:
343 case HAMMER2_LABEL_BOOT
:
345 case HAMMER2_LABEL_ROOT
:
347 case HAMMER2_LABEL_DATA
:
356 hammer2_validate(const char *dir
, fsnode
*root
, fsinfo_t
*fsopts
)
358 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
359 hammer2_mkfs_options_t
*opt
= &h2_opt
->mkfs_options
;
360 hammer2_off_t image_size
, minsize
, maxsize
;
364 assert(root
!= NULL
);
365 assert(fsopts
!= NULL
);
367 if (debug
& DEBUG_FS_VALIDATE
) {
368 APRINTF("before defaults set:\n");
369 hammer2_dump_fsinfo(fsopts
);
372 /* makefs only supports "DATA" for default PFS label */
373 if (!h2_opt
->label_specified
) {
374 opt
->DefaultLabelType
= HAMMER2_LABEL_DATA
;
375 s
= hammer2_label_name(opt
->DefaultLabelType
);
376 printf("using default label \"%s\"\n", s
);
379 /* set default mount PFS label */
380 if (!strcmp(h2_opt
->mount_label
, "")) {
381 s
= hammer2_label_name(HAMMER2_LABEL_DATA
);
382 strlcpy(h2_opt
->mount_label
, s
, sizeof(h2_opt
->mount_label
));
383 printf("using default mount label \"%s\"\n", s
);
386 /* set default number of volume headers */
387 if (!h2_opt
->num_volhdr
) {
388 h2_opt
->num_volhdr
= HAMMER2_NUM_VOLHDRS
;
389 printf("using default %d volume headers\n", h2_opt
->num_volhdr
);
392 /* calculate data size */
393 if (fsopts
->size
!= 0)
394 fsopts
->size
= 0; /* shouldn't reach here to begin with */
395 hammer2_size_dir(root
, fsopts
);
396 printf("estimated data size %s from %lld inode\n",
397 sizetostr(fsopts
->size
), (long long)fsopts
->inodes
);
399 /* determine image size from data size */
400 image_size
= hammer2_image_size(fsopts
);
401 assert((image_size
& HAMMER2_FREEMAP_LEVEL1_MASK
) == 0);
403 minsize
= roundup(fsopts
->minsize
, HAMMER2_FREEMAP_LEVEL1_SIZE
);
404 maxsize
= roundup(fsopts
->maxsize
, HAMMER2_FREEMAP_LEVEL1_SIZE
);
405 if (image_size
< minsize
)
406 image_size
= minsize
;
407 else if (maxsize
> 0 && image_size
> maxsize
)
408 errx(1, "`%s' size of %lld is larger than the maxsize of %lld",
409 dir
, (long long)image_size
, (long long)maxsize
);
411 assert((image_size
& HAMMER2_FREEMAP_LEVEL1_MASK
) == 0);
412 h2_opt
->image_size
= image_size
;
413 printf("using %s image size\n", sizetostr(h2_opt
->image_size
));
415 if (debug
& DEBUG_FS_VALIDATE
) {
416 APRINTF("after defaults set:\n");
417 hammer2_dump_fsinfo(fsopts
);
422 hammer2_dump_fsinfo(fsinfo_t
*fsopts
)
424 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
425 hammer2_mkfs_options_t
*opt
= &h2_opt
->mkfs_options
;
429 assert(fsopts
!= NULL
);
431 APRINTF("fsinfo_t at %p\n", fsopts
);
433 printf("\tinodes %lld\n", (long long)fsopts
->inodes
);
434 printf("\tsize %lld, minsize %lld, maxsize %lld\n",
435 (long long)fsopts
->size
,
436 (long long)fsopts
->minsize
,
437 (long long)fsopts
->maxsize
);
439 printf("\thammer2_debug 0x%x\n", hammer2_debug
);
441 printf("\tlabel_specified %d\n", h2_opt
->label_specified
);
442 printf("\tmount_label \"%s\"\n", h2_opt
->mount_label
);
443 printf("\tnum_volhdr %d\n", h2_opt
->num_volhdr
);
444 printf("\timage_size 0x%llx\n", (long long)h2_opt
->image_size
);
446 printf("\tHammer2Version %d\n", opt
->Hammer2Version
);
447 printf("\tBootAreaSize 0x%jx\n", opt
->BootAreaSize
);
448 printf("\tAuxAreaSize 0x%jx\n", opt
->AuxAreaSize
);
449 printf("\tNLabels %d\n", opt
->NLabels
);
450 printf("\tCompType %d\n", opt
->CompType
);
451 printf("\tCheckType %d\n", opt
->CheckType
);
452 printf("\tDefaultLabelType %d\n", opt
->DefaultLabelType
);
453 printf("\tDebugOpt %d\n", opt
->DebugOpt
);
456 hammer2_uuid_to_str(&opt
->Hammer2_FSType
, &s
);
457 printf("\tHammer2_FSType \"%s\"\n", s
);
459 hammer2_uuid_to_str(&opt
->Hammer2_VolFSID
, &s
);
460 printf("\tHammer2_VolFSID \"%s\"\n", s
);
462 hammer2_uuid_to_str(&opt
->Hammer2_SupCLID
, &s
);
463 printf("\tHammer2_SupCLID \"%s\"\n", s
);
465 hammer2_uuid_to_str(&opt
->Hammer2_SupFSID
, &s
);
466 printf("\tHammer2_SupFSID \"%s\"\n", s
);
468 for (i
= 0; i
< opt
->NLabels
; i
++) {
469 printf("\tLabel[%d] \"%s\"\n", i
, opt
->Label
[i
]);
471 hammer2_uuid_to_str(&opt
->Hammer2_PfsCLID
[i
], &s
);
472 printf("\t Hammer2_PfsCLID[%d] \"%s\"\n", i
, s
);
474 hammer2_uuid_to_str(&opt
->Hammer2_PfsFSID
[i
], &s
);
475 printf("\t Hammer2_PfsFSID[%d] \"%s\"\n", i
, s
);
482 hammer2_create_image(const char *image
, fsinfo_t
*fsopts
)
484 hammer2_makefs_options_t
*h2_opt
= fsopts
->fs_specific
;
485 hammer2_mkfs_options_t
*opt
= &h2_opt
->mkfs_options
;
486 char *av
[] = { (char *)image
, }; /* XXX support multi-volumes */
488 int i
, bufsize
, oflags
;
491 assert(image
!= NULL
);
492 assert(fsopts
!= NULL
);
495 oflags
= O_RDWR
| O_CREAT
;
496 if (fsopts
->offset
== 0)
498 if ((fsopts
->fd
= open(image
, oflags
, 0666)) == -1) {
499 warn("can't open `%s' for writing", image
);
504 bufsize
= HAMMER2_PBUFSIZE
;
505 bufrem
= h2_opt
->image_size
;
506 if (fsopts
->sparse
) {
507 if (ftruncate(fsopts
->fd
, bufrem
) == -1) {
508 warn("sparse option disabled");
512 if (fsopts
->sparse
) {
513 /* File truncated at bufrem. Remaining is 0 */
517 if (debug
& DEBUG_FS_CREATE_IMAGE
)
518 APRINTF("zero-ing image `%s', %lld sectors, "
519 "using %d byte chunks\n",
520 image
, (long long)bufrem
, bufsize
);
521 buf
= ecalloc(1, bufsize
);
524 if (fsopts
->offset
!= 0) {
525 if (lseek(fsopts
->fd
, fsopts
->offset
, SEEK_SET
) == -1) {
533 i
= write(fsopts
->fd
, buf
, MIN(bufsize
, bufrem
));
535 warn("zeroing image, %lld bytes to go",
545 /* make the file system */
546 if (debug
& DEBUG_FS_CREATE_IMAGE
)
547 APRINTF("calling mkfs(\"%s\", ...)\n", image
);
548 hammer2_mkfs(1, av
, opt
); /* success if returned */
554 hammer2_phys_size(off_t size
)
556 off_t radix_size
, phys_size
= 0;
559 if (size
> HAMMER2_PBUFSIZE
) {
560 phys_size
+= rounddown(size
, HAMMER2_PBUFSIZE
);
561 size
= size
% HAMMER2_PBUFSIZE
;
564 for (i
= HAMMER2_RADIX_MIN
; i
<= HAMMER2_RADIX_MAX
; i
++) {
565 radix_size
= 1UL << i
;
566 if (radix_size
>= size
) {
567 phys_size
+= radix_size
;
575 /* calculate data size */
577 hammer2_size_dir(fsnode
*root
, fsinfo_t
*fsopts
)
581 assert(fsopts
!= NULL
);
583 if (debug
& DEBUG_FS_SIZE_DIR
)
584 APRINTF("entry: bytes %lld inodes %lld\n",
585 (long long)fsopts
->size
, (long long)fsopts
->inodes
);
587 for (node
= root
; node
!= NULL
; node
= node
->next
) {
588 if (node
== root
) { /* we're at "." */
589 assert(strcmp(node
->name
, ".") == 0);
590 } else if ((node
->inode
->flags
& FI_SIZED
) == 0) {
591 /* don't count duplicate names */
592 node
->inode
->flags
|= FI_SIZED
;
593 if (debug
& DEBUG_FS_SIZE_DIR_NODE
)
594 APRINTF("`%s' size %lld\n",
596 (long long)node
->inode
->st
.st_size
);
598 fsopts
->size
+= sizeof(hammer2_inode_data_t
);
599 if (node
->type
== S_IFREG
) {
600 size_t st_size
= node
->inode
->st
.st_size
;
601 if (st_size
> HAMMER2_EMBEDDED_BYTES
)
602 fsopts
->size
+= hammer2_phys_size(st_size
);
603 } else if (node
->type
== S_IFLNK
) {
604 size_t nlen
= strlen(node
->symlink
);
605 if (nlen
> HAMMER2_EMBEDDED_BYTES
)
606 fsopts
->size
+= hammer2_phys_size(nlen
);
609 if (node
->type
== S_IFDIR
)
610 hammer2_size_dir(node
->child
, fsopts
);
613 if (debug
& DEBUG_FS_SIZE_DIR
)
614 APRINTF("exit: size %lld inodes %lld\n",
615 (long long)fsopts
->size
, (long long)fsopts
->inodes
);
619 hammer2_print(const struct m_vnode
*dvp
, const struct m_vnode
*vp
,
620 const fsnode
*node
, int depth
, const char *msg
)
622 if (debug
& DEBUG_FS_POPULATE
) {
624 int indent
= depth
* 2;
626 if (S_ISDIR(node
->type
))
628 else if (S_ISREG(node
->type
))
630 else if (S_ISLNK(node
->type
))
632 else if (S_ISFIFO(node
->type
))
636 printf("%*.*s", indent
, indent
, "");
637 printf("dvp=%p/%d vp=%p/%d \"%s\" %s %s\n",
638 dvp
, dvp
? VTOI(dvp
)->refs
: 0,
639 vp
, vp
? VTOI(vp
)->refs
: 0,
640 node
->name
, type
, msg
);
643 if (S_ISDIR(node
->type
))
645 else if (S_ISREG(node
->type
))
647 else if (S_ISLNK(node
->type
))
649 else if (S_ISFIFO(node
->type
))
660 hammer2_populate_dir(struct m_vnode
*dvp
, const char *dir
, fsnode
*root
,
661 fsnode
*parent
, fsinfo_t
*fsopts
, int depth
)
673 assert(root
!= NULL
);
674 assert(parent
!= NULL
);
675 assert(fsopts
!= NULL
);
677 /* assert root directory */
678 assert(S_ISDIR(root
->type
));
679 assert(!strcmp(root
->name
, "."));
680 assert(!root
->child
);
681 assert(!root
->parent
|| root
->parent
->child
== root
);
683 hammer2_print(dvp
, NULL
, root
, depth
, "enter");
684 if (stat(dir
, &st
) == -1)
685 err(1, "no such path %s", dir
);
686 if (!S_ISDIR(st
.st_mode
))
687 errx(1, "no such dir %s", dir
);
689 for (cur
= root
->next
; cur
!= NULL
; cur
= cur
->next
) {
690 /* global variable for HAMMER2 vnops */
691 hammer2_curnode
= cur
;
693 /* construct source path */
695 path
= cur
->contents
;
697 if (S_ISDIR(cur
->type
)) {
698 /* this should be same as root/path/name */
699 if (snprintf(f
, sizeof(f
), "%s/%s",
700 dir
, cur
->name
) >= (int)sizeof(f
))
701 errx(1, "path %s too long", f
);
703 if (snprintf(f
, sizeof(f
), "%s/%s/%s",
704 cur
->root
, cur
->path
, cur
->name
) >= (int)sizeof(f
))
705 errx(1, "path %s too long", f
);
709 if (stat(path
, &st
) == -1)
710 err(1, "no such file %s", f
);
712 /* update node state */
713 if ((cur
->inode
->flags
& FI_ALLOCATED
) == 0) {
714 cur
->inode
->flags
|= FI_ALLOCATED
;
716 cur
->parent
= parent
;
719 /* detect hardlink */
720 if (cur
->inode
->flags
& FI_WRITTEN
) {
721 assert(!S_ISDIR(cur
->type
));
726 cur
->inode
->flags
|= FI_WRITTEN
;
728 /* make sure it doesn't exist yet */
730 error
= hammer2_nresolve(dvp
, &vp
, cur
->name
,
733 errx(1, "hammer2_nresolve(\"%s\") already exists",
735 hammer2_print(dvp
, vp
, cur
, depth
, "nresolve");
737 /* if directory, mkdir and recurse */
738 if (S_ISDIR(cur
->type
)) {
742 error
= hammer2_nmkdir(dvp
, &vp
, cur
->name
,
743 strlen(cur
->name
), cur
->inode
->st
.st_mode
);
745 errx(1, "hammer2_nmkdir(\"%s\") failed: %s",
746 cur
->name
, strerror(error
));
748 hammer2_print(dvp
, vp
, cur
, depth
, "nmkdir");
750 error
= hammer2_populate_dir(vp
, path
, cur
->child
, cur
,
753 errx(1, "failed to populate %s: %s",
754 path
, strerror(error
));
755 cur
->inode
->param
= vp
;
759 /* if regular file, creat and write its data */
760 if (S_ISREG(cur
->type
) && !hardlink
) {
761 assert(cur
->child
== NULL
);
764 error
= hammer2_ncreate(dvp
, &vp
, cur
->name
,
765 strlen(cur
->name
), cur
->inode
->st
.st_mode
);
767 errx(1, "hammer2_ncreate(\"%s\") failed: %s",
768 cur
->name
, strerror(error
));
770 hammer2_print(dvp
, vp
, cur
, depth
, "ncreate");
772 error
= hammer2_write_file(vp
, path
, cur
);
774 errx(1, "hammer2_write_file(\"%s\") failed: %s",
775 path
, strerror(error
));
776 cur
->inode
->param
= vp
;
780 /* if symlink, create a symlink against target */
781 if (S_ISLNK(cur
->type
)) {
782 assert(cur
->child
== NULL
);
785 error
= hammer2_nsymlink(dvp
, &vp
, cur
->name
,
786 strlen(cur
->name
), cur
->symlink
,
787 cur
->inode
->st
.st_mode
);
789 errx(1, "hammer2_nsymlink(\"%s\") failed: %s",
790 cur
->name
, strerror(error
));
792 hammer2_print(dvp
, vp
, cur
, depth
, "nsymlink");
793 cur
->inode
->param
= vp
;
797 /* if fifo, create a fifo */
798 if (S_ISFIFO(cur
->type
) && !hardlink
) {
799 assert(cur
->child
== NULL
);
802 error
= hammer2_nmknod(dvp
, &vp
, cur
->name
,
803 strlen(cur
->name
), VFIFO
, cur
->inode
->st
.st_mode
);
805 errx(1, "hammer2_nmknod(\"%s\") failed: %s",
806 cur
->name
, strerror(error
));
808 hammer2_print(dvp
, vp
, cur
, depth
, "nmknod");
809 cur
->inode
->param
= vp
;
813 /* if hardlink, creat a hardlink */
814 if ((S_ISREG(cur
->type
) || S_ISFIFO(cur
->type
)) && hardlink
) {
816 assert(cur
->child
== NULL
);
818 /* source vnode must not be NULL */
819 vp
= cur
->inode
->param
;
821 /* currently these conditions must be true */
823 assert(vp
->v_type
== VREG
|| vp
->v_type
== VFIFO
);
824 assert(vp
->v_logical
);
825 assert(!vp
->v_vflushed
);
826 assert(vp
->v_malloced
);
827 assert(VTOI(vp
)->refs
> 0);
829 error
= hammer2_nlink(dvp
, vp
, cur
->name
,
832 errx(1, "hammer2_nlink(\"%s\") failed: %s",
833 cur
->name
, strerror(error
));
834 snprintf(buf
, sizeof(buf
), "nlink=%lld",
835 (long long)VTOI(vp
)->meta
.nlinks
);
836 hammer2_print(dvp
, vp
, cur
, depth
, buf
);
840 /* other types are unsupported */
841 printf("ignore %s 0%o\n", path
, cur
->type
);
848 hammer2_write_file(struct m_vnode
*vp
, const char *path
, fsnode
*node
)
850 struct stat
*st
= &node
->inode
->st
;
851 size_t nsize
, bufsize
;
859 /* check nsize vs maximum file size */
861 fd
= open(path
, O_RDONLY
);
863 err(1, "failed to open %s", path
);
865 p
= mmap(0, nsize
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
867 err(1, "failed to mmap %s", path
);
870 for (offset
= 0; offset
< nsize
; ) {
871 bufsize
= MIN(nsize
- offset
, HAMMER2_PBUFSIZE
);
872 assert(bufsize
<= HAMMER2_PBUFSIZE
);
873 error
= hammer2_write(vp
, p
+ offset
, bufsize
, offset
);
875 errx(1, "failed to write to %s vnode: %s",
876 path
, strerror(error
));
878 if (bufsize
== HAMMER2_PBUFSIZE
)
879 assert((offset
& (HAMMER2_PBUFSIZE
- 1)) == 0);