V10/netfs/serv/f6.c

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

/*
 * read an old (V6 and before) PDP-11 Unix filesystem
 * quick, cheap hack; runs only on VAXes
 */

/*
 * miscellaneous filesystem definitions
 * some are magic numbers here
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/inode.h>
#include <sys/dir.h>	/* hack: pdp11 dirs == vax dirs */

#define	BLSIZE	512

/*
 * v6 disk inode
 */
#define	V6NADDR	8

struct v6dinode {
	short flags;
	unsigned char nlinks;
	unsigned char uid;
	unsigned char gid;
	unsigned char hisize;
	unsigned short losize;
	unsigned short addr[V6NADDR];
	unsigned short atime[2];	/* pdp-11 order */
	unsigned short mtime[2];	/* pdp-11 order */
};

/*
 * type part of mode
 */
#define	V6FMT	0160000
#define	V6IFREG	0100000
#define	V6IFDIR	0140000
#define	V6IFCHR	0120000
#define	V6IFBLK	0160000
#define	V6MODE	07777
#define	V6LARGE	010000

#define	V6SUPERB	1
#define	V6ROOT		1	/* root inode */

/*
 * local file data
 */
typedef struct Fsfile {
	long addr[V6NADDR];
	int large;
} Fsfile;

#define	fsp(f)	((Fsfile *)((f)->fs))

#include "rf.h"
#include <errno.h>
#include <libc.h>

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

/*
 * init:
 * open the device
 */

Rfile *
fsinit(argc, argv)
int argc;
char **argv;
{
	register Rfile *f;
	char *passwd, *group;

	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)
		passwd = argv[2];
	else
		passwd = "/etc/passwd";
	if (argc > 3)
		group = argv[3];
	else
		group = "/etc/group";
	rfuidmap = rfmkidmap(passwd, (Namemap *)0);
	rfgidmap = rfmkidmap(group, (Namemap *)0);
	/* never mind the super-block */
	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 = V6ROOT;
	fsstat(f);
	root = f;
	return (f);
}

/*
 * access a file
 */

Rfile *
fswalk(df, name)
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;
{
	char blk[BLSIZE];
	int rest;
	daddr_t bno;

	switch (f->mode & IFMT) {
	case IFREG:
	case IFDIR:
		break;

	default:
		return (0);
	}
	if (off >= f->size)
		return (0);
	if (off + len > f->size)
		len = f->size - off;
	bno = off / BLSIZE;
	if (getlblk(f, bno, blk) == 0)
		return (-1);
	rest = (bno + 1)*BLSIZE - off;
	if (len > rest)
		len = rest;
	memcpy(buf, blk + (off % BLSIZE), 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 struct direct *de;
	char blk[BLSIZE];
	char one[BLSIZE];
	int n;

	if (off % sizeof(struct direct)) {
		fserrno = EINVAL;
		return (-1);
	}
	stlen = len;
	de = (struct direct *)&blk[BLSIZE];
	for (; off < f->size; de++, off += sizeof(struct direct)) {
		if (de >= (struct direct *)&blk[BLSIZE]) {
			if (getlblk(f, off/BLSIZE, blk) == 0)
				break;
			de = (struct direct *)&blk[off%BLSIZE];
		}
		if (de->d_ino == 0)
			continue;
		n = sprintf(one, "%d\t%.14s", de->d_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);
}

/*
 * fetch an i-node
 * -- no sanity check for now
 * -- magic inode-to-disk-block stuff here
 */

#define	LINOPB	(BLSIZE/sizeof(struct v6dinode))
int
getino(f)
register Rfile *f;
{
	char buf[BLSIZE];
	register struct v6dinode *dp;
	register int ioff;
	register int i;
	int mode;

	ioff = f->ino - 1;
	lseek(devfd, (long)BLSIZE*(ioff/LINOPB + V6SUPERB + 1), 0);
	if (read(devfd, buf, BLSIZE) != BLSIZE) {
		/* print error */
		return (0);
	}
	dp = ((struct v6dinode *)buf) + (ioff%LINOPB);
	switch (dp->flags & V6FMT) {
	case V6IFREG:
		mode = IFREG;
		break;

	case V6IFDIR:
		mode = IFDIR;
		break;

	case V6IFCHR:
		mode = IFCHR;
		break;

	case V6IFBLK:
		mode = IFBLK;
		break;

	default:
		return (0);	/* unalloc or illegal */
	}
	for (i = 0; i < V6NADDR; i++)
		fsp(f)->addr[i] = dp->addr[i];
	f->dev = 0;		/* all the same device */
	f->rdev = fsp(f)->addr[0];
	f->mode = mode | (dp->flags & V6MODE);
	fsp(f)->large = (dp->flags & V6LARGE) != 0;
	f->nlink = dp->nlinks;
	f->uid = dp->uid;
	f->gid = dp->gid;
	f->size = (dp->hisize << 16) + dp->losize;
	f->tm = (dp->mtime[0]<<16) + dp->mtime[1];
	f->ta = (dp->atime[0]<<16) + dp->atime[1];
	f->tc = f->tm;
	return (1);
}

/*
 * look up a file
 */

#define	LNDPB	(BLSIZE/sizeof(struct direct))

int
dsearch(f, name)
Rfile *f;
char *name;
{
	struct direct dbuf[LNDPB];
	register struct direct *de;
	register int i;
	register long b, size;

	for (b = 0, size = f->size; size > 0; b++, size -= BLSIZE) {
		if (getlblk(f, b, (char *)dbuf) == 0)
			continue;
		for (i = 0, de = dbuf; i < LNDPB; i++, de++) {
			if (de->d_ino == 0)
				continue;
			if (strncmp(de->d_name, name, DIRSIZ) == 0)
				return (de->d_ino);
		}
	}
	return (0);
}

/*
 * read a block from a file
 */
daddr_t bmap();

getlblk(f, bno, buf)
Rfile *f;
daddr_t bno;
char *buf;
{
	daddr_t dbno;

	if ((dbno = bmap(f, bno)) == 0) {
		memset(buf, 0, BLSIZE);
		return (1);
	}
	lseek(devfd, dbno*BLSIZE, 0);
	if (read(devfd, buf, BLSIZE) != BLSIZE) {
		fserrno = errno;
		return (0);
	}
	return (1);
}

/*
 * logical to physical block
 * only singly-indirect files for now
 */
#define	LNINDIR	(BLSIZE/sizeof(unsigned short))

daddr_t
bmap(f, bno)
register Rfile *f;
daddr_t bno;
{
	unsigned short indbuf[LNINDIR];

	if (fsp(f)->large == 0) {
		if (bno < V6NADDR)
			return (fsp(f)->addr[bno]);
		return (0);
	}
	if (bno < V6NADDR*LNINDIR) {
		lseek(devfd, fsp(f)->addr[bno/LNINDIR]*BLSIZE, 0);
		if (read(devfd, (char *)indbuf, BLSIZE) != BLSIZE)
			return (0);
		return (indbuf[bno%LNINDIR]);
	}
	return (0);
}