698 lines · 14.3 KB · C
RawDownload
#include <time.h>#include <lib9.h>#include <draw.h>#include <cursor.h>#include "dat.h"#include "fns.h"#include "fsys.h" #include <ixp.h>#define bool inttypedef union IxpFileIdU IxpFileIdU;union IxpFileIdU {	Client*	client;	Window*	window;	void*	ref;};#include <ixp_srvutil.h> /* Error messages */const char	*Ebadarg = "bad arg in system call",	*Edeleted = "window deleted",	*Einterrupted = "interrupted",	*Einuse = "file in use",	*Enodev = "no free devices",	*Enofile = "file not found",	*Enodrawimage = "unknown id for draw image",	*Enomem = "out of memory",	*Enoperm = "permission denied",	*Eshortread =	"draw read too short",	*Eshortwrite =	"draw write too short"; /* Macros */#define debug9p(...) if(1) debug(__VA_ARGS__)#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF)) /* Global Vars */ /* ad-hoc file tree. Empty names ("") indicate dynamic entries to be filled * in by lookup_file */static IxpDirtab	/* name		qtype	type			perm */dirtab_root[] = {	{".",			QTDIR,	FsRoot,		0500|DMDIR },	{"draw",		QTDIR,	FsDDraw,		0500|DMDIR },	{"wsys",		QTDIR,	FsDWsys,		0500|DMDIR },	{"keyboard",	QTFILE,	FsFCons,		0600 },	{"cons",		QTFILE,	FsFCons,		0600 },	{"consctl",		QTFILE,	FsFConsctl,	0200 },	{"cursor",		QTFILE,	FsFCursor,	0600 },	{"pointer",		QTFILE,	FsFMouse,	0600 },	{"mouse",		QTFILE,	FsFMouse,	0600 },	{"snarf",		QTFILE,	FsFSnarf,		0600 },	{"kill",		QTFILE,	FsFKill,		0400 },	{"label",		QTFILE,	FsFLabel,		0600 },	{"wctl",		QTFILE,	FsFWctl,		0600 },	{"winid",		QTFILE,	FsFWinid,		0400 },	{"winname",	QTFILE,	FsFWinname,	0400 },	{nil}},dirtab_draw[] = {	{".",			QTDIR,	FsDDraw,		0500|DMDIR },	{"",			QTDIR,	FsDDrawn,	0500|DMDIR },	{"new",		QTFILE,	FsFNew,		0600 },	{nil}},dirtab_drawn[] = {	{".",			QTDIR,	FsDDrawn,	0500|DMDIR },	{"ctl",		QTFILE,	FsFCtl,		0600 },	{"data",		QTFILE,	FsFData,		0600 },	{"colormap",	QTFILE,	FsFColormap,	0400 },	{"refresh",		QTFILE,	FsFRefresh,	0400 },	{nil}},dirtab_wsys[] = {	{".",			QTDIR,	FsDWsys,		0500|DMDIR },	{"",			QTDIR,	FsDWsysn,	0500|DMDIR },	{nil}},dirtab_wsysn[] = {	{".",			QTDIR,	FsDWsysn,	0500|DMDIR },	{"wsys",		QTDIR,	FsDWsys,		0500|DMDIR },	{"keyboard",	QTFILE,	FsFCons,		0600 },	{"cons",		QTFILE,	FsFCons,		0600 },	{"consctl",		QTFILE,	FsFConsctl,	0200 },	{"cursor",		QTFILE,	FsFCursor,	0600 },	{"pointer",		QTFILE,	FsFMouse,	0600 },	{"mouse",		QTFILE,	FsFMouse,	0600 },	{"snarf",		QTFILE,	FsFSnarf,		0600 },	{"kill",		QTFILE,	FsFKill,		0400 },	{"label",		QTFILE,	FsFLabel,		0600 },	{"wctl",		QTFILE,	FsFWctl,		0600 },	{"winid",		QTFILE,	FsFWinid,		0400 },	{"winname",	QTFILE,	FsFWinname,	0400 },	{nil}}; static IxpDirtab* dirtab[] = {	[FsRoot] = dirtab_root,	[FsDDraw] = dirtab_draw,	[FsDDrawn] = dirtab_drawn,	[FsDWsys] = dirtab_wsys,	[FsDWsysn] = dirtab_wsysn,}; typedef char* (*MsgFunc)(void*, IxpMsg*);typedef char* (*BufFunc)(void*); static char *snarfbuf; static voiddostat(IxpStat *s, IxpFileId *f) {	s->type = 0;	s->dev = 0;	s->qid.path = QID(f->tab.type, f->id);	s->qid.version = 0;	s->qid.type = f->tab.qtype;	s->mode = f->tab.perm;	s->mtime = time(nil);	s->atime = s->mtime;	s->length = 0;	s->name = f->tab.name;	s->uid = s->gid = s->muid = "";} /* * All lookups and directory organization should be performed through * lookup_file, mostly through the dirtab[] tree. */static IxpFileId*lookup_file(IxpFileId *parent, char *name){	int i, id, clientid;	IxpFileId *ret, *file, **last;	IxpDirtab *dir;	Client *cl;	Window *w; 	if(!(parent->tab.perm & DMDIR))		return nil;	dir = dirtab[parent->tab.type];	last = &ret;	ret = nil;	for(; dir->name; dir++) {#               define push_file(nam, id_, vol) \			file = ixp_srv_getfile(); \			file->id = id_; \			file->volatil = vol; \			*last = file; \			last = &file->next; \			file->tab = *dir; \			file->tab.name = nam; \			assert(file->tab.name);		/* Dynamic dirs */		if(dir->name[0] == '\0') {			switch(parent->tab.type) {			case FsDDraw:				id = 0;				if(name) {					id = (int)strtol(name, &name, 10);					if(*name)						continue;				}				for(i = 0; i < nclient; i++) {					if(!(cl = client[i]))						continue;					clientid = drawclientid(cl);					if(!name || clientid == id) {						push_file(smprint("%d", clientid), clientid, 1);						file->p.client = cl;						file->index = id;						if(name)							goto LastItem;					}				}				break;			case FsDWsys:				id = 0;				if(name) {					id = (int)strtol(name, &name, 10);					if(*name)						continue;				}				for(i = 0; i < nwindow; i++) {					w = window[i];					if(!name || w->id == id) {						push_file(smprint("%d", w->id), w->id, 1);						file->p.window = w;						file->index = id;						if(name)							goto LastItem;					}				}				break;			}		}else /* Static dirs */		if(!name || name && !strcmp(name, dir->name)) {			push_file(strdup(file->tab.name), 0, 0);			file->p.ref = parent->p.ref;			file->index = parent->index;			if(name)				goto LastItem;		}#		undef push_file	}LastItem:	*last = nil;	return ret;} /* Service Functions */voidfs_attach(Ixp9Req *r) {	char *label;	IxpFileId *f;	Window *w; 	debug9p("fs_attach(%p)\n", r); 	f = ixp_srv_getfile();	f->tab = dirtab[FsRoot][0];	f->tab.name = strdup("/");	if(!f->tab.name)		ixp_respond(r, Enomem);	f->nref = 0;	r->fid->aux = f;	r->fid->qid.type = f->tab.qtype;	r->fid->qid.path = QID(f->tab.type, 0);	r->ofcall.rattach.qid = r->fid->qid;	label = nil; /* pjw face */	if(!(w = newwin(label)) || !drawattach(w, r->ifcall.tattach.aname)) {		if(w){			assert(w == window[nwindow-1]);			free(w);			nwindow--;		}		ixp_respond(r, Enomem);		return;	}	f->p.window = w;	ixp_respond(r, nil);} voidfs_open(Ixp9Req *r) {	const char *err;	IxpFileId *f;	Window *w;	Client *cl; 	debug9p("fs_open(%p)\n", r); 	f = r->fid->aux;	if(!ixp_srv_verifyfile(f, lookup_file)) {		ixp_respond(r, Enofile);		return;	}	w = f->p.window;	if(iswindow(f->tab.type)) {		if(w->deleted) {			ixp_respond(r, Edeleted);			return;		}		if(f->tab.type == FsFNew){			cl = drawnewclient(w->draw);			if(cl == 0) {				ixp_respond(r, Enodev);				return;			}			f->p.client = cl;			f->tab.type = FsFCtl;		}	}	if(!iswindow(f->tab.type)){		cl = f->p.client;		err = drawopen(cl, f->tab.type);		if(err != nil){			ixp_respond(r, err);			return;		}	}	w = f->p.window;	switch(f->tab.type) {	case FsFNew:		break;	case FsFMouse:		if(w->mouse.open){			ixp_respond(r, Einuse);			return;		}		w->mouse.open = 1;		break;	case FsFSnarf:		if((r->ifcall.topen.mode&3) == ORDWR){			/* one at a time please */			ixp_respond(r, Enoperm);			return;		}		break;	} 	if((r->ifcall.topen.mode&3) == OEXEC	|| (r->ifcall.topen.mode&3) != OREAD && !(f->tab.perm & 0200)	|| (r->ifcall.topen.mode&3) != OWRITE && !(f->tab.perm & 0400)	|| (r->ifcall.topen.mode & ~(3|OTRUNC)))		ixp_respond(r, Enoperm);	else		ixp_respond(r, nil);} voidfs_walk(Ixp9Req *r) { 	debug9p("fs_walk(%p)\n", r); 	ixp_srv_walkandclone(r, lookup_file);} voidfs_read(Ixp9Req *r) {	char buf[512], *s;	IxpFileId *f;	Client *cl;	Window *w;	IOResponse rread; 	debug9p("fs_read(%p)\n", r); 	f = r->fid->aux;	if(!ixp_srv_verifyfile(f, lookup_file)) {		ixp_respond(r, Enofile);		return;	}	if(!f->tab.perm & 0400) {		ixp_respond(r, Enoperm);		return;	}	if(f->tab.perm & DMDIR) {		ixp_srv_readdir(r, lookup_file, dostat);		return;	}	cl = f->p.client;	w = f->p.window;	if(!iswindow(f->tab.type))		w = drawwindow(cl);	if(w->deleted && f->tab.type != FsFKill){		ixp_respond(r, Edeleted);		return;	}	if(!iswindow(f->tab.type)) {		rread = drawread(cl, f->tab.type, buf, r->ifcall.io.count);		if(rread.err != nil){			ixp_respond(r, rread.err);			return;		}		if(f->tab.type == FsFRefresh && rread.count == 0)			return;		if(f->tab.type == FsFCtl || f->tab.type == FsFData || f->tab.type == FsFRefresh)			ixp_srv_readbuf(r, rread.data, rread.count);		if(f->tab.type == FsFData)			drawread(cl, FsFData, nil, -1); /* clear cl->readdata */		ixp_respond(r, nil);		return;	}	switch(f->tab.type) {	case FsFCons:		readkbd(w, r);		return;	case FsFKill:		w->killr = r;		if(w->deleted){			sprint(buf, "%d", w->pid);			ixp_srv_readbuf(r, buf, strlen(buf));			ixp_respond(r, nil);		}		return;	case FsFLabel:		if(w->label)			ixp_srv_readbuf(r, w->label, strlen(w->label));		ixp_respond(r, nil);		return;	case FsFMouse:		readmouse(w, r);		return;	case FsFSnarf:		s= xgetsnarf(w);		ixp_srv_readbuf(r, s, strlen(s));		ixp_respond(r, nil);		return;	case FsFWctl:		// XXX TODO: current		s = w-> visible ? "visible" : "hidden";		sprint(buf, "%11d %11d %11d %11d %s %s ", w->orig.x +  w->screenr.min.x, w->orig.y + w->screenr.min.y, w->screenr.max.x, w->screenr.max.y, s, "current");		ixp_srv_readbuf(r, buf, strlen(buf));		ixp_respond(r, nil);		return;	case FsFWinid:		sprint(buf, "%11d ", w->id);		ixp_srv_readbuf(r, buf, strlen(buf));		ixp_respond(r, nil);		return;	case FsFWinname:		ixp_srv_readbuf(r, w->name, strlen(w->name));		ixp_respond(r, nil);		return;	}	/* This should not be called if the file is not open for reading. */	fatal("Read called on an unreadable file");} voidfs_stat(Ixp9Req *r) {	IxpMsg m;	IxpStat s;	int size;	char *buf;	IxpFileId *f;	Window *w;	Client *cl; 	debug9p("fs_stat(%p)\n", r); 	f = r->fid->aux;	if(!ixp_srv_verifyfile(f, lookup_file)) {		ixp_respond(r, Enofile);		return;	}	cl = f->p.client;	w = f->p.window;	if(!iswindow(f->tab.type))		w = drawwindow(cl);	if(w->deleted){		ixp_respond(r, Edeleted);		return;	} 	dostat(&s, f);	size = ixp_sizeof_stat(&s);	r->ofcall.rstat.nstat = size;	buf = malloc(size);	if(!buf)		ixp_respond(r, Enomem); 	m = ixp_message(buf, size, MsgPack);	ixp_pstat(&m, &s); 	r->ofcall.rstat.stat = (uchar*)m.data;	ixp_respond(r, nil);} voidfs_write(Ixp9Req *r) {	char *label, *p;	char err[256];	IxpFileId *f;	Window *w;	Client *cl;	IOResponse rwrite;	Point pt; 	debug9p("fs_write(%p)\n", r); 	f = r->fid->aux;	if(!ixp_srv_verifyfile(f, lookup_file)) {		ixp_respond(r, Enofile);		return;	}	if(!f->tab.perm & 0200) {		ixp_respond(r, Enoperm);		return;	}	cl = f->p.client;	w = f->p.window;	if(!iswindow(f->tab.type))		w = drawwindow(cl);	if(w->deleted){		ixp_respond(r, Edeleted);		return;	} 	if(!iswindow(f->tab.type)) {		if(f->tab.type == FsFRefresh)			return;		rwrite = drawwrite(cl, f->tab.type, r->ifcall.twrite.data, r->ifcall.io.count);		r->ofcall.rwrite.count = rwrite.count;		if(rwrite.err != nil){			ixp_respond(r, rwrite.err);			return;		}		ixp_respond(r, nil);		return;	}	switch(f->tab.type) {	case FsFCursor:		r->ofcall.io.count = r->ifcall.io.count;		if(cursorwrite(w, r->ifcall.twrite.data, r->ofcall.rwrite.count) < 0){			r->ofcall.rwrite.count = 0;			ixp_respond(r, "error"); // XXX TODO			return;

Lines 1–500 of 698.