xref: /plan9/sys/src/cmd/wikifs/fs.c (revision 1052a86abe4783012df9e7959032cbd3f59e6d9c)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <String.h>
59a747e4fSDavid du Colombier #include <thread.h>
69a747e4fSDavid du Colombier #include "wiki.h"
79a747e4fSDavid du Colombier 
89a747e4fSDavid du Colombier #include <auth.h>
99a747e4fSDavid du Colombier #include <fcall.h>
109a747e4fSDavid du Colombier #include <9p.h>
119a747e4fSDavid du Colombier 
129a747e4fSDavid du Colombier enum {
139a747e4fSDavid du Colombier 	Qindexhtml,
149a747e4fSDavid du Colombier 	Qindextxt,
159a747e4fSDavid du Colombier 	Qraw,
169a747e4fSDavid du Colombier 	Qhistoryhtml,
179a747e4fSDavid du Colombier 	Qhistorytxt,
189a747e4fSDavid du Colombier 	Qdiffhtml,
199a747e4fSDavid du Colombier 	Qedithtml,
209a747e4fSDavid du Colombier 	Qwerrorhtml,
219a747e4fSDavid du Colombier 	Qwerrortxt,
22b7327ca2SDavid du Colombier 	Qhttplogin,
239a747e4fSDavid du Colombier 	Nfile,
249a747e4fSDavid du Colombier };
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier static char *filelist[] = {
279a747e4fSDavid du Colombier 	"index.html",
289a747e4fSDavid du Colombier 	"index.txt",
299a747e4fSDavid du Colombier 	"current",
309a747e4fSDavid du Colombier 	"history.html",
319a747e4fSDavid du Colombier 	"history.txt",
329a747e4fSDavid du Colombier 	"diff.html",
339a747e4fSDavid du Colombier 	"edit.html",
349a747e4fSDavid du Colombier 	"werror.html",
359a747e4fSDavid du Colombier 	"werror.txt",
36b7327ca2SDavid du Colombier 	".httplogin",
379a747e4fSDavid du Colombier };
389a747e4fSDavid du Colombier 
399a747e4fSDavid du Colombier static int needhist[Nfile] = {
409a747e4fSDavid du Colombier [Qhistoryhtml] 1,
419a747e4fSDavid du Colombier [Qhistorytxt] 1,
429a747e4fSDavid du Colombier [Qdiffhtml] 1,
439a747e4fSDavid du Colombier };
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier /*
469a747e4fSDavid du Colombier  * The qids are <8-bit type><16-bit page number><16-bit page version><8-bit file index>.
479a747e4fSDavid du Colombier  */
489a747e4fSDavid du Colombier enum {		/* <8-bit type> */
499a747e4fSDavid du Colombier 	Droot = 1,
509a747e4fSDavid du Colombier 	D1st,
519a747e4fSDavid du Colombier 	D2nd,
529a747e4fSDavid du Colombier 	Fnew,
539a747e4fSDavid du Colombier 	Fmap,
549a747e4fSDavid du Colombier 	F1st,
559a747e4fSDavid du Colombier 	F2nd,
569a747e4fSDavid du Colombier };
579a747e4fSDavid du Colombier 
589a747e4fSDavid du Colombier uvlong
mkqid(int type,int num,int vers,int file)599a747e4fSDavid du Colombier mkqid(int type, int num, int vers, int file)
609a747e4fSDavid du Colombier {
619a747e4fSDavid du Colombier 	return ((uvlong)type<<40) | ((uvlong)num<<24) | (vers<<8) | file;
629a747e4fSDavid du Colombier }
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier int
qidtype(uvlong path)659a747e4fSDavid du Colombier qidtype(uvlong path)
669a747e4fSDavid du Colombier {
679a747e4fSDavid du Colombier 	return (path>>40)&0xFF;
689a747e4fSDavid du Colombier }
699a747e4fSDavid du Colombier 
709a747e4fSDavid du Colombier int
qidnum(uvlong path)719a747e4fSDavid du Colombier qidnum(uvlong path)
729a747e4fSDavid du Colombier {
739a747e4fSDavid du Colombier 	return (path>>24)&0xFFFF;
749a747e4fSDavid du Colombier }
759a747e4fSDavid du Colombier 
769a747e4fSDavid du Colombier int
qidvers(uvlong path)779a747e4fSDavid du Colombier qidvers(uvlong path)
789a747e4fSDavid du Colombier {
799a747e4fSDavid du Colombier 	return (path>>8)&0xFFFF;
809a747e4fSDavid du Colombier }
819a747e4fSDavid du Colombier 
829a747e4fSDavid du Colombier int
qidfile(uvlong path)839a747e4fSDavid du Colombier qidfile(uvlong path)
849a747e4fSDavid du Colombier {
859a747e4fSDavid du Colombier 	return path&0xFF;
869a747e4fSDavid du Colombier }
879a747e4fSDavid du Colombier 
889a747e4fSDavid du Colombier typedef struct Aux Aux;
899a747e4fSDavid du Colombier struct Aux {
90af2e6ba6SDavid du Colombier 	String *name;
919a747e4fSDavid du Colombier 	Whist *w;
929a747e4fSDavid du Colombier 	int n;
939a747e4fSDavid du Colombier 	ulong t;
949a747e4fSDavid du Colombier 	String *s;
959a747e4fSDavid du Colombier 	Map *map;
969a747e4fSDavid du Colombier };
979a747e4fSDavid du Colombier 
989a747e4fSDavid du Colombier static void
fsattach(Req * r)999a747e4fSDavid du Colombier fsattach(Req *r)
1009a747e4fSDavid du Colombier {
1019a747e4fSDavid du Colombier 	Aux *a;
1029a747e4fSDavid du Colombier 
1039a747e4fSDavid du Colombier 	if(r->ifcall.aname && r->ifcall.aname[0]){
1049a747e4fSDavid du Colombier 		respond(r, "invalid attach specifier");
1059a747e4fSDavid du Colombier 		return;
1069a747e4fSDavid du Colombier 	}
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier 	a = emalloc(sizeof(Aux));
1099a747e4fSDavid du Colombier 	r->fid->aux = a;
110af2e6ba6SDavid du Colombier 	a->name = s_copy(r->ifcall.uname);
1119a747e4fSDavid du Colombier 
112690670dcSDavid du Colombier 	r->ofcall.qid = (Qid){mkqid(Droot, 0, 0, 0), 0, QTDIR};
1139a747e4fSDavid du Colombier 	r->fid->qid = r->ofcall.qid;
1149a747e4fSDavid du Colombier 	respond(r, nil);
1159a747e4fSDavid du Colombier }
1169a747e4fSDavid du Colombier 
117b7327ca2SDavid du Colombier static String *
httplogin(void)118b7327ca2SDavid du Colombier httplogin(void)
119b7327ca2SDavid du Colombier {
120b7327ca2SDavid du Colombier 	String *s=s_new();
121b7327ca2SDavid du Colombier 	Biobuf *b;
122b7327ca2SDavid du Colombier 
123b7327ca2SDavid du Colombier 	if((b = wBopen(".httplogin", OREAD)) == nil)
124b7327ca2SDavid du Colombier 		goto Return;
125b7327ca2SDavid du Colombier 
126b7327ca2SDavid du Colombier 	while(s_read(b, s, Bsize) > 0)
127b7327ca2SDavid du Colombier 		;
128b7327ca2SDavid du Colombier 	Bterm(b);
129b7327ca2SDavid du Colombier 
130b7327ca2SDavid du Colombier Return:
131b7327ca2SDavid du Colombier 	return s;
132b7327ca2SDavid du Colombier }
133b7327ca2SDavid du Colombier 
1349a747e4fSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)1359a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
1369a747e4fSDavid du Colombier {
1379a747e4fSDavid du Colombier 	char *q;
1389a747e4fSDavid du Colombier 	int i, isdotdot, n, t;
1399a747e4fSDavid du Colombier 	uvlong path;
1409a747e4fSDavid du Colombier 	Aux *a;
1419a747e4fSDavid du Colombier 	Whist *wh;
1429a747e4fSDavid du Colombier 	String *s;
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 	isdotdot = strcmp(name, "..")==0;
1459a747e4fSDavid du Colombier 	n = strtoul(name, &q, 10);
1469a747e4fSDavid du Colombier 	path = fid->qid.path;
1479a747e4fSDavid du Colombier 	a = fid->aux;
1489a747e4fSDavid du Colombier 
1499a747e4fSDavid du Colombier 	switch(qidtype(path)){
1509a747e4fSDavid du Colombier 	case 0:
1519a747e4fSDavid du Colombier 		return "wikifs: bad path in server (bug)";
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	case Droot:
1549a747e4fSDavid du Colombier 		if(isdotdot){
1559a747e4fSDavid du Colombier 			*qid = fid->qid;
1569a747e4fSDavid du Colombier 			return nil;
1579a747e4fSDavid du Colombier 		}
1589a747e4fSDavid du Colombier 		if(strcmp(name, "new")==0){
1599a747e4fSDavid du Colombier 			*qid = (Qid){mkqid(Fnew, 0, 0, 0), 0, 0};
1609a747e4fSDavid du Colombier 			return nil;
1619a747e4fSDavid du Colombier 		}
1629a747e4fSDavid du Colombier 		if(strcmp(name, "map")==0){
1639a747e4fSDavid du Colombier 			*qid = (Qid){mkqid(Fmap, 0, 0, 0), 0, 0};
1649a747e4fSDavid du Colombier 			return nil;
1659a747e4fSDavid du Colombier 		}
1669a747e4fSDavid du Colombier 		if((*q!='\0' || (wh=getcurrent(n))==nil)
1679a747e4fSDavid du Colombier 		&& (wh=getcurrentbyname(name))==nil)
1689a747e4fSDavid du Colombier 			return "file does not exist";
1699a747e4fSDavid du Colombier 		*qid = (Qid){mkqid(D1st, wh->n, 0, 0), wh->doc->time, QTDIR};
1709a747e4fSDavid du Colombier 		a->w = wh;
1719a747e4fSDavid du Colombier 		return nil;
1729a747e4fSDavid du Colombier 
1739a747e4fSDavid du Colombier 	case D1st:
1749a747e4fSDavid du Colombier 		if(isdotdot){
1759a747e4fSDavid du Colombier 			*qid = (Qid){mkqid(Droot, 0, 0, 0), 0, QTDIR};
1769a747e4fSDavid du Colombier 			return nil;
1779a747e4fSDavid du Colombier 		}
1789a747e4fSDavid du Colombier 
1799a747e4fSDavid du Colombier 		/* handle history directories */
1809a747e4fSDavid du Colombier 		if(*q == '\0'){
1819a747e4fSDavid du Colombier 			if((wh = gethistory(qidnum(path))) == nil)
1829a747e4fSDavid du Colombier 				return "file does not exist";
1839a747e4fSDavid du Colombier 			for(i=0; i<wh->ndoc; i++)
1849a747e4fSDavid du Colombier 				if(wh->doc[i].time == n)
1859a747e4fSDavid du Colombier 					break;
1869a747e4fSDavid du Colombier 			if(i==wh->ndoc){
1879a747e4fSDavid du Colombier 				closewhist(wh);
1889a747e4fSDavid du Colombier 				return "file does not exist";
1899a747e4fSDavid du Colombier 			}
1909a747e4fSDavid du Colombier 			closewhist(a->w);
1919a747e4fSDavid du Colombier 			a->w = wh;
1929a747e4fSDavid du Colombier 			a->n = i;
1939a747e4fSDavid du Colombier 			*qid = (Qid){mkqid(D2nd, qidnum(path), i, 0), wh->doc[i].time, QTDIR};
1949a747e4fSDavid du Colombier 			return nil;
1959a747e4fSDavid du Colombier 		}
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier 		/* handle files other than index */
1989a747e4fSDavid du Colombier 		for(i=0; i<nelem(filelist); i++){
1999a747e4fSDavid du Colombier 			if(strcmp(name, filelist[i])==0){
2009a747e4fSDavid du Colombier 				if(needhist[i]){
2019a747e4fSDavid du Colombier 					if((wh = gethistory(qidnum(path))) == nil)
2029a747e4fSDavid du Colombier 						return "file does not exist";
2039a747e4fSDavid du Colombier 					closewhist(a->w);
2049a747e4fSDavid du Colombier 					a->w = wh;
2059a747e4fSDavid du Colombier 				}
2069a747e4fSDavid du Colombier 				*qid = (Qid){mkqid(F1st, qidnum(path), 0, i), a->w->doc->time, 0};
2079a747e4fSDavid du Colombier 				goto Gotfile;
2089a747e4fSDavid du Colombier 			}
2099a747e4fSDavid du Colombier 		}
2109a747e4fSDavid du Colombier 		return "file does not exist";
2119a747e4fSDavid du Colombier 
2129a747e4fSDavid du Colombier 	case D2nd:
2139a747e4fSDavid du Colombier 		if(isdotdot){
2149a747e4fSDavid du Colombier 			/*
2159a747e4fSDavid du Colombier 			 * Can't use a->w[a->ndoc-1] because that
2169a747e4fSDavid du Colombier 			 * might be a failed write rather than the real one.
2179a747e4fSDavid du Colombier 			 */
2189a747e4fSDavid du Colombier 			*qid = (Qid){mkqid(D1st, qidnum(path), 0, 0), 0, QTDIR};
2199a747e4fSDavid du Colombier 			if((wh = getcurrent(qidnum(path))) == nil)
2209a747e4fSDavid du Colombier 				return "file does not exist";
2219a747e4fSDavid du Colombier 			closewhist(a->w);
2229a747e4fSDavid du Colombier 			a->w = wh;
2239a747e4fSDavid du Colombier 			a->n = 0;
2249a747e4fSDavid du Colombier 			return nil;
2259a747e4fSDavid du Colombier 		}
2269a747e4fSDavid du Colombier 		for(i=0; i<=Qraw; i++){
2279a747e4fSDavid du Colombier 			if(strcmp(name, filelist[i])==0){
2289a747e4fSDavid du Colombier 				*qid = (Qid){mkqid(F2nd, qidnum(path), qidvers(path), i), a->w->doc->time, 0};
2299a747e4fSDavid du Colombier 				goto Gotfile;
2309a747e4fSDavid du Colombier 			}
2319a747e4fSDavid du Colombier 		}
2329a747e4fSDavid du Colombier 		return "file does not exist";
2339a747e4fSDavid du Colombier 
2349a747e4fSDavid du Colombier 	default:
2359a747e4fSDavid du Colombier 		return "bad programming";
2369a747e4fSDavid du Colombier 	}
237b85a8364SDavid du Colombier 	/* not reached */
2389a747e4fSDavid du Colombier 
2399a747e4fSDavid du Colombier Gotfile:
2409a747e4fSDavid du Colombier 	t = qidtype(qid->path);
2419a747e4fSDavid du Colombier 	switch(qidfile(qid->path)){
2429a747e4fSDavid du Colombier 	case Qindexhtml:
2439a747e4fSDavid du Colombier 		s = tohtml(a->w, a->w->doc+a->n,
2449a747e4fSDavid du Colombier 			t==F1st? Tpage : Toldpage);
2459a747e4fSDavid du Colombier 		break;
2469a747e4fSDavid du Colombier 	case Qindextxt:
2479a747e4fSDavid du Colombier 		s = totext(a->w, a->w->doc+a->n,
2489a747e4fSDavid du Colombier 			t==F1st? Tpage : Toldpage);
2499a747e4fSDavid du Colombier 		break;
2509a747e4fSDavid du Colombier 	case Qraw:
2519a747e4fSDavid du Colombier 		s = s_copy(a->w->title);
2529a747e4fSDavid du Colombier 		s = s_append(s, "\n");
2539a747e4fSDavid du Colombier 		s = doctext(s, &a->w->doc[a->n]);
2549a747e4fSDavid du Colombier 		break;
2559a747e4fSDavid du Colombier 	case Qhistoryhtml:
2569a747e4fSDavid du Colombier 		s = tohtml(a->w, a->w->doc+a->n, Thistory);
2579a747e4fSDavid du Colombier 		break;
2589a747e4fSDavid du Colombier 	case Qhistorytxt:
2599a747e4fSDavid du Colombier 		s = totext(a->w, a->w->doc+a->n, Thistory);
2609a747e4fSDavid du Colombier 		break;
2619a747e4fSDavid du Colombier 	case Qdiffhtml:
2629a747e4fSDavid du Colombier 		s = tohtml(a->w, a->w->doc+a->n, Tdiff);
2639a747e4fSDavid du Colombier 		break;
2649a747e4fSDavid du Colombier 	case Qedithtml:
2659a747e4fSDavid du Colombier 		s = tohtml(a->w, a->w->doc+a->n, Tedit);
2669a747e4fSDavid du Colombier 		break;
2679a747e4fSDavid du Colombier 	case Qwerrorhtml:
2689a747e4fSDavid du Colombier 		s = tohtml(a->w, a->w->doc+a->n, Twerror);
2699a747e4fSDavid du Colombier 		break;
2709a747e4fSDavid du Colombier 	case Qwerrortxt:
2719a747e4fSDavid du Colombier 		s = totext(a->w, a->w->doc+a->n, Twerror);
2729a747e4fSDavid du Colombier 		break;
273b7327ca2SDavid du Colombier 	case Qhttplogin:
274b7327ca2SDavid du Colombier 		s = httplogin();
275b7327ca2SDavid du Colombier 		break;
2769a747e4fSDavid du Colombier 	default:
2779a747e4fSDavid du Colombier 		return "internal error";
2789a747e4fSDavid du Colombier 	}
2799a747e4fSDavid du Colombier 	a->s = s;
2809a747e4fSDavid du Colombier 	return nil;
2819a747e4fSDavid du Colombier }
2829a747e4fSDavid du Colombier 
2839a747e4fSDavid du Colombier static void
fsopen(Req * r)2849a747e4fSDavid du Colombier fsopen(Req *r)
2859a747e4fSDavid du Colombier {
2869a747e4fSDavid du Colombier 	int t;
2879a747e4fSDavid du Colombier 	uvlong path;
2889a747e4fSDavid du Colombier 	Aux *a;
2899a747e4fSDavid du Colombier 	Fid *fid;
2909a747e4fSDavid du Colombier 	Whist *wh;
2919a747e4fSDavid du Colombier 
2929a747e4fSDavid du Colombier 	fid = r->fid;
2939a747e4fSDavid du Colombier 	path = fid->qid.path;
2949a747e4fSDavid du Colombier 	t = qidtype(fid->qid.path);
2959a747e4fSDavid du Colombier 	if((r->ifcall.mode != OREAD && t != Fnew && t != Fmap)
2969a747e4fSDavid du Colombier 	|| (r->ifcall.mode&ORCLOSE)){
2979a747e4fSDavid du Colombier 		respond(r, "permission denied");
2989a747e4fSDavid du Colombier 		return;
2999a747e4fSDavid du Colombier 	}
3009a747e4fSDavid du Colombier 
3019a747e4fSDavid du Colombier 	a = fid->aux;
3029a747e4fSDavid du Colombier 	switch(t){
3039a747e4fSDavid du Colombier 	case Droot:
3049a747e4fSDavid du Colombier 		currentmap(0);
3059a747e4fSDavid du Colombier 		rlock(&maplock);
3069a747e4fSDavid du Colombier 		a->map = map;
3079a747e4fSDavid du Colombier 		incref(map);
3089a747e4fSDavid du Colombier 		runlock(&maplock);
3099a747e4fSDavid du Colombier 		respond(r, nil);
3109a747e4fSDavid du Colombier 		break;
3119a747e4fSDavid du Colombier 
3129a747e4fSDavid du Colombier 	case D1st:
3139a747e4fSDavid du Colombier 		if((wh = gethistory(qidnum(path))) == nil){
3149a747e4fSDavid du Colombier 			respond(r, "file does not exist");
3159a747e4fSDavid du Colombier 			return;
3169a747e4fSDavid du Colombier 		}
3179a747e4fSDavid du Colombier 		closewhist(a->w);
3189a747e4fSDavid du Colombier 		a->w = wh;
3199a747e4fSDavid du Colombier 		a->n = a->w->ndoc-1;
3209a747e4fSDavid du Colombier 		r->ofcall.qid.vers = wh->doc[a->n].time;
3219a747e4fSDavid du Colombier 		r->fid->qid = r->ofcall.qid;
3229a747e4fSDavid du Colombier 		respond(r, nil);
3239a747e4fSDavid du Colombier 		break;
3249a747e4fSDavid du Colombier 
3259a747e4fSDavid du Colombier 	case D2nd:
3269a747e4fSDavid du Colombier 		respond(r, nil);
3279a747e4fSDavid du Colombier 		break;
3289a747e4fSDavid du Colombier 
3299a747e4fSDavid du Colombier 	case Fnew:
3309a747e4fSDavid du Colombier 		a->s = s_copy("");
3319a747e4fSDavid du Colombier 		respond(r, nil);
3329a747e4fSDavid du Colombier 		break;
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier 	case Fmap:
3359a747e4fSDavid du Colombier 	case F1st:
3369a747e4fSDavid du Colombier 	case F2nd:
3379a747e4fSDavid du Colombier 		respond(r, nil);
3389a747e4fSDavid du Colombier 		break;
3399a747e4fSDavid du Colombier 
3409a747e4fSDavid du Colombier 	default:
3419a747e4fSDavid du Colombier 		respond(r, "programmer error");
3429a747e4fSDavid du Colombier 		break;
3439a747e4fSDavid du Colombier 	}
3449a747e4fSDavid du Colombier }
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier static char*
fsclone(Fid * old,Fid * new)3479a747e4fSDavid du Colombier fsclone(Fid *old, Fid *new)
3489a747e4fSDavid du Colombier {
3499a747e4fSDavid du Colombier 	Aux *a;
3509a747e4fSDavid du Colombier 
3519a747e4fSDavid du Colombier 	a = emalloc(sizeof(*a));
3529a747e4fSDavid du Colombier 	*a = *(Aux*)old->aux;
3539a747e4fSDavid du Colombier 	if(a->s)
3549a747e4fSDavid du Colombier 		s_incref(a->s);
3559a747e4fSDavid du Colombier 	if(a->w)
3569a747e4fSDavid du Colombier 		incref(a->w);
3579a747e4fSDavid du Colombier 	if(a->map)
3589a747e4fSDavid du Colombier 		incref(a->map);
359af2e6ba6SDavid du Colombier 	if(a->name)
360af2e6ba6SDavid du Colombier 		s_incref(a->name);
3619a747e4fSDavid du Colombier 	new->aux = a;
3629a747e4fSDavid du Colombier 	new->qid = old->qid;
3639a747e4fSDavid du Colombier 
3649a747e4fSDavid du Colombier 	return nil;
3659a747e4fSDavid du Colombier }
3669a747e4fSDavid du Colombier 
3679a747e4fSDavid du Colombier static void
fsdestroyfid(Fid * fid)3689a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
3699a747e4fSDavid du Colombier {
3709a747e4fSDavid du Colombier 	Aux *a;
3719a747e4fSDavid du Colombier 
3729a747e4fSDavid du Colombier 	a = fid->aux;
3739a747e4fSDavid du Colombier 	if(a==nil)
3749a747e4fSDavid du Colombier 		return;
3759a747e4fSDavid du Colombier 
376af2e6ba6SDavid du Colombier 	if(a->name)
377af2e6ba6SDavid du Colombier 		s_free(a->name);
3789a747e4fSDavid du Colombier 	if(a->map)
3799a747e4fSDavid du Colombier 		closemap(a->map);
3809a747e4fSDavid du Colombier 	if(a->s)
3819a747e4fSDavid du Colombier 		s_free(a->s);
3829a747e4fSDavid du Colombier 	if(a->w)
3839a747e4fSDavid du Colombier 		closewhist(a->w);
3849a747e4fSDavid du Colombier 	free(a);
3859a747e4fSDavid du Colombier 	fid->aux = nil;
3869a747e4fSDavid du Colombier }
3879a747e4fSDavid du Colombier 
3889a747e4fSDavid du Colombier static void
fillstat(Dir * d,uvlong path,ulong tm,ulong length)3899a747e4fSDavid du Colombier fillstat(Dir *d, uvlong path, ulong tm, ulong length)
3909a747e4fSDavid du Colombier {
3919a747e4fSDavid du Colombier 	char tmp[32], *p;
3929a747e4fSDavid du Colombier 	int type;
3939a747e4fSDavid du Colombier 
3949a747e4fSDavid du Colombier 	memset(d, 0, sizeof(Dir));
3959a747e4fSDavid du Colombier 	d->uid = estrdup9p("wiki");
3969a747e4fSDavid du Colombier 	d->gid = estrdup9p("wiki");
3979a747e4fSDavid du Colombier 
3989a747e4fSDavid du Colombier 	switch(qidtype(path)){
3999a747e4fSDavid du Colombier 	case Droot:
4009a747e4fSDavid du Colombier 	case D1st:
4019a747e4fSDavid du Colombier 	case D2nd:
4029a747e4fSDavid du Colombier 		type = QTDIR;
4039a747e4fSDavid du Colombier 		break;
4049a747e4fSDavid du Colombier 	default:
4059a747e4fSDavid du Colombier 		type = 0;
4069a747e4fSDavid du Colombier 		break;
4079a747e4fSDavid du Colombier 	}
4089a747e4fSDavid du Colombier 	d->qid = (Qid){path, tm, type};
4099a747e4fSDavid du Colombier 
4109a747e4fSDavid du Colombier 	d->atime = d->mtime = tm;
4119a747e4fSDavid du Colombier 	d->length = length;
4129a747e4fSDavid du Colombier 	if(qidfile(path) == Qedithtml)
4139a747e4fSDavid du Colombier 		d->atime = d->mtime = time(0);
4149a747e4fSDavid du Colombier 
4159a747e4fSDavid du Colombier 	switch(qidtype(path)){
4169a747e4fSDavid du Colombier 	case Droot:
4179a747e4fSDavid du Colombier 		d->name = estrdup("/");
4189a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
4199a747e4fSDavid du Colombier 		break;
4209a747e4fSDavid du Colombier 
4219a747e4fSDavid du Colombier 	case D1st:
4229a747e4fSDavid du Colombier 		d->name = numtoname(qidnum(path));
4239a747e4fSDavid du Colombier 		if(d->name == nil)
4249a747e4fSDavid du Colombier 			d->name = estrdup("<dead>");
4259a747e4fSDavid du Colombier 		for(p=d->name; *p; p++)
4269a747e4fSDavid du Colombier 			if(*p==' ')
4279a747e4fSDavid du Colombier 				*p = '_';
4289a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
4299a747e4fSDavid du Colombier 		break;
4309a747e4fSDavid du Colombier 
4319a747e4fSDavid du Colombier 	case D2nd:
4329a747e4fSDavid du Colombier 		snprint(tmp, sizeof tmp, "%lud", tm);
4339a747e4fSDavid du Colombier 		d->name = estrdup(tmp);
4349a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
4359a747e4fSDavid du Colombier 		break;
4369a747e4fSDavid du Colombier 
4379a747e4fSDavid du Colombier 	case Fmap:
4389a747e4fSDavid du Colombier 		d->name = estrdup("map");
4399a747e4fSDavid du Colombier 		d->mode = 0666;
4409a747e4fSDavid du Colombier 		break;
4419a747e4fSDavid du Colombier 
4429a747e4fSDavid du Colombier 	case Fnew:
4439a747e4fSDavid du Colombier 		d->name = estrdup("new");
4449a747e4fSDavid du Colombier 		d->mode = 0666;
4459a747e4fSDavid du Colombier 		break;
4469a747e4fSDavid du Colombier 
4479a747e4fSDavid du Colombier 	case F1st:
4489a747e4fSDavid du Colombier 		d->name = estrdup(filelist[qidfile(path)]);
4499a747e4fSDavid du Colombier 		d->mode = 0444;
4509a747e4fSDavid du Colombier 		break;
4519a747e4fSDavid du Colombier 
4529a747e4fSDavid du Colombier 	case F2nd:
4539a747e4fSDavid du Colombier 		d->name = estrdup(filelist[qidfile(path)]);
4549a747e4fSDavid du Colombier 		d->mode = 0444;
4559a747e4fSDavid du Colombier 		break;
4569a747e4fSDavid du Colombier 
4579a747e4fSDavid du Colombier 	default:
4589a747e4fSDavid du Colombier 		print("bad qid path 0x%.8llux\n", path);
4599a747e4fSDavid du Colombier 		break;
4609a747e4fSDavid du Colombier 	}
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier static void
fsstat(Req * r)4649a747e4fSDavid du Colombier fsstat(Req *r)
4659a747e4fSDavid du Colombier {
4669a747e4fSDavid du Colombier 	Aux *a;
4679a747e4fSDavid du Colombier 	Fid *fid;
4689a747e4fSDavid du Colombier 	ulong t;
4699a747e4fSDavid du Colombier 
4709a747e4fSDavid du Colombier 	t = 0;
4719a747e4fSDavid du Colombier 	fid = r->fid;
4729a747e4fSDavid du Colombier 	if((a = fid->aux) && a->w)
4739a747e4fSDavid du Colombier 		t = a->w->doc[a->n].time;
4749a747e4fSDavid du Colombier 
4759a747e4fSDavid du Colombier 	fillstat(&r->d, fid->qid.path, t, a->s ? s_len(a->s) : 0);
4769a747e4fSDavid du Colombier 	respond(r, nil);
4779a747e4fSDavid du Colombier }
4789a747e4fSDavid du Colombier 
4799a747e4fSDavid du Colombier typedef struct Bogus Bogus;
4809a747e4fSDavid du Colombier struct Bogus {
4819a747e4fSDavid du Colombier 	uvlong path;
4829a747e4fSDavid du Colombier 	Aux *a;
4839a747e4fSDavid du Colombier };
4849a747e4fSDavid du Colombier 
4859a747e4fSDavid du Colombier static int
rootgen(int i,Dir * d,void * aux)4869a747e4fSDavid du Colombier rootgen(int i, Dir *d, void *aux)
4879a747e4fSDavid du Colombier {
4889a747e4fSDavid du Colombier 	Aux *a;
4899a747e4fSDavid du Colombier 	Bogus *b;
4909a747e4fSDavid du Colombier 
4919a747e4fSDavid du Colombier 	b = aux;
4929a747e4fSDavid du Colombier 	a = b->a;
4939a747e4fSDavid du Colombier 	switch(i){
4949a747e4fSDavid du Colombier 	case 0:	/* new */
4959a747e4fSDavid du Colombier 		fillstat(d, mkqid(Fnew, 0, 0, 0), a->map->t, 0);
4969a747e4fSDavid du Colombier 		return 0;
4979a747e4fSDavid du Colombier 	case 1:	/* map */
4989a747e4fSDavid du Colombier 		fillstat(d, mkqid(Fmap, 0, 0, 0), a->map->t, 0);
4999a747e4fSDavid du Colombier 		return 0;
5009a747e4fSDavid du Colombier 	default:	/* first-level directory */
5019a747e4fSDavid du Colombier 		i -= 2;
5029a747e4fSDavid du Colombier 		if(i >= a->map->nel)
5039a747e4fSDavid du Colombier 			return -1;
5049a747e4fSDavid du Colombier 		fillstat(d, mkqid(D1st, a->map->el[i].n, 0, 0), a->map->t, 0);
5059a747e4fSDavid du Colombier 		return 0;
5069a747e4fSDavid du Colombier 	}
5079a747e4fSDavid du Colombier }
5089a747e4fSDavid du Colombier 
5099a747e4fSDavid du Colombier static int
firstgen(int i,Dir * d,void * aux)5109a747e4fSDavid du Colombier firstgen(int i, Dir *d, void *aux)
5119a747e4fSDavid du Colombier {
5129a747e4fSDavid du Colombier 	ulong t;
5139a747e4fSDavid du Colombier 	Bogus *b;
5149a747e4fSDavid du Colombier 	int num;
5159a747e4fSDavid du Colombier 	Aux *a;
5169a747e4fSDavid du Colombier 
5179a747e4fSDavid du Colombier 	b = aux;
5189a747e4fSDavid du Colombier 	num = qidnum(b->path);
5199a747e4fSDavid du Colombier 	a = b->a;
5209a747e4fSDavid du Colombier 	t = a->w->doc[a->n].time;
5219a747e4fSDavid du Colombier 
5229a747e4fSDavid du Colombier 	if(i < Nfile){	/* file in first-level directory */
5239a747e4fSDavid du Colombier 		fillstat(d, mkqid(F1st, num, 0, i), t, 0);
5249a747e4fSDavid du Colombier 		return 0;
5259a747e4fSDavid du Colombier 	}
5269a747e4fSDavid du Colombier 	i -= Nfile;
5279a747e4fSDavid du Colombier 
5289a747e4fSDavid du Colombier 	if(i < a->w->ndoc){	/* second-level (history) directory */
5299a747e4fSDavid du Colombier 		fillstat(d, mkqid(D2nd, num, i, 0), a->w->doc[i].time, 0);
5309a747e4fSDavid du Colombier 		return 0;
5319a747e4fSDavid du Colombier 	}
5329a747e4fSDavid du Colombier 	//i -= a->w->ndoc;
5339a747e4fSDavid du Colombier 
5349a747e4fSDavid du Colombier 	return -1;
5359a747e4fSDavid du Colombier }
5369a747e4fSDavid du Colombier 
5379a747e4fSDavid du Colombier static int
secondgen(int i,Dir * d,void * aux)5389a747e4fSDavid du Colombier secondgen(int i, Dir *d, void *aux)
5399a747e4fSDavid du Colombier {
5409a747e4fSDavid du Colombier 	Bogus *b;
5419a747e4fSDavid du Colombier 	uvlong path;
5429a747e4fSDavid du Colombier 	Aux *a;
5439a747e4fSDavid du Colombier 
5449a747e4fSDavid du Colombier 	b = aux;
5459a747e4fSDavid du Colombier 	path = b->path;
5469a747e4fSDavid du Colombier 	a = b->a;
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier 	if(i <= Qraw){	/* index.html, index.txt, raw */
5499a747e4fSDavid du Colombier 		fillstat(d, mkqid(F2nd, qidnum(path), qidvers(path), i), a->w->doc[a->n].time, 0);
5509a747e4fSDavid du Colombier 		return 0;
5519a747e4fSDavid du Colombier 	}
5529a747e4fSDavid du Colombier 	//i -= Qraw;
5539a747e4fSDavid du Colombier 
5549a747e4fSDavid du Colombier 	return -1;
5559a747e4fSDavid du Colombier }
5569a747e4fSDavid du Colombier 
5579a747e4fSDavid du Colombier static void
fsread(Req * r)5589a747e4fSDavid du Colombier fsread(Req *r)
5599a747e4fSDavid du Colombier {
5609a747e4fSDavid du Colombier 	char *t, *s;
5619a747e4fSDavid du Colombier 	uvlong path;
5629a747e4fSDavid du Colombier 	Aux *a;
5639a747e4fSDavid du Colombier 	Bogus b;
5649a747e4fSDavid du Colombier 
5659a747e4fSDavid du Colombier 	a = r->fid->aux;
5669a747e4fSDavid du Colombier 	path = r->fid->qid.path;
5679a747e4fSDavid du Colombier 	b.a = a;
5689a747e4fSDavid du Colombier 	b.path = path;
5699a747e4fSDavid du Colombier 	switch(qidtype(path)){
5709a747e4fSDavid du Colombier 	default:
5719a747e4fSDavid du Colombier 		respond(r, "cannot happen (bad qid)");
5729a747e4fSDavid du Colombier 		return;
5739a747e4fSDavid du Colombier 
5749a747e4fSDavid du Colombier 	case Droot:
5759a747e4fSDavid du Colombier 		if(a == nil || a->map == nil){
5769a747e4fSDavid du Colombier 			respond(r, "cannot happen (no map)");
5779a747e4fSDavid du Colombier 			return;
5789a747e4fSDavid du Colombier 		}
5799a747e4fSDavid du Colombier 		dirread9p(r, rootgen, &b);
5809a747e4fSDavid du Colombier 		respond(r, nil);
5819a747e4fSDavid du Colombier 		return;
5829a747e4fSDavid du Colombier 
5839a747e4fSDavid du Colombier 	case D1st:
5849a747e4fSDavid du Colombier 		if(a == nil || a->w == nil){
5859a747e4fSDavid du Colombier 			respond(r, "cannot happen (no wh)");
5869a747e4fSDavid du Colombier 			return;
5879a747e4fSDavid du Colombier 		}
5889a747e4fSDavid du Colombier 		dirread9p(r, firstgen, &b);
5899a747e4fSDavid du Colombier 		respond(r, nil);
5909a747e4fSDavid du Colombier 		return;
5919a747e4fSDavid du Colombier 
5929a747e4fSDavid du Colombier 	case D2nd:
5939a747e4fSDavid du Colombier 		dirread9p(r, secondgen, &b);
5949a747e4fSDavid du Colombier 		respond(r, nil);
5959a747e4fSDavid du Colombier 		return;
5969a747e4fSDavid du Colombier 
5979a747e4fSDavid du Colombier 	case Fnew:
5989a747e4fSDavid du Colombier 		if(a->s){
5999a747e4fSDavid du Colombier 			respond(r, "protocol botch");
6009a747e4fSDavid du Colombier 			return;
6019a747e4fSDavid du Colombier 		}
6029a747e4fSDavid du Colombier 		/* fall through */
6039a747e4fSDavid du Colombier 	case Fmap:
6049a747e4fSDavid du Colombier 		t = numtoname(a->n);
6059a747e4fSDavid du Colombier 		if(t == nil){
6069a747e4fSDavid du Colombier 			respond(r, "unknown name");
6079a747e4fSDavid du Colombier 			return;
6089a747e4fSDavid du Colombier 		}
6099a747e4fSDavid du Colombier 		for(s=t; *s; s++)
6109a747e4fSDavid du Colombier 			if(*s == ' ')
6119a747e4fSDavid du Colombier 				*s = '_';
6129a747e4fSDavid du Colombier 		readstr(r, t);
6139a747e4fSDavid du Colombier 		free(t);
6149a747e4fSDavid du Colombier 		respond(r, nil);
6159a747e4fSDavid du Colombier 		return;
6169a747e4fSDavid du Colombier 
6179a747e4fSDavid du Colombier 	case F1st:
6189a747e4fSDavid du Colombier 	case F2nd:
6199a747e4fSDavid du Colombier 		if(a == nil || a->s == nil){
6209a747e4fSDavid du Colombier 			respond(r, "cannot happen (no s)");
6219a747e4fSDavid du Colombier 			return;
6229a747e4fSDavid du Colombier 		}
6239a747e4fSDavid du Colombier 		readbuf(r, s_to_c(a->s), s_len(a->s));
6249a747e4fSDavid du Colombier 		respond(r, nil);
6259a747e4fSDavid du Colombier 		return;
6269a747e4fSDavid du Colombier 	}
6279a747e4fSDavid du Colombier }
6289a747e4fSDavid du Colombier 
6299a747e4fSDavid du Colombier typedef struct Sread Sread;
6309a747e4fSDavid du Colombier struct Sread {
6319a747e4fSDavid du Colombier 	char *rp;
6329a747e4fSDavid du Colombier };
6339a747e4fSDavid du Colombier 
6349a747e4fSDavid du Colombier static char*
Srdline(void * v,int c)6359a747e4fSDavid du Colombier Srdline(void *v, int c)
6369a747e4fSDavid du Colombier {
6379a747e4fSDavid du Colombier 	char *p, *rv;
6389a747e4fSDavid du Colombier 	Sread *s;
6399a747e4fSDavid du Colombier 
6409a747e4fSDavid du Colombier 	s = v;
6419a747e4fSDavid du Colombier 	if(s->rp == nil)
6429a747e4fSDavid du Colombier 		rv = nil;
6439a747e4fSDavid du Colombier 	else if(p = strchr(s->rp, c)){
6449a747e4fSDavid du Colombier 		*p = '\0';
6459a747e4fSDavid du Colombier 		rv = s->rp;
6469a747e4fSDavid du Colombier 		s->rp = p+1;
6479a747e4fSDavid du Colombier 	}else{
6489a747e4fSDavid du Colombier 		rv = s->rp;
6499a747e4fSDavid du Colombier 		s->rp = nil;
6509a747e4fSDavid du Colombier 	}
6519a747e4fSDavid du Colombier 	return rv;
6529a747e4fSDavid du Colombier }
6539a747e4fSDavid du Colombier 
6549a747e4fSDavid du Colombier static void
responderrstr(Req * r)6559a747e4fSDavid du Colombier responderrstr(Req *r)
6569a747e4fSDavid du Colombier {
6579a747e4fSDavid du Colombier 	char buf[ERRMAX];
6589a747e4fSDavid du Colombier 
6599a747e4fSDavid du Colombier 	rerrstr(buf, sizeof buf);
6609a747e4fSDavid du Colombier 	if(buf[0] == '\0')
6619a747e4fSDavid du Colombier 		strcpy(buf, "unknown error");
6629a747e4fSDavid du Colombier 	respond(r, buf);
6639a747e4fSDavid du Colombier }
6649a747e4fSDavid du Colombier 
6659a747e4fSDavid du Colombier static void
fswrite(Req * r)6669a747e4fSDavid du Colombier fswrite(Req *r)
6679a747e4fSDavid du Colombier {
6689a747e4fSDavid du Colombier 	char *author, *comment, *net, *err, *p, *title, tmp[40];
6699a747e4fSDavid du Colombier 	int rv, n;
6709a747e4fSDavid du Colombier 	ulong t;
6719a747e4fSDavid du Colombier 	Aux *a;
6729a747e4fSDavid du Colombier 	Fid *fid;
6739a747e4fSDavid du Colombier 	Sread s;
6749a747e4fSDavid du Colombier 	String *stmp;
6759a747e4fSDavid du Colombier 	Whist *w;
6769a747e4fSDavid du Colombier 
6779a747e4fSDavid du Colombier 	fid = r->fid;
6789a747e4fSDavid du Colombier 	a = fid->aux;
6799a747e4fSDavid du Colombier 	switch(qidtype(fid->qid.path)){
6809a747e4fSDavid du Colombier 	case Fmap:
6819a747e4fSDavid du Colombier 		stmp = s_nappend(s_reset(nil), r->ifcall.data, r->ifcall.count);
6829a747e4fSDavid du Colombier 		a->n = nametonum(s_to_c(stmp));
6839a747e4fSDavid du Colombier 		s_free(stmp);
6849a747e4fSDavid du Colombier 		if(a->n < 0)
6859a747e4fSDavid du Colombier 			respond(r, "name not found");
6869a747e4fSDavid du Colombier 		else
6879a747e4fSDavid du Colombier 			respond(r, nil);
6889a747e4fSDavid du Colombier 		return;
6899a747e4fSDavid du Colombier 	case Fnew:
6909a747e4fSDavid du Colombier 		break;
6919a747e4fSDavid du Colombier 	default:
6929a747e4fSDavid du Colombier 		respond(r, "cannot happen");
6939a747e4fSDavid du Colombier 		return;
6949a747e4fSDavid du Colombier 	}
6959a747e4fSDavid du Colombier 
6969a747e4fSDavid du Colombier 	if(a->s == nil){
6979a747e4fSDavid du Colombier 		respond(r, "protocol botch");
6989a747e4fSDavid du Colombier 		return;
6999a747e4fSDavid du Colombier 	}
7009a747e4fSDavid du Colombier 	if(r->ifcall.count==0){	/* do final processing */
7019a747e4fSDavid du Colombier 		s.rp = s_to_c(a->s);
7029a747e4fSDavid du Colombier 		w = nil;
7039a747e4fSDavid du Colombier 		err = "bad format";
7049a747e4fSDavid du Colombier 		if((title = Srdline(&s, '\n')) == nil){
7059a747e4fSDavid du Colombier 		Error:
7069a747e4fSDavid du Colombier 			if(w)
7079a747e4fSDavid du Colombier 				closewhist(w);
7089a747e4fSDavid du Colombier 			s_free(a->s);
7099a747e4fSDavid du Colombier 			a->s = nil;
7109a747e4fSDavid du Colombier 			respond(r, err);
7119a747e4fSDavid du Colombier 			return;
7129a747e4fSDavid du Colombier 		}
7139a747e4fSDavid du Colombier 
7149a747e4fSDavid du Colombier 		w = emalloc(sizeof(*w));
7159a747e4fSDavid du Colombier 		incref(w);
7169a747e4fSDavid du Colombier 		w->title = estrdup(title);
7179a747e4fSDavid du Colombier 
7189a747e4fSDavid du Colombier 		t = 0;
719af2e6ba6SDavid du Colombier 		author = estrdup(s_to_c(a->name));
7209a747e4fSDavid du Colombier 
7219a747e4fSDavid du Colombier 		comment = nil;
7229a747e4fSDavid du Colombier 		while(s.rp && *s.rp && *s.rp != '\n'){
7239a747e4fSDavid du Colombier 			p = Srdline(&s, '\n');
7249a747e4fSDavid du Colombier 			assert(p != nil);
7259a747e4fSDavid du Colombier 			switch(p[0]){
7269a747e4fSDavid du Colombier 			case 'A':
7279a747e4fSDavid du Colombier 				free(author);
7289a747e4fSDavid du Colombier 				author = estrdup(p+1);
7299a747e4fSDavid du Colombier 				break;
7309a747e4fSDavid du Colombier 			case 'D':
7319a747e4fSDavid du Colombier 				t = strtoul(p+1, &p, 10);
7329a747e4fSDavid du Colombier 				if(*p != '\0')
7339a747e4fSDavid du Colombier 					goto Error;
7349a747e4fSDavid du Colombier 				break;
7359a747e4fSDavid du Colombier 			case 'C':
7369a747e4fSDavid du Colombier 				free(comment);
7379a747e4fSDavid du Colombier 				comment = estrdup(p+1);
7389a747e4fSDavid du Colombier 				break;
7399a747e4fSDavid du Colombier 			}
7409a747e4fSDavid du Colombier 		}
7419a747e4fSDavid du Colombier 
7429a747e4fSDavid du Colombier 		w->doc = emalloc(sizeof(w->doc[0]));
7439a747e4fSDavid du Colombier 		w->doc->time = time(0);
7449a747e4fSDavid du Colombier 		w->doc->comment = comment;
7459a747e4fSDavid du Colombier 
7469a747e4fSDavid du Colombier 		if(net = r->pool->srv->aux){
7479a747e4fSDavid du Colombier 			p = emalloc(strlen(author)+10+strlen(net));
7489a747e4fSDavid du Colombier 			strcpy(p, author);
7499a747e4fSDavid du Colombier 			strcat(p, " (");
7509a747e4fSDavid du Colombier 			strcat(p, net);
7519a747e4fSDavid du Colombier 			strcat(p, ")");
7529a747e4fSDavid du Colombier 			free(author);
7539a747e4fSDavid du Colombier 			author = p;
7549a747e4fSDavid du Colombier 		}
7559a747e4fSDavid du Colombier 		w->doc->author = author;
7569a747e4fSDavid du Colombier 
7579a747e4fSDavid du Colombier 		if((w->doc->wtxt = Brdpage(Srdline, &s)) == nil){
7589a747e4fSDavid du Colombier 			err = "empty document";
7599a747e4fSDavid du Colombier 			goto Error;
7609a747e4fSDavid du Colombier 		}
7619a747e4fSDavid du Colombier 
7629a747e4fSDavid du Colombier 		w->ndoc = 1;
7639a747e4fSDavid du Colombier 		if((n = allocnum(w->title, 0)) < 0)
7649a747e4fSDavid du Colombier 			goto Error;
7659a747e4fSDavid du Colombier 		sprint(tmp, "D%lud\n", w->doc->time);
7669a747e4fSDavid du Colombier 		a->s = s_reset(a->s);
7679a747e4fSDavid du Colombier 		a->s = doctext(a->s, w->doc);
7689a747e4fSDavid du Colombier 		rv = writepage(n, t, a->s, w->title);
7699a747e4fSDavid du Colombier 		s_free(a->s);
7709a747e4fSDavid du Colombier 		a->s = nil;
7719a747e4fSDavid du Colombier 		a->n = n;
7729a747e4fSDavid du Colombier 		closewhist(w);
7739a747e4fSDavid du Colombier 		if(rv < 0)
7749a747e4fSDavid du Colombier 			responderrstr(r);
7759a747e4fSDavid du Colombier 		else
7769a747e4fSDavid du Colombier 			respond(r, nil);
7779a747e4fSDavid du Colombier 		return;
7789a747e4fSDavid du Colombier 	}
7799a747e4fSDavid du Colombier 
7809a747e4fSDavid du Colombier 	if(s_len(a->s)+r->ifcall.count > Maxfile){
7819a747e4fSDavid du Colombier 		respond(r, "file too large");
7829a747e4fSDavid du Colombier 		s_free(a->s);
7839a747e4fSDavid du Colombier 		a->s = nil;
7849a747e4fSDavid du Colombier 		return;
7859a747e4fSDavid du Colombier 	}
7869a747e4fSDavid du Colombier 	a->s = s_nappend(a->s, r->ifcall.data, r->ifcall.count);
7879a747e4fSDavid du Colombier 	r->ofcall.count = r->ifcall.count;
7889a747e4fSDavid du Colombier 	respond(r, nil);
7899a747e4fSDavid du Colombier }
7909a747e4fSDavid du Colombier 
7919a747e4fSDavid du Colombier Srv wikisrv = {
7929a747e4fSDavid du Colombier .attach=	fsattach,
7939a747e4fSDavid du Colombier .destroyfid=	fsdestroyfid,
7949a747e4fSDavid du Colombier .clone=	fsclone,
7959a747e4fSDavid du Colombier .walk1=	fswalk1,
7969a747e4fSDavid du Colombier .open=	fsopen,
7979a747e4fSDavid du Colombier .read=	fsread,
7989a747e4fSDavid du Colombier .write=	fswrite,
7999a747e4fSDavid du Colombier .stat=	fsstat,
8009a747e4fSDavid du Colombier };
8019a747e4fSDavid du Colombier 
8029a747e4fSDavid du Colombier void
usage(void)8039a747e4fSDavid du Colombier usage(void)
8049a747e4fSDavid du Colombier {
8059a747e4fSDavid du Colombier 	fprint(2, "usage: wikifs [-D] [-a addr]... [-m mtpt] [-p perm] [-s service] dir\n");
8069a747e4fSDavid du Colombier 	exits("usage");
8079a747e4fSDavid du Colombier }
8089a747e4fSDavid du Colombier 
8099a747e4fSDavid du Colombier void
main(int argc,char ** argv)8109a747e4fSDavid du Colombier main(int argc, char **argv)
8119a747e4fSDavid du Colombier {
8129a747e4fSDavid du Colombier 	char **addr;
8139a747e4fSDavid du Colombier 	int i, naddr;
8149a747e4fSDavid du Colombier 	char *buf;
8159a747e4fSDavid du Colombier 	char *service, *mtpt;
8169a747e4fSDavid du Colombier 	ulong perm;
8179a747e4fSDavid du Colombier 	Dir d, *dp;
8189a747e4fSDavid du Colombier 	Srv *s;
8199a747e4fSDavid du Colombier 
8209a747e4fSDavid du Colombier 	naddr = 0;
8219a747e4fSDavid du Colombier 	addr = nil;
8229a747e4fSDavid du Colombier 	perm = 0;
8239a747e4fSDavid du Colombier 	service = nil;
8249a747e4fSDavid du Colombier 	mtpt = "/mnt/wiki";
8259a747e4fSDavid du Colombier 	ARGBEGIN{
8269a747e4fSDavid du Colombier 	case 'D':
8279a747e4fSDavid du Colombier 		chatty9p++;
8289a747e4fSDavid du Colombier 		break;
8299a747e4fSDavid du Colombier 	case 'a':
8309a747e4fSDavid du Colombier 		if(naddr%8 == 0)
8319a747e4fSDavid du Colombier 			addr = erealloc(addr, (naddr+8)*sizeof(addr[0]));
8329a747e4fSDavid du Colombier 		addr[naddr++] = EARGF(usage());
8339a747e4fSDavid du Colombier 		break;
8349a747e4fSDavid du Colombier 	case 'm':
8359a747e4fSDavid du Colombier 		mtpt = EARGF(usage());
8369a747e4fSDavid du Colombier 		break;
8379a747e4fSDavid du Colombier 	case 'M':
8389a747e4fSDavid du Colombier 		mtpt = nil;
8399a747e4fSDavid du Colombier 		break;
8409a747e4fSDavid du Colombier 	case 'p':
8419a747e4fSDavid du Colombier 		perm = strtoul(EARGF(usage()), nil, 8);
8429a747e4fSDavid du Colombier 		break;
8439a747e4fSDavid du Colombier 	case 's':
8449a747e4fSDavid du Colombier 		service = EARGF(usage());
8459a747e4fSDavid du Colombier 		break;
8469a747e4fSDavid du Colombier 	default:
8479a747e4fSDavid du Colombier 		usage();
8489a747e4fSDavid du Colombier 		break;
8499a747e4fSDavid du Colombier 	}ARGEND
8509a747e4fSDavid du Colombier 
8519a747e4fSDavid du Colombier 	if(argc != 1)
8529a747e4fSDavid du Colombier 		usage();
8539a747e4fSDavid du Colombier 
8549a747e4fSDavid du Colombier 	if((dp = dirstat(argv[0])) == nil)
8559a747e4fSDavid du Colombier 		sysfatal("dirstat %s: %r", argv[0]);
8569a747e4fSDavid du Colombier 	if((dp->mode&DMDIR) == 0)
8579a747e4fSDavid du Colombier 		sysfatal("%s: not a directory", argv[0]);
8589a747e4fSDavid du Colombier 	free(dp);
8599a747e4fSDavid du Colombier 	wikidir = argv[0];
8609a747e4fSDavid du Colombier 
8619a747e4fSDavid du Colombier 	currentmap(0);
8629a747e4fSDavid du Colombier 
8639a747e4fSDavid du Colombier 	for(i=0; i<naddr; i++)
8649a747e4fSDavid du Colombier 		listensrv(&wikisrv, addr[i]);
8659a747e4fSDavid du Colombier 
8669a747e4fSDavid du Colombier 	s = emalloc(sizeof *s);
8679a747e4fSDavid du Colombier 	*s = wikisrv;
8689a747e4fSDavid du Colombier 	postmountsrv(s, service, mtpt, MREPL|MCREATE);
8699a747e4fSDavid du Colombier 	if(perm){
8709a747e4fSDavid du Colombier 		buf = emalloc9p(5+strlen(service)+1);
8719a747e4fSDavid du Colombier 		strcpy(buf, "/srv/");
8729a747e4fSDavid du Colombier 		strcat(buf, service);
8739a747e4fSDavid du Colombier 		nulldir(&d);
8749a747e4fSDavid du Colombier 		d.mode = perm;
8759a747e4fSDavid du Colombier 		if(dirwstat(buf, &d) < 0)
8769a747e4fSDavid du Colombier 			fprint(2, "wstat: %r\n");
877*1052a86aSDavid du Colombier 		free(buf);
8789a747e4fSDavid du Colombier 	}
8799a747e4fSDavid du Colombier 	exits(nil);
8809a747e4fSDavid du Colombier }
881