V10/netfs/serv/f11.c

/*
 * file service routines for FILES-11 ODS-1
 * in its modern instance, with subdirectories
 */

#include <rf.h>
#include "files11.h"
#include "f11.h"

#define	NULL	0
#define	HUGE	0x7fffffff

int diskfd;
struct homeblock home;
Fsfile indexf;
unsigned short dirtyp;

static htorf();
static char *itoa();
static int binchk();
char *r50toa();
char *malloc();

/*
 * permission hacks
 */
#define	UXOTHER	1
static Idmap gmap[] = { "other", UXOTHER, 0 };

/*
 * init:
 * install the root
 *
 * argv[1] == the file containing our filesystem
 */
Rfile *
fsinit(argc, argv)
int argc;
char **argv;
{
	register Rfile *f;
	register long firsthdr;
	char *p;

	p = "dir";
	dirtyp = ator50(&p);
	if (argc <= 1)
		rfpanic("no files-11 filesystem specified\n");
	if ((diskfd = open(argv[1], 0)) < 0)	/* readonly for now */
		rfpanic("%s: cannot open\n", argv[1]);
	if (lseek(diskfd, (long)HOMEBLK * BLKSIZ, 0) < 0)
		rfpanic("can't seek for home block\n");
	if (read(diskfd, (char *)&home, sizeof(home)) != sizeof(home))
		rfpanic("can't read homeblock\n");
	if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL
	||  (f->fs = malloc(sizeof(Fsfile))) == NULL)
		rfpanic("no mem for root\n");
	firsthdr = plong(home.H_iblb)+home.H_ibsz;
	lseek(diskfd, (firsthdr + fidtob(FINDEX)) * BLKSIZ, 0);
	if (read(diskfd, (char *)&indexf.h, sizeof(indexf.h)) != sizeof(indexf.h))
		rfpanic("can't read index header\n");
	indexf.lbase = HUGE;
	if (gethdr(FROOT, &fsp(f)->h) == 0)
		rfpanic("can't read root header\n");
	htorf(f, &fsp(f)->h);
	fsp(f)->parent = FROOT;
	fsp(f)->lbase = HUGE;
	fsp(f)->flags = FBIN;
	fsp(f)->tboff = fsp(f)->tbno = fsp(f)->tuoff = 0;
	rfgidmap = gmap;
	return (f);
}

/*
 * access a file
 */
Rfile *
fswalk(df, name)
Rfile *df;
char *name;
{
	register Rfile *f;
	unsigned short fid;
	int binary;

	binary = binchk(name);
	if (strcmp(name, ".") == 0)
		return (df);
	else if (strcmp(name, "..") == 0) {
		if (df->ino == FROOT) {
			fserrno = 0;		/* magic: popped out */
			return (NULL);
		}
		fid = fsp(df)->parent;
	} else if ((fid = f11walk(df, name)) == 0)
		return (NULL);
	if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) {
		rflog("no mem\n");
		fserrno = RFEINVAL;
		return (NULL);
	}
	if ((f->fs = malloc(sizeof(Fsfile))) == NULL) {
		free((char *)f);
		rflog("no mem\n");
		fserrno = RFEINVAL;
		return (NULL);
	}
	fsp(f)->lbase = HUGE;
	if (gethdr(fid, &fsp(f)->h) == 0) {
		free((char *)f);
		fserrno = RFEIO;
		return (NULL);
	}
	if (fsp(f)->h.h_ident.i_fnam.f_typ == dirtyp)
		fsp(f)->parent = fsp(df)->h.h_fnum;
	htorf(f, &fsp(f)->h);
	fsp(f)->tboff = fsp(f)->tbno = fsp(f)->tuoff = 0;
	if (binary)
		fsp(f)->flags = FBIN;
	else if (fsp(f)->h.h_fcs.f_rtyp == RTVAR && fsp(f)->h.h_fcs.f_ratt & RTCR)
		fsp(f)->flags = 0;
	else
		fsp(f)->flags = FBIN;
	return (f);
}

