forsyth20121205-174063a80cc13 years agoHistory
1073 lines · 19.0 KB · C
RawDownload
#include <lib9.h>#include <styx.h>#include "styxserver.h"#include "styxaux.h" #define MAXSTAT	512#define EMSGLEN			256		/* %r */ #define TABSZ	32	/* power of 2 */ static	unsigned long		boottime;static	char*	eve = "inferno";static	int		Debug = 0; char Enomem[] =		"out of memory";char Eperm[] =			"permission denied";char Enodev[] =		"no free devices";char Ehungup[] =		"write to hungup channel";char	Eexist[] =			"file exists";char Enonexist[] =		"file does not exist";char Ebadcmd[] =		"bad command";char Ebadarg[] =			"bad arg in system call";char Enofid[] =			"no such fid";char Enotdir[] =		"not a directory";char	Eopen[] =			"already open";char	Ebadfid[] =		"bad fid"; /* client state */enum{	CDISC = 01,	CNREAD = 02,	CRECV = 04,}; typedef struct Walkqid Walkqid; struct Fid{	Client 	*client;	Fid *next;	short	fid;	ushort	open;	ushort	mode;	/* read/write */	ulong	offset;	/* in file */	int		dri;		/* dirread index */	Qid		qid;}; struct Walkqid{	Fid	*clone;	int	nqid;	Qid	qid[1];}; #define ASSERT(A,B) styxassert((int)A,B) static int hash(Path);static void deletefids(Client *); static voidstyxfatal(char *fmt, ...){	char buf[1024], *out;	va_list arg;	out = seprint(buf, buf+sizeof(buf), "Fatal error: ");	va_start(arg, fmt);	out = vseprint(out, buf+sizeof(buf), fmt, arg);	va_end(arg);	write(2, buf, out-buf);	styxexit(1);} static voidstyxassert(int true, char *reason){	if(!true)		styxfatal("assertion failed: %s\n", reason);} void *styxmalloc(int bytes){	char *m = malloc(bytes);	if(m == nil)		styxfatal(Enomem);	memset(m, 0, bytes);	return m;} voidstyxfree(void *p){	free(p);} voidstyxdebug(){	Debug = 1;} static Client *newclient(Styxserver *server, int fd){	Client *c = (Client *)styxmalloc(sizeof(Client)); 	if(Debug)		fprint(2, "New client at %lux\n", (ulong)c);	c->server = server;	c->fd = fd;	c->nread = 0;	c->nc = 0;	c->state = 0;	c->fids = nil;	c->uname = strdup(eve);	c->aname = strdup("");	c->next = server->clients;	server->clients = c;	if(server->ops->newclient)		server->ops->newclient(c);	return c;} static voidfreeclient(Client *c){	Client **p;	Styxserver *server; 	if(Debug)		fprint(2, "Freeing client at %lux\n", (ulong)c);	server = c->server;	if(server->ops->freeclient)		server->ops->freeclient(c);	for(p = &server->clients; *p; p = &(*p)->next)		if(*p == c){			styxclosesocket(c->fd);			*p = c->next;			deletefids(c);			free(c->uname);			free(c->aname);			styxfree(c);			return;		}} static intnbread(Client *c, int nr){	int nb; 	if(c->state&CDISC)		return -1;	nb = styxrecv(c->server, c->fd, c->msg + c->nread, nr, 0);	if(nb <= 0){		c->nread = 0;		c->state |= CDISC;		return -1;	}	c->nread += nb;	return 0;} static intrd(Client *c, Fcall *r){	if(c->nc > 0){	/* last convM2S consumed nc bytes */		c->nread -= c->nc;		if((int)c->nread < 0){			r->ename = "negative size in rd";			return -1;		}		memmove(c->msg, c->msg+c->nc, c->nread);		c->nc = 0;	}	if(c->state&CRECV){		if(nbread(c, MSGMAX - c->nread) != 0){			r->ename = "unexpected EOF";			return -1;		}		c->state &= ~CRECV;	}	c->nc = convM2S((uchar*)(c->msg), c->nread, r);	if(c->nc < 0){		r->ename = "bad message format";		return -1;	}	if(c->nc == 0 && c->nread > 0){		c->nread = 0;		c->state &= ~CNREAD;		return 0;	}	if(c->nread > c->nc)		c->state |= CNREAD;	else		c->state &= ~CNREAD;	if(c->nc == 0)		return 0;	/* fprint(2, "rd: %F\n", r); */	return 1;} static intwr(Client *c, Fcall *r){	int n;	char buf[MSGMAX]; 	n = convS2M(r, (uchar*)buf, sizeof(buf));	if(n < 0){		r->ename = "bad message type in wr";		return -1;	}	/* fprint(2, "wr: %F\n", r); */	return styxsend(c->server, c->fd, buf, n, 0);} static voidsremove(Styxserver *server, Styxfile *f){	Styxfile *s, *next, **p; 	if(f == nil)		return;	if(Debug)		fprint(2, "Remove file %s Qid=%llx\n", f->d.name, f->d.qid.path);	if(f->d.qid.type&QTDIR)		for(s = f->child; s != nil; s = next){			next = s->sibling;			sremove(server, s);	}	for(p = &server->ftab[hash(f->d.qid.path)]; *p; p = &(*p)->next)		if(*p == f){			*p = f->next;			break;		}	for(p = &f->parent->child; *p; p = &(*p)->sibling)		if(*p == f){			*p = f->sibling;			break;		}	styxfree(f->d.name);	styxfree(f->d.uid);	styxfree(f->d.gid);	styxfree(f);} intstyxrmfile(Styxserver *server, Path qid){	Styxfile *f; 	f = styxfindfile(server, qid);	if(f != nil){		if(f->parent == nil)			return -1;		sremove(server, f);		return 0;	}	return -1;} static voidincref(Styxfile *f){	if(f != nil)		f->ref++;} static voiddecref(Styxfile *f){	if(f != nil)		--f->ref;} static voidincreff(Fid *f){	incref(styxfindfile(f->client->server, f->qid.path));} static voiddecreff(Fid *f){	decref(styxfindfile(f->client->server, f->qid.path));} static voidincopen(Fid *f){	Styxfile *file; 	if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil)		file->open++;} static voiddecopen(Fid *f){	Styxfile *file; 	if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil)		file->open--;} intstyxperm(Styxfile *f, char *uid, int mode){	int m, p; 	p = 0;	switch(mode&3){	case OREAD:	p = AREAD;	break;	case OWRITE:	p = AWRITE;	break;	case ORDWR:	p = AREAD+AWRITE;	break;	case OEXEC:	p = AEXEC;	break;	}	if(mode&OTRUNC)		p |= AWRITE;	m = f->d.mode&7;	if((p&m) == p)		return 1;	if(strcmp(f->d.uid, uid) == 0){		m |= (f->d.mode>>6)&7;		if((p&m) == p)			return 1;	}	if(strcmp(f->d.gid, uid) == 0){		m |= (f->d.mode>>3)&7;		if((p&m) == p)			return 1;	}	return 0;} static inthash(Path path){	return path&(TABSZ-1);} Styxfile *styxfindfile(Styxserver *server, Path path){	Styxfile *f; 	for(f = server->ftab[hash(path)]; f != nil; f = f->next){		if(f->d.qid.path == path)			return f;	}	return nil;} static Fid *findfid(Client *c, short fid){	Fid *f;	for(f = c->fids; f && f->fid != fid; f = f->next)		;	return f;} static voiddeletefid(Client *c, Fid *d){	/* TODO: end any outstanding reads on this fid */	Fid **f; 	for(f = &c->fids; *f; f = &(*f)->next)		if(*f == d){			decreff(d);			decopen(d);			*f = d->next;			styxfree(d);			return;		}} static voiddeletefids(Client *c){	Fid *f, *g; 	for(f = c->fids; f; f = g){		decreff(f);		decopen(f);		g = f->next;		styxfree(f);	}} Fid *newfid(Client *c, short fid, Qid qid){	Fid *f; 	f = styxmalloc(sizeof(Fid));	ASSERT(f, "newfid");	f->client = c;	f->fid = fid;	f->open = 0;	f->dri = 0;	f->qid = qid;	f->next = c->fids;	c->fids = f;	increff(f);	return f;} static voidflushtag(int oldtag){	USED(oldtag);} inteqqid(Qid a, Qid b){	return a.path == b.path && a.vers == b.vers;} static Fid *fidclone(Fid *old, short fid){	Fid *new; 	new = newfid(old->client, fid, old->qid);	return new;} static Walkqid*devwalk(Client *c, Styxfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err){	Styxserver *server;	long j;	Walkqid *wq;	char *n;	Styxfile *p, *f;	Styxops *ops;	Qid qid; 	*err = nil;	server = c->server;	ops = server->ops; 	wq = styxmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));	wq->nqid = 0; 	p = file;	qid = p != nil ? p->d.qid : fp->qid;	for(j = 0; j < nname; j++){		if(!(qid.type&QTDIR)){			if(j == 0)				styxfatal("devwalk error");			*err = Enotdir;			goto Done;		}		if(p != nil && !styxperm(p, c->uname, OEXEC)){			*err = Eperm;			goto Done;		}		n = name[j];		if(strcmp(n, ".") == 0){    Accept:			wq->qid[wq->nqid++] = nfp->qid;			continue;		}		if(p != nil && strcmp(n, "..") == 0 && p->parent){			decref(p);			nfp->qid.path = p->parent->d.qid.path;			nfp->qid.type = p->parent->d.qid.type;			nfp->qid.vers = 0;			incref(p->parent);			p = p->parent;			qid = p->d.qid;			goto Accept;		}				if(ops->walk != nil){			char *e; 			e = ops->walk(&qid, n);			if(e == nil){				decreff(nfp);				nfp->qid = qid;				increff(nfp);				p = styxfindfile(server, qid.path);				if(server->needfile && p == nil)					goto Done;				qid = p != nil ? p->d.qid : nfp->qid;				goto Accept;			}		} 		if(p != nil)		for(f = p->child; f != nil; f = f->sibling){			if(strcmp(n, f->d.name) == 0){				decref(p);				nfp->qid.path = f->d.qid.path;

Lines 1–500 of 1073.