static void gencurrent(Wcache *w, Qid *q, char *file, char *lock, uint32_t *t, Whist **wp, int n) { Dir *d; Whist *wh; if(*wp && *t+Tcache >= time(0)) return; wlock(w); if(*wp && *t+Tcache >= time(0)){ wunlock(w); return; } if(((d = wdirstat(file)) == nil) || (d->qid.path==q->path && d->qid.vers==q->vers)){ *t = time(0); wunlock(w); free(d); return; } free(d); if(wh = readwhist(file, lock, q)){ wh->n = n; *t = time(0); closewhist(*wp); *wp = wh; } else fprint(2, "error file=%s lock=%s %r\n", file, lock); wunlock(w); }
void voidcache(int n) { Wcache *c; rlock(&cachelock); if(c = findcache(n)){ wlock(c); c->tcurrent = 0; c->thist = 0; /* aggressively free memory */ closewhist(c->hist); c->hist = nil; closewhist(c->current); c->current = nil; wunlock(c); } runlock(&cachelock); }
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* 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 Whist* getcache(int n, int hist) { int i, isw; uint32_t t; Wcache *c, **cp, **evict; Whist *wh; isw = 0; rlock(&cachelock); if(c = findcache(n)){ Found: current(c); if(hist) currenthist(c); rlock(c); if(hist) wh = c->hist; else wh = c->current; if(wh) incref(wh); runlock(c); if(isw) wunlock(&cachelock); else runlock(&cachelock); return wh; } runlock(&cachelock); wlock(&cachelock); if(c = findcache(n)){ isw = 1; /* better to downgrade lock but can't */ goto Found; } if(ncache < Mcache){ Alloc: c = emalloc(sizeof *c); ncache++; }else{ /* find something to evict. */ t = ~0; evict = nil; for(i=0; i<Nhash; i++){ for(cp=&tab[i], c=*cp; c; cp=&c->hash, c=*cp){ if(c->use < t && (!c->hist || c->hist->ref==1) && (!c->current || c->current->ref==1)){ evict = cp; t = c->use; } } } if(evict == nil){ fprint(2, "wikifs: nothing to evict\n"); goto Alloc; } c = *evict; *evict = c->hash; closewhist(c->current); closewhist(c->hist); memset(c, 0, sizeof *c); } c->n = n; c->hash = tab[n%Nhash]; tab[n%Nhash] = c; isw = 1; goto Found; }