[BACK]Return to ffs.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / makefs

Annotation of src/usr.sbin/makefs/ffs.c, Revision 1.1.1.1

1.1       lukem       1: /*     $NetBSD$        */
                      2:
                      3: /*
                      4:  * Copyright 2001 Wasabi Systems, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Written by Luke Mewburn for Wasabi Systems, Inc.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed for the NetBSD Project by
                     20:  *      Wasabi Systems, Inc.
                     21:  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
                     22:  *    or promote products derived from this software without specific prior
                     23:  *    written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
                     26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     27:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     28:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
                     29:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     30:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     31:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     32:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     33:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     34:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     35:  * POSSIBILITY OF SUCH DAMAGE.
                     36:  */
                     37: /*
                     38:  * Copyright (c) 1982, 1986, 1989, 1993
                     39:  *     The Regents of the University of California.  All rights reserved.
                     40:  *
                     41:  * Redistribution and use in source and binary forms, with or without
                     42:  * modification, are permitted provided that the following conditions
                     43:  * are met:
                     44:  * 1. Redistributions of source code must retain the above copyright
                     45:  *    notice, this list of conditions and the following disclaimer.
                     46:  * 2. Redistributions in binary form must reproduce the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer in the
                     48:  *    documentation and/or other materials provided with the distribution.
                     49:  * 3. All advertising materials mentioning features or use of this software
                     50:  *    must display the following acknowledgement:
                     51:  *     This product includes software developed by the University of
                     52:  *     California, Berkeley and its contributors.
                     53:  * 4. Neither the name of the University nor the names of its contributors
                     54:  *    may be used to endorse or promote products derived from this software
                     55:  *    without specific prior written permission.
                     56:  *
                     57:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     58:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     59:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     60:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     61:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     62:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     63:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     64:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     65:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     66:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     67:  * SUCH DAMAGE.
                     68:  *
                     69:  *     @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95
                     70:  */
                     71:
                     72: #include <sys/param.h>
                     73: #include <sys/mount.h>
                     74:
                     75: #include <assert.h>
                     76: #include <err.h>
                     77: #include <errno.h>
                     78: #include <fcntl.h>
                     79: #include <stdarg.h>
                     80: #include <stdio.h>
                     81: #include <stdlib.h>
                     82: #include <string.h>
                     83: #include <unistd.h>
                     84:
                     85: #include "makefs.h"
                     86:
                     87: #include <ufs/ffs/fs.h>
                     88: #include <ufs/ufs/dir.h>
                     89: #include <ufs/ufs/dinode.h>
                     90: #include <ufs/ufs/inode.h>
                     91: #include <ufs/ufs/ufs_bswap.h>
                     92:
                     93: #include "ffs/newfs_extern.h"
                     94: #include "ffs/ffs_extern.h"
                     95:
                     96: /*
                     97:  * Various file system defaults (cribbed from newfs(8)).
                     98:  */
                     99: #define        DFL_FRAGSIZE            1024            /* fragment size */
                    100: #define        DFL_BLKSIZE             8192            /* block size */
                    101: #define        DFL_SECSIZE             512             /* sector size */
                    102: #define        DFL_CYLSPERGROUP        16              /* cylinders per group */
                    103: #define        DFL_FRAGSPERINODE       4               /* fragments per inode - XXX */
                    104: #define        DFL_ROTDELAY            0               /* rotational delay */
                    105: #define        DFL_NRPOS               1               /* rotational positions */
                    106: #define        DFL_RPM                 3600            /* rpm of disk */
                    107: #define        DFL_NSECTORS            64              /* # of sectors */
                    108: #define        DFL_NTRACKS             16              /* # of tracks */
                    109:
                    110:
                    111: typedef struct {
                    112:        u_char          *buf;           /* buf for directory */
                    113:        doff_t          size;           /* full size of buf */
                    114:        doff_t          cur;            /* offset of current entry */
                    115: } dirbuf_t;
                    116:
                    117:
                    118: static int     ffs_create_image(const char *, fsinfo_t *);
                    119: static void    ffs_dump_fsinfo(fsinfo_t *);
                    120: static void    ffs_dump_dirbuf(dirbuf_t *, const char *, int);
                    121: static void    ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int);
                    122: static int     ffs_populate_dir(const char *, fsnode *, fsinfo_t *);
                    123: static void    ffs_size_dir(fsnode *, fsinfo_t *);
                    124: static void    ffs_validate(const char *, fsnode *, fsinfo_t *);
                    125: static void    ffs_write_file(struct dinode *, uint32_t, void *, fsinfo_t *);
                    126: static void    ffs_write_inode(struct dinode *, uint32_t, const fsinfo_t *);
                    127:
                    128:
                    129: int    sectorsize;             /* XXX: for buf.c::getblk() */
                    130:
                    131:        /* publically visible functions */
                    132:
                    133: int
                    134: ffs_parse_opts(const char *option, fsinfo_t *fsopts)
                    135: {
                    136:        option_t ffs_options[] = {
                    137:                { "bsize",      &fsopts->bsize,         1,      INT_MAX,
                    138:                                        "block size" },
                    139:                { "fsize",      &fsopts->fsize,         1,      INT_MAX,
                    140:                                        "fragment size" },
                    141:                { "cpg",        &fsopts->cpg,           1,      INT_MAX,
                    142:                                        "cylinders per group" },
                    143:                { "density",    &fsopts->density,       1,      INT_MAX,
                    144:                                        "bytes per inode" },
                    145:                { "ntracks",    &fsopts->ntracks,       1,      INT_MAX,
                    146:                                        "number of tracks" },
                    147:                { "nsectors",   &fsopts->nsectors,      1,      INT_MAX,
                    148:                                        "number of sectors" },
                    149:                { "rpm",        &fsopts->rpm,           1,      INT_MAX,
                    150:                                        "revolutions per minute" },
                    151:                { "minfree",    &fsopts->minfree,       0,      99,
                    152:                                        "minfree" },
                    153:                { "rotdelay",   &fsopts->rotdelay,      0,      INT_MAX,
                    154:                                        "rotational delay" },
                    155:                { "maxbpg",     &fsopts->maxbpg,        1,      INT_MAX,
                    156:                                        "max blocks per cylgroup" },
                    157:                { "nrpos",      &fsopts->nrpos,         1,      INT_MAX,
                    158:                                        "number of rotational positions" },
                    159:                { "avgfilesize", &fsopts->avgfilesize,  1,      INT_MAX,
                    160:                                        "expected average file size" },
                    161:                { "avgfpdir",   &fsopts->avgfpdir,      1,      INT_MAX,
                    162:                                        "expected # of files per directory" },
                    163:                { NULL }
                    164:        };
                    165:
                    166:        char    *var, *val;
                    167:        int     rv;
                    168:
                    169:        (void)&ffs_options;
                    170:        assert(option != NULL);
                    171:        assert(fsopts != NULL);
                    172:
                    173:        if (debug & DEBUG_FS_PARSE_OPTS)
                    174:                printf("ffs_parse_opts: got `%s'\n", option);
                    175:
                    176:        if ((var = strdup(option)) == NULL)
                    177:                err(1, "Allocating memory for copy of option string");
                    178:        rv = 0;
                    179:
                    180:        if ((val = strchr(var, '=')) == NULL) {
                    181:                warnx("Option `%s' doesn't contain a value", var);
                    182:                goto leave_ffs_parse_opts;
                    183:        }
                    184:        *val++ = '\0';
                    185:
                    186:        if (strcmp(var, "optimization") == 0) {
                    187:                if (strcmp(val, "time") == 0) {
                    188:                        fsopts->optimization = FS_OPTTIME;
                    189:                } else if (strcmp(val, "space") == 0) {
                    190:                        fsopts->optimization = FS_OPTSPACE;
                    191:                } else {
                    192:                        warnx("Invalid optimization `%s'", val);
                    193:                        goto leave_ffs_parse_opts;
                    194:                }
                    195:                rv = 1;
                    196:        } else
                    197:                rv = set_option(ffs_options, var, val);
                    198:
                    199:  leave_ffs_parse_opts:
                    200:        if (var)
                    201:                free(var);
                    202:        return (rv);
                    203: }
                    204:
                    205:
                    206: void
                    207: ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
                    208: {
                    209:        struct timeval start;
                    210:
                    211:        assert(image != NULL);
                    212:        assert(dir != NULL);
                    213:        assert(root != NULL);
                    214:        assert(fsopts != NULL);
                    215:
                    216:        if (debug & DEBUG_FS_MAKEFS)
                    217:                printf("ffs_makefs: image %s directory %s root %p\n",
                    218:                    image, dir, root);
                    219:
                    220:                /* validate tree and options */
                    221:        TIMER_START(start);
                    222:        ffs_validate(dir, root, fsopts);
                    223:        TIMER_RESULTS(start, "ffs_validate");
                    224:
                    225:                /* create image */
                    226:        TIMER_START(start);
                    227:        if (ffs_create_image(image, fsopts) == -1)
                    228:                errx(1, "Image file `%s' not created.", image);
                    229:        TIMER_RESULTS(start, "ffs_create_image");
                    230:
                    231:        fsopts->curinode = ROOTINO;
                    232:
                    233:        if (debug & DEBUG_FS_MAKEFS)
                    234:                putchar('\n');
                    235:
                    236:                /* populate image */
                    237:        TIMER_START(start);
                    238:        if (! ffs_populate_dir(dir, root, fsopts))
                    239:                errx(1, "Image file `%s' not populated.", image);
                    240:        TIMER_RESULTS(start, "ffs_populate_dir");
                    241:
                    242:                /* ensure no outstanding buffers remain */
                    243:        if (debug & DEBUG_FS_MAKEFS)
                    244:                bcleanup();
                    245:
                    246:                /* write out superblock; image is now complete */
                    247:        ffs_write_superblock(fsopts->superblock, fsopts);
                    248: }
                    249:
                    250:        /* end of public functions */
                    251:
                    252:
                    253: static void
                    254: ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
                    255: {
                    256:        int32_t spc, nspf, ncyl, ncg, fssize;
                    257:
                    258:        assert(dir != NULL);
                    259:        assert(root != NULL);
                    260:        assert(fsopts != NULL);
                    261:
                    262:        if (debug & DEBUG_FS_VALIDATE) {
                    263:                printf("ffs_validate: before defaults set:\n");
                    264:                ffs_dump_fsinfo(fsopts);
                    265:        }
                    266:
                    267:                /* set FFS defaults */
                    268:        if (fsopts->sectorsize == 0)
                    269:                fsopts->sectorsize = DFL_SECSIZE;
                    270:        if (fsopts->fsize == 0)
                    271:                fsopts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
                    272:        if (fsopts->bsize == 0)
                    273:                fsopts->bsize = MIN(DFL_BLKSIZE, 8 * fsopts->fsize);
                    274:        if (fsopts->cpg == 0)
                    275:                fsopts->cpg = DFL_CYLSPERGROUP;
                    276:                                /* fsopts->density is set below */
                    277:        if (fsopts->ntracks == 0)
                    278:                fsopts->ntracks = DFL_NTRACKS;
                    279:        if (fsopts->nsectors == 0)
                    280:                fsopts->nsectors = DFL_NSECTORS;
                    281:        if (fsopts->rpm == 0)
                    282:                fsopts->rpm = DFL_RPM;
                    283:        if (fsopts->minfree == 0)
                    284:                fsopts->minfree = MINFREE;
                    285:        if (fsopts->optimization == 0)
                    286:                fsopts->optimization = DEFAULTOPT;
                    287:        if (fsopts->maxcontig == 0)
                    288:                fsopts->maxcontig =
                    289:                    MAX(1, MIN(MAXPHYS, MAXBSIZE) / fsopts->bsize);
                    290:        if (fsopts->rotdelay == 0)
                    291:                fsopts->rotdelay = DFL_ROTDELAY;
                    292:        if (fsopts->maxbpg == 0)
                    293:                fsopts->maxbpg = fsopts->bsize / sizeof(ufs_daddr_t);
                    294:        if (fsopts->nrpos == 0)
                    295:                fsopts->nrpos = DFL_NRPOS;
                    296:        if (fsopts->avgfilesize == 0)
                    297:                fsopts->avgfilesize = AVFILESIZ;
                    298:        if (fsopts->avgfpdir == 0)
                    299:                fsopts->avgfpdir = AFPDIR;
                    300:
                    301:                /* calculate size of tree */
                    302:        ffs_size_dir(root, fsopts);
                    303:        fsopts->inodes += ROOTINO;              /* include first two inodes */
                    304:
                    305:        if (debug & DEBUG_FS_VALIDATE)
                    306:                printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n",
                    307:                    (long long)fsopts->size, (long long)fsopts->inodes);
                    308:
                    309:                /* add requested slop */
                    310:        fsopts->size += fsopts->freeblocks;
                    311:        fsopts->inodes += fsopts->freefiles;
                    312:        if (fsopts->freefilepc > 0)
                    313:                fsopts->inodes =
                    314:                    fsopts->inodes * (100 + fsopts->freefilepc) / 100;
                    315:        if (fsopts->freeblockpc > 0)
                    316:                fsopts->size =
                    317:                    fsopts->size * (100 + fsopts->freeblockpc) / 100;
                    318:
                    319:                /*
                    320:                 * estimate number of cylinder groups
                    321:                 */
                    322:        spc = fsopts->nsectors * fsopts->ntracks;
                    323:        nspf = fsopts->fsize / fsopts->sectorsize;
                    324:        fssize = fsopts->size / fsopts->sectorsize;
                    325:        ncyl = fssize * nspf / spc;
                    326:        if (fssize * nspf > ncyl * spc)
                    327:                ncyl++;
                    328:        ncg = ncyl / fsopts->cpg;
                    329:        if (ncg == 0)
                    330:                ncg = 1;
                    331:        if (debug & DEBUG_FS_VALIDATE)
                    332:                printf(
                    333:                    "ffs_validate: spc %d nspf %d fssize %d ncyl %d ncg %d\n",
                    334:                    spc, nspf, fssize, ncyl, ncg);
                    335:
                    336:                /* add space needed for superblocks */
                    337:        fsopts->size += (SBOFF + SBSIZE) * ncg;
                    338:                /* add space needed to store inodes, x3 for blockmaps, etc */
                    339:        fsopts->size += ncg * DINODE_SIZE * 3 *
                    340:            roundup(fsopts->inodes / ncg, fsopts->bsize / DINODE_SIZE);
                    341:                /* add minfree */
                    342:        if (fsopts->minfree > 0)
                    343:                fsopts->size =
                    344:                    fsopts->size * (100 + fsopts->minfree) / 100;
                    345:        /*
                    346:         * XXX  any other fs slop to add, such as csum's, etc ??
                    347:         */
                    348:
                    349:        if (fsopts->size < fsopts->minsize)     /* ensure meets minimum size */
                    350:                fsopts->size = fsopts->minsize;
                    351:
                    352:                /* round up to the next sector */
                    353:        fsopts->size = roundup(fsopts->size, fsopts->sectorsize);
                    354:
                    355:                /* calculate density if necessary */
                    356:        if (fsopts->density == 0)
                    357:                fsopts->density = fsopts->size / fsopts->inodes + 1;
                    358:
                    359:        if (debug & DEBUG_FS_VALIDATE) {
                    360:                printf("ffs_validate: after defaults set:\n");
                    361:                ffs_dump_fsinfo(fsopts);
                    362:                printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n",
                    363:                    dir, (long long)fsopts->size, (long long)fsopts->inodes);
                    364:        }
                    365:        sectorsize = fsopts->sectorsize;        /* XXX - see earlier */
                    366:
                    367:                /* now check calculated sizes vs requested sizes */
                    368:        if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
                    369:                errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
                    370:                    dir, (long long)fsopts->size, (long long)fsopts->maxsize);
                    371:        }
                    372: }
                    373:
                    374:
                    375: static void
                    376: ffs_dump_fsinfo(fsinfo_t *f)
                    377: {
                    378:
                    379:        printf("fsopts at %p\n", f);
                    380:
                    381:        printf("\tsize %lld, inodes %lld, curinode %u\n",
                    382:            (long long)f->size, (long long)f->inodes, f->curinode);
                    383:
                    384:        printf("\tminsize %lld, maxsize %lld\n",
                    385:            (long long)f->minsize, (long long)f->maxsize);
                    386:        printf("\tfree files %lld, freefile %% %d\n",
                    387:            (long long)f->freefiles, f->freefilepc);
                    388:        printf("\tfree blocks %lld, freeblock %% %d\n",
                    389:            (long long)f->freeblocks, f->freeblockpc);
                    390:        printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
                    391:
                    392:        printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
                    393:            f->bsize, f->fsize, f->cpg, f->density);
                    394:        printf("\tntracks %d, nsectors %d, rpm %d, minfree %d\n",
                    395:            f->ntracks, f->nsectors, f->rpm, f->minfree);
                    396:        printf("\tmaxcontig %d, rotdelay %d, maxbpg %d, nrpos %d\n",
                    397:            f->maxcontig, f->rotdelay, f->maxbpg, f->nrpos);
                    398:        printf("\toptimization %s\n",
                    399:            f->optimization == FS_OPTSPACE ? "space" : "time");
                    400: }
                    401:
                    402:
                    403: static int
                    404: ffs_create_image(const char *image, fsinfo_t *fsopts)
                    405: {
                    406:        struct statfs   sfs;
                    407:        struct fs       *fs;
                    408:        char    *buf;
                    409:        int     i, bufsize;
                    410:        off_t   bufrem;
                    411:
                    412:        assert (image != NULL);
                    413:        assert (fsopts != NULL);
                    414:
                    415:                /* create image */
                    416:        if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0777))
                    417:            == -1) {
                    418:                warn("Can't open `%s' for writing", image);
                    419:                return (-1);
                    420:        }
                    421:
                    422:                /* zero image */
                    423:        if (fstatfs(fsopts->fd, &sfs) == -1) {
                    424:                bufsize = 8192;
                    425:                warn("can't fstatfs `%s', using default %d byte chunk",
                    426:                    image, bufsize);
                    427:        } else
                    428:                bufsize = sfs.f_iosize;
                    429:        bufrem = fsopts->size;
                    430:        if (debug & DEBUG_FS_CREATE_IMAGE)
                    431:                printf(
                    432:                    "zero-ing image `%s', %lld sectors, using %d byte chunks\n",
                    433:                    image, (long long)bufrem, bufsize);
                    434:        if ((buf = calloc(1, bufsize)) == NULL) {
                    435:                warn("Can't create buffer for sector");
                    436:                return (-1);
                    437:        }
                    438:        while (bufrem > 0) {
                    439:                i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
                    440:                if (i == -1) {
                    441:                        warn("zeroing image, %lld bytes to go",
                    442:                            (long long)bufrem);
                    443:                        return (-1);
                    444:                }
                    445:                bufrem -= i;
                    446:        }
                    447:
                    448:                /* make the file system */
                    449:        if (debug & DEBUG_FS_CREATE_IMAGE)
                    450:                printf("calling mkfs(\"%s\", ...)\n", image);
                    451:        fs = ffs_mkfs(image, fsopts);
                    452:        fsopts->superblock = (void *)fs;
                    453:        if (debug & DEBUG_FS_CREATE_IMAGE) {
                    454:                time_t t;
                    455:
                    456:                t = ((struct fs *)fsopts->superblock)->fs_time;
                    457:                printf("mkfs returned %p; fs_time %s",
                    458:                    fsopts->superblock, ctime(&t));
                    459:        }
                    460:
                    461:        if ((long long)fs->fs_ncg * fs->fs_ipg < fsopts->inodes) {
                    462:                warnx(
                    463:                "Image file `%s' only has %lld inodes, but %lld are required.",
                    464:                    image,
                    465:                    (long long)fs->fs_ncg * fs->fs_ipg,
                    466:                    (long long)fsopts->inodes);
                    467:                return (-1);
                    468:        }
                    469:        return (fsopts->fd);
                    470: }
                    471:
                    472:
                    473: static void
                    474: ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
                    475: {
                    476:        struct direct   tmpdir;
                    477:        fsnode *        node;
                    478:        int             curdirsize, this;
                    479:
                    480:        /* node may be NULL (empty directory) */
                    481:        assert(fsopts != NULL);
                    482:
                    483:        if (debug & DEBUG_FS_SIZE_DIR)
                    484:                printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
                    485:                    (long long)fsopts->size, (long long)fsopts->inodes);
                    486:
                    487: #define        ADDDIRENT(e) do {                                               \
                    488:        tmpdir.d_namlen = strlen((e));                                  \
                    489:        this = DIRSIZ(0, &tmpdir, 0);                                   \
                    490:        if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)                       \
                    491:                printf("ADDDIRENT: was: %s (%d) this %d cur %d\n",      \
                    492:                    e, tmpdir.d_namlen, this, curdirsize);              \
                    493:        if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ))         \
                    494:                curdirsize = roundup(curdirsize, DIRBLKSIZ);            \
                    495:        curdirsize += this;                                             \
                    496:        if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)                       \
                    497:                printf("ADDDIRENT: now: %s (%d) this %d cur %d\n",      \
                    498:                    e, tmpdir.d_namlen, this, curdirsize);              \
                    499: } while (0);
                    500:
                    501:        /*
                    502:         * XXX  this must take into account extra space consumed
                    503:         *      by indirect blocks, etc.
                    504:         */
                    505: #define        ADDSIZE(x) do {                                                 \
                    506:        fsopts->size += roundup((x), fsopts->bsize);                    \
                    507: } while (0);
                    508:
                    509:        curdirsize = 0;
                    510:        for (node = root; node != NULL; node = node->next) {
                    511:                ADDDIRENT(node->name);
                    512:                if (node == root) {                     /* we're at "." */
                    513:                        assert(strcmp(node->name, ".") == 0);
                    514:                        ADDDIRENT("..");
                    515:                }
                    516:                if (node->dup == NULL) { /* don't count duplicate names */
                    517:                        if (debug & DEBUG_FS_SIZE_DIR_NODE)
                    518:                                printf("ffs_size_dir: %s size %lld\n",
                    519:                                    node->name,
                    520:                                    (long long)node->statbuf.st_size);
                    521:                        fsopts->inodes++;
                    522:                        if (node->type == S_IFREG)
                    523:                                ADDSIZE(node->statbuf.st_size);
                    524:                        if (node->type == S_IFLNK) {
                    525:                                int     slen;
                    526:
                    527:                                slen = strlen(node->symlink) + 1;
                    528:                                if (slen >= MAXSYMLINKLEN)
                    529:                                        ADDSIZE(slen);
                    530:                        }
                    531:                }
                    532:                if (node->type == S_IFDIR)
                    533:                        ffs_size_dir(node->child, fsopts);
                    534:        }
                    535:        ADDSIZE(curdirsize);
                    536:
                    537:        if (debug & DEBUG_FS_SIZE_DIR)
                    538:                printf("ffs_size_dir: exit: size %lld inodes %lld\n",
                    539:                    (long long)fsopts->size, (long long)fsopts->inodes);
                    540: }
                    541:
                    542:
                    543: static int
                    544: ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
                    545: {
                    546:        fsnode          *cur;
                    547:        dirbuf_t        dirbuf;
                    548:        struct dinode   din;
                    549:        void            *membuf;
                    550:        char            path[MAXPATHLEN + 1];
                    551:
                    552:        assert(dir != NULL);
                    553:        assert(root != NULL);
                    554:        assert(fsopts != NULL);
                    555:
                    556:        (void)memset(&dirbuf, 0, sizeof(dirbuf));
                    557:
                    558:        if (debug & DEBUG_FS_POPULATE)
                    559:                printf("ffs_populate_dir: PASS 1  dir %s node %p\n", dir, root);
                    560:
                    561:                /*
                    562:                 * pass 1: allocate inode numbers, build directory `file'
                    563:                 */
                    564:        for (cur = root; cur != NULL; cur = cur->next) {
                    565:                if (cur->dup == NULL) {
                    566:                        if (cur == root && cur->parent)
                    567:                                cur->ino = cur->parent->ino;
                    568:                        else {
                    569:                                cur->ino = fsopts->curinode;
                    570:                                fsopts->curinode++;
                    571:                        }
                    572:                } else
                    573:                        cur->ino = cur->dup->ino;
                    574:                ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap);
                    575:                if (cur == root) {              /* we're at "."; add ".." */
                    576:                        ffs_make_dirbuf(&dirbuf, "..",
                    577:                            cur->parent == NULL ? cur : cur->parent->first,
                    578:                            fsopts->needswap);
                    579:                        root->nlink++;          /* count my parent's link */
                    580:                } else if (cur->child != NULL)
                    581:                        root->nlink++;          /* count my child's link */
                    582:
                    583:                /*
                    584:                 * XXX  possibly write file and long symlinks here,
                    585:                 *      ensuring that blocks get written before inodes?
                    586:                 *      otoh, this isn't a real filesystem, so who
                    587:                 *      cares about ordering? :-)
                    588:                 */
                    589:        }
                    590:        if (debug & DEBUG_FS_POPULATE_DIRBUF)
                    591:                ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap);
                    592:
                    593:                /*
                    594:                 * pass 2: write out dirbuf, then non-directories at this level
                    595:                 */
                    596:        if (debug & DEBUG_FS_POPULATE)
                    597:                printf("ffs_populate_dir: PASS 2  dir %s\n", dir);
                    598:        for (cur = root; cur != NULL; cur = cur->next) {
                    599:                if (cur->dup != NULL)
                    600:                        continue;               /* skip hard-linked entries */
                    601:
                    602:                if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
                    603:                    >= sizeof(path))
                    604:                        errx(1, "Pathname too long.");
                    605:
                    606:                if (cur->child != NULL)
                    607:                        continue;               /* child creates own inode */
                    608:
                    609:                                /* build on-disk inode */
                    610:                memset(&din, 0, sizeof(din));
                    611:                din.di_mode = cur->statbuf.st_mode;
                    612:                din.di_nlink = cur->nlink;
                    613:                din.di_size = cur->statbuf.st_size;
                    614:                din.di_atime = cur->statbuf.st_atime;
                    615:                din.di_atimensec = cur->statbuf.st_atimensec;
                    616:                din.di_mtime = cur->statbuf.st_mtime;
                    617:                din.di_mtimensec = cur->statbuf.st_mtimensec;
                    618:                din.di_ctime = cur->statbuf.st_ctime;
                    619:                din.di_ctimensec = cur->statbuf.st_ctimensec;
                    620:                din.di_flags = cur->statbuf.st_flags;
                    621:                din.di_gen = cur->statbuf.st_gen;
                    622:                din.di_uid = cur->statbuf.st_uid;
                    623:                din.di_gid = cur->statbuf.st_gid;
                    624:                        /* not set: di_db, di_ib, di_blocks, di_spare */
                    625:
                    626:                membuf = NULL;
                    627:                if (cur == root) {                      /* "."; write dirbuf */
                    628:                        membuf = dirbuf.buf;
                    629:                        din.di_size = dirbuf.size;
                    630:                } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
                    631:                        din.di_size = 0;        /* a device */
                    632:                        din.di_rdev =
                    633:                            ufs_rw32(cur->statbuf.st_rdev, fsopts->needswap);
                    634:                } else if (S_ISLNK(cur->type)) {        /* symlink */
                    635:                        int slen;
                    636:
                    637:                        slen = strlen(cur->symlink);
                    638:                        if (slen < MAXSYMLINKLEN) {     /* short link */
                    639:                                memcpy(din.di_shortlink, cur->symlink, slen);
                    640:                        } else
                    641:                                membuf = cur->symlink;
                    642:                        din.di_size = slen;
                    643:                }
                    644:
                    645:                if (debug & DEBUG_FS_POPULATE_NODE) {
                    646:                        printf("ffs_populate_dir: writing ino %d, %s",
                    647:                            cur->ino, inode_type(cur->type));
                    648:                        if (cur->nlink > 1)
                    649:                                printf(", nlink %d", cur->nlink);
                    650:                        putchar('\n');
                    651:                }
                    652:
                    653:                if (membuf != NULL) {
                    654:                        ffs_write_file(&din, cur->ino, membuf, fsopts);
                    655:                } else if (S_ISREG(cur->type)) {
                    656:                        ffs_write_file(&din, cur->ino, path, fsopts);
                    657:                } else {
                    658:                        assert (! S_ISDIR(cur->type));
                    659:                        ffs_write_inode(&din, cur->ino, fsopts);
                    660:                }
                    661:        }
                    662:
                    663:                /*
                    664:                 * pass 3: write out sub-directories
                    665:                 */
                    666:        if (debug & DEBUG_FS_POPULATE)
                    667:                printf("ffs_populate_dir: PASS 3  dir %s\n", dir);
                    668:        for (cur = root; cur != NULL; cur = cur->next) {
                    669:                if (cur->child == NULL)
                    670:                        continue;
                    671:                if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
                    672:                    >= sizeof(path))
                    673:                        errx(1, "Pathname too long.");
                    674:                if (! ffs_populate_dir(path, cur->child, fsopts))
                    675:                        return (0);
                    676:        }
                    677:
                    678:        if (debug & DEBUG_FS_POPULATE)
                    679:                printf("ffs_populate_dir: DONE dir %s\n", dir);
                    680:
                    681:                /* cleanup */
                    682:        if (dirbuf.buf != NULL)
                    683:                free(dirbuf.buf);
                    684:        return (1);
                    685: }
                    686:
                    687:
                    688: static void
                    689: ffs_write_file(struct dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
                    690: {
                    691:        int     isfile, ffd;
                    692:        char    *fbuf, *p;
                    693:        off_t   bufleft, chunk, offset;
                    694:        struct inode    in;
                    695:        struct buf *    bp;
                    696:
                    697:        assert (din != NULL);
                    698:        assert (buf != NULL);
                    699:        assert (fsopts != NULL);
                    700:
                    701:        isfile = S_ISREG(din->di_mode);
                    702:        fbuf = NULL;
                    703:        ffd = -1;
                    704:
                    705:        if (debug & DEBUG_FS_WRITE_FILE) {
                    706:                printf(
                    707:                    "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld",
                    708:                    ino, din, isfile, inode_type(din->di_mode & S_IFMT),
                    709:                    (long long)din->di_size);
                    710:                if (isfile)
                    711:                        printf(", file '%s'\n", (char *)buf);
                    712:                else
                    713:                        printf(", buffer %p\n", buf);
                    714:        }
                    715:
                    716:        in.i_number = ino;
                    717:        in.i_fs = (struct fs *)fsopts->superblock;
                    718:        memcpy(&in.i_din.ffs_din, din, sizeof(in.i_din.ffs_din));
                    719:        in.i_fd = fsopts->fd;
                    720:
                    721:        if (din->di_size == 0)
                    722:                goto write_inode_and_leave;             /* mmm, cheating */
                    723:
                    724:        if (isfile) {
                    725:                if ((fbuf = malloc(fsopts->bsize)) == NULL)
                    726:                        err(1, "Allocating memory for write buffer");
                    727:                if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
                    728:                        warn("Can't open `%s' for reading", (char *)buf);
                    729:                        goto leave_ffs_write_file;
                    730:                }
                    731:        } else {
                    732:                p = buf;
                    733:        }
                    734:
                    735:        chunk = 0;
                    736:        for (bufleft = din->di_size; bufleft > 0; bufleft -= chunk) {
                    737:                chunk = MIN(bufleft, fsopts->bsize);
                    738:                if (isfile) {
                    739:                        if (read(ffd, fbuf, chunk) != chunk)
                    740:                                err(1, "reading %s, %lld bytes to go",
                    741:                                    (char *)buf, (long long)bufleft);
                    742:                        p = fbuf;
                    743:                }
                    744:                offset = din->di_size - bufleft;
                    745:                if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
                    746:                        printf(
                    747:                "ffs_write_file: write %p offset %lld size %lld left %lld\n",
                    748:                            p, (long long)offset,
                    749:                            (long long)chunk, (long long)bufleft);
                    750:        /*
                    751:         * XXX  if holey support is desired, do the check here
                    752:         *
                    753:         * XXX  might need to write out last bit in fragroundup
                    754:         *      sized chunk. however, ffs_balloc() handles this for us
                    755:         */
                    756:                errno = ffs_balloc(&in, offset, chunk, &bp);
                    757:                if (errno != 0)
                    758:                        err(1,
                    759:                            "ffs_write_file: ffs_balloc %lld %lld",
                    760:                            (long long)offset, (long long)chunk);
                    761:                memcpy(bp->b_data, p, chunk);
                    762:                errno = bwrite(bp);
                    763:                if (errno != 0)
                    764:                        err(1, "ffs_write_file: bwrite");
                    765:                brelse(bp);
                    766:                if (!isfile)
                    767:                        p += chunk;
                    768:        }
                    769:
                    770:  write_inode_and_leave:
                    771:        ffs_write_inode(&in.i_din.ffs_din, in.i_number, fsopts);
                    772:
                    773:  leave_ffs_write_file:
                    774:        if (fbuf)
                    775:                free(fbuf);
                    776:        if (ffd != -1)
                    777:                close(ffd);
                    778: }
                    779:
                    780:
                    781: static void
                    782: ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap)
                    783: {
                    784:        doff_t          i;
                    785:        struct direct   *de;
                    786:        u_int16_t       reclen;
                    787:
                    788:        assert (dbuf != NULL);
                    789:        assert (dir != NULL);
                    790:        printf("ffs_dump_dirbuf: dir %s size %d cur %d\n",
                    791:            dir, dbuf->size, dbuf->cur);
                    792:
                    793:        for (i = 0; i < dbuf->size; ) {
                    794:                de = (struct direct *)(dbuf->buf + i);
                    795:                reclen = ufs_rw16(de->d_reclen, needswap);
                    796:                printf(
                    797:            " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n",
                    798:                    ufs_rw32(de->d_ino, needswap),
                    799:                    inode_type(DTTOIF(de->d_type)), i, reclen,
                    800:                    de->d_namlen, de->d_name);
                    801:                i += reclen;
                    802:                assert(reclen > 0);
                    803:        }
                    804: }
                    805:
                    806: static void
                    807: ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
                    808: {
                    809:        struct direct   de, *dp;
                    810:        u_int16_t       llen, reclen;
                    811:
                    812:        assert (dbuf != NULL);
                    813:        assert (name != NULL);
                    814:        assert (node != NULL);
                    815:                                        /* create direct entry */
                    816:        (void)memset(&de, 0, sizeof(de));
                    817:        de.d_ino = ufs_rw32(node->ino, needswap);
                    818:        de.d_type = IFTODT(node->type);
                    819:        de.d_namlen = (u_int8_t)strlen(name);
                    820:        assert (de.d_namlen < (sizeof(de.d_name)));
                    821:        strcpy(de.d_name, name);
                    822:        reclen = DIRSIZ(0, &de, needswap);
                    823:        de.d_reclen = ufs_rw16(reclen, needswap);
                    824:
                    825:        dp = (struct direct *)(dbuf->buf + dbuf->cur);
                    826:        llen = 0;
                    827:        if (dp != NULL)
                    828:                llen = DIRSIZ(0, dp, needswap);
                    829:
                    830:        if (debug & DEBUG_FS_MAKE_DIRBUF)
                    831:                printf(
                    832:                    "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n"
                    833:                    "  ino %d type %d reclen %d namlen %d name %.30s\n",
                    834:                    dbuf->size, dbuf->cur, llen,
                    835:                    ufs_rw32(de.d_ino, needswap), de.d_type, reclen,
                    836:                    de.d_namlen, de.d_name);
                    837:
                    838:        if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) {
                    839:                dbuf->size += DIRBLKSIZ;        /* need another chunk */
                    840:                if (debug & DEBUG_FS_MAKE_DIRBUF)
                    841:                        printf("ffs_make_dirbuf: growing buf to %d\n",
                    842:                            dbuf->size);
                    843:                if ((dbuf->buf = realloc(dbuf->buf, dbuf->size)) == NULL)
                    844:                        err(1, "Allocating memory for directory buffer");
                    845:                memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
                    846:                dbuf->cur = dbuf->size - DIRBLKSIZ;
                    847:        } else {                                /* shrink end of previous */
                    848:                dp->d_reclen = ufs_rw16(llen,needswap);
                    849:                dbuf->cur += llen;
                    850:        }
                    851:        dp = (struct direct *)(dbuf->buf + dbuf->cur);
                    852:        memcpy(dp, &de, reclen);
                    853:        dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap);
                    854: }
                    855:
                    856: /*
                    857:  * cribbed from sys/ufs/ffs/ffs_alloc.c
                    858:  */
                    859: static void
                    860: ffs_write_inode(struct dinode *ip, uint32_t ino, const fsinfo_t *fsopts)
                    861: {
                    862:        struct dinode   ibuf[MAXINOPB];
                    863:        struct cg       *cgp;
                    864:        struct fs       *fs;
                    865:        int             cg, cgino;
                    866:        daddr_t         d;
                    867:        char            sbbuf[MAXBSIZE];
                    868:
                    869:        assert (ip != NULL);
                    870:        assert (ino > 0);
                    871:        assert (fsopts != NULL);
                    872:
                    873:        fs = (struct fs *)fsopts->superblock;
                    874:        cg = ino_to_cg(fs, ino);
                    875:        cgino = ino % fs->fs_ipg;
                    876:        if (debug & DEBUG_FS_WRITE_INODE)
                    877:                printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n",
                    878:                    ip, ino, cg, cgino);
                    879:
                    880:        ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
                    881:            fsopts);
                    882:        cgp = (struct cg *)sbbuf;
                    883:        if (!cg_chkmagic(cgp, fsopts->needswap))
                    884:                errx(1, "ffs_write_inode: cg %d: bad magic number", cg);
                    885:
                    886:        assert (isclr(cg_inosused(cgp, fsopts->needswap), cgino));
                    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).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, fsopts->needswap), cgino);
                    896:        ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap);
                    897:        fs->fs_cstotal.cs_nifree--;
                    898:        fs->fs_cs(fs, cg).cs_nifree--;
                    899:        if (S_ISDIR(ip->di_mode)) {
                    900:                ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap);
                    901:                fs->fs_cstotal.cs_ndir++;
                    902:                fs->fs_cs(fs, cg).cs_ndir++;
                    903:        }
                    904:        ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
                    905:            fsopts);
                    906:
                    907:                                        /* now write inode */
                    908:        d = fsbtodb(fs, ino_to_fsba(fs, ino));
                    909:        ffs_rdfs(d, fs->fs_bsize, ibuf, fsopts);
                    910:        if (fsopts->needswap)
                    911:                ffs_dinode_swap(ip, &ibuf[ino_to_fsbo(fs, ino)]);
                    912:        else
                    913:                ibuf[ino_to_fsbo(fs, ino)] = *ip;
                    914:        ffs_wtfs(d, fs->fs_bsize, ibuf, fsopts);
                    915: }
                    916:
                    917: void
                    918: panic(const char *fmt, ...)
                    919: {
                    920:        va_list ap;
                    921:
                    922:        va_start(ap, fmt);
                    923:        vwarnx(fmt, ap);
                    924:        va_end(ap);
                    925:        exit(1);
                    926: }

CVSweb <webmaster@jp.NetBSD.org>