|
|
researchv10 Norman
/*
* read a Berkeley `fast file system'
* quick, cheap hack
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h> /* for file modes; they happen to match */
#include "bsdffs.h"
#include "rf.h"
#include <errno.h>
#include <libc.h>
int fserrno;
static int devfd;
static Rfile *root;
static union {
char buf[SBSIZE];
struct fs super;
} super;
#define sb (super.super)
static long firstblk; /* offset to beginning of filsys */
static char *blk;
typedef struct Fsfile {
long dir[NDADDR];
long ind[NIADDR];
} Fsfile;
#define fsp(f) ((Fsfile *)((f)->fs))
/*
* init:
* open the device
*/
Rfile *
fsinit(argc, argv)
int argc;
char **argv;
{
register Rfile *f;
if (argc <= 1)
rfpanic("no device specified\n");
if ((devfd = open(argv[1], 0)) < 0)
rfpanic("%s: cannot open\n", argv[1]);
if (argc > 2)
firstblk = atol(argv[2]) * 512;
lseek(devfd, firstblk + SBLOCK, 0);
if (read(devfd, super.buf, SBSIZE) != SBSIZE)
rfpanic("can't read super block\n");
if ((blk = malloc(sb.fs_bsize)) == NULL)
rfpanic("can't alloc %d for block buf\n", sb.fs_bsize);
if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL)
rfpanic("no mem for root\n");
if ((f->fs = malloc(sizeof(Fsfile))) == NULL)
rfpanic("no mem for root\n");
f->ino = ROOTINO;
fsstat(f);
root = f;
return (f);
}
/*
* access a file
*/
Rfile *
fswalk(df, name)
register Rfile *df;
char *name;
{
register Rfile *f;
int ino;
if ((ino = dsearch(df, name)) == 0) {
fserrno = ENOENT;
return (NULL);
}
if (df == root) { /* "." and ".." magic */
if (strcmp(name, ".") == 0)
return (df);
if (strcmp(name, "..") == 0) {
fserrno = 0; /* pseudo-error: popped out of root */
return (NULL);
}
}
if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) {
fserrno = ENOMEM;
return (NULL);
}
if ((f->fs = malloc(sizeof(Fsfile))) == NULL) {
free((char *)f);
fserrno = ENOMEM;
return (NULL);
}
f->ino = ino;
fsstat(f);
return (f);
}
/*
* discard a file reference
*/
int
fsdone(f)
Rfile *f;
{
free(f->fs);
free((char *)f);
return (0);
}
/*
* return file status
*/
int
fsstat(f)
Rfile *f;
{
getino(f);
return (0);
}
/*
* read data
*/
int
fsread(f, off, buf, len)
register Rfile *f;
long off;
char *buf;
int len;
{
int rest;
long bno;
switch (f->mode & S_IFMT) {
case S_IFREG:
case S_IFDIR:
break;
default:
return (0);
}
if (off >= f->size)
return (0);
if (off + len > f->size)
len = f->size - off;
bno = off / sb.fs_bsize;
if (getlblk(f, bno, blk, f->size - bno*sb.fs_bsize) == 0)
return (-1);
rest = (bno + 1)*sb.fs_bsize - off;
if (len > rest)
len = rest;
memcpy(buf, blk + (off % sb.fs_bsize), len);
return (len);
}
/*
* read a piece of a directory
*/
int
fsdirread(f, off, buf, len, offp)
register Rfile *f;
long off;
char *buf;
int len;
long *offp;
{
int stlen;
register struct direct *de;
struct direct *endblk;
char one[MAXNAMLEN+30];
int n;
stlen = len;
endblk = de = (struct direct *)&blk[sb.fs_bsize];
for (; off < f->size; off += de->d_reclen,
de = (struct direct *)&blk[off%sb.fs_bsize]) {
if (de >= endblk) {
if (getlblk(f, off/sb.fs_bsize, blk, f->size - off) == 0)
break;
de = (struct direct *)&blk[off%sb.fs_bsize];
}
if (de->d_reclen == 0)
break;
if (de->d_ino == 0)
continue;
sprintf(one, "%ld\t%s", de->d_ino, de->d_name);
n = strlen(one)+1;
if (n > len)
break;
memcpy(buf, one, n);
len -= n;
buf += n;
}
*offp = off;
return (stlen - len);
}
/*
* fetch an i-node
* -- no sanity check for now
* -- magic inode-to-disk-block stuff here
*/
int
getino(f)
register Rfile *f;
{
register struct icommon *dp;
register int cg;
register long ifrag;
register long ino;
cg = f->ino / sb.fs_ipg;
ino = f->ino % sb.fs_ipg;
ifrag = cg*sb.fs_fpg + sb.fs_cgoffset*(cg&~sb.fs_cgmask) + sb.fs_iblkno;
ifrag += ino / (sb.fs_fsize/sizeof(struct icommon));
lseek(devfd, firstblk + ifrag * sb.fs_fsize, 0);
if (read(devfd, blk, sb.fs_fsize) != sb.fs_fsize) {
/* print error */
return (0);
}
dp = ((struct icommon *)blk) + (ino % (sb.fs_fsize/sizeof(struct icommon)));
switch (dp->i_mode & S_IFMT) {
case S_IFREG:
case S_IFDIR:
case S_IFBLK:
case S_IFCHR:
break;
default:
return (0); /* unalloc or illegal */
}
memcpy((char *)fsp(f)->dir, (char *)dp->i_db, NDADDR*sizeof(long));
memcpy((char *)fsp(f)->ind, (char *)dp->i_ib, NIADDR*sizeof(long));
f->dev = 0;
f->rdev = 0; /* well ... */
f->mode = dp->i_mode;
f->nlink = dp->i_nlink;
f->uid = dp->i_uid;
f->gid = dp->i_gid;
f->size = dp->i_size;
f->tm = dp->i_mtime;
f->ta = dp->i_atime;
f->tc = dp->i_ctime;
return (1);
}
/*
* look up a file
*/
int
dsearch(f, name)
Rfile *f;
char *name;
{
register struct direct *de;
register struct direct *endblk;
register long b, size;
endblk = (struct direct *)(blk + sb.fs_bsize);
for (b = 0, size = f->size; size > 0; b++, size -= sb.fs_bsize) {
if (getlblk(f, b, blk, size) == 0)
continue;
for (de = (struct direct *)blk; de < endblk;
de = (struct direct *)((char *)de + de->d_reclen)) {
if (de->d_reclen == 0) /* safety */
break;
if (de->d_ino == 0)
continue;
if (strcmp(de->d_name, name) == 0)
return (de->d_ino);
}
}
return (0);
}
/*
* read a block from a file
*/
long bmap();
getlblk(f, bno, buf, maxlen)
Rfile *f;
long bno;
char *buf;
int maxlen;
{
long dbno;
if (maxlen > sb.fs_bsize)
maxlen = sb.fs_bsize;
if ((dbno = bmap(f, bno)) == 0) {
memset(buf, 0, maxlen);
return (1);
}
lseek(devfd, firstblk + dbno*sb.fs_fsize, 0);
if (read(devfd, buf, maxlen) != maxlen) {
fserrno = errno;
return (0);
}
return (1);
}
/*
* logical to physical block
* only singly-indirect files for now
*/
long
bmap(f, bno)
register Rfile *f;
long bno;
{
if (bno < NDADDR)
return (fsp(f)->dir[bno]);
bno -= NDADDR;
if (bno >= sb.fs_nindir)
return (0);
lseek(devfd, firstblk + fsp(f)->ind[0] * sb.fs_fsize, 0);
if (read(devfd, blk, sb.fs_bsize) != sb.fs_bsize)
return (0);
return (((long *)blk)[bno]);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.