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>