Charles.Forsyth20070319-1153 devsrvf9c975b19 years agoHistory
725 lines · 10.8 KB · C
RawDownload
#include	"dat.h"#include	"fns.h"#include	"error.h"#include	"interp.h"#include	<isa.h>#include	"runt.h" typedef struct SrvFile SrvFile;struct SrvFile{	char*	spec;	char*	name;	char*	user;	ulong		perm;	vlong	length;	Qid		qid;	int		ref;	int		opens;	int		flags;	Channel*	read;	Channel*	write;	SrvFile*	entry;	SrvFile*	dir;	SrvFile*	devlist;}; enum{	SORCLOSE	= (1<<0),	SRDCLOSE	= (1<<1),	SWRCLOSE	= (1<<2),	SREMOVED	= (1<<3),}; typedef struct SrvDev SrvDev;struct SrvDev{	Type*	Rread;	Type*	Rwrite;	QLock	l;	ulong	pathgen;	SrvFile*	devices;}; static SrvDev dev; void	freechan(Heap*, int);static void	freerdchan(Heap*, int);static void	freewrchan(Heap*, int); Type	*Trdchan;Type	*Twrchan; static intsrvgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp){	SrvFile *f; 	USED(name);	USED(tab);	USED(ntab); 	if(s == DEVDOTDOT){		devdir(c, c->qid, "#s", 0, eve, 0555, dp);		return 1;	}	f = c->aux;	if((c->qid.type & QTDIR) == 0){		if(s > 0)			return -1;		devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp);		return 1;	} 	for(f = f->entry; f != nil; f = f->entry){		if(s-- == 0)			break;	}	if(f == nil)		return -1; 	devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp);	return 1;} static voidsrvinit(void){	static uchar rmap[] = Sys_Rread_map;	static uchar wmap[] = Sys_Rwrite_map; 	Trdchan = dtype(freerdchan, sizeof(Channel), Tchannel.map, Tchannel.np);	Twrchan = dtype(freewrchan, sizeof(Channel), Tchannel.map, Tchannel.np); 	dev.pathgen = 1;	dev.Rread = dtype(freeheap, Sys_Rread_size, rmap, sizeof(rmap));	dev.Rwrite = dtype(freeheap, Sys_Rwrite_size, wmap, sizeof(wmap));} static intsrvchkattach(SrvFile *d){	if(strcmp(d->user, up->env->user) == 0)		return 1; 	/*	 * Need write permission in other to allow attaches if	 * we are not the owner	 */	if(d->perm & 2)		return 1; 	return 0;} static Chan*srvattach(char *spec){	Chan *c;	SrvFile *d; 	if(spec[0] != '\0'){		qlock(&dev.l);		for(d = dev.devices; d != nil; d = d->devlist){			if(strcmp(spec, d->spec) == 0){				if(srvchkattach(d) == 0){					qunlock(&dev.l);					error(Eperm);				}				d->ref++;				break;			}		}		qunlock(&dev.l); 		if(d != nil){			c = devattach('s', spec);			c->aux = d;			c->qid = d->qid;			return c;		}	} 	d = malloc(sizeof(SrvFile));	if(d == nil)		error(Enomem); 	c = devattach('s', spec); 	d->ref = 1;	kstrdup(&d->spec, spec);	kstrdup(&d->user, up->env->user);	snprint(up->genbuf, sizeof(up->genbuf), "srv%ld", up->env->pgrp->pgrpid);	kstrdup(&d->name, up->genbuf);	d->perm = DMDIR|0770; 	qlock(&dev.l);	mkqid(&d->qid, dev.pathgen++, 0, QTDIR);	d->devlist = dev.devices;	dev.devices = d;	qunlock(&dev.l); 	c->aux = d;	c->qid = d->qid; 	return c;} static Walkqid*srvwalk(Chan *c, Chan *nc, char **name, int nname){	SrvFile *d, *pd;	Walkqid *w; 	pd = c->aux;	qlock(&dev.l);	if(waserror()){		qunlock(&dev.l);		nexterror();	} 	w = devwalk(c, nc, name, nname, nil, 0, srvgen);	if(w != nil && w->clone != nil){		if(nname != 0){			for(d = pd->entry; d != nil; d = d->entry)				if(d->qid.path == w->clone->qid.path)					break;			if(d == nil)				panic("srvwalk");			if(w->clone == c)				pd->ref--;		}else			d = pd;		w->clone->aux = d;		d->ref++;	}	poperror();	qunlock(&dev.l);	return w;} static intsrvstat(Chan *c, uchar *db, int n){	qlock(&dev.l);	if(waserror()){		qunlock(&dev.l);		nexterror();	}	n = devstat(c, db, n, 0, 0, srvgen);	poperror();	qunlock(&dev.l);	return n;} static Chan*srvopen(Chan *c, int omode){	SrvFile *sf; 	openmode(omode);	/* check it */	if(c->qid.type & QTDIR){		if(omode != OREAD)			error(Eisdir);		c->mode = omode;		c->flag |= COPEN;		c->offset = 0;		return c;	} 	sf = c->aux; 	qlock(&dev.l);	if(waserror()){		qunlock(&dev.l);		nexterror();	}	devpermcheck(sf->user, sf->perm, omode);	if(omode&ORCLOSE && strcmp(sf->user, up->env->user) != 0)		error(Eperm);	if(sf->perm & DMEXCL && sf->opens != 0)		error(Einuse);	sf->opens++;	if(omode&ORCLOSE)		sf->flags |= SORCLOSE;	poperror();	qunlock(&dev.l); 	c->offset = 0;	c->flag |= COPEN;	c->mode = openmode(omode); 	return c;} static intsrvwstat(Chan *c, uchar *dp, int n){	Dir *d;	SrvFile *sf, *f; 	sf = c->aux;	if(strcmp(up->env->user, sf->user) != 0)		error(Eperm); 	d = smalloc(sizeof(*d)+n);	if(waserror()){		free(d);		nexterror();	}	n = convM2D(dp, n, d, (char*)&d[1]);	if(n == 0)		error(Eshortstat);	if(!emptystr(d->name)){		if(sf->dir == nil)			error(Eperm);		validwstatname(d->name);		qlock(&dev.l);		for(f = sf->dir; f != nil; f = f->entry)			if(strcmp(f->name, d->name) == 0){				qunlock(&dev.l);				error(Eexist);			}		kstrdup(&sf->name, d->name);		qunlock(&dev.l);	}	if(d->mode != ~0UL)		sf->perm = d->mode & (DMEXCL|DMAPPEND|0777);	if(d->length != (vlong)-1)		sf->length = d->length;	poperror();	free(d);	return n;} static voidsrvputdir(SrvFile *sf){	SrvFile **l, *d; 	sf->ref--;	if(sf->ref != 0)		return; 	for(l = &dev.devices; (d = *l) != nil; l = &d->devlist)		if(d == sf){			*l = d->devlist;			break;		}	free(sf->spec);	free(sf->user);	free(sf->name);	free(sf);} static voidsrvunblock(SrvFile *sf, int fid){	Channel *d;	Sys_FileIO_read rreq;	Sys_FileIO_write wreq; 	acquire();	if(waserror()){		release();		nexterror();	}	d = sf->read;	if(d != H){		rreq.t0 = 0;		rreq.t1 = 0;		rreq.t2 = fid;		rreq.t3 = H;		csendalt(d, &rreq, d->mid.t, -1);	} 	d = sf->write;	if(d != H){		wreq.t0 = 0;		wreq.t1 = H;		wreq.t2 = fid;		wreq.t3 = H;		csendalt(d, &wreq, d->mid.t, -1);	}	poperror();	release();} static voidsrvdecr(SrvFile *sf, int remove){	SrvFile *f, **l; 	if(remove){		l = &sf->dir->entry;		for(f = *l; f != nil; f = f->entry){			if(sf == f){				*l = f->entry;				break;			}			l = &f->entry;		}		sf->ref--;		sf->flags |= SREMOVED;	} 	if(sf->ref != 0)		return; 	if(sf->dir != nil)		srvputdir(sf->dir); 	free(sf->spec);	free(sf->user);	free(sf->name);	free(sf);} static voidsrvfree(SrvFile *sf, int flag){	sf->flags |= flag;	if((sf->flags & (SRDCLOSE | SWRCLOSE)) == (SRDCLOSE | SWRCLOSE)){		sf->ref--;		srvdecr(sf, (sf->flags & SREMOVED) == 0);	}} static voidfreerdchan(Heap *h, int swept){	SrvFile *sf; 	release();	qlock(&dev.l);	sf = H2D(Channel*, h)->aux;	sf->read = H;	srvfree(sf, SRDCLOSE);	qunlock(&dev.l);	acquire();	freechan(h, swept);} static voidfreewrchan(Heap *h, int swept){	SrvFile *sf; 	release();	qlock(&dev.l);	sf = H2D(Channel*, h)->aux;	sf->write = H;	srvfree(sf, SWRCLOSE);	qunlock(&dev.l);	acquire();	freechan(h, swept);} static voidsrvclunk(Chan *c, int remove){	int opens, noperm;	SrvFile *sf; 	sf = c->aux;	qlock(&dev.l);	if(c->qid.type & QTDIR){		srvputdir(sf);		qunlock(&dev.l);		if(remove)			error(Eperm);		return;	} 	opens = 0;	if(c->flag & COPEN){		opens = sf->opens--;		if (sf->read != H || sf->write != H)			srvunblock(sf, c->fid);	} 	sf->ref--;	if(opens == 1){		if((sf->flags & (SORCLOSE | SREMOVED)) == SORCLOSE)			remove = 1;	} 	noperm = 0;	if(remove && strcmp(sf->dir->user, up->env->user) != 0){		noperm = 1;		remove = 0;	} 	srvdecr(sf, remove);	qunlock(&dev.l); 	if(noperm)		error(Eperm);} static voidsrvclose(Chan *c){	srvclunk(c, 0);} static voidsrvremove(Chan *c){	srvclunk(c, 1);} static longsrvread(Chan *c, void *va, long count, vlong offset){	int l;	Heap * volatile h;	Array *a;	SrvFile *sp;	Channel *rc;	Channel *rd;	Sys_Rread * volatile r;	Sys_FileIO_read req; 	if(c->qid.type & QTDIR){		qlock(&dev.l);		if(waserror()){			qunlock(&dev.l);			nexterror();		}		l = devdirread(c, va, count, 0, 0, srvgen);		poperror();		qunlock(&dev.l);		return l;	} 	sp = c->aux; 	acquire();	if(waserror()){

Lines 1–500 of 725.