1234 lines · 21.5 KB · C
RawDownload
#include <lib9.h>#include "ninep.h"#include "ninepserver.h"#include "ninepaux.h" #define MAXSTAT	512#define EMSGLEN			256		/* %r */ #define HASHSZ	32	/* power of 2 */ static	unsigned long	boottime;static	char*	eve = "eve";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"; enum{	CDISC = 01,	CNREAD = 02,	CRECV = 04,}; typedef struct Parent Parent;typedef struct Walkqid Walkqid; struct Fid{	Client 	*client;	Fid 		*next;	Parent	*parent;	short		fid;	ushort	open;	ushort	mode;	/* read/write */	ulong	offset;	/* in file */	int		dri;		/* dirread index */	Qid		qid;}; struct Parent{	Ninepfile	*file;	Parent	*parent;}; struct Walkqid{	Fid	*clone;	int	nqid;	Qid	qid[1];}; #define ASSERT(A,B) ninepassert((int)A,B) extern time_t time(time_t *t); static int hash(int);static void deletefids(Client*);static Pending* findpending(Client*, ushort); staticvoidninepfatal(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);	ninepexit(1);} staticvoidninepassert(int true, char *reason){	if(!true)		ninepfatal("assertion failed: %s\n", reason);} void *ninepmalloc(int bytes){	char *m = malloc(bytes);	if(m == nil)		ninepfatal(Enomem);	memset(m, 0, bytes);	return m;} voidninepfree(void *p){	free(p);} voidninepdebug(){	Debug = 1;} staticClient *newclient(Ninepserver *server, int fd){	Client *c = (Client *)ninepmalloc(sizeof(Client)); 	if(Debug)		fprint(2, "New client at fd %d\n", fd);	c->server = server;	c->fd = fd;	c->nread = 0;	c->nc = 0;	c->state = 0;	c->fids = nil;	c->pending = (Pending**)ninepmalloc(HASHSZ*sizeof(Pending*));	c->uname = strdup(eve);	c->aname = strdup("");	c->next = server->clients;	server->clients = c;	if(server->ops->newclient)		server->ops->newclient(c);	return c;} staticvoidfreeclient(Client *c){	Client **p;	Ninepserver *server; 	if(Debug)		fprint(2, "Freeing client at fd %d\n", c->fd);	server = c->server;	if(server->ops->freeclient)		server->ops->freeclient(c);	for(p = &server->clients; *p; p = &(*p)->next)		if(*p == c){			ninepclosesocket(c->fd);			*p = c->next;			deletefids(c);			free(c->uname);			free(c->aname);			ninepfree(c);			return;		}} staticintnbread(Client *c, int nr){	int nb; 	if(c->state&CDISC)		return -1;	nb = nineprecv(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;} staticintrd(Client *c, Fcall *f){	memset(c->data, 0, sizeof(c->data));	if(c->nc > 0){	/* last convM2S consumed nc bytes */		c->nread -= c->nc;		if((int)c->nread < 0){			f->ename = "negative size in rd";			return -1;		}		memmove(c->msg, c->msg+c->nc, c->nread);		c->nc = 0;		c->nc = convM2S((uchar*)(c->msg), c->nread, f);		if(c->nc > 0){			if(c->nread == c->nc)				c->state &= ~CRECV;			goto Newmsg;		}	}	if(c->state&CRECV){		if(nbread(c, MSGMAX - c->nread) != 0){			f->ename = "unexpected EOF";			return -1;		}		c->state &= ~CRECV;	}	c->nc = convM2S((uchar*)(c->msg), c->nread, f);Newmsg:	if(c->nc < 0){		f->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;} staticintwr(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 ninepsend(c->server, c->fd, buf, n, 0);} staticvoidsremove(Ninepserver *server, Ninepfile *f){	Ninepfile *s, *next, **p; 	if(f == nil)		return;	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;		}	ninepfree(f->d.name);	ninepfree(f->d.uid);	ninepfree(f->d.gid);	ninepfree(f);} intnineprmfile(Ninepserver *server, Path qid){	Ninepfile *f; 	f = ninepfindfile(server, qid);	if(f != nil){		if(f->parent == nil)			return -1;		sremove(server, f);		return 0;	}	return -1;} staticvoidincref(Ninepfile *f){	if(f != nil)		f->ref++;} staticvoiddecref(Ninepfile *f){	if(f != nil)		--f->ref;} staticvoidincreff(Fid *f){	incref(ninepfindfile(f->client->server, f->qid.path));} staticvoiddecreff(Fid *f){	decref(ninepfindfile(f->client->server, f->qid.path));} staticvoidincopen(Fid *f){	Ninepfile *file; 	if(f->open && (file = ninepfindfile(f->client->server, f->qid.path)) != nil)		file->open++;} staticvoiddecopen(Fid *f){	Ninepfile *file; 	if(f->open && (file = ninepfindfile(f->client->server, f->qid.path)) != nil)		file->open--;} intninepperm(Ninepfile *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;} staticinthash(int n){	return n&(HASHSZ-1);} Ninepfile *ninepfindfile(Ninepserver *server, Path path){	Ninepfile *f; 	for(f = server->ftab[hash(path)]; f != nil; f = f->next){		if(f->d.qid.path == path)			return f;	}	return nil;} staticFid *findfid(Client *c, short fid){	Fid *f;	for(f = c->fids; f && f->fid != fid; f = f->next)		;	return f;} staticvoiddeletefid(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;			ninepfree(d);			return;		}} staticvoiddeletefids(Client *c){	Fid *f, *g; 	for(f = c->fids; f; f = g){		decreff(f);		decopen(f);		g = f->next;		ninepfree(f);	}} Fid *newfid(Client *c, short fid, Qid qid){	Fid *f; 	f = ninepmalloc(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;} inteqqid(Qid a, Qid b){	return a.path == b.path && a.vers == b.vers;} staticFid *fidclone(Fid *old, short fid){	Fid *new; 	new = newfid(old->client, fid, old->qid);	return new;} staticNinepfile *nextfile(Ninepfile *f, int first){	static int n, cap;	static Ninepfile **nf; 	if(first)		n = 0;	if(f == nil && n > 0)		f = nf[--n];	if(f == nil || f->bind == nil)		return f;	if(n == cap){		cap = (cap == 0) ? 12 : cap * 3/2;		nf = realloc(nf, cap);	}	nf[n++] = f->sibling;	return nextfile(f->bind->child, 0);} staticWalkqid*devwalk(Client *c, Ninepfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err){	Ninepserver *server;	long j;	Walkqid *wq;	char *n;	Ninepfile *p, *f;	Ninepops *ops;	Parent *parent;	Qid qid; 	*err = nil;	server = c->server;	ops = server->ops; 	wq = ninepmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));

Lines 1–500 of 1234.