/*
 * see if filename is `binary': trailing % in name
 * stamp it out if so
 */
static
binchk(name)
register char *name;
{
	name += strlen(name);
	if (*--name == '%') {
		*name = 0;
		return (1);
	}
	return (0);
}

/*
 * discard a file reference
 */
int
fsdone(f)
Rfile *f;
{

	free(f->fs);
	free((char *)f);
	return (0);
}

/*
 * return file status
 */
fsstat(f)
register Rfile *f;
{

	if (gethdr(fsp(f)->h.h_fnum, &fsp(f)->h) == 0) {
		fserrno = RFEINVAL;
		return (-1);
	}
	htorf(f, &fsp(f)->h);
	return (0);
}

/*
 * read
 */
int
fsread(f, off, buf, len)
Rfile *f;
long off;
char *buf;
int len;
{

	if (fsp(f)->flags & FBIN)
		return (binread(f, off, buf, len));
	else
		return (textread(f, off, buf, len));
}

int
binread(f, off, buf, len)
Rfile *f;
long off;
char *buf;
int len;
{
	char bbuf[BLKSIZ];
	int boff;
	long bno;
	int nread, r;
	int ncpy;

	nread = 0;
	bno = off / BLKSIZ;
	boff = off % BLKSIZ;
	/*
	 * contract this loop later
	 */
	r = 0;
	while (len > 0) {
		if ((r = f11rblk(f, bno, bbuf)) <= 0)
			break;
		ncpy = BLKSIZ - boff;
		ncpy = (len > ncpy) ? ncpy : len;
		memcpy(buf, bbuf+boff, ncpy);
		len -= ncpy;
		buf += ncpy;
		nread += ncpy;
		boff = 0;
		bno++;
	}
	if (nread || r >= 0)
		return (nread);
	fserrno = RFEIO;
	return (-1);
}

int
textread(f, off, buf, len)
Rfile *f;
long off;
char *buf;
int len;
{
	unsigned char bbuf[BLKSIZ];
	int boff;
	long bno;
	int nread, r;
	int ncpy;
	int rlen;
	unsigned char *p;

	nread = 0;
	if (off == fsp(f)->tuoff) {
		bno = fsp(f)->tbno;
		boff = fsp(f)->tboff;
	} else if (off == 0) {
		bno = 0;
		boff = 0;
	} else {				/* wrong, but so what? */
		bno = off / BLKSIZ;
		boff = off % BLKSIZ;
	}
	if ((r = f11rblk(f, bno, bbuf)) <= 0)
		goto out;
	p = bbuf + boff;
	while (len > 0) {
		if (boff & 01) {
			p++;
			boff++;
		}
		if ((bno * BLKSIZ) + boff >= f->size)
			break;
		rlen = p[0] + (p[1]<<8);
		if (rlen == -1) {	/* skip to next block */
			if ((r = f11rblk(f, ++bno, bbuf)) <= 0)
				goto out;
			p = bbuf;
			boff = 0;
			continue;
		}
		if (rlen + 1 > len)	/* +1 for newline */
			/* set a particular error here? */
			break;
		p += 2;
		for (; rlen > 0; rlen -= ncpy) {
			ncpy = &bbuf[BLKSIZ] - p;
			if (ncpy > rlen)
				ncpy = rlen;
			memcpy(buf, p, ncpy);
			p += ncpy;
			boff = p - bbuf;
			nread += ncpy;
			buf += ncpy;
			len -= ncpy;
			if (ncpy < rlen) {	/* next block */
				if ((r = f11rblk(f, ++bno, bbuf)) <= 0)
					goto out;
				p = bbuf;
				boff = 0;
			}
		}
		*buf++ = '\n';
		nread++;
		len--;
		if (boff > BLKSIZ - 2) {	/* about to need new block */
			if ((r = f11rblk(f, ++bno, bbuf)) <= 0)
				goto out;
			p = bbuf;
			boff = 0;
		}
	}
out:
	if (boff == BLKSIZ) {
		boff = 0;
		bno++;
	}
	if (nread) {
		fsp(f)->tuoff = off + nread;
		fsp(f)->tbno = bno;
		fsp(f)->tboff = boff;
	}
	if (nread || r >= 0)
		return (nread);
	fserrno = RFEIO;
	return (-1);
}

