[BACK]Return to minixfs3.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / lib / libsa

Annotation of src/sys/lib/libsa/minixfs3.c, Revision 1.1.4.2

1.1.4.2 ! mrg         1: /*     $NetBSD: minixfs3.c,v 1.1 2012/01/16 18:44:13 christos Exp $    */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 2012
        !             5:  *     Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
        !             6:  *
        !             7:  * Author: Evgeniy Ivanov (based on libsa/ext2fs.c).
        !             8:  *
        !             9:  * This code is derived from src/sys/lib/libsa/ext2fs.c contributed to
        !            10:  * The NetBSD Foundation, see copyrights below.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
        !            22:  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
        !            23:  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            24:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE
        !            25:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            26:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            27:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            28:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            30:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            31:  * POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: /*
        !            35:  * Copyright (c) 1997 Manuel Bouyer.
        !            36:  *
        !            37:  * Redistribution and use in source and binary forms, with or without
        !            38:  * modification, are permitted provided that the following conditions
        !            39:  * are met:
        !            40:  * 1. Redistributions of source code must retain the above copyright
        !            41:  *    notice, this list of conditions and the following disclaimer.
        !            42:  * 2. Redistributions in binary form must reproduce the above copyright
        !            43:  *    notice, this list of conditions and the following disclaimer in the
        !            44:  *    documentation and/or other materials provided with the distribution.
        !            45:  *
        !            46:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            47:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            48:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            49:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            50:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            51:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            52:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            53:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            54:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            55:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            56:  */
        !            57:
        !            58: /*-
        !            59:  * Copyright (c) 1993
        !            60:  *     The Regents of the University of California.  All rights reserved.
        !            61:  *
        !            62:  * This code is derived from software contributed to Berkeley by
        !            63:  * The Mach Operating System project at Carnegie-Mellon University.
        !            64:  *
        !            65:  * Redistribution and use in source and binary forms, with or without
        !            66:  * modification, are permitted provided that the following conditions
        !            67:  * are met:
        !            68:  * 1. Redistributions of source code must retain the above copyright
        !            69:  *    notice, this list of conditions and the following disclaimer.
        !            70:  * 2. Redistributions in binary form must reproduce the above copyright
        !            71:  *    notice, this list of conditions and the following disclaimer in the
        !            72:  *    documentation and/or other materials provided with the distribution.
        !            73:  * 3. Neither the name of the University nor the names of its contributors
        !            74:  *    may be used to endorse or promote products derived from this software
        !            75:  *    without specific prior written permission.
        !            76:  *
        !            77:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            78:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            79:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            80:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            81:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            82:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            83:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            84:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            85:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            86:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            87:  * SUCH DAMAGE.
        !            88:  *
        !            89:  *
        !            90:  * Copyright (c) 1990, 1991 Carnegie Mellon University
        !            91:  * All Rights Reserved.
        !            92:  *
        !            93:  * Author: David Golub
        !            94:  *
        !            95:  * Permission to use, copy, modify and distribute this software and its
        !            96:  * documentation is hereby granted, provided that both the copyright
        !            97:  * notice and this permission notice appear in all copies of the
        !            98:  * software, derivative works or modified versions, and any portions
        !            99:  * thereof, and that both notices appear in supporting documentation.
        !           100:  *
        !           101:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !           102:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !           103:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !           104:  *
        !           105:  * Carnegie Mellon requests users of this software to return to
        !           106:  *
        !           107:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
        !           108:  *  School of Computer Science
        !           109:  *  Carnegie Mellon University
        !           110:  *  Pittsburgh PA 15213-3890
        !           111:  *
        !           112:  * any improvements or extensions that they make and grant Carnegie the
        !           113:  * rights to redistribute these changes.
        !           114:  */
        !           115:
        !           116: /*
        !           117:  *     Stand-alone file reading package for MFS file system.
        !           118:  */
        !           119:
        !           120: #include <sys/param.h>
        !           121: #include <sys/time.h>
        !           122: #ifdef _STANDALONE
        !           123: #include <lib/libkern/libkern.h>
        !           124: #else
        !           125: #include <string.h>
        !           126: #endif
        !           127:
        !           128: #include "stand.h"
        !           129: #include "minixfs3.h"
        !           130:
        !           131: #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
        !           132: #define LIBSA_NO_FS_SYMLINK
        !           133: #endif
        !           134:
        !           135: #if defined(LIBSA_NO_TWIDDLE)
        !           136: #define twiddle()
        !           137: #endif
        !           138:
        !           139: typedef uint32_t       ino32_t;
        !           140: #ifndef FSBTODB
        !           141: #define FSBTODB(fs, indp) fsbtodb(fs, indp)
        !           142: #endif
        !           143:
        !           144: /*
        !           145:  * To avoid having a lot of filesystem-block sized buffers lurking (which
        !           146:  * could be 32k) we only keep a few entries of the indirect block map.
        !           147:  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
        !           148:  * ~13 times pulling in a 6M kernel.
        !           149:  * The cache size must be smaller than the smallest filesystem block,
        !           150:  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
        !           151:  */
        !           152: #define LN2_IND_CACHE_SZ       6
        !           153: #define IND_CACHE_SZ           (1 << LN2_IND_CACHE_SZ)
        !           154: #define IND_CACHE_MASK         (IND_CACHE_SZ - 1)
        !           155:
        !           156: /*
        !           157:  * In-core open file.
        !           158:  */
        !           159: struct file {
        !           160:        off_t           f_seekp;        /* seek pointer */
        !           161:        struct mfs_sblock  *f_fs;       /* pointer to super-block */
        !           162:        struct mfs_dinode  f_di;        /* copy of on-disk inode */
        !           163:        uint            f_nishift;      /* for blocks in indirect block */
        !           164:        block_t         f_ind_cache_block;
        !           165:        block_t         f_ind_cache[IND_CACHE_SZ];
        !           166:
        !           167:        char            *f_buf;         /* buffer for data block */
        !           168:        size_t          f_buf_size;     /* size of data block */
        !           169:        daddr_t         f_buf_blkno;    /* block number of data block */
        !           170: };
        !           171:
        !           172: #if defined(LIBSA_ENABLE_LS_OP)
        !           173:
        !           174: #define NELEM(x) (sizeof (x) / sizeof(*x))
        !           175:
        !           176: typedef struct entry_t entry_t;
        !           177: struct entry_t {
        !           178:        entry_t *e_next;
        !           179:        ino32_t e_ino;
        !           180:        char    e_name[1];
        !           181: };
        !           182:
        !           183: #endif /* LIBSA_ENABLE_LS_OP */
        !           184:
        !           185:
        !           186: static int read_inode(ino32_t, struct open_file *);
        !           187: static int block_map(struct open_file *, block_t, block_t *);
        !           188: static int buf_read_file(struct open_file *, void *, size_t *);
        !           189: static int search_directory(const char *, int, struct open_file *, ino32_t *);
        !           190: static int read_sblock(struct open_file *, struct mfs_sblock *);
        !           191:
        !           192: /*
        !           193:  * Read a new inode into a file structure.
        !           194:  */
        !           195: static int
        !           196: read_inode(ino32_t inumber, struct open_file *f)
        !           197: {
        !           198:        struct file *fp = (struct file *)f->f_fsdata;
        !           199:        struct mfs_sblock *fs = fp->f_fs;
        !           200:        char *buf;
        !           201:        size_t rsize;
        !           202:        int rc;
        !           203:        daddr_t inode_sector;
        !           204:        struct mfs_dinode *dip;
        !           205:
        !           206:        inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
        !           207:
        !           208:        /*
        !           209:         * Read inode and save it.
        !           210:         */
        !           211:        buf = fp->f_buf;
        !           212:        twiddle();
        !           213:        rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
        !           214:            inode_sector, fs->mfs_block_size, buf, &rsize);
        !           215:        if (rc)
        !           216:                return rc;
        !           217:        if (rsize != fs->mfs_block_size)
        !           218:                return EIO;
        !           219:
        !           220:        dip = (struct mfs_dinode *)(buf +
        !           221:            INODE_SIZE * ino_to_fsbo(fs, inumber));
        !           222:        mfs_iload(dip, &fp->f_di);
        !           223:
        !           224:        /*
        !           225:         * Clear out the old buffers
        !           226:         */
        !           227:        fp->f_ind_cache_block = ~0;
        !           228:        fp->f_buf_blkno = -1;
        !           229:        return rc;
        !           230: }
        !           231:
        !           232: /*
        !           233:  * Given an offset in a file, find the disk block number (not zone!)
        !           234:  * that contains that block.
        !           235:  */
        !           236: static int
        !           237: block_map(struct open_file *f, block_t file_block, block_t *disk_block_p)
        !           238: {
        !           239:        struct file *fp = (struct file *)f->f_fsdata;
        !           240:        struct mfs_sblock *fs = fp->f_fs;
        !           241:        uint level;
        !           242:        block_t ind_cache;
        !           243:        block_t ind_block_num;
        !           244:        zone_t zone;
        !           245:        size_t rsize;
        !           246:        int rc;
        !           247:        int boff;
        !           248:        int scale = fs->mfs_log_zone_size; /* for block-zone conversion */
        !           249:        block_t *buf = (void *)fp->f_buf;
        !           250:
        !           251:        /*
        !           252:         * Index structure of an inode:
        !           253:         *
        !           254:         * mdi_blocks[0..NR_DZONES-1]
        !           255:         *                      hold zone numbers for zones
        !           256:         *                      0..NR_DZONES-1
        !           257:         *
        !           258:         * mdi_blocks[NR_DZONES+0]
        !           259:         *                      block NDADDR+0 is the single indirect block
        !           260:         *                      holds zone numbers for zones
        !           261:         *                      NR_DZONES .. NR_DZONES + NINDIR(fs)-1
        !           262:         *
        !           263:         * mdi_blocks[NR_DZONES+1]
        !           264:         *                      block NDADDR+1 is the double indirect block
        !           265:         *                      holds zone numbers for INDEX blocks for zones
        !           266:         *                      NR_DZONES + NINDIR(fs) ..
        !           267:         *                      NR_TZONES + NINDIR(fs) + NINDIR(fs)**2 - 1
        !           268:         */
        !           269:
        !           270:        zone = file_block >> scale;
        !           271:        boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */
        !           272:
        !           273:        if (zone < NR_DZONES) {
        !           274:                /* Direct zone */
        !           275:                zone_t z = fs2h32(fp->f_di.mdi_zone[zone]);
        !           276:                if (z == NO_ZONE) {
        !           277:                        *disk_block_p = NO_BLOCK;
        !           278:                        return 0;
        !           279:                }
        !           280:                *disk_block_p = (block_t) ((z << scale) + boff);
        !           281:                return 0;
        !           282:        }
        !           283:
        !           284:        zone -= NR_DZONES;
        !           285:
        !           286:        ind_cache = zone >> LN2_IND_CACHE_SZ;
        !           287:        if (ind_cache == fp->f_ind_cache_block) {
        !           288:                *disk_block_p =
        !           289:                    fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]);
        !           290:                return 0;
        !           291:        }
        !           292:
        !           293:        for (level = 0;;) {
        !           294:                level += fp->f_nishift;
        !           295:
        !           296:                if (zone < (block_t)1 << level)
        !           297:                        break;
        !           298:                if (level > NIADDR * fp->f_nishift)
        !           299:                        /* Zone number too high */
        !           300:                        return EFBIG;
        !           301:                zone -= (block_t)1 << level;
        !           302:        }
        !           303:
        !           304:        ind_block_num =
        !           305:            fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]);
        !           306:
        !           307:        for (;;) {
        !           308:                level -= fp->f_nishift;
        !           309:                if (ind_block_num == 0) {
        !           310:                        *disk_block_p = NO_BLOCK;       /* missing */
        !           311:                        return 0;
        !           312:                }
        !           313:
        !           314:                twiddle();
        !           315:                /*
        !           316:                 * If we were feeling brave, we could work out the number
        !           317:                 * of the disk sector and read a single disk sector instead
        !           318:                 * of a filesystem block.
        !           319:                 * However we don't do this very often anyway...
        !           320:                 */
        !           321:                rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
        !           322:                        FSBTODB(fs, ind_block_num), fs->mfs_block_size,
        !           323:                        buf, &rsize);
        !           324:                if (rc)
        !           325:                        return rc;
        !           326:                if (rsize != fs->mfs_block_size)
        !           327:                        return EIO;
        !           328:
        !           329:                ind_block_num = fs2h32(buf[zone >> level]);
        !           330:                if (level == 0)
        !           331:                        break;
        !           332:                zone &= (1 << level) - 1;
        !           333:        }
        !           334:
        !           335:        /* Save the part of the block that contains this sector */
        !           336:        memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK],
        !           337:            IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
        !           338:        fp->f_ind_cache_block = ind_cache;
        !           339:
        !           340:        zone = (zone_t)ind_block_num;
        !           341:        *disk_block_p = (block_t)((zone << scale) + boff);
        !           342:        return 0;
        !           343: }
        !           344:
        !           345: /*
        !           346:  * Read a portion of a file into an internal buffer.
        !           347:  * Return the location in the buffer and the amount in the buffer.
        !           348:  */
        !           349: static int
        !           350: buf_read_file(struct open_file *f, void *v, size_t *size_p)
        !           351: {
        !           352:        char **buf_p = v;
        !           353:        struct file *fp = (struct file *)f->f_fsdata;
        !           354:        struct mfs_sblock *fs = fp->f_fs;
        !           355:        long off;
        !           356:        block_t file_block;
        !           357:        block_t disk_block;
        !           358:        size_t block_size;
        !           359:        int rc;
        !           360:
        !           361:        off = blkoff(fs, fp->f_seekp);
        !           362:        file_block = lblkno(fs, fp->f_seekp);
        !           363:        block_size = fs->mfs_block_size;
        !           364:
        !           365:        if (file_block != fp->f_buf_blkno) {
        !           366:                rc = block_map(f, file_block, &disk_block);
        !           367:                if (rc)
        !           368:                        return rc;
        !           369:
        !           370:                if (disk_block == 0) {
        !           371:                        memset(fp->f_buf, 0, block_size);
        !           372:                        fp->f_buf_size = block_size;
        !           373:                } else {
        !           374:                        twiddle();
        !           375:                        rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
        !           376:                                FSBTODB(fs, disk_block),
        !           377:                                block_size, fp->f_buf, &fp->f_buf_size);
        !           378:                        if (rc)
        !           379:                                return rc;
        !           380:                }
        !           381:
        !           382:                fp->f_buf_blkno = file_block;
        !           383:        }
        !           384:
        !           385:        /*
        !           386:         * Return address of byte in buffer corresponding to
        !           387:         * offset, and size of remainder of buffer after that
        !           388:         * byte.
        !           389:         */
        !           390:        *buf_p = fp->f_buf + off;
        !           391:        *size_p = block_size - off;
        !           392:
        !           393:        /*
        !           394:         * But truncate buffer at end of file.
        !           395:         */
        !           396:        if (*size_p > fp->f_di.mdi_size - fp->f_seekp)
        !           397:                *size_p = fp->f_di.mdi_size - fp->f_seekp;
        !           398:
        !           399:        return 0;
        !           400: }
        !           401:
        !           402: /*
        !           403:  * Search a directory for a name and return its
        !           404:  * inode number.
        !           405:  */
        !           406: static int
        !           407: search_directory(const char *name, int length, struct open_file *f,
        !           408:        ino32_t *inumber_p)
        !           409: {
        !           410:        struct file *fp = (struct file *)f->f_fsdata;
        !           411:        struct mfs_sblock *fs = fp->f_fs;
        !           412:        struct mfs_direct *dp;
        !           413:        struct mfs_direct *dbuf;
        !           414:        size_t buf_size;
        !           415:        int namlen;
        !           416:        int rc;
        !           417:
        !           418:        fp->f_seekp = 0;
        !           419:
        !           420:        while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
        !           421:                rc = buf_read_file(f, (void *)&dbuf, &buf_size);
        !           422:                if (rc)
        !           423:                        return rc;
        !           424:                if (buf_size == 0)
        !           425:                        return EIO;
        !           426:
        !           427:                /* XXX we assume, that buf_read_file reads an fs block and
        !           428:                 * doesn't truncate buffer. Currently i_size in MFS doesn't
        !           429:                 * the same as size of allocated blocks, it makes buf_read_file
        !           430:                 * to truncate buf_size.
        !           431:                 */
        !           432:                if (buf_size < fs->mfs_block_size)
        !           433:                        buf_size = fs->mfs_block_size;
        !           434:
        !           435:                for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
        !           436:                        char *cp;
        !           437:                        if (fs2h32(dp->mfsd_ino) == (ino32_t) 0)
        !           438:                                continue;
        !           439:                        /* Compute the length of the name */
        !           440:                        cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
        !           441:                        if (cp == NULL)
        !           442:                                namlen = sizeof(dp->mfsd_name);
        !           443:                        else
        !           444:                                namlen = cp - (dp->mfsd_name);
        !           445:
        !           446:                        if (namlen == length &&
        !           447:                            !memcmp(name, dp->mfsd_name, length)) {
        !           448:                                /* found entry */
        !           449:                                *inumber_p = fs2h32(dp->mfsd_ino);
        !           450:                                return 0;
        !           451:                        }
        !           452:                }
        !           453:                fp->f_seekp += buf_size;
        !           454:        }
        !           455:        return ENOENT;
        !           456: }
        !           457:
        !           458: int
        !           459: read_sblock(struct open_file *f, struct mfs_sblock *fs)
        !           460: {
        !           461:        static uint8_t sbbuf[MINBSIZE];
        !           462:        size_t buf_size;
        !           463:        int rc;
        !           464:
        !           465:        /* We must read amount multiple of sector size, hence we can't
        !           466:         * read SBSIZE and read MINBSIZE.
        !           467:         */
        !           468:        if (SBSIZE > MINBSIZE)
        !           469:                return EINVAL;
        !           470:
        !           471:        rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
        !           472:            SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size);
        !           473:        if (rc)
        !           474:                return rc;
        !           475:
        !           476:        if (buf_size != MINBSIZE)
        !           477:                return EIO;
        !           478:
        !           479:        mfs_sbload((void *)sbbuf, fs);
        !           480:
        !           481:        if (fs->mfs_magic != SUPER_MAGIC)
        !           482:                return EINVAL;
        !           483:        if (fs->mfs_block_size < MINBSIZE)
        !           484:                return EINVAL;
        !           485:        if ((fs->mfs_block_size % 512) != 0)
        !           486:                return EINVAL;
        !           487:        if (SBSIZE > fs->mfs_block_size)
        !           488:                return EINVAL;
        !           489:        if ((fs->mfs_block_size % INODE_SIZE) != 0)
        !           490:                return EINVAL;
        !           491:
        !           492:        /* For even larger disks, a similar problem occurs with s_firstdatazone.
        !           493:         * If the on-disk field contains zero, we assume that the value was too
        !           494:         * large to fit, and compute it on the fly.
        !           495:         */
        !           496:        if (fs->mfs_firstdatazone_old == 0) {
        !           497:                block_t offset;
        !           498:                offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks;
        !           499:                offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) /
        !           500:                                fs->mfs_inodes_per_block;
        !           501:
        !           502:                fs->mfs_firstdatazone =
        !           503:                        (offset + (1 << fs->mfs_log_zone_size) - 1) >>
        !           504:                                fs->mfs_log_zone_size;
        !           505:        } else {
        !           506:                fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old;
        !           507:        }
        !           508:
        !           509:        if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1
        !           510:                        || fs->mfs_ninodes < 1 || fs->mfs_zones < 1
        !           511:                        || fs->mfs_firstdatazone <= 4
        !           512:                        || fs->mfs_firstdatazone >= fs->mfs_zones
        !           513:                        || (unsigned) fs->mfs_log_zone_size > 4)
        !           514:                return EINVAL;
        !           515:
        !           516:        /* compute in-memory mfs_sblock values */
        !           517:        fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE;
        !           518:
        !           519:
        !           520:        {
        !           521:                int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE;
        !           522:                int ln2 = LOG_MINBSIZE;
        !           523:
        !           524:                for (; mult != 1; ln2++)
        !           525:                        mult >>= 1;
        !           526:
        !           527:                fs->mfs_bshift = ln2;
        !           528:                /* XXX assume hw bsize = 512 */
        !           529:                fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1;
        !           530:        }
        !           531:
        !           532:        fs->mfs_qbmask = fs->mfs_block_size - 1;
        !           533:        fs->mfs_bmask = ~fs->mfs_qbmask;
        !           534:
        !           535:        return 0;
        !           536: }
        !           537:
        !           538: /*
        !           539:  * Open a file.
        !           540:  */
        !           541: __compactcall int
        !           542: minixfs3_open(const char *path, struct open_file *f)
        !           543: {
        !           544: #ifndef LIBSA_FS_SINGLECOMPONENT
        !           545:        const char *cp, *ncp;
        !           546:        int c;
        !           547: #endif
        !           548:        ino32_t inumber;
        !           549:        struct file *fp;
        !           550:        struct mfs_sblock *fs;
        !           551:        int rc;
        !           552: #ifndef LIBSA_NO_FS_SYMLINK
        !           553:        ino32_t parent_inumber;
        !           554:        int nlinks = 0;
        !           555:        char namebuf[MAXPATHLEN+1];
        !           556:        char *buf;
        !           557: #endif
        !           558:
        !           559:        /* allocate file system specific data structure */
        !           560:        fp = alloc(sizeof(struct file));
        !           561:        memset(fp, 0, sizeof(struct file));
        !           562:        f->f_fsdata = (void *)fp;
        !           563:
        !           564:        /* allocate space and read super block */
        !           565:        fs = alloc(sizeof(*fs));
        !           566:        memset(fs, 0, sizeof(*fs));
        !           567:        fp->f_fs = fs;
        !           568:        twiddle();
        !           569:
        !           570:        rc = read_sblock(f, fs);
        !           571:        if (rc)
        !           572:                goto out;
        !           573:
        !           574:        /* alloc a block sized buffer used for all fs transfers */
        !           575:        fp->f_buf = alloc(fs->mfs_block_size);
        !           576:
        !           577:        /*
        !           578:         * Calculate indirect block levels.
        !           579:         */
        !           580:        {
        !           581:                int32_t mult;
        !           582:                int ln2;
        !           583:
        !           584:                /*
        !           585:                 * We note that the number of indirect blocks is always
        !           586:                 * a power of 2.  This lets us use shifts and masks instead
        !           587:                 * of divide and remainder and avoinds pulling in the
        !           588:                 * 64bit division routine into the boot code.
        !           589:                 */
        !           590:                mult = NINDIR(fs);
        !           591: #ifdef DEBUG
        !           592:                if (!powerof2(mult)) {
        !           593:                        /* Hummm was't a power of 2 */
        !           594:                        rc = EINVAL;
        !           595:                        goto out;
        !           596:                }
        !           597: #endif
        !           598:                for (ln2 = 0; mult != 1; ln2++)
        !           599:                        mult >>= 1;
        !           600:
        !           601:                fp->f_nishift = ln2;
        !           602:        }
        !           603:
        !           604:        inumber = ROOT_INODE;
        !           605:        if ((rc = read_inode(inumber, f)) != 0)
        !           606:                goto out;
        !           607:
        !           608: #ifndef LIBSA_FS_SINGLECOMPONENT
        !           609:        cp = path;
        !           610:        while (*cp) {
        !           611:
        !           612:                /*
        !           613:                 * Remove extra separators
        !           614:                 */
        !           615:                while (*cp == '/')
        !           616:                        cp++;
        !           617:                if (*cp == '\0')
        !           618:                        break;
        !           619:
        !           620:                /*
        !           621:                 * Check that current node is a directory.
        !           622:                 */
        !           623:                if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) {
        !           624:                        rc = ENOTDIR;
        !           625:                        goto out;
        !           626:                }
        !           627:
        !           628:                /*
        !           629:                 * Get next component of path name.
        !           630:                 */
        !           631:                ncp = cp;
        !           632:                while ((c = *cp) != '\0' && c != '/')
        !           633:                        cp++;
        !           634:
        !           635:                /*
        !           636:                 * Look up component in current directory.
        !           637:                 * Save directory inumber in case we find a
        !           638:                 * symbolic link.
        !           639:                 */
        !           640: #ifndef LIBSA_NO_FS_SYMLINK
        !           641:                parent_inumber = inumber;
        !           642: #endif
        !           643:                rc = search_directory(ncp, cp - ncp, f, &inumber);
        !           644:                if (rc)
        !           645:                        goto out;
        !           646:
        !           647:                /*
        !           648:                 * Open next component.
        !           649:                 */
        !           650:                if ((rc = read_inode(inumber, f)) != 0)
        !           651:                        goto out;
        !           652:
        !           653: #ifndef LIBSA_NO_FS_SYMLINK
        !           654:                /*
        !           655:                 * Check for symbolic link.
        !           656:                 */
        !           657:                if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) {
        !           658:                        int link_len = fp->f_di.mdi_size;
        !           659:                        int len;
        !           660:                        size_t buf_size;
        !           661:                        block_t disk_block;
        !           662:
        !           663:                        len = strlen(cp);
        !           664:
        !           665:                        if (link_len + len > MAXPATHLEN ||
        !           666:                            ++nlinks > MAXSYMLINKS) {
        !           667:                                rc = ENOENT;
        !           668:                                goto out;
        !           669:                        }
        !           670:
        !           671:                        memmove(&namebuf[link_len], cp, len + 1);
        !           672:
        !           673:                        /*
        !           674:                         * Read file for symbolic link
        !           675:                         */
        !           676:                        buf = fp->f_buf;
        !           677:                        rc = block_map(f, (block_t)0, &disk_block);
        !           678:                        if (rc)
        !           679:                                goto out;
        !           680:
        !           681:                        twiddle();
        !           682:                        rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
        !           683:                                        F_READ, FSBTODB(fs, disk_block),
        !           684:                                        fs->mfs_block_size, buf, &buf_size);
        !           685:                        if (rc)
        !           686:                                goto out;
        !           687:
        !           688:                        memcpy(namebuf, buf, link_len);
        !           689:
        !           690:                        /*
        !           691:                         * If relative pathname, restart at parent directory.
        !           692:                         * If absolute pathname, restart at root.
        !           693:                         */
        !           694:                        cp = namebuf;
        !           695:                        if (*cp != '/')
        !           696:                                inumber = parent_inumber;
        !           697:                        else
        !           698:                                inumber = (ino32_t) ROOT_INODE;
        !           699:
        !           700:                        if ((rc = read_inode(inumber, f)) != 0)
        !           701:                                goto out;
        !           702:                }
        !           703: #endif /* !LIBSA_NO_FS_SYMLINK */
        !           704:        }
        !           705:
        !           706:        /*
        !           707:         * Found terminal component.
        !           708:         */
        !           709:        rc = 0;
        !           710:
        !           711: #else /* !LIBSA_FS_SINGLECOMPONENT */
        !           712:
        !           713:        /* look up component in the current (root) directory */
        !           714:        rc = search_directory(path, strlen(path), f, &inumber);
        !           715:        if (rc)
        !           716:                goto out;
        !           717:
        !           718:        /* open it */
        !           719:        rc = read_inode(inumber, f);
        !           720:
        !           721: #endif /* !LIBSA_FS_SINGLECOMPONENT */
        !           722:
        !           723:        fp->f_seekp = 0;                /* reset seek pointer */
        !           724:
        !           725: out:
        !           726:        if (rc)
        !           727:                minixfs3_close(f);
        !           728:
        !           729:        return rc;
        !           730: }
        !           731:
        !           732: __compactcall int
        !           733: minixfs3_close(struct open_file *f)
        !           734: {
        !           735:        struct file *fp = (struct file *)f->f_fsdata;
        !           736:
        !           737:        f->f_fsdata = NULL;
        !           738:        if (fp == NULL)
        !           739:                return 0;
        !           740:
        !           741:        if (fp->f_buf)
        !           742:                dealloc(fp->f_buf, fp->f_fs->mfs_block_size);
        !           743:        dealloc(fp->f_fs, sizeof(*fp->f_fs));
        !           744:        dealloc(fp, sizeof(struct file));
        !           745:        return 0;
        !           746: }
        !           747:
        !           748: /*
        !           749:  * Copy a portion of a file into kernel memory.
        !           750:  * Cross block boundaries when necessary.
        !           751:  */
        !           752: __compactcall int
        !           753: minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid)
        !           754: {
        !           755:        struct file *fp = (struct file *)f->f_fsdata;
        !           756:        size_t csize;
        !           757:        char *buf;
        !           758:        size_t buf_size;
        !           759:        int rc = 0;
        !           760:        char *addr = start;
        !           761:
        !           762:        while (size != 0) {
        !           763:                if (fp->f_seekp >= (off_t)fp->f_di.mdi_size)
        !           764:                        break;
        !           765:
        !           766:                rc = buf_read_file(f, &buf, &buf_size);
        !           767:                if (rc)
        !           768:                        break;
        !           769:
        !           770:                csize = size;
        !           771:                if (csize > buf_size)
        !           772:                        csize = buf_size;
        !           773:
        !           774:                memcpy(addr, buf, csize);
        !           775:
        !           776:                fp->f_seekp += csize;
        !           777:                addr += csize;
        !           778:                size -= csize;
        !           779:        }
        !           780:
        !           781:        if (resid)
        !           782:                *resid = size;
        !           783:        return rc;
        !           784: }
        !           785:
        !           786: /*
        !           787:  * Not implemented.
        !           788:  */
        !           789: #ifndef LIBSA_NO_FS_WRITE
        !           790: __compactcall int
        !           791: minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid)
        !           792: {
        !           793:
        !           794:        return EROFS;
        !           795: }
        !           796: #endif /* !LIBSA_NO_FS_WRITE */
        !           797:
        !           798: #ifndef LIBSA_NO_FS_SEEK
        !           799: __compactcall off_t
        !           800: minixfs3_seek(struct open_file *f, off_t offset, int where)
        !           801: {
        !           802:        struct file *fp = (struct file *)f->f_fsdata;
        !           803:
        !           804:        switch (where) {
        !           805:        case SEEK_SET:
        !           806:                fp->f_seekp = offset;
        !           807:                break;
        !           808:        case SEEK_CUR:
        !           809:                fp->f_seekp += offset;
        !           810:                break;
        !           811:        case SEEK_END:
        !           812:                fp->f_seekp = fp->f_di.mdi_size - offset;
        !           813:                break;
        !           814:        default:
        !           815:                return -1;
        !           816:        }
        !           817:        return fp->f_seekp;
        !           818: }
        !           819: #endif /* !LIBSA_NO_FS_SEEK */
        !           820:
        !           821: __compactcall int
        !           822: minixfs3_stat(struct open_file *f, struct stat *sb)
        !           823: {
        !           824:        struct file *fp = (struct file *)f->f_fsdata;
        !           825:
        !           826:        /* only important stuff */
        !           827:        memset(sb, 0, sizeof *sb);
        !           828:        sb->st_mode = fp->f_di.mdi_mode;
        !           829:        sb->st_uid = fp->f_di.mdi_uid;
        !           830:        sb->st_gid = fp->f_di.mdi_gid;
        !           831:        sb->st_size = fp->f_di.mdi_size;
        !           832:        return 0;
        !           833: }
        !           834:
        !           835: #if defined(LIBSA_ENABLE_LS_OP)
        !           836: __compactcall void
        !           837: minixfs3_ls(struct open_file *f, const char *pattern)
        !           838: {
        !           839:        struct file *fp = (struct file *)f->f_fsdata;
        !           840:        struct mfs_sblock *fs = fp->f_fs;
        !           841:        struct mfs_direct *dp;
        !           842:        struct mfs_direct *dbuf;
        !           843:        size_t buf_size;
        !           844:        entry_t *names = 0, *n, **np;
        !           845:
        !           846:        fp->f_seekp = 0;
        !           847:        while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
        !           848:                int rc = buf_read_file(f, &dbuf, &buf_size);
        !           849:                if (rc)
        !           850:                        goto out;
        !           851:
        !           852:                /* XXX we assume, that buf_read_file reads an fs block and
        !           853:                 * doesn't truncate buffer. Currently i_size in MFS doesn't
        !           854:                 * the same as size of allocated blocks, it makes buf_read_file
        !           855:                 * to truncate buf_size.
        !           856:                 */
        !           857:                if (buf_size < fs->mfs_block_size)
        !           858:                        buf_size = fs->mfs_block_size;
        !           859:
        !           860:                for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
        !           861:                        char *cp;
        !           862:                        int namlen;
        !           863:
        !           864:                        if (fs2h32(dp->mfsd_ino) == 0)
        !           865:                                continue;
        !           866:
        !           867:                        if (pattern && !fnmatch(dp->mfsd_name, pattern))
        !           868:                                continue;
        !           869:
        !           870:                        /* Compute the length of the name,
        !           871:                         * We don't use strlen and strcpy, because original MFS
        !           872:                         * code doesn't.
        !           873:                         */
        !           874:                        cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
        !           875:                        if (cp == NULL)
        !           876:                                namlen = sizeof(dp->mfsd_name);
        !           877:                        else
        !           878:                                namlen = cp - (dp->mfsd_name);
        !           879:
        !           880:                        n = alloc(sizeof *n + namlen);
        !           881:                        if (!n) {
        !           882:                                printf("%d: %s\n",
        !           883:                                        fs2h32(dp->mfsd_ino), dp->mfsd_name);
        !           884:                                continue;
        !           885:                        }
        !           886:                        n->e_ino = fs2h32(dp->mfsd_ino);
        !           887:                        strncpy(n->e_name, dp->mfsd_name, namlen);
        !           888:                        n->e_name[namlen] = '\0';
        !           889:                        for (np = &names; *np; np = &(*np)->e_next) {
        !           890:                                if (strcmp(n->e_name, (*np)->e_name) < 0)
        !           891:                                        break;
        !           892:                        }
        !           893:                        n->e_next = *np;
        !           894:                        *np = n;
        !           895:                }
        !           896:                fp->f_seekp += buf_size;
        !           897:        }
        !           898:
        !           899:        if (names) {
        !           900:                entry_t *p_names = names;
        !           901:                do {
        !           902:                        n = p_names;
        !           903:                        printf("%d: %s\n",
        !           904:                                n->e_ino, n->e_name);
        !           905:                        p_names = n->e_next;
        !           906:                } while (p_names);
        !           907:        } else {
        !           908:                printf("not found\n");
        !           909:        }
        !           910: out:
        !           911:        if (names) {
        !           912:                do {
        !           913:                        n = names;
        !           914:                        names = n->e_next;
        !           915:                        dealloc(n, 0);
        !           916:                } while (names);
        !           917:        }
        !           918:        return;
        !           919: }
        !           920: #endif
        !           921:
        !           922: /*
        !           923:  * byte swap functions for big endian machines
        !           924:  * (mfs is always little endian)
        !           925:  */
        !           926:
        !           927: /* These functions are only needed if native byte order is not big endian */
        !           928: #if BYTE_ORDER == BIG_ENDIAN
        !           929: void
        !           930: minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new)
        !           931: {
        !           932:        new->mfs_ninodes        =       bswap32(old->mfs_ninodes);
        !           933:        new->mfs_nzones         =       bswap16(old->mfs_nzones);
        !           934:        new->mfs_imap_blocks    =       bswap16(old->mfs_imap_blocks);
        !           935:        new->mfs_zmap_blocks    =       bswap16(old->mfs_zmap_blocks);
        !           936:        new->mfs_firstdatazone_old =    bswap16(old->mfs_firstdatazone_old);
        !           937:        new->mfs_log_zone_size  =       bswap16(old->mfs_log_zone_size);
        !           938:        new->mfs_max_size       =       bswap32(old->mfs_max_size);
        !           939:        new->mfs_zones          =       bswap32(old->mfs_zones);
        !           940:        new->mfs_magic          =       bswap16(old->mfs_magic);
        !           941:        new->mfs_block_size     =       bswap16(old->mfs_block_size);
        !           942:        new->mfs_disk_version   =       old->mfs_disk_version;
        !           943: }
        !           944:
        !           945: void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new)
        !           946: {
        !           947:        int i;
        !           948:
        !           949:        new->mdi_mode           =       bswap16(old->mdi_mode);
        !           950:        new->mdi_nlinks         =       bswap16(old->mdi_nlinks);
        !           951:        new->mdi_uid            =       bswap16(old->mdi_uid);
        !           952:        new->mdi_gid            =       bswap16(old->mdi_gid);
        !           953:        new->mdi_size           =       bswap32(old->mdi_size);
        !           954:        new->mdi_atime          =       bswap32(old->mdi_atime);
        !           955:        new->mdi_mtime          =       bswap32(old->mdi_mtime);
        !           956:        new->mdi_ctime          =       bswap32(old->mdi_ctime);
        !           957:
        !           958:        /* We don't swap here, because indirects must be swapped later
        !           959:         * anyway, hence everything is done by block_map().
        !           960:         */
        !           961:        for (i = 0; i < NR_TZONES; i++)
        !           962:                new->mdi_zone[i] = old->mdi_zone[i];
        !           963: }
        !           964: #endif

CVSweb <webmaster@jp.NetBSD.org>