/* * 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. Load more
/* * 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, }; uvlong mkqid(int type, int num, int vers, int file) { return ((uvlong)type<<40) | ((uvlong)num<<24) | (vers<<8) | file; } int qidtype(uvlong path) { return (path>>40)&0xFF; } int qidnum(uvlong path) { return (path>>24)&0xFFFF; } int qidvers(uvlong path) { return (path>>8)&0xFFFF; } int qidfile(uvlong path) { return path&0xFF; } typedef struct Aux Aux; struct Aux { String *name; Whist *w; int n; ulong t; String *s; Map *map; }; static void fsattach(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 void fsopen(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 void fsdestroyfid(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 void fillstat(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 void fsstat(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 int rootgen(int i, Dir *d, void *aux) { Aux *a; Bogus *b; b = aux;