V10/netfs/serv/d7.c

Compare this file to the similar file:
Show the results in this format:

/*
 * read a V7 PDP-11 dump tape as a filesystem
 */
#include <stdio.h>
#include <rf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

/*
 * PDP-11 integers
 */
#define	p11s(c)	((c)[0]|((c)[1]<<8))
#define	p11l(c)	((c)[2]|((c)[3]<<8)|((c)[0]<<16)|((c)[1]<<24))	/* wretched FP-11 */
#define	P11S	2	/* size of PDP-11 short */
#define	P11L	4	/* size of PDP-11 long */

/*
 * PDP-11 disk inode offsets
 */

#define	DI_MODE	0	/* (short) */
#define	DI_NLINK 2	/* (short) */
#define	DI_UID	4	/* (short) */
#define	DI_GID	6	/* (short) */
#define	DI_SIZE	8	/* (long) */
#define	DI_ADDR	12	/* 40 bytes */
#define	DI_ATIME 52	/* (long) */
#define	DI_MTIME 56	/* (long) */
#define	DI_CTIME 60	/* (long) */
#define	DILEN	64

/*
 * PDP-11 directory entry
 */

#define	D_INO	0	/* (short) */
#define	D_NAME	2	/* 14 characters */
#define	DNSIZE	14
#define	DLEN	16

/*
 * dump records
 */

#define	TBSIZE	512

#define	MAGIC	(int)60011

#define	TS_TAPE	1
#define	TS_INODE 2
#define	TS_BITS	3
#define	TS_ADDR	4
#define	TS_END	5
#define	TS_CLRI	6

struct spcl11 {		/* header as found on the tape */
	unsigned char c_type[P11S];
	unsigned char c_date[P11L];
	unsigned char c_ddate[P11L];
	unsigned char c_volume[P11S];
	unsigned char c_tapea[P11L];
	unsigned char c_inumber[P11S];
	unsigned char c_magic[P11S];
	unsigned char c_checksum[P11S];
	unsigned char c_dinode[DILEN];
	unsigned char c_count[P11S];
	unsigned char c_addr[TBSIZE];
};

struct spcl {		/* header we use internally */
	int c_type;
	int c_inumber;
	unsigned char c_dinode[DILEN];
	int c_count;
	char c_addr[TBSIZE];
};

/*
 * our data
 */

typedef unsigned int taddr_t;

#define	MAXINO	10000	/* dynamic would be better */
static taddr_t iaddr[MAXINO];	/* offset of TS_INODE for this file */

static int devfd;
static Rfile *root;
int fserrno;

struct spcl *getspcl();
taddr_t curtblock();
Rfile *getino();

char *malloc();
long lseek();

/*
 * init
 */
Rfile *
fsinit(argc, argv)
int argc;
char **argv;
{

	if (argc <= 1)
		rfpanic("no device\n");
	if ((devfd = open(argv[1], 0)) < 0)
		rfpanic("%s: cannot open\n", argv[1]);
	scantape();
	if ((root = getino(2)) == NULL)
		rfpanic("no root\n");
	return (root);
}

/*
 * look up a file
 */
Rfile *
fswalk(df, name)
Rfile *df;
char *name;
{
	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 */
			return (NULL);
		}
	}
	return (getino(ino));
}

/*
 * all done with a file
 */
fsdone(f)
Rfile *f;
{
	free(f->fs);
	free((char *)f);
	return (0);
}

/*
 * read data
 */
int
fsread(f, off, buf, len)
register Rfile *f;
long off;
char *buf;
int len;
{
	char blk[TBSIZE];
	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 / TBSIZE;
	if (getblk(f, bno, blk) == 0)
		return (-1);
	rest = (bno + 1)*TBSIZE - off;
	if (len > rest)
		len = rest;
	memcpy(buf, blk + (off % TBSIZE), len);
	return (len);
}

/*
 * read a piece of a directory
 * -- cheap out for now: just return one
 */