/*
 * read directory --
 * return ascii records: decimal `i-number', tab, filename, NUL
 * filename is filname.typ.ver
 * *offp gets new file offset for directory
 */
#define	DENTSIZE	(6+9+4+6+1)	/* max len of a directory record */

int
fsdirread(f, off, buf, len, offp)
Rfile *f;
long off;
char *buf;
int len;
long *offp;
{
	char bbuf[BLKSIZ];
	register char *p;
	register struct directory *dp;
	struct directory *dend;
	char *op;
	int r;
	long bno;
	int boff;

	bno = off / BLKSIZ;
	if ((r = f11rblk(f, bno, bbuf)) <= 0) {
		fserrno = RFEIO;
		return (r);
	}
	boff = off % BLKSIZ;
	dp = (struct directory *)bbuf + (boff/sizeof(struct directory));
	dend = (struct directory *)&bbuf[BLKSIZ];
	p = buf;
	while (len >= DENTSIZE) {
		while (dp < dend && dp->d_fid.f_num == 0)
			dp++;
		if (dp >= dend) {
			bno++;
			dp = (struct directory *)bbuf;
			if ((r = f11rblk(f, bno, bbuf)) <= 0)
				break;
		}
		op = p;
		p = itoa(p, dp->d_fid.f_num);
		*p++ = '\t';
		p = r50toa(p, dp->d_fname.f_nam[0]);
		p = r50toa(p, dp->d_fname.f_nam[1]);
		p = r50toa(p, dp->d_fname.f_nam[2]);
		while (p[-1] == ' ')
			--p;
		*p++ = '.';
		p = r50toa(p, dp->d_fname.f_typ);
		while (p[-1] == ' ')
			--p;
		*p++ = '.';
		p = itoa(p, dp->d_fname.f_ver);
		*p++ = 0;
		len -= p - op;
		dp++;
	}
	if (p == buf && r < 0) {
		fserrno = RFEIO;
		return (-1);
	}
	*offp = (bno * BLKSIZ) + (char *)dp - bbuf;
	return (p - buf);
}

/*
 * f11 to rf file attributes
 * -- temporary permission hack:
 * turn apparent f11 other to asserted unix other group
 */
#define	F11OTHER (-1)

static
htorf(f, h)
register Rfile *f;
register struct header *h;
{
	f->ino = h->h_fnum;
	f->dev = 0;
	f->mode = htouperm(h->h_fpro);
	if (h->h_ident.i_fnam.f_typ != dirtyp)
		f->type = RFTREG;
	else {
		f->mode |= (f->mode & 0444)>>2;	/* copy `read' into `execute' */
		f->type = RFTDIR;
	}
	f->nlink = 1;
	f->uid = h->h_fown.u_prog;
	f->gid = h->h_fown.u_proj;
	if (f->gid == F11OTHER)
		f->gid = UXOTHER;
	f->rdev = 0;
	f->size = hfilesize(h);
	f->ta = 0;
	f->tm = htoutime(h->h_ident.i_rvdt);
	f->tc = htoutime(h->h_ident.i_crdt);	/* wrong, but let it stand */
	if (f->tm == 0)
		f->tm = f->tc;
}

/*
 * number to string
 */

static char digits[] = "0123456789";

static char *
itoa(s, n)
register char *s;
register unsigned int n;
{
	register int d;

	if ((d = n / 10) == 0)
		*s++ = digits[n];
	else {
		s = itoa(s, d);
		*s++ = digits[n % 10];
	}
	return (s);
}