| File: | src/usr.sbin/makefs/ffs.c |
| Warning: | line 453, column 2 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ffs.c,v 1.36 2022/01/11 05:34:32 jsg Exp $ */ | |||
| 2 | /* $NetBSD: ffs.c,v 1.66 2015/12/21 00:58:08 christos Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 2001 Wasabi Systems, Inc. | |||
| 6 | * All rights reserved. | |||
| 7 | * | |||
| 8 | * Written by Luke Mewburn for Wasabi Systems, Inc. | |||
| 9 | * | |||
| 10 | * Redistribution and use in source and binary forms, with or without | |||
| 11 | * modification, are permitted provided that the following conditions | |||
| 12 | * are met: | |||
| 13 | * 1. Redistributions of source code must retain the above copyright | |||
| 14 | * notice, this list of conditions and the following disclaimer. | |||
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 16 | * notice, this list of conditions and the following disclaimer in the | |||
| 17 | * documentation and/or other materials provided with the distribution. | |||
| 18 | * 3. All advertising materials mentioning features or use of this software | |||
| 19 | * must display the following acknowledgement: | |||
| 20 | * This product includes software developed for the NetBSD Project by | |||
| 21 | * Wasabi Systems, Inc. | |||
| 22 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | |||
| 23 | * or promote products derived from this software without specific prior | |||
| 24 | * written permission. | |||
| 25 | * | |||
| 26 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | |||
| 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
| 28 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
| 29 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | |||
| 30 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
| 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
| 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
| 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
| 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
| 35 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 36 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 37 | */ | |||
| 38 | /* | |||
| 39 | * Copyright (c) 1982, 1986, 1989, 1993 | |||
| 40 | * The Regents of the University of California. All rights reserved. | |||
| 41 | * | |||
| 42 | * Redistribution and use in source and binary forms, with or without | |||
| 43 | * modification, are permitted provided that the following conditions | |||
| 44 | * are met: | |||
| 45 | * 1. Redistributions of source code must retain the above copyright | |||
| 46 | * notice, this list of conditions and the following disclaimer. | |||
| 47 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 48 | * notice, this list of conditions and the following disclaimer in the | |||
| 49 | * documentation and/or other materials provided with the distribution. | |||
| 50 | * 3. Neither the name of the University nor the names of its contributors | |||
| 51 | * may be used to endorse or promote products derived from this software | |||
| 52 | * without specific prior written permission. | |||
| 53 | * | |||
| 54 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 55 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 56 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 57 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 58 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 59 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 60 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 61 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 62 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 63 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 64 | * SUCH DAMAGE. | |||
| 65 | * | |||
| 66 | * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95 | |||
| 67 | */ | |||
| 68 | ||||
| 69 | #include <sys/param.h> /* roundup DEV_BSIZE */ | |||
| 70 | #include <sys/types.h> | |||
| 71 | #include <sys/disklabel.h> | |||
| 72 | ||||
| 73 | #include <assert.h> | |||
| 74 | #include <errno(*__errno()).h> | |||
| 75 | #include <fcntl.h> | |||
| 76 | #include <stdarg.h> | |||
| 77 | #include <stdio.h> | |||
| 78 | #include <stdint.h> | |||
| 79 | #include <limits.h> | |||
| 80 | #include <stdlib.h> | |||
| 81 | #include <string.h> | |||
| 82 | #include <unistd.h> | |||
| 83 | ||||
| 84 | #include <ufs/ufs/dinode.h> | |||
| 85 | #include <ufs/ufs/dir.h> | |||
| 86 | #include <ufs/ffs/fs.h> | |||
| 87 | ||||
| 88 | #include "ffs/ufs_inode.h" | |||
| 89 | #include "ffs/ffs_extern.h" | |||
| 90 | ||||
| 91 | #include "makefs.h" | |||
| 92 | #include "ffs.h" | |||
| 93 | #include "ffs/newfs_extern.h" | |||
| 94 | ||||
| 95 | #undef DIP | |||
| 96 | #define DIP(dp, field)((ffs_opts->version == 1) ? (dp)->ffs1_din.di_field : ( dp)->ffs2_din.di_field) \ | |||
| 97 | ((ffs_opts->version == 1) ? \ | |||
| 98 | (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field) | |||
| 99 | ||||
| 100 | /* | |||
| 101 | * Various file system defaults (cribbed from newfs(8)). | |||
| 102 | */ | |||
| 103 | #define DFL_FRAGSIZE2048 2048 /* fragment size */ | |||
| 104 | #define DFL_BLKSIZE16384 16384 /* block size */ | |||
| 105 | #define DFL_SECSIZE512 512 /* sector size */ | |||
| 106 | ||||
| 107 | ||||
| 108 | typedef struct { | |||
| 109 | u_char *buf; /* buf for directory */ | |||
| 110 | doff_tint32_t size; /* full size of buf */ | |||
| 111 | doff_tint32_t cur; /* offset of current entry */ | |||
| 112 | } dirbuf_t; | |||
| 113 | ||||
| 114 | ||||
| 115 | static int ffs_create_image(const char *, fsinfo_t *); | |||
| 116 | static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *); | |||
| 117 | static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *); | |||
| 118 | static void ffs_size_dir(fsnode *, fsinfo_t *); | |||
| 119 | static void ffs_validate(const char *, fsnode *, fsinfo_t *); | |||
| 120 | static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *); | |||
| 121 | static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *); | |||
| 122 | static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *, | |||
| 123 | fsnode *, fsinfo_t *); | |||
| 124 | static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, | |||
| 125 | fsnode *, fsinfo_t *); | |||
| 126 | ||||
| 127 | ||||
| 128 | ||||
| 129 | /* publicly visible functions */ | |||
| 130 | void | |||
| 131 | ffs_prep_opts(fsinfo_t *fsopts) | |||
| 132 | { | |||
| 133 | ffs_opt_t *ffs_opts = ecalloc(1, sizeof(*ffs_opts)); | |||
| 134 | ||||
| 135 | const option_t ffs_options[] = { | |||
| 136 | { "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 137 | { "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 138 | { "bsize", &ffs_opts->bsize, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 139 | { "density", &ffs_opts->density, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 140 | { "disklabel", NULL((void*)0), OPT_STRBUF, 0, 0 }, | |||
| 141 | { "extent", &ffs_opts->maxbsize, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 142 | { "fsize", &ffs_opts->fsize, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 143 | { "label", ffs_opts->label, OPT_STRARRAY, 1, MAXVOLLEN32 }, | |||
| 144 | { "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 145 | { "maxbpg", &ffs_opts->maxbpg, OPT_INT32, 1, INT_MAX2147483647 }, | |||
| 146 | { "minfree", &ffs_opts->minfree, OPT_INT32, 0, 99 }, | |||
| 147 | { "optimization", NULL((void*)0), OPT_STRBUF, 0, 0 }, | |||
| 148 | { "version", &ffs_opts->version, OPT_INT32, 1, 2 }, | |||
| 149 | { .name = NULL((void*)0) } | |||
| 150 | }; | |||
| 151 | ||||
| 152 | ffs_opts->bsize = -1; | |||
| 153 | ffs_opts->fsize = -1; | |||
| 154 | ffs_opts->density = -1; | |||
| 155 | ffs_opts->minfree = MINFREE5; | |||
| 156 | ffs_opts->optimization = FS_OPTSPACE1; | |||
| 157 | ffs_opts->maxbpg = -1; | |||
| 158 | ffs_opts->avgfilesize = AVFILESIZ16384; | |||
| 159 | ffs_opts->avgfpdir = AFPDIR64; | |||
| 160 | ffs_opts->version = 1; | |||
| 161 | ffs_opts->lp = NULL((void*)0); | |||
| 162 | ffs_opts->pp = NULL((void*)0); | |||
| 163 | ||||
| 164 | fsopts->fs_specific = ffs_opts; | |||
| 165 | fsopts->fs_options = copy_opts(ffs_options); | |||
| 166 | } | |||
| 167 | ||||
| 168 | void | |||
| 169 | ffs_cleanup_opts(fsinfo_t *fsopts) | |||
| 170 | { | |||
| 171 | free(fsopts->fs_specific); | |||
| 172 | free(fsopts->fs_options); | |||
| 173 | } | |||
| 174 | ||||
| 175 | int | |||
| 176 | ffs_parse_opts(const char *option, fsinfo_t *fsopts) | |||
| 177 | { | |||
| 178 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 179 | option_t *ffs_options = fsopts->fs_options; | |||
| 180 | char buf[1024]; | |||
| 181 | ||||
| 182 | int rv; | |||
| 183 | ||||
| 184 | assert(option != NULL)((option != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 184, __func__, "option != NULL")); | |||
| 185 | assert(fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 185, __func__, "fsopts != NULL")); | |||
| 186 | assert(ffs_opts != NULL)((ffs_opts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 186, __func__, "ffs_opts != NULL")); | |||
| 187 | ||||
| 188 | rv = set_option(ffs_options, option, buf, sizeof(buf)); | |||
| 189 | if (rv == -1) | |||
| 190 | return 0; | |||
| 191 | ||||
| 192 | if (ffs_options[rv].name == NULL((void*)0)) | |||
| 193 | abort(); | |||
| 194 | ||||
| 195 | if (strcmp(ffs_options[rv].name, "disklabel") == 0) { | |||
| 196 | struct disklabel *dp; | |||
| 197 | ||||
| 198 | dp = getdiskbyname(buf); | |||
| 199 | if (dp == NULL((void*)0)) | |||
| 200 | errx(1, "unknown disk type: %s", buf); | |||
| 201 | ||||
| 202 | ffs_opts->lp = emalloc(sizeof(struct disklabel)); | |||
| 203 | *ffs_opts->lp = *dp; | |||
| 204 | } else if (strcmp(ffs_options[rv].name, "optimization") == 0) { | |||
| 205 | if (strcmp(buf, "time") == 0) { | |||
| 206 | ffs_opts->optimization = FS_OPTTIME0; | |||
| 207 | } else if (strcmp(buf, "space") == 0) { | |||
| 208 | ffs_opts->optimization = FS_OPTSPACE1; | |||
| 209 | } else { | |||
| 210 | warnx("Invalid optimization `%s'", buf); | |||
| 211 | return 0; | |||
| 212 | } | |||
| 213 | } | |||
| 214 | return 1; | |||
| 215 | } | |||
| 216 | ||||
| 217 | ||||
| 218 | void | |||
| 219 | ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) | |||
| 220 | { | |||
| 221 | struct fs *superblock; | |||
| 222 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 223 | ||||
| 224 | assert(image != NULL)((image != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 224, __func__, "image != NULL")); | |||
| ||||
| 225 | assert(dir != NULL)((dir != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 225, __func__, "dir != NULL")); | |||
| 226 | assert(root != NULL)((root != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 226, __func__, "root != NULL")); | |||
| 227 | assert(fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 227, __func__, "fsopts != NULL")); | |||
| 228 | ||||
| 229 | /* validate tree and options */ | |||
| 230 | ffs_validate(dir, root, fsopts); | |||
| 231 | ||||
| 232 | printf("Calculated size of `%s': %lld bytes, %lld inodes\n", | |||
| 233 | image, (long long)fsopts->size, (long long)fsopts->inodes); | |||
| 234 | ||||
| 235 | /* create image */ | |||
| 236 | if (ffs_create_image(image, fsopts) == -1) | |||
| 237 | errx(1, "Image file `%s' not created.", image); | |||
| 238 | ||||
| 239 | fsopts->curinode = ROOTINO((ufsino_t)2); | |||
| 240 | ||||
| 241 | /* populate image */ | |||
| 242 | printf("Populating `%s'\n", image); | |||
| 243 | if (! ffs_populate_dir(dir, root, fsopts)) | |||
| 244 | errx(1, "Image file `%s' not populated.", image); | |||
| 245 | ||||
| 246 | bcleanup(); | |||
| 247 | ||||
| 248 | /* update various superblock parameters */ | |||
| 249 | superblock = fsopts->superblock; | |||
| 250 | superblock->fs_fmod = 0; | |||
| 251 | superblock->fs_ffs1_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir; | |||
| 252 | superblock->fs_ffs1_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree; | |||
| 253 | superblock->fs_ffs1_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree; | |||
| 254 | superblock->fs_ffs1_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree; | |||
| 255 | ||||
| 256 | /* write out superblock; image is now complete */ | |||
| 257 | ffs_write_superblock(fsopts->superblock, fsopts); | |||
| 258 | ||||
| 259 | if (ffs_opts->lp != NULL((void*)0)) { | |||
| 260 | struct disklabel *lp = ffs_opts->lp; | |||
| 261 | uint16_t *p, *end, sum = 0; | |||
| 262 | ssize_t n; | |||
| 263 | uint32_t bpg; | |||
| 264 | ||||
| 265 | bpg = superblock->fs_fpg / superblock->fs_frag; | |||
| 266 | while (bpg > UINT16_MAX0xffff) | |||
| 267 | bpg >>= 1; | |||
| 268 | ffs_opts->pp->p_cpg = bpg; | |||
| 269 | ||||
| 270 | lp->d_magic = DISKMAGIC((u_int32_t)0x82564557); | |||
| 271 | lp->d_magic2 = DISKMAGIC((u_int32_t)0x82564557); | |||
| 272 | arc4random_buf(lp->d_uid, sizeof(lp->d_uid)); | |||
| 273 | lp->d_checksum = 0; | |||
| 274 | ||||
| 275 | p = (uint16_t *)lp; | |||
| 276 | end = (uint16_t *)&lp->d_partitions[lp->d_npartitions]; | |||
| 277 | while (p < end) | |||
| 278 | sum ^= *p++; | |||
| 279 | lp->d_checksum = sum; | |||
| 280 | ||||
| 281 | n = pwrite(fsopts->fd, lp, sizeof(struct disklabel), | |||
| 282 | fsopts->offset + LABELSECTOR1 * DEV_BSIZE(1 << 9) + LABELOFFSET0); | |||
| 283 | if (n == -1) | |||
| 284 | err(1, "failed to write disklabel"); | |||
| 285 | else if (n < sizeof(struct disklabel)) | |||
| 286 | errx(1, "failed to write disklabel: short write"); | |||
| 287 | } | |||
| 288 | ||||
| 289 | if (close(fsopts->fd) == -1) | |||
| 290 | err(1, "Closing `%s'", image); | |||
| 291 | fsopts->fd = -1; | |||
| 292 | printf("Image `%s' complete\n", image); | |||
| 293 | } | |||
| 294 | ||||
| 295 | /* end of public functions */ | |||
| 296 | ||||
| 297 | ||||
| 298 | static void | |||
| 299 | ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) | |||
| 300 | { | |||
| 301 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 302 | struct disklabel *lp = ffs_opts->lp; | |||
| 303 | struct partition *pp = NULL((void*)0); | |||
| 304 | int32_t ncg = 1; | |||
| 305 | int i; | |||
| 306 | ||||
| 307 | assert(dir != NULL)((dir != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 307, __func__, "dir != NULL")); | |||
| 308 | assert(root != NULL)((root != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 308, __func__, "root != NULL")); | |||
| 309 | assert(fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 309, __func__, "fsopts != NULL")); | |||
| 310 | assert(ffs_opts != NULL)((ffs_opts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 310, __func__, "ffs_opts != NULL")); | |||
| 311 | ||||
| 312 | if (lp != NULL((void*)0)) { | |||
| 313 | for (i = 0; i < lp->d_npartitions; i++) { | |||
| 314 | pp = &lp->d_partitions[i]; | |||
| 315 | if (pp->p_fstype == FS_BSDFFS7 && | |||
| 316 | pp->p_offset * lp->d_secsize == fsopts->offset) { | |||
| 317 | break; | |||
| 318 | } | |||
| 319 | } | |||
| 320 | if (i == lp->d_npartitions) | |||
| 321 | errx(1, "no matching partition found in the disklabel"); | |||
| 322 | ffs_opts->pp = pp; | |||
| 323 | ||||
| 324 | if (pp->p_fragblock == 0) | |||
| 325 | errx(1, "fragment size missing in disktab"); | |||
| 326 | if (fsopts->freeblocks != 0 || fsopts->freeblockpc != 0 || | |||
| 327 | fsopts->freefiles != 0 || fsopts->freefilepc != 0 || | |||
| 328 | fsopts->minsize != 0 || fsopts->maxsize != 0 || | |||
| 329 | fsopts->sectorsize != -1 || fsopts->size != 0) | |||
| 330 | errx(1, "-bfMmSs and disklabel are mutually exclusive"); | |||
| 331 | if (ffs_opts->fsize != -1 || ffs_opts->bsize != -1) | |||
| 332 | errx(1, "b/fsize and disklabel are mutually exclusive"); | |||
| 333 | ||||
| 334 | fsopts->sectorsize = lp->d_secsize; | |||
| 335 | fsopts->minsize = fsopts->maxsize = | |||
| 336 | DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) * lp->d_secsize; | |||
| 337 | ffs_opts->fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock)(((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) & 0x07) - 1))) == 0 ? 0 : (((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock) >> 3) + 12))) / ((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) & 0x07) - 1))))); | |||
| 338 | ffs_opts->bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock)((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) >> 3) + 12))); | |||
| 339 | } | |||
| 340 | ||||
| 341 | /* set FFS defaults */ | |||
| 342 | if (fsopts->sectorsize == -1) | |||
| 343 | fsopts->sectorsize = DFL_SECSIZE512; | |||
| 344 | if (ffs_opts->fsize == -1) | |||
| 345 | ffs_opts->fsize = MAXIMUM(DFL_FRAGSIZE, fsopts->sectorsize)(((2048) > (fsopts->sectorsize)) ? (2048) : (fsopts-> sectorsize)); | |||
| 346 | if (ffs_opts->bsize == -1) | |||
| 347 | ffs_opts->bsize = MINIMUM(DFL_BLKSIZE, 8 * ffs_opts->fsize)(((16384) < (8 * ffs_opts->fsize)) ? (16384) : (8 * ffs_opts ->fsize)); | |||
| 348 | /* fsopts->density is set below */ | |||
| 349 | /* XXX ondisk32 */ | |||
| 350 | if (ffs_opts->maxbpg == -1) | |||
| 351 | ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t); | |||
| 352 | ||||
| 353 | /* calculate size of tree */ | |||
| 354 | ffs_size_dir(root, fsopts); | |||
| 355 | fsopts->inodes += ROOTINO((ufsino_t)2); /* include first two inodes */ | |||
| 356 | ||||
| 357 | /* add requested slop */ | |||
| 358 | fsopts->size += fsopts->freeblocks; | |||
| 359 | fsopts->inodes += fsopts->freefiles; | |||
| 360 | if (fsopts->freefilepc > 0) | |||
| 361 | fsopts->inodes = | |||
| 362 | fsopts->inodes * (100 + fsopts->freefilepc) / 100; | |||
| 363 | if (fsopts->freeblockpc > 0) | |||
| 364 | fsopts->size = | |||
| 365 | fsopts->size * (100 + fsopts->freeblockpc) / 100; | |||
| 366 | ||||
| 367 | /* add space needed for superblocks */ | |||
| 368 | /* | |||
| 369 | * The old SBOFF (SBLOCK_UFS1) is used here because makefs is | |||
| 370 | * typically used for small filesystems where space matters. | |||
| 371 | * XXX make this an option. | |||
| 372 | */ | |||
| 373 | fsopts->size += (SBLOCK_UFS18192 + SBLOCKSIZE8192) * ncg; | |||
| 374 | /* add space needed to store inodes, x3 for blockmaps, etc */ | |||
| 375 | if (ffs_opts->version == 1) | |||
| 376 | fsopts->size += ncg * sizeof(struct ufs1_dinode) * | |||
| 377 | roundup(fsopts->inodes / ncg,((((fsopts->inodes / ncg)+((ffs_opts->bsize / sizeof(struct ufs1_dinode))-1))/(ffs_opts->bsize / sizeof(struct ufs1_dinode )))*(ffs_opts->bsize / sizeof(struct ufs1_dinode))) | |||
| 378 | ffs_opts->bsize / sizeof(struct ufs1_dinode))((((fsopts->inodes / ncg)+((ffs_opts->bsize / sizeof(struct ufs1_dinode))-1))/(ffs_opts->bsize / sizeof(struct ufs1_dinode )))*(ffs_opts->bsize / sizeof(struct ufs1_dinode))); | |||
| 379 | else | |||
| 380 | fsopts->size += ncg * sizeof(struct ufs2_dinode) * | |||
| 381 | roundup(fsopts->inodes / ncg,((((fsopts->inodes / ncg)+((ffs_opts->bsize / sizeof(struct ufs2_dinode))-1))/(ffs_opts->bsize / sizeof(struct ufs2_dinode )))*(ffs_opts->bsize / sizeof(struct ufs2_dinode))) | |||
| 382 | ffs_opts->bsize / sizeof(struct ufs2_dinode))((((fsopts->inodes / ncg)+((ffs_opts->bsize / sizeof(struct ufs2_dinode))-1))/(ffs_opts->bsize / sizeof(struct ufs2_dinode )))*(ffs_opts->bsize / sizeof(struct ufs2_dinode))); | |||
| 383 | ||||
| 384 | /* add minfree */ | |||
| 385 | if (ffs_opts->minfree > 0) | |||
| 386 | fsopts->size = | |||
| 387 | fsopts->size * (100 + ffs_opts->minfree) / 100; | |||
| 388 | /* | |||
| 389 | * XXX any other fs slop to add, such as csum's, bitmaps, etc ?? | |||
| 390 | */ | |||
| 391 | ||||
| 392 | if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */ | |||
| 393 | fsopts->size = fsopts->minsize; | |||
| 394 | ||||
| 395 | /* round up to the next block */ | |||
| 396 | fsopts->size = roundup(fsopts->size, ffs_opts->bsize)((((fsopts->size)+((ffs_opts->bsize)-1))/(ffs_opts-> bsize))*(ffs_opts->bsize)); | |||
| 397 | ||||
| 398 | /* calculate density if necessary */ | |||
| 399 | if (ffs_opts->density == -1) | |||
| 400 | ffs_opts->density = fsopts->size / fsopts->inodes + 1; | |||
| 401 | ||||
| 402 | /* now check calculated sizes vs requested sizes */ | |||
| 403 | if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { | |||
| 404 | errx(1, "`%s' size of %lld is larger than the maxsize of %lld.", | |||
| 405 | dir, (long long)fsopts->size, (long long)fsopts->maxsize); | |||
| 406 | } | |||
| 407 | } | |||
| 408 | ||||
| 409 | ||||
| 410 | static int | |||
| 411 | ffs_create_image(const char *image, fsinfo_t *fsopts) | |||
| 412 | { | |||
| 413 | struct fs *fs; | |||
| 414 | char *buf; | |||
| 415 | int i, bufsize; | |||
| 416 | off_t bufrem; | |||
| 417 | time_t tstamp; | |||
| 418 | int oflags = O_RDWR0x0002 | O_CREAT0x0200; | |||
| 419 | ||||
| 420 | assert (image != NULL)((image != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 420, __func__, "image != NULL")); | |||
| 421 | assert (fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 421, __func__, "fsopts != NULL")); | |||
| 422 | ||||
| 423 | /* create image */ | |||
| 424 | if (fsopts->offset == 0) | |||
| 425 | oflags |= O_TRUNC0x0400; | |||
| 426 | if ((fsopts->fd = open(image, oflags, 0666)) == -1) { | |||
| 427 | warn("Can't open `%s' for writing", image); | |||
| 428 | return (-1); | |||
| 429 | } | |||
| 430 | ||||
| 431 | /* zero image */ | |||
| 432 | bufsize = 8192; | |||
| 433 | bufrem = fsopts->size; | |||
| 434 | ||||
| 435 | if (fsopts->offset
| |||
| 436 | if (lseek(fsopts->fd, fsopts->offset, SEEK_SET0) == -1) { | |||
| 437 | warn("can't seek"); | |||
| 438 | return -1; | |||
| 439 | } | |||
| 440 | ||||
| 441 | if (bufrem > 0) | |||
| 442 | buf = ecalloc(1, bufsize); | |||
| 443 | while (bufrem
| |||
| 444 | i = write(fsopts->fd, buf, MINIMUM(bufsize, bufrem)(((bufsize) < (bufrem)) ? (bufsize) : (bufrem))); | |||
| 445 | if (i == -1) { | |||
| 446 | warn("zeroing image, %lld bytes to go", | |||
| 447 | (long long)bufrem); | |||
| 448 | free(buf); | |||
| 449 | return (-1); | |||
| 450 | } | |||
| 451 | bufrem -= i; | |||
| 452 | } | |||
| 453 | free(buf); | |||
| ||||
| 454 | ||||
| 455 | /* make the file system */ | |||
| 456 | if (Tflag) { | |||
| 457 | tstamp = stampts; | |||
| 458 | srandom_deterministic(stampts); | |||
| 459 | } else | |||
| 460 | tstamp = start_time.tv_sec; | |||
| 461 | ||||
| 462 | fs = ffs_mkfs(image, fsopts, tstamp); | |||
| 463 | fsopts->superblock = (void *)fs; | |||
| 464 | ||||
| 465 | if ((off_t)(fs->fs_cstotal.cs_nifree + ROOTINO((ufsino_t)2)) < fsopts->inodes) { | |||
| 466 | warnx( | |||
| 467 | "Image file `%s' has %lld free inodes; %lld are required.", | |||
| 468 | image, | |||
| 469 | (long long)(fs->fs_cstotal.cs_nifree + ROOTINO((ufsino_t)2)), | |||
| 470 | (long long)fsopts->inodes); | |||
| 471 | return (-1); | |||
| 472 | } | |||
| 473 | return (fsopts->fd); | |||
| 474 | } | |||
| 475 | ||||
| 476 | ||||
| 477 | static void | |||
| 478 | ffs_size_dir(fsnode *root, fsinfo_t *fsopts) | |||
| 479 | { | |||
| 480 | struct direct tmpdir; | |||
| 481 | fsnode * node; | |||
| 482 | int curdirsize, this; | |||
| 483 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 484 | ||||
| 485 | /* node may be NULL (empty directory) */ | |||
| 486 | assert(fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 486, __func__, "fsopts != NULL")); | |||
| 487 | assert(ffs_opts != NULL)((ffs_opts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 487, __func__, "ffs_opts != NULL")); | |||
| 488 | ||||
| 489 | #define ADDDIRENT(e)do { tmpdir.d_namlen = strlen((e)); this = ((0) ? ((sizeof(struct direct) - (255 +1)) + (((&tmpdir)->d_type+1 + 3) & ~ 3)) : ((sizeof(struct direct) - (255 +1)) + (((&tmpdir) ->d_namlen+1 + 3) &~ 3))); if (this + curdirsize > ( (((curdirsize)+(((1 << 9))-1))/((1 << 9)))*((1 << 9)))) curdirsize = ((((curdirsize)+(((1 << 9))-1))/((1 << 9)))*((1 << 9))); curdirsize += this; } while (0); do { \ | |||
| 490 | tmpdir.d_namlen = strlen((e)); \ | |||
| 491 | this = DIRSIZ(NEWDIRFMT, &tmpdir)((0) ? ((sizeof(struct direct) - (255 +1)) + (((&tmpdir)-> d_type+1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1) ) + (((&tmpdir)->d_namlen+1 + 3) &~ 3))); \ | |||
| 492 | if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ)((((curdirsize)+(((1 << 9))-1))/((1 << 9)))*((1 << 9)))) \ | |||
| 493 | curdirsize = roundup(curdirsize, DIRBLKSIZ)((((curdirsize)+(((1 << 9))-1))/((1 << 9)))*((1 << 9))); \ | |||
| 494 | curdirsize += this; \ | |||
| 495 | } while (0); | |||
| 496 | ||||
| 497 | /* | |||
| 498 | * XXX this needs to take into account extra space consumed | |||
| 499 | * by indirect blocks, etc. | |||
| 500 | */ | |||
| 501 | #define ADDSIZE(x)do { fsopts->size += (((((x))+((ffs_opts->fsize)-1))/(ffs_opts ->fsize))*(ffs_opts->fsize)); } while (0); do { \ | |||
| 502 | fsopts->size += roundup((x), ffs_opts->fsize)(((((x))+((ffs_opts->fsize)-1))/(ffs_opts->fsize))*(ffs_opts ->fsize)); \ | |||
| 503 | } while (0); | |||
| 504 | ||||
| 505 | curdirsize = 0; | |||
| 506 | for (node = root; node != NULL((void*)0); node = node->next) { | |||
| 507 | ADDDIRENT(node->name)do { tmpdir.d_namlen = strlen((node->name)); this = ((0) ? ((sizeof(struct direct) - (255 +1)) + (((&tmpdir)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (&tmpdir)->d_namlen+1 + 3) &~ 3))); if (this + curdirsize > ((((curdirsize)+(((1 << 9))-1))/((1 << 9))) *((1 << 9)))) curdirsize = ((((curdirsize)+(((1 << 9))-1))/((1 << 9)))*((1 << 9))); curdirsize += this ; } while (0);; | |||
| 508 | if (node == root) { /* we're at "." */ | |||
| 509 | assert(strcmp(node->name, ".") == 0)((strcmp(node->name, ".") == 0) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 509, __func__, "strcmp(node->name, \".\") == 0")); | |||
| 510 | ADDDIRENT("..")do { tmpdir.d_namlen = strlen(("..")); this = ((0) ? ((sizeof (struct direct) - (255 +1)) + (((&tmpdir)->d_type+1 + 3 ) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (((& tmpdir)->d_namlen+1 + 3) &~ 3))); if (this + curdirsize > ((((curdirsize)+(((1 << 9))-1))/((1 << 9))) *((1 << 9)))) curdirsize = ((((curdirsize)+(((1 << 9))-1))/((1 << 9)))*((1 << 9))); curdirsize += this ; } while (0);; | |||
| 511 | } else if ((node->inode->flags & FI_SIZED) == 0) { | |||
| 512 | /* don't count duplicate names */ | |||
| 513 | node->inode->flags |= FI_SIZED; | |||
| 514 | fsopts->inodes++; | |||
| 515 | if (node->type == S_IFREG0100000) | |||
| 516 | ADDSIZE(node->inode->st.st_size)do { fsopts->size += (((((node->inode->st.st_size))+ ((ffs_opts->fsize)-1))/(ffs_opts->fsize))*(ffs_opts-> fsize)); } while (0);; | |||
| 517 | if (node->type == S_IFLNK0120000) { | |||
| 518 | size_t slen; | |||
| 519 | ||||
| 520 | slen = strlen(node->symlink) + 1; | |||
| 521 | if (slen >= (ffs_opts->version == 1 ? | |||
| 522 | MAXSYMLINKLEN_UFS1((12 + 3) * sizeof(int32_t)) : | |||
| 523 | MAXSYMLINKLEN_UFS2((12 + 3) * sizeof(int64_t)))) | |||
| 524 | ADDSIZE(slen)do { fsopts->size += (((((slen))+((ffs_opts->fsize)-1)) /(ffs_opts->fsize))*(ffs_opts->fsize)); } while (0);; | |||
| 525 | } | |||
| 526 | } | |||
| 527 | if (node->type == S_IFDIR0040000) | |||
| 528 | ffs_size_dir(node->child, fsopts); | |||
| 529 | } | |||
| 530 | ADDSIZE(curdirsize)do { fsopts->size += (((((curdirsize))+((ffs_opts->fsize )-1))/(ffs_opts->fsize))*(ffs_opts->fsize)); } while (0 );; | |||
| 531 | } | |||
| 532 | ||||
| 533 | static void * | |||
| 534 | ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, | |||
| 535 | fsnode *root, fsinfo_t *fsopts) | |||
| 536 | { | |||
| 537 | size_t slen; | |||
| 538 | void *membuf; | |||
| 539 | ||||
| 540 | memset(dinp, 0, sizeof(*dinp)); | |||
| 541 | dinp->di_mode = cur->inode->st.st_mode; | |||
| 542 | dinp->di_nlink = cur->inode->nlink; | |||
| 543 | dinp->di_size = cur->inode->st.st_size; | |||
| 544 | dinp->di_flags = cur->inode->st.st_flags; | |||
| 545 | dinp->di_gen = cur->inode->st.st_gen; | |||
| 546 | dinp->di_uid = cur->inode->st.st_uid; | |||
| 547 | dinp->di_gid = cur->inode->st.st_gid; | |||
| 548 | ||||
| 549 | dinp->di_atime = cur->inode->st.st_atimest_atim.tv_sec; | |||
| 550 | dinp->di_mtime = cur->inode->st.st_mtimest_mtim.tv_sec; | |||
| 551 | dinp->di_ctime = cur->inode->st.st_ctimest_ctim.tv_sec; | |||
| 552 | dinp->di_atimensec = cur->inode->st.st_atimensecst_atim.tv_nsec; | |||
| 553 | dinp->di_mtimensec = cur->inode->st.st_mtimensecst_mtim.tv_nsec; | |||
| 554 | dinp->di_ctimensec = cur->inode->st.st_ctimensecst_ctim.tv_nsec; | |||
| 555 | /* not set: di_db, di_ib, di_blocks, di_spare */ | |||
| 556 | ||||
| 557 | membuf = NULL((void*)0); | |||
| 558 | if (cur == root) { /* "."; write dirbuf */ | |||
| 559 | membuf = dbufp->buf; | |||
| 560 | dinp->di_size = dbufp->size; | |||
| 561 | } else if (S_ISBLK(cur->type)((cur->type & 0170000) == 0060000) || S_ISCHR(cur->type)((cur->type & 0170000) == 0020000)) { | |||
| 562 | dinp->di_size = 0; /* a device */ | |||
| 563 | dinp->di_rdevdi_db[0] = cur->inode->st.st_rdev; | |||
| 564 | } else if (S_ISLNK(cur->type)((cur->type & 0170000) == 0120000)) { /* symlink */ | |||
| 565 | slen = strlen(cur->symlink); | |||
| 566 | if (slen < MAXSYMLINKLEN_UFS1((12 + 3) * sizeof(int32_t))) { /* short link */ | |||
| 567 | memcpy(dinp->di_db, cur->symlink, slen); | |||
| 568 | } else | |||
| 569 | membuf = cur->symlink; | |||
| 570 | dinp->di_size = slen; | |||
| 571 | } | |||
| 572 | return membuf; | |||
| 573 | } | |||
| 574 | ||||
| 575 | static void * | |||
| 576 | ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, | |||
| 577 | fsnode *root, fsinfo_t *fsopts) | |||
| 578 | { | |||
| 579 | size_t slen; | |||
| 580 | void *membuf; | |||
| 581 | ||||
| 582 | memset(dinp, 0, sizeof(*dinp)); | |||
| 583 | dinp->di_mode = cur->inode->st.st_mode; | |||
| 584 | dinp->di_nlink = cur->inode->nlink; | |||
| 585 | dinp->di_size = cur->inode->st.st_size; | |||
| 586 | dinp->di_flags = cur->inode->st.st_flags; | |||
| 587 | dinp->di_gen = cur->inode->st.st_gen; | |||
| 588 | dinp->di_uid = cur->inode->st.st_uid; | |||
| 589 | dinp->di_gid = cur->inode->st.st_gid; | |||
| 590 | ||||
| 591 | dinp->di_atime = cur->inode->st.st_atimest_atim.tv_sec; | |||
| 592 | dinp->di_mtime = cur->inode->st.st_mtimest_mtim.tv_sec; | |||
| 593 | dinp->di_ctime = cur->inode->st.st_ctimest_ctim.tv_sec; | |||
| 594 | dinp->di_atimensec = cur->inode->st.st_atimensecst_atim.tv_nsec; | |||
| 595 | dinp->di_mtimensec = cur->inode->st.st_mtimensecst_mtim.tv_nsec; | |||
| 596 | dinp->di_ctimensec = cur->inode->st.st_ctimensecst_ctim.tv_nsec; | |||
| 597 | /* not set: di_db, di_ib, di_blocks, di_spare */ | |||
| 598 | ||||
| 599 | membuf = NULL((void*)0); | |||
| 600 | if (cur == root) { /* "."; write dirbuf */ | |||
| 601 | membuf = dbufp->buf; | |||
| 602 | dinp->di_size = dbufp->size; | |||
| 603 | } else if (S_ISBLK(cur->type)((cur->type & 0170000) == 0060000) || S_ISCHR(cur->type)((cur->type & 0170000) == 0020000)) { | |||
| 604 | dinp->di_size = 0; /* a device */ | |||
| 605 | dinp->di_rdevdi_db[0] = cur->inode->st.st_rdev; | |||
| 606 | } else if (S_ISLNK(cur->type)((cur->type & 0170000) == 0120000)) { /* symlink */ | |||
| 607 | slen = strlen(cur->symlink); | |||
| 608 | if (slen < MAXSYMLINKLEN_UFS2((12 + 3) * sizeof(int64_t))) { /* short link */ | |||
| 609 | memcpy(dinp->di_db, cur->symlink, slen); | |||
| 610 | } else | |||
| 611 | membuf = cur->symlink; | |||
| 612 | dinp->di_size = slen; | |||
| 613 | } | |||
| 614 | return membuf; | |||
| 615 | } | |||
| 616 | ||||
| 617 | static int | |||
| 618 | ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts) | |||
| 619 | { | |||
| 620 | fsnode *cur; | |||
| 621 | dirbuf_t dirbuf; | |||
| 622 | union dinode din; | |||
| 623 | void *membuf; | |||
| 624 | char path[PATH_MAX1024 + 1]; | |||
| 625 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 626 | ||||
| 627 | assert(dir != NULL)((dir != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 627, __func__, "dir != NULL")); | |||
| 628 | assert(root != NULL)((root != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 628, __func__, "root != NULL")); | |||
| 629 | assert(fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 629, __func__, "fsopts != NULL")); | |||
| 630 | assert(ffs_opts != NULL)((ffs_opts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 630, __func__, "ffs_opts != NULL")); | |||
| 631 | ||||
| 632 | (void)memset(&dirbuf, 0, sizeof(dirbuf)); | |||
| 633 | ||||
| 634 | /* | |||
| 635 | * pass 1: allocate inode numbers, build directory `file' | |||
| 636 | */ | |||
| 637 | for (cur = root; cur != NULL((void*)0); cur = cur->next) { | |||
| 638 | if ((cur->inode->flags & FI_ALLOCATED) == 0) { | |||
| 639 | cur->inode->flags |= FI_ALLOCATED; | |||
| 640 | if (cur == root && cur->parent != NULL((void*)0)) | |||
| 641 | cur->inode->ino = cur->parent->inode->ino; | |||
| 642 | else { | |||
| 643 | cur->inode->ino = fsopts->curinode; | |||
| 644 | fsopts->curinode++; | |||
| 645 | } | |||
| 646 | } | |||
| 647 | ffs_make_dirbuf(&dirbuf, cur->name, cur); | |||
| 648 | if (cur == root) { /* we're at "."; add ".." */ | |||
| 649 | ffs_make_dirbuf(&dirbuf, "..", | |||
| 650 | cur->parent == NULL((void*)0) ? cur : cur->parent->first); | |||
| 651 | root->inode->nlink++; /* count my parent's link */ | |||
| 652 | } else if (cur->child != NULL((void*)0)) | |||
| 653 | root->inode->nlink++; /* count my child's link */ | |||
| 654 | ||||
| 655 | /* | |||
| 656 | * XXX possibly write file and long symlinks here, | |||
| 657 | * ensuring that blocks get written before inodes? | |||
| 658 | * otoh, this isn't a real filesystem, so who | |||
| 659 | * cares about ordering? :-) | |||
| 660 | */ | |||
| 661 | } | |||
| 662 | ||||
| 663 | /* | |||
| 664 | * pass 2: write out dirbuf, then non-directories at this level | |||
| 665 | */ | |||
| 666 | for (cur = root; cur != NULL((void*)0); cur = cur->next) { | |||
| 667 | if (cur->inode->flags & FI_WRITTEN) | |||
| 668 | continue; /* skip hard-linked entries */ | |||
| 669 | cur->inode->flags |= FI_WRITTEN; | |||
| 670 | ||||
| 671 | if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root, | |||
| 672 | cur->path, cur->name) >= sizeof(path)) | |||
| 673 | errx(1, "Pathname too long."); | |||
| 674 | ||||
| 675 | if (cur->child != NULL((void*)0)) | |||
| 676 | continue; /* child creates own inode */ | |||
| 677 | ||||
| 678 | /* build on-disk inode */ | |||
| 679 | if (ffs_opts->version == 1) | |||
| 680 | membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur, | |||
| 681 | root, fsopts); | |||
| 682 | else | |||
| 683 | membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur, | |||
| 684 | root, fsopts); | |||
| 685 | ||||
| 686 | if (membuf != NULL((void*)0)) { | |||
| 687 | ffs_write_file(&din, cur->inode->ino, membuf, fsopts); | |||
| 688 | } else if (S_ISREG(cur->type)((cur->type & 0170000) == 0100000)) { | |||
| 689 | ffs_write_file(&din, cur->inode->ino, path, fsopts); | |||
| 690 | } else { | |||
| 691 | assert (! S_ISDIR(cur->type))((! ((cur->type & 0170000) == 0040000)) ? (void)0 : __assert2 ("/usr/src/usr.sbin/makefs/ffs.c", 691, __func__, "! S_ISDIR(cur->type)" )); | |||
| 692 | ffs_write_inode(&din, cur->inode->ino, fsopts); | |||
| 693 | } | |||
| 694 | } | |||
| 695 | ||||
| 696 | /* | |||
| 697 | * pass 3: write out sub-directories | |||
| 698 | */ | |||
| 699 | for (cur = root; cur != NULL((void*)0); cur = cur->next) { | |||
| 700 | if (cur->child == NULL((void*)0)) | |||
| 701 | continue; | |||
| 702 | if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir, | |||
| 703 | cur->name) >= sizeof(path)) | |||
| 704 | errx(1, "Pathname too long."); | |||
| 705 | if (! ffs_populate_dir(path, cur->child, fsopts)) | |||
| 706 | return (0); | |||
| 707 | } | |||
| 708 | ||||
| 709 | /* cleanup */ | |||
| 710 | free(dirbuf.buf); | |||
| 711 | return (1); | |||
| 712 | } | |||
| 713 | ||||
| 714 | ||||
| 715 | static void | |||
| 716 | ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts) | |||
| 717 | { | |||
| 718 | int isfile, ffd; | |||
| 719 | char *fbuf, *p; | |||
| 720 | off_t bufleft, chunk, offset; | |||
| 721 | ssize_t nread; | |||
| 722 | struct inode in; | |||
| 723 | struct mkfsbuf * bp; | |||
| 724 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 725 | struct mkfsvnode vp = { fsopts, NULL((void*)0) }; | |||
| 726 | ||||
| 727 | assert (din != NULL)((din != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 727, __func__, "din != NULL")); | |||
| 728 | assert (buf != NULL)((buf != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 728, __func__, "buf != NULL")); | |||
| 729 | assert (fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 729, __func__, "fsopts != NULL")); | |||
| 730 | assert (ffs_opts != NULL)((ffs_opts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 730, __func__, "ffs_opts != NULL")); | |||
| 731 | ||||
| 732 | isfile = S_ISREG(DIP(din, mode))((((ffs_opts->version == 1) ? (din)->ffs1_din.di_mode : (din)->ffs2_din.di_mode) & 0170000) == 0100000); | |||
| 733 | fbuf = NULL((void*)0); | |||
| 734 | ffd = -1; | |||
| 735 | p = NULL((void*)0); | |||
| 736 | ||||
| 737 | in.i_fs = (struct fs *)fsopts->superblock; | |||
| 738 | in.i_devvp = &vp; | |||
| 739 | ||||
| 740 | in.i_number = ino; | |||
| 741 | in.i_size = DIP(din, size)((ffs_opts->version == 1) ? (din)->ffs1_din.di_size : ( din)->ffs2_din.di_size); | |||
| 742 | if (ffs_opts->version == 1) | |||
| 743 | memcpy(&in.i_din.ffs1_din, &din->ffs1_din, | |||
| 744 | sizeof(in.i_din.ffs1_din)); | |||
| 745 | else | |||
| 746 | memcpy(&in.i_din.ffs2_din, &din->ffs2_din, | |||
| 747 | sizeof(in.i_din.ffs2_din)); | |||
| 748 | ||||
| 749 | if (DIP(din, size)((ffs_opts->version == 1) ? (din)->ffs1_din.di_size : ( din)->ffs2_din.di_size) == 0) | |||
| 750 | goto write_inode_and_leave; /* mmm, cheating */ | |||
| 751 | ||||
| 752 | if (isfile) { | |||
| 753 | fbuf = emalloc(ffs_opts->bsize); | |||
| 754 | if ((ffd = open((char *)buf, O_RDONLY0x0000)) == -1) { | |||
| 755 | warn("Can't open `%s' for reading", (char *)buf); | |||
| 756 | goto leave_ffs_write_file; | |||
| 757 | } | |||
| 758 | } else { | |||
| 759 | p = buf; | |||
| 760 | } | |||
| 761 | ||||
| 762 | chunk = 0; | |||
| 763 | for (bufleft = DIP(din, size)((ffs_opts->version == 1) ? (din)->ffs1_din.di_size : ( din)->ffs2_din.di_size); bufleft > 0; bufleft -= chunk) { | |||
| 764 | chunk = MINIMUM(bufleft, ffs_opts->bsize)(((bufleft) < (ffs_opts->bsize)) ? (bufleft) : (ffs_opts ->bsize)); | |||
| 765 | if (!isfile) | |||
| 766 | ; | |||
| 767 | else if ((nread = read(ffd, fbuf, chunk)) == -1) | |||
| 768 | err(1, "Reading `%s', %lld bytes to go", (char *)buf, | |||
| 769 | (long long)bufleft); | |||
| 770 | else if (nread != chunk) | |||
| 771 | errx(1, "Reading `%s', %lld bytes to go, " | |||
| 772 | "read %zd bytes, expected %ju bytes, does " | |||
| 773 | "metalog size= attribute mismatch source size?", | |||
| 774 | (char *)buf, (long long)bufleft, nread, | |||
| 775 | (uintmax_t)chunk); | |||
| 776 | else | |||
| 777 | p = fbuf; | |||
| 778 | offset = DIP(din, size)((ffs_opts->version == 1) ? (din)->ffs1_din.di_size : ( din)->ffs2_din.di_size) - bufleft; | |||
| 779 | /* | |||
| 780 | * XXX if holey support is desired, do the check here | |||
| 781 | * | |||
| 782 | * XXX might need to write out last bit in fragroundup | |||
| 783 | * sized chunk. however, ffs_balloc() handles this for us | |||
| 784 | */ | |||
| 785 | errno(*__errno()) = ffs_balloc(&in, offset, chunk, &bp); | |||
| 786 | bad_ffs_write_file: | |||
| 787 | if (errno(*__errno()) != 0) | |||
| 788 | err(1, | |||
| 789 | "Writing inode %d (%s), bytes %lld + %lld", | |||
| 790 | ino, | |||
| 791 | isfile ? (char *)buf : | |||
| 792 | inode_type(DIP(din, mode)((ffs_opts->version == 1) ? (din)->ffs1_din.di_mode : ( din)->ffs2_din.di_mode) & S_IFMT0170000), | |||
| 793 | (long long)offset, (long long)chunk); | |||
| 794 | memcpy(bp->b_data, p, chunk); | |||
| 795 | errno(*__errno()) = bwrite(bp); | |||
| 796 | if (errno(*__errno()) != 0) | |||
| 797 | goto bad_ffs_write_file; | |||
| 798 | if (!isfile) | |||
| 799 | p += chunk; | |||
| 800 | } | |||
| 801 | ||||
| 802 | write_inode_and_leave: | |||
| 803 | ffs_write_inode(&in.i_din, in.i_number, fsopts); | |||
| 804 | ||||
| 805 | leave_ffs_write_file: | |||
| 806 | free(fbuf); | |||
| 807 | if (ffd != -1) | |||
| 808 | close(ffd); | |||
| 809 | } | |||
| 810 | ||||
| 811 | ||||
| 812 | static void | |||
| 813 | ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node) | |||
| 814 | { | |||
| 815 | struct direct de, *dp; | |||
| 816 | uint16_t llen; | |||
| 817 | u_char *newbuf; | |||
| 818 | ||||
| 819 | assert (dbuf != NULL)((dbuf != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 819, __func__, "dbuf != NULL")); | |||
| 820 | assert (name != NULL)((name != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 820, __func__, "name != NULL")); | |||
| 821 | assert (node != NULL)((node != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 821, __func__, "node != NULL")); | |||
| 822 | /* create direct entry */ | |||
| 823 | (void)memset(&de, 0, sizeof(de)); | |||
| 824 | de.d_ino = node->inode->ino; | |||
| 825 | de.d_type = IFTODT(node->type)(((node->type) & 0170000) >> 12); | |||
| 826 | de.d_namlen = (uint8_t)strlen(name); | |||
| 827 | strlcpy(de.d_name, name, sizeof de.d_name); | |||
| 828 | de.d_reclen = DIRSIZ(NEWDIRFMT, &de)((0) ? ((sizeof(struct direct) - (255 +1)) + (((&de)-> d_type+1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1) ) + (((&de)->d_namlen+1 + 3) &~ 3))); | |||
| 829 | ||||
| 830 | dp = (struct direct *)(dbuf->buf + dbuf->cur); | |||
| 831 | llen = 0; | |||
| 832 | if (dp != NULL((void*)0)) | |||
| 833 | llen = DIRSIZ(NEWDIRFMT, dp)((0) ? ((sizeof(struct direct) - (255 +1)) + (((dp)->d_type +1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (( (dp)->d_namlen+1 + 3) &~ 3))); | |||
| 834 | ||||
| 835 | if (de.d_reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)((((dbuf->size)+(((1 << 9))-1))/((1 << 9)))*(( 1 << 9)))) { | |||
| 836 | newbuf = erealloc(dbuf->buf, dbuf->size + DIRBLKSIZ(1 << 9)); | |||
| 837 | dbuf->buf = newbuf; | |||
| 838 | dbuf->size += DIRBLKSIZ(1 << 9); | |||
| 839 | memset(dbuf->buf + dbuf->size - DIRBLKSIZ(1 << 9), 0, DIRBLKSIZ(1 << 9)); | |||
| 840 | dbuf->cur = dbuf->size - DIRBLKSIZ(1 << 9); | |||
| 841 | } else if (dp) { /* shrink end of previous */ | |||
| 842 | dp->d_reclen = llen; | |||
| 843 | dbuf->cur += llen; | |||
| 844 | } | |||
| 845 | dp = (struct direct *)(dbuf->buf + dbuf->cur); | |||
| 846 | memcpy(dp, &de, de.d_reclen); | |||
| 847 | dp->d_reclen = dbuf->size - dbuf->cur; | |||
| 848 | } | |||
| 849 | ||||
| 850 | /* | |||
| 851 | * cribbed from sys/ufs/ffs/ffs_alloc.c | |||
| 852 | */ | |||
| 853 | static void | |||
| 854 | ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts) | |||
| 855 | { | |||
| 856 | char *buf; | |||
| 857 | struct ufs1_dinode *dp1; | |||
| 858 | struct ufs2_dinode *dp2, *dip; | |||
| 859 | struct cg *cgp; | |||
| 860 | struct fs *fs; | |||
| 861 | int cg, cgino, i; | |||
| 862 | daddr_t d; | |||
| 863 | char sbbuf[FFS_MAXBSIZE65536]; | |||
| 864 | uint32_t initediblk; | |||
| 865 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | |||
| 866 | ||||
| 867 | assert (dp != NULL)((dp != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 867, __func__, "dp != NULL")); | |||
| 868 | assert (ino > 0)((ino > 0) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 868, __func__, "ino > 0")); | |||
| 869 | assert (fsopts != NULL)((fsopts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 869, __func__, "fsopts != NULL")); | |||
| 870 | assert (ffs_opts != NULL)((ffs_opts != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 870, __func__, "ffs_opts != NULL")); | |||
| 871 | ||||
| 872 | fs = (struct fs *)fsopts->superblock; | |||
| 873 | cg = ino_to_cg(fs, ino)((ino) / (fs)->fs_ipg); | |||
| 874 | cgino = ino % fs->fs_ipg; | |||
| 875 | ||||
| 876 | ffs_rdfs(fsbtodb(fs, cgtod(fs, cg))((((((daddr_t)(fs)->fs_fpg * (cg)) + (fs)->fs_cgoffset * ((cg) & ~((fs)->fs_cgmask))) + (fs)->fs_cblkno)) << (fs)->fs_fsbtodb), (int)fs->fs_cgsize, &sbbuf, | |||
| 877 | fsopts); | |||
| 878 | cgp = (struct cg *)sbbuf; | |||
| 879 | if (!cg_chkmagic(cgp)((cgp)->cg_magic == 0x090255 || ((struct ocg *)(cgp))-> cg_magic == 0x090255)) | |||
| 880 | errx(1, "ffs_write_inode: cg %d: bad magic number", cg); | |||
| 881 | ||||
| 882 | assert (isclr(cg_inosused(cgp), cgino))((((((((cgp)->cg_magic != 0x090255) ? (((struct ocg *)(cgp ))->cg_iused) : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)-> cg_iusedoff))))[(cgino)>>3] & (1<<((cgino)& (8 -1)))) == 0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/ffs.c" , 882, __func__, "isclr(cg_inosused(cgp), cgino)")); | |||
| 883 | ||||
| 884 | buf = emalloc(fs->fs_bsize); | |||
| 885 | dp1 = (struct ufs1_dinode *)buf; | |||
| 886 | dp2 = (struct ufs2_dinode *)buf; | |||
| 887 | ||||
| 888 | if (fs->fs_cstotal.cs_nifree == 0) | |||
| 889 | errx(1, "ffs_write_inode: fs out of inodes for ino %u", | |||
| 890 | ino); | |||
| 891 | if (fs->fs_cs(fs, cg)fs_csp[cg].cs_nifree == 0) | |||
| 892 | errx(1, | |||
| 893 | "ffs_write_inode: cg %d out of inodes for ino %u", | |||
| 894 | cg, ino); | |||
| 895 | setbit(cg_inosused(cgp), cgino)(((((cgp)->cg_magic != 0x090255) ? (((struct ocg *)(cgp))-> cg_iused) : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff ))))[(cgino)>>3] |= 1<<((cgino)&(8 -1))); | |||
| 896 | cgp->cg_cs.cs_nifree -= 1; | |||
| 897 | fs->fs_cstotal.cs_nifree--; | |||
| 898 | fs->fs_cs(fs, cg)fs_csp[cg].cs_nifree--; | |||
| 899 | if (S_ISDIR(DIP(dp, mode))((((ffs_opts->version == 1) ? (dp)->ffs1_din.di_mode : ( dp)->ffs2_din.di_mode) & 0170000) == 0040000)) { | |||
| 900 | cgp->cg_cs.cs_ndir += 1; | |||
| 901 | fs->fs_cstotal.cs_ndir++; | |||
| 902 | fs->fs_cs(fs, cg)fs_csp[cg].cs_ndir++; | |||
| 903 | } | |||
| 904 | ||||
| 905 | /* | |||
| 906 | * Initialize inode blocks on the fly for UFS2. | |||
| 907 | */ | |||
| 908 | initediblk = cgp->cg_initediblk; | |||
| 909 | if (ffs_opts->version == 2 && | |||
| 910 | (uint32_t)(cgino + INOPB(fs)((fs)->fs_inopb)) > initediblk && | |||
| 911 | initediblk < cgp->cg_ffs2_niblk) { | |||
| 912 | memset(buf, 0, fs->fs_bsize); | |||
| 913 | dip = (struct ufs2_dinode *)buf; | |||
| 914 | for (i = 0; i < INOPB(fs)((fs)->fs_inopb); i++) { | |||
| 915 | dip->di_gen = random() / 2 + 1; | |||
| 916 | dip++; | |||
| 917 | } | |||
| 918 | ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs,((((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((cg * fs->fs_ipg + initediblk) / (fs)->fs_ipg))) + (fs)->fs_cgoffset * ( (((cg * fs->fs_ipg + initediblk) / (fs)->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno) + ((((((cg * fs ->fs_ipg + initediblk) % (fs)->fs_ipg) / ((fs)->fs_inopb ))) << ((fs))->fs_fragshift))))) << (fs)->fs_fsbtodb ) | |||
| 919 | cg * fs->fs_ipg + initediblk))((((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((cg * fs->fs_ipg + initediblk) / (fs)->fs_ipg))) + (fs)->fs_cgoffset * ( (((cg * fs->fs_ipg + initediblk) / (fs)->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno) + ((((((cg * fs ->fs_ipg + initediblk) % (fs)->fs_ipg) / ((fs)->fs_inopb ))) << ((fs))->fs_fragshift))))) << (fs)->fs_fsbtodb ), | |||
| 920 | fs->fs_bsize, buf, fsopts); | |||
| 921 | initediblk += INOPB(fs)((fs)->fs_inopb); | |||
| 922 | cgp->cg_initediblk = initediblk; | |||
| 923 | } | |||
| 924 | ||||
| 925 | ||||
| 926 | ffs_wtfs(fsbtodb(fs, cgtod(fs, cg))((((((daddr_t)(fs)->fs_fpg * (cg)) + (fs)->fs_cgoffset * ((cg) & ~((fs)->fs_cgmask))) + (fs)->fs_cblkno)) << (fs)->fs_fsbtodb), (int)fs->fs_cgsize, &sbbuf, | |||
| 927 | fsopts); | |||
| 928 | ||||
| 929 | /* now write inode */ | |||
| 930 | d = fsbtodb(fs, ino_to_fsba(fs, ino))((((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((ino) / (fs)-> fs_ipg))) + (fs)->fs_cgoffset * ((((ino) / (fs)->fs_ipg )) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno) + (((( ((ino) % (fs)->fs_ipg) / ((fs)->fs_inopb))) << (( fs))->fs_fragshift))))) << (fs)->fs_fsbtodb); | |||
| 931 | ffs_rdfs(d, fs->fs_bsize, buf, fsopts); | |||
| 932 | if (ffs_opts->version == 1) | |||
| 933 | dp1[ino_to_fsbo(fs, ino)((ino) % ((fs)->fs_inopb))] = dp->ffs1_din; | |||
| 934 | else | |||
| 935 | dp2[ino_to_fsbo(fs, ino)((ino) % ((fs)->fs_inopb))] = dp->ffs2_din; | |||
| 936 | ffs_wtfs(d, fs->fs_bsize, buf, fsopts); | |||
| 937 | free(buf); | |||
| 938 | } |