int
fsdirread(f, off, buf, len, offp)
register Rfile *f;
long off;
char *buf;
int len;
long *offp;
{
	int stlen;
	register unsigned char *de;
	unsigned char blk[TBSIZE];
	unsigned char one[TBSIZE];
	int n, ino;

	if (off % DLEN) {
		fserrno = EINVAL;
		return (-1);
	}
	stlen = len;
	de = &blk[TBSIZE];
	for (; off < f->size; de += DLEN, off += DLEN) {
		if (de >= &blk[TBSIZE]) {
			if (getblk(f, off/TBSIZE, blk) == 0)
				break;
			de = &blk[off%TBSIZE];
		}
		ino = p11s(&de[D_INO]);
		if (ino == 0)
			continue;
		n = sprintf(one, "%d\t%.14s", ino, &de[D_NAME]);
		n++;	/* need the NUL too */
		if (n > len)
			break;
		memcpy(buf, one, n);
		len -= n;
		buf += n;
	}
	*offp = off;
	return (stlen - len);
}

/*
 * search a directory
 */
int
dsearch(f, name)
Rfile *f;
char *name;
{
	unsigned char dbuf[TBSIZE];
	register unsigned char *de;
	register int ino;
	register long b, size;

	for (b = 0, size = f->size; size > 0; b++, size -= TBSIZE) {
		if (getblk(f, b, dbuf) == 0)
			continue;
		for (de = dbuf; de < &dbuf[TBSIZE]; de += DLEN) {
			ino = p11s(&de[D_INO]);
			if (ino == 0)
				continue;
			if (strncmp(&de[D_NAME], name, DNSIZE) == 0)
				return (ino);
		}
	}
	return (0);
}

/*
 * retrieve file data
 */
Rfile *
getino(i)
int i;
{
	register Rfile *f;
	register struct spcl *sp;
	long nblocks;

	if (i >= MAXINO || i < 0 || iaddr[i] == 0) {
		rflog("%d: bad i-number\n", i);
		fserrno = EINVAL;
		return (NULL);
	}
	lseek(devfd, (long)iaddr[i] * TBSIZE, 0);
	if ((sp = getspcl()) == NULL
	||  sp->c_type != TS_INODE) {
		rflog("%d: can't find header\n", i);
		fserrno = EIO;
		return (NULL);
	}
	if (sp->c_inumber != i) {
		rflog("%d: found header for %d instead\n",
			i, sp->c_inumber);
		fserrno = EIO;
		return (NULL);
	}
	if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) {
		rflog("%d: no memory for header\n", i);
		fserrno = ENOMEM;
		return (NULL);
	}
	f->ino = i;
	f->dev = 0;
	f->mode = p11s(&sp->c_dinode[DI_MODE]);	/* understood same bits */
	f->nlink = p11s(&sp->c_dinode[DI_NLINK]);
	f->uid = p11s(&sp->c_dinode[DI_UID]);
	f->gid = p11s(&sp->c_dinode[DI_GID]);
	f->rdev = 0;
	f->size = p11l(&sp->c_dinode[DI_SIZE]);
	f->ta = p11l(&sp->c_dinode[DI_ATIME]);
	f->tm = p11l(&sp->c_dinode[DI_MTIME]);
	f->tc = p11l(&sp->c_dinode[DI_CTIME]);
	nblocks = (f->size + TBSIZE - 1)/TBSIZE;
	if ((f->fs = malloc(nblocks * sizeof(taddr_t))) == NULL) {
		rflog("%d: no mem for %d block addresses\n", i, nblocks);
		fserrno = ENOMEM;
		free((char *)f);
		return (NULL);
	}
	scanfile(sp, (taddr_t *)f->fs, nblocks);
	return (f);
}

/*
 * read a TBSIZE block from file
 */
