889 lines · 14.5 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include <String.h>#include <thread.h>#include "wiki.h" #include <auth.h>#include <fcall.h>#include <9p.h> enum {	Qindexhtml,	Qindextxt,	Qraw,	Qhistoryhtml,	Qhistorytxt,	Qdiffhtml,	Qedithtml,	Qwerrorhtml,	Qwerrortxt,	Qhttplogin,	Nfile,}; static char *filelist[] = {	"index.html",	"index.txt",	"current",	"history.html",	"history.txt",	"diff.html",	"edit.html",	"werror.html",	"werror.txt",	".httplogin",}; static int needhist[Nfile] = {[Qhistoryhtml] 1,[Qhistorytxt] 1,[Qdiffhtml] 1,}; /* * The qids are <8-bit type><16-bit page number><16-bit page version><8-bit file index>. */enum {		/* <8-bit type> */	Droot = 1,	D1st,	D2nd,	Fnew,	Fmap,	F1st,	F2nd,}; uvlongmkqid(int type, int num, int vers, int file){	return ((uvlong)type<<40) | ((uvlong)num<<24) | (vers<<8) | file;} intqidtype(uvlong path){	return (path>>40)&0xFF;} intqidnum(uvlong path){	return (path>>24)&0xFFFF;} intqidvers(uvlong path){	return (path>>8)&0xFFFF;} intqidfile(uvlong path){	return path&0xFF;} typedef struct Aux Aux;struct Aux {	String *name;	Whist *w;	int n;	ulong t;	String *s;	Map *map;}; static voidfsattach(Req *r){	Aux *a; 	if(r->ifcall.aname && r->ifcall.aname[0]){		respond(r, "invalid attach specifier");		return;	} 	a = emalloc(sizeof(Aux));	r->fid->aux = a;	a->name = s_copy(r->ifcall.uname); 	r->ofcall.qid = (Qid){mkqid(Droot, 0, 0, 0), 0, QTDIR};	r->fid->qid = r->ofcall.qid;	respond(r, nil);} static String *httplogin(void){	String *s=s_new();	Biobuf *b; 	if((b = wBopen(".httplogin", OREAD)) == nil)		goto Return; 	while(s_read(b, s, Bsize) > 0)		;	Bterm(b); Return:	return s;} static char*fswalk1(Fid *fid, char *name, Qid *qid){	char *q;	int i, isdotdot, n, t;	uvlong path;	Aux *a;	Whist *wh;	String *s; 	isdotdot = strcmp(name, "..")==0;	n = strtoul(name, &q, 10);	path = fid->qid.path;	a = fid->aux; 	switch(qidtype(path)){	case 0:		return "wikifs: bad path in server (bug)"; 	case Droot:		if(isdotdot){			*qid = fid->qid;			return nil;		}		if(strcmp(name, "new")==0){			*qid = (Qid){mkqid(Fnew, 0, 0, 0), 0, 0};			return nil;		}		if(strcmp(name, "map")==0){			*qid = (Qid){mkqid(Fmap, 0, 0, 0), 0, 0};			return nil;		}		if((*q!='\0' || (wh=getcurrent(n))==nil)		&& (wh=getcurrentbyname(name))==nil)			return "file does not exist";		*qid = (Qid){mkqid(D1st, wh->n, 0, 0), wh->doc->time, QTDIR};		a->w = wh;		return nil; 	case D1st:		if(isdotdot){			*qid = (Qid){mkqid(Droot, 0, 0, 0), 0, QTDIR};			return nil;		} 		/* handle history directories */		if(*q == '\0'){			if((wh = gethistory(qidnum(path))) == nil)				return "file does not exist";			for(i=0; i<wh->ndoc; i++)				if(wh->doc[i].time == n)					break;			if(i==wh->ndoc){				closewhist(wh);				return "file does not exist";			}			closewhist(a->w);			a->w = wh;			a->n = i;			*qid = (Qid){mkqid(D2nd, qidnum(path), i, 0), wh->doc[i].time, QTDIR};			return nil;		} 		/* handle files other than index */		for(i=0; i<nelem(filelist); i++){			if(strcmp(name, filelist[i])==0){				if(needhist[i]){					if((wh = gethistory(qidnum(path))) == nil)						return "file does not exist";					closewhist(a->w);					a->w = wh;				}				*qid = (Qid){mkqid(F1st, qidnum(path), 0, i), a->w->doc->time, 0};				goto Gotfile;			}		}		return "file does not exist"; 	case D2nd:		if(isdotdot){			/*			 * Can't use a->w[a->ndoc-1] because that			 * might be a failed write rather than the real one.			 */			*qid = (Qid){mkqid(D1st, qidnum(path), 0, 0), 0, QTDIR};			if((wh = getcurrent(qidnum(path))) == nil)				return "file does not exist";			closewhist(a->w);			a->w = wh;			a->n = 0;			return nil;		}		for(i=0; i<=Qraw; i++){			if(strcmp(name, filelist[i])==0){				*qid = (Qid){mkqid(F2nd, qidnum(path), qidvers(path), i), a->w->doc->time, 0};				goto Gotfile;			}		}		return "file does not exist"; 	default:		return "bad programming";	}	/* not reached */ Gotfile:	t = qidtype(qid->path);	switch(qidfile(qid->path)){	case Qindexhtml:		s = tohtml(a->w, a->w->doc+a->n,			t==F1st? Tpage : Toldpage);		break;	case Qindextxt:		s = totext(a->w, a->w->doc+a->n,			t==F1st? Tpage : Toldpage);		break;	case Qraw:		s = s_copy(a->w->title);		s = s_append(s, "\n");		s = doctext(s, &a->w->doc[a->n]);		break;	case Qhistoryhtml:		s = tohtml(a->w, a->w->doc+a->n, Thistory);		break;	case Qhistorytxt:		s = totext(a->w, a->w->doc+a->n, Thistory);		break;	case Qdiffhtml:		s = tohtml(a->w, a->w->doc+a->n, Tdiff);		break;	case Qedithtml:		s = tohtml(a->w, a->w->doc+a->n, Tedit);		break;	case Qwerrorhtml:		s = tohtml(a->w, a->w->doc+a->n, Twerror);		break;	case Qwerrortxt:		s = totext(a->w, a->w->doc+a->n, Twerror);		break;	case Qhttplogin:		s = httplogin();		break;	default:		return "internal error";	}	a->s = s;	return nil;} static voidfsopen(Req *r){	int t;	uvlong path;	Aux *a;	Fid *fid;	Whist *wh; 	fid = r->fid;	path = fid->qid.path;	t = qidtype(fid->qid.path);	if((r->ifcall.mode != OREAD && t != Fnew && t != Fmap)	|| (r->ifcall.mode&ORCLOSE)){		respond(r, "permission denied");		return;	} 	a = fid->aux;	switch(t){	case Droot:		currentmap(0);		rlock(&maplock);		a->map = map;		incref(map);		runlock(&maplock);		respond(r, nil);		break;			case D1st:		if((wh = gethistory(qidnum(path))) == nil){			respond(r, "file does not exist");			return;		}		closewhist(a->w);		a->w = wh;		a->n = a->w->ndoc-1;		r->ofcall.qid.vers = wh->doc[a->n].time;		r->fid->qid = r->ofcall.qid;		respond(r, nil);		break;			case D2nd:		respond(r, nil);		break; 	case Fnew:		a->s = s_copy("");		respond(r, nil);		break; 	case Fmap:	case F1st:	case F2nd:		respond(r, nil);		break; 	default:		respond(r, "programmer error");		break;	}} static char*fsclone(Fid *old, Fid *new){	Aux *a; 	a = emalloc(sizeof(*a));	*a = *(Aux*)old->aux;	if(a->s)		s_incref(a->s);	if(a->w)		incref(a->w);	if(a->map)		incref(a->map);	if(a->name)		s_incref(a->name);	new->aux = a;	new->qid = old->qid; 	return nil;} static voidfsdestroyfid(Fid *fid){	Aux *a; 	a = fid->aux;	if(a==nil)		return; 	if(a->name)		s_free(a->name);	if(a->map)		closemap(a->map);	if(a->s)		s_free(a->s);	if(a->w)		closewhist(a->w);	free(a);	fid->aux = nil;} static voidfillstat(Dir *d, uvlong path, ulong tm, ulong length){	char tmp[32], *p;	int type; 	memset(d, 0, sizeof(Dir));	d->uid = estrdup9p("wiki");	d->gid = estrdup9p("wiki"); 	switch(qidtype(path)){	case Droot:	case D1st:	case D2nd:		type = QTDIR;		break;	default:		type = 0;		break;	}	d->qid = (Qid){path, tm, type}; 	d->atime = d->mtime = tm;	d->length = length;	if(qidfile(path) == Qedithtml)		d->atime = d->mtime = time(0); 	switch(qidtype(path)){	case Droot:		d->name = estrdup("/");		d->mode = DMDIR|0555;		break; 	case D1st:		d->name = numtoname(qidnum(path));		if(d->name == nil)			d->name = estrdup("<dead>");		for(p=d->name; *p; p++)			if(*p==' ')				*p = '_';		d->mode = DMDIR|0555;		break; 	case D2nd:		snprint(tmp, sizeof tmp, "%lud", tm);		d->name = estrdup(tmp);		d->mode = DMDIR|0555;		break; 	case Fmap:		d->name = estrdup("map");		d->mode = 0666;		break; 	case Fnew:		d->name = estrdup("new");		d->mode = 0666;		break; 	case F1st:		d->name = estrdup(filelist[qidfile(path)]);		d->mode = 0444;		break; 	case F2nd:		d->name = estrdup(filelist[qidfile(path)]);		d->mode = 0444;		break; 	default:		print("bad qid path 0x%.8llux\n", path);		break;	}} static voidfsstat(Req *r){	Aux *a;	Fid *fid;	ulong t; 	t = 0;	fid = r->fid;	if((a = fid->aux) && a->w)		t = a->w->doc[a->n].time; 	fillstat(&r->d, fid->qid.path, t, a->s ? s_len(a->s) : 0);	respond(r, nil);} typedef struct Bogus Bogus;struct Bogus {	uvlong path;	Aux *a;}; static introotgen(int i, Dir *d, void *aux){	Aux *a;	Bogus *b; 	b = aux;

Lines 1–500 of 889.