123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- /*
- * Mach Operating System
- * Copyright (c) 1993 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- * HISTORY
- * $Log: ufs.c,v $
- * Revision 1.1.1.2 2007/08/16 07:04:23 vorlon
- * Import upstream "release" 1.0pre20040408 to CVS to facilitate rebasing
- * against the current upstream work and avoid copying patches one-by-one.
- *
- * Revision 1.2 2003/11/08 00:03:36 wgwoods
- * Reverted changes from 0.10, merged doc changes
- *
- * Revision 1.1.1.1.2.1 2003/03/21 23:32:23 wgwoods
- * Warning cleanups
- *
- * Revision 1.1.1.1 2001/10/08 23:03:52 wgwoods
- * initial import of CVS source from alphalinux.org, plus a couple bugfixes
- *
- * Revision 1.1.1.1 2000/05/03 03:58:22 dhd
- * Initial import (from 0.7 release)
- *
- * Revision 2.2 93/02/05 08:01:36 danner
- * Adapted for alpha.
- * [93/02/04 af]
- *
- */
- /*
- * File: ufs.c
- * Author: David Golub, Carnegie Mellon University
- * Date: 12/90
- *
- * Stand-alone file reading package.
- *
- * Modified for use by Linux/Alpha by David Mosberger
- * (davidm@cs.arizona.edu)
- */
- #include <linux/kernel.h>
- #include <asm/stat.h>
- #include "aboot.h"
- #include "bootfs.h"
- #include "cons.h"
- #include "disklabel.h"
- #include "ufs.h"
- #include "utils.h"
- #include "string.h"
- #define MAX_OPEN_FILES 1
- extern struct bootfs ufs;
- static long dev;
- static long partition_offset;
- static struct fs *fs;
- static struct file {
- int inuse;
- struct icommon i_ic; /* copy of on-disk inode */
- int f_nindir[NIADDR+1];
- /* number of blocks mapped by
- indirect block at level i */
- void *f_blk[NIADDR]; /* buffer for indir block at level i */
- long f_blksize[NIADDR];
- /* size of buffer */
- __kernel_daddr_t f_blkno[NIADDR];
- /* disk address of block in buffer */
- void *f_buf; /* buffer for data block */
- long f_buf_size; /* size of data block */
- __kernel_daddr_t f_buf_blkno; /* block number of data block */
- } inode_table[MAX_OPEN_FILES];
- static int read_inode(__kernel_ino_t inumber, struct file *fp)
- {
- __kernel_daddr_t disk_block;
- long offset;
- struct dinode *dp;
- int level;
- disk_block = itod(fs, inumber);
- offset = fsbtodb(fs, disk_block) * DEV_BSIZE + partition_offset;
- if (cons_read(dev, fp->f_buf, fs->fs_bsize, offset) != fs->fs_bsize) {
- printf("ufs_read_inode: read error\n");
- return 1;
- }
- dp = (struct dinode *)fp->f_buf;
- dp += itoo(fs, inumber);
- fp->i_ic = dp->di_ic;
- /*
- * Clear out the old buffers
- */
- for (level = 0; level < NIADDR; level++) {
- if (fp->f_blk[level]) {
- free(fp->f_blk[level]);
- fp->f_blk[level] = 0;
- }
- fp->f_blkno[level] = -1;
- }
- return 0;
- }
- /*
- * Given an offset in a file, find the disk block number that
- * contains that block.
- */
- static __kernel_daddr_t block_map(struct file *fp, __kernel_daddr_t file_block)
- {
- __kernel_daddr_t ind_block_num, *ind_p;
- int level, idx;
- long offset;
- /*
- * Index structure of an inode:
- *
- * i_db[0..NDADDR-1] hold block numbers for blocks
- * 0..NDADDR-1
- *
- * i_ib[0] index block 0 is the single indirect
- * block
- * holds block numbers for blocks
- * NDADDR .. NDADDR + NINDIR(fs)-1
- *
- * i_ib[1] index block 1 is the double indirect
- * block
- * holds block numbers for INDEX blocks
- * for blocks
- * NDADDR + NINDIR(fs) ..
- * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
- *
- * i_ib[2] index block 2 is the triple indirect
- * block
- * holds block numbers for double-indirect
- * blocks for blocks
- * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
- * NDADDR + NINDIR(fs) + NINDIR(fs)**2
- * + NINDIR(fs)**3 - 1
- */
- if (file_block < NDADDR) {
- /* Direct block. */
- return fp->i_db[file_block];
- }
- file_block -= NDADDR;
- /*
- * nindir[0] = NINDIR
- * nindir[1] = NINDIR**2
- * nindir[2] = NINDIR**3
- * etc
- */
- for (level = 0; level < NIADDR; level++) {
- if (file_block < fp->f_nindir[level])
- break;
- file_block -= fp->f_nindir[level];
- }
- if (level == NIADDR) {
- printf("ufs_block_map: block number too high\n");
- return -1;
- }
- ind_block_num = fp->i_ib[level];
- for (; level >= 0; level--) {
- if (ind_block_num == 0) {
- return 0;
- }
- if (fp->f_blkno[level] != ind_block_num) {
- if (fp->f_blk[level]) {
- free(fp->f_blk[level]);
- }
- offset = fsbtodb(fs, ind_block_num) * DEV_BSIZE
- + partition_offset;
- fp->f_blk[level] = malloc(fs->fs_bsize);
- if (cons_read(dev, fp->f_blk[level], fs->fs_bsize,
- offset)
- != fs->fs_bsize)
- {
- printf("ufs_block_map: read error\n");
- return -1;
- }
- fp->f_blkno[level] = ind_block_num;
- }
- ind_p = (__kernel_daddr_t *)fp->f_blk[level];
- if (level > 0) {
- idx = file_block / fp->f_nindir[level-1];
- file_block %= fp->f_nindir[level-1];
- } else {
- idx = file_block;
- }
- ind_block_num = ind_p[idx];
- }
- return ind_block_num;
- }
- static int breadi(struct file *fp, long blkno, long nblks, char *buffer)
- {
- long block_size, offset, tot_bytes, nbytes, ncontig;
- __kernel_daddr_t disk_block;
- tot_bytes = 0;
- while (nblks) {
- /*
- * Contiguous reads are a lot faster, so we try to group
- * as many blocks as possible:
- */
- ncontig = 0; /* # of *fragments* that are contiguous */
- nbytes = 0;
- disk_block = block_map(fp, blkno);
- do {
- block_size = blksize(fs, fp, blkno);
- nbytes += block_size;
- ncontig += numfrags(fs, block_size);
- ++blkno; --nblks;
- } while (nblks &&
- block_map(fp, blkno) == disk_block + ncontig);
- if (!disk_block) {
- /* it's a hole... */
- memset(buffer, 0, nbytes);
- } else {
- offset = fsbtodb(fs, disk_block) * DEV_BSIZE
- + partition_offset;
- if (cons_read(dev, buffer, nbytes, offset) != nbytes) {
- printf("ufs_breadi: read error\n");
- return -1;
- }
- }
- buffer += nbytes;
- tot_bytes += nbytes;
- }
- return tot_bytes;
- }
- /*
- * Search a directory for a name and return its
- * i_number.
- */
- static int search_dir(const char *name, struct file *fp, __kernel_ino_t *inumber_p)
- {
- long offset, blockoffset;
- struct direct *dp;
- int len;
- len = strlen(name);
- offset = 0;
- while (offset < fp->i_size) {
- blockoffset = 0;
- if (breadi(fp, offset / fs->fs_bsize, 1, fp->f_buf) < 0) {
- return -1;
- }
- while (blockoffset < fs->fs_bsize) {
- dp = (struct direct *)((char*)fp->f_buf + blockoffset);
- if (dp->d_ino) {
- if (dp->d_namlen == len
- && strcmp(name, dp->d_name) == 0)
- {
- /* found entry */
- *inumber_p = dp->d_ino;
- return 0;
- }
- }
- blockoffset += dp->d_reclen;
- }
- offset += fs->fs_bsize;
- }
- return -1;
- }
- /*
- * Initialize a BSD FFS partition starting at offset P_OFFSET; this is
- * sort-of the same idea as "mounting" it. Read in the relevant
- * control structures and make them available to the user. Returns 0
- * if successful, -1 on failure.
- */
- static int ufs_mount(long cons_dev, long p_offset, long quiet)
- {
- static char buf[SBSIZE]; /* minimize frame size */
- long rc;
- memset(&inode_table, 0, sizeof(inode_table));
- dev = cons_dev;
- partition_offset = p_offset;
- rc = cons_read(dev, buf, SBSIZE, SBLOCK*DEV_BSIZE + partition_offset);
- if (rc != SBSIZE)
- {
- printf("ufs_mount: superblock read failed (retval=%ld)\n", rc);
- return -1;
- }
- fs = (struct fs *)buf;
- if (fs->fs_magic != FS_MAGIC ||
- fs->fs_bsize > MAXBSIZE ||
- fs->fs_bsize < (int) sizeof(struct fs))
- {
- if (!quiet) {
- printf("ufs_mount: invalid superblock "
- "(magic=%x, bsize=%d)\n",
- fs->fs_magic, fs->fs_bsize);
- }
- return -1;
- }
- ufs.blocksize = fs->fs_bsize;
- /* don't read cylinder groups - we aren't modifying anything */
- return 0;
- }
- static int ufs_open(const char *path)
- {
- char *cp = 0, *component;
- int fd;
- __kernel_ino_t inumber, parent_inumber;
- int nlinks = 0;
- struct file *fp;
- static char namebuf[MAXPATHLEN+1];
-
- if (!path || !*path) {
- return -1;
- }
- for (fd = 0; inode_table[fd].inuse; ++fd) {
- if (fd >= MAX_OPEN_FILES) {
- return -1;
- }
- }
- fp = &inode_table[fd];
- fp->f_buf_size = fs->fs_bsize;
- fp->f_buf = malloc(fp->f_buf_size);
- /* copy name into buffer to allow modifying it: */
- memcpy(namebuf, path, (unsigned)(strlen(path) + 1));
- inumber = (__kernel_ino_t) ROOTINO;
- if (read_inode(inumber, fp) < 0) {
- return -1;
- }
- component = strtok(namebuf, "/");
- while (component) {
- /* verify that current node is a directory: */
- if ((fp->i_mode & IFMT) != IFDIR) {
- return -1;
- }
- /*
- * Look up component in current directory.
- * Save directory inumber in case we find a
- * symbolic link.
- */
- parent_inumber = inumber;
- if (search_dir(component, fp, &inumber))
- return -1;
- /* open next component: */
- if (read_inode(inumber, fp))
- return -1;
- /* check for symbolic link: */
- if ((fp->i_mode & IFMT) == IFLNK) {
- int link_len = fp->i_size;
- int len;
- len = strlen(cp) + 1;
- if (link_len + len >= MAXPATHLEN - 1) {
- return -1;
- }
- if (++nlinks > MAXSYMLINKS) {
- return FS_SYMLINK_LOOP;
- }
- memcpy(&namebuf[link_len], cp, len);
- #ifdef IC_FASTLINK
- if ((fp->i_flags & IC_FASTLINK) != 0) {
- memcpy(namebuf, fp->i_symlink, link_len);
- } else
- #endif /* IC_FASTLINK */
- {
- /* read file for symbolic link: */
- long rc, offset;
- __kernel_daddr_t disk_block;
- disk_block = block_map(fp, (__kernel_daddr_t)0);
- offset = fsbtodb(fs, disk_block) * DEV_BSIZE
- + partition_offset;
- rc = cons_read(dev, namebuf, sizeof(namebuf),
- offset);
- if (rc != sizeof(namebuf)) {
- return -1;
- }
- }
- /*
- * If relative pathname, restart at parent directory.
- * If absolute pathname, restart at root.
- */
- cp = namebuf;
- if (*cp != '/') {
- inumber = parent_inumber;
- } else
- inumber = (__kernel_ino_t)ROOTINO;
- if (read_inode(inumber, fp))
- return -1;
- }
- component = strtok(NULL, "/");
- }
- /* calculate indirect block levels: */
- {
- register int mult;
- register int level;
- mult = 1;
- for (level = 0; level < NIADDR; level++) {
- mult *= NINDIR(fs);
- fp->f_nindir[level] = mult;
- }
- }
- return fd;
- }
- static int ufs_bread(int fd, long blkno, long nblks, char *buffer)
- {
- struct file *fp;
- fp = &inode_table[fd];
- return breadi(fp, blkno, nblks, buffer);
- }
- static void ufs_close(int fd)
- {
- inode_table[fd].inuse = 0;
- }
- static const char *
- ufs_readdir(int fd, int rewind)
- {
- return NULL;
- }
- static int
- ufs_fstat(int fd, struct stat* buf)
- {
- return -1;
- }
- struct bootfs ufs = {
- FS_BSDFFS, 0,
- ufs_mount,
- ufs_open, ufs_bread, ufs_close, ufs_readdir, ufs_fstat
- };
|