getblk(f, bno, buf)
register Rfile *f;
long bno;
char *buf;
{

	if (bno * TBSIZE > f->size) {
		fserrno = 0;
		return (0);
	}
	lseek(devfd, (long)((taddr_t *)f->fs)[bno] * TBSIZE, 0);
	if (read(devfd, buf, TBSIZE) != TBSIZE) {
		rflog("%d: bno %ld: errno %d\n", f->ino, bno, errno);
		fserrno = errno;
		return (0);
	}
	return (1);
}

/*
 * scan the tape,
 * remember where all the file records are
 */

scantape()
{
	register struct spcl *sp;
	register int i;

	for (;;) {
		if ((sp = getspcl()) == NULL) {
			rflog("unexpected tape EOF\n");
			return;
		}
		switch (sp->c_type) {
		case TS_END:
			return;

		case TS_TAPE:
			continue;

		case TS_BITS:
		case TS_CLRI:
			lseek(devfd, (long)sp->c_count * TBSIZE, 1);
			continue;

		case TS_ADDR:
			rflog("unexpected TS_ADDR i %d\n", sp->c_inumber);
			continue;

		default:
			rflog("ill spcl type %d i %d\n",
				sp->c_type, sp->c_inumber);
			continue;

		case TS_INODE:
			i = sp->c_inumber;
			if (i <= 0 || i >= MAXINO)
				rflog("ill TS_FILE i %d\n", i);
			else
				iaddr[i] = curtblock() - 1;
			scanfile(sp, (taddr_t *)NULL,
				(p11l(&sp->c_dinode[DI_SIZE])+TBSIZE-1)/TBSIZE);
			continue;
		}
	}
}

/*
 * skip lightly through a file,
 * remembering where the blocks are
 * ip is an array of tape addresses;
 * n is the length of the array, if present,
 * which is the same as the number of blocks expected
 * call with the TS_INODE record,
 * since that contains the first list of blocks
 */

scanfile(sp, ip, n)
register struct spcl *sp;
register taddr_t *ip;
register int n;
{
	register int i;
	taddr_t tblock;

	tblock = curtblock();
	while (n) {
		for (i = 0; i < sp->c_count; i++) {
			if (sp->c_count == 0) {		/* hole */
				if (ip)
					*ip++ = 0;
			} else {			/* real */
				if (ip)
					*ip++ = tblock;
				tblock++;
			}
			if (--n <= 0)
				break;
		}
		lseek(devfd, (long)tblock*TBSIZE, 0);	/* past data */
		if (n <= 0)
			return;
		/*
		 * more: get TS_ADDR
		 */
		if ((sp = getspcl()) == NULL) {
			rflog("unexpected tape EOF\n");
			return;
		}
		if (sp->c_type != TS_ADDR) {
			rflog("wanted TS_ADDR, got type %d i %d\n",
				sp->c_type, sp->c_inumber);
			unspcl();
			return;
		}
		tblock++;		/* count the header we just read */
	}
}

struct spcl *
getspcl()
{
	char buf[TBSIZE];
	static struct spcl s;
	register struct spcl11 *tp;
	int nbad;

	nbad = 0;
	tp = (struct spcl11 *)buf;
	for (;;) {
		if (read(devfd, buf, TBSIZE) != TBSIZE) {
			rflog("tape scan read, errno %d\n", errno);
			return (NULL);
		}
		if (p11s(tp->c_magic) != MAGIC) {
			nbad++;
			continue;
		}
		s.c_type = p11s(tp->c_type);
		s.c_inumber = p11s(tp->c_inumber);
		s.c_count = p11s(tp->c_count);
		/* a sanity check or two would go well here */
		memcpy(s.c_dinode, tp->c_dinode, DILEN);
		memcpy(s.c_addr, tp->c_addr, s.c_count);
		if (nbad)
			rflog("skipped %d to type %d i %d\n",
				nbad, s.c_type, s.c_inumber);
		return (&s);
	}
}

/*
 * reread the current header: cheap hack
 */
unspcl()
{
	lseek(devfd, (long)-TBSIZE, 1);
}

taddr_t
curtblock()
{
	return (lseek(devfd, 0L, 1)/TBSIZE);
}