#include #include #include #include #include #include <9p.h> #include "flashfs.h" static Srv flashsrv; typedef struct State State; struct State { Entry *e; Dirr *r; }; #define writeable(e) ((e)->mode & 0222) static State * state(Entry *e) { State *s; s = emalloc9p(sizeof(State)); s->e = e; s->r = nil; return s; } static void flclunkaux(Fid *f) { State *s; s = f->aux; if(s->e) edestroy(s->e); if(s->r) edirclose(s->r); free(s); } static void trace(Req *) { edump(); } /** T_ **/ static void flattach(Req *r, Fid *fid, char *, Qid *qid) { root->ref++; *qid = eqid(root); fid->aux = state(root); respond(r, nil); } static void flclone(Req *r, Fid *old, Fid *new) { State *s; s = old->aux; s->e->ref++; new->aux = state(s->e); respond(r, nil); } static void flopen(Req *r, Fid *fid, int omode, Qid *qid) { Jrec j; int m, p; Entry *e; State *s; char *err; s = fid->aux; e = s->e; m = e->mode; m = (m | (m >> 3) | (m >> 6)) & 7; switch(omode & 3) { case OREAD: p = AREAD; break; case OWRITE: p = AWRITE; break; case ORDWR: p = AREAD|AWRITE; break; case OEXEC: p = AEXEC; break; default: p = 0; break; } if((p & m) != p) { respond(r, Eperm); return; } if(readonly && (p & AWRITE) != 0) { respond(r, Erofs); return; } *qid = eqid(e); if(qid->path & CHDIR) { if((p & AWRITE) != 0) { respond(r, Eisdir); return; } s->r = ediropen(s->e); } else if(omode & OTRUNC) { err = need(Ntrunc); if(err != nil) { respond(r, err); return; } j.type = FT_trunc; j.tnum = e->fnum; j.mtime = now(); etrunc(e, 0, j.mtime); j.fnum = e->fnum; j.parent = e->parent->fnum; j.mode = e->mode; strcpy(j.name, e->name); put(&j, 1); } respond(r, nil); } static void flcreate(Req *r, Fid *fid, char *name, int, ulong perm, Qid *qid) { Jrec j; State *s; char *err; Entry *e, *f; if(readonly) { respond(r, Erofs); return; } s = fid->aux; e = s->e; if((e->mode & DMDIR) == 0) { respond(r, Eisdir); return; } if(!writeable(e)) { respond(r, Eperm); return; } if(strlen(name) > MAXNSIZE) { respond(r, "filename too long"); return; } err = need(Ncreate); if(err != nil) { respond(r, err); return; } j.type = FT_create; j.mtime = now(); j.parent = e->fnum; j.mode = perm; strcpy(j.name, name); f = ecreate(e, name, 0, perm, j.mtime, &err); if(f == nil) { respond(r, err); return; } j.fnum = f->fnum; put(&j, 1); s->e = f; *qid = eqid(f); respond(r, nil); } static void flread(Req *r, Fid *fid, void *buf, long *count, vlong offset) { Entry *e; State *s; s = fid->aux; e = s->e; if(e->mode & DMDIR) *count = edirread(s->r, buf, *count, offset); else *count = eread(e, eparity, buf, *count, offset); respond(r, nil); } static void flwrite(Req *r, Fid *fid, void *buf, long *count, vlong offset) { Jrec j; uchar *a; Entry *e; State *s; Extent *x; char *err; ulong c, n, o, mtime; c = *count; o = offset; a = (uchar *)buf; if(c == 0) { respond(r, nil); return; } if(o + c >= MAXFSIZE) { respond(r, "file too big"); return; } if(used + c > limit) { respond(r, "filesystem full"); return; } *count = c; s = fid->aux; e = s->e; mtime = now(); for(;;) { n = c; if(n > maxwrite) n = maxwrite; err = need(Nwrite + n); if(err != nil) { respond(r, err); return; } x = emalloc9p(sizeof(Extent)); x->size = n; x->off = o; ewrite(e, x, eparity, mtime); j.type = FT_WRITE; j.fnum = e->fnum; j.size = n; j.offset = o; j.mtime = mtime; putw(&j, 1, x, a); c -= n; if(c == 0) break; o += n; a += n; } respond(r, nil); } static void flremove(Req *r, Fid *fid) { Jrec j; State *s; Entry *e; char *d, *err; if(readonly) { respond(r, Erofs); return; } s = fid->aux; e = s->e; if(writeable(e->parent)) { err = need(Nremove); if(err != nil) { respond(r, err); return; } d = eremove(e); if(d == nil) { j.type = FT_REMOVE; j.fnum = e->fnum; put(&j, 0); } respond(r, d); } else respond(r, Eperm); } static void flstat(Req *r, Fid *fid, Dir *d) { State *s; s = fid->aux; estat(s->e, d); respond(r, nil); } static void flwstat(Req *r, Fid *fid, Dir *d) { int m; Jrec j; State *s; Entry *e; char *err; s = fid->aux; e = s->e; if(readonly) { respond(r, Erofs); return; } if(e->fnum == 0) { respond(r, Eperm); return; } m = d->mode & 0777; if(m != (e->mode & 0777)) { err = need(Nchmod); if(err != nil) { respond(r, err); return; } echmod(e, m, 0); j.type = FT_chmod; j.mode = m; j.fnum = e->fnum; j.mnum = e->mnum; put(&j, 0); } respond(r, nil); } static void flwalk(Req *r, Fid *fid, char *name, Qid *qid) { State *s; char *err; Entry *e, *f; s = fid->aux; e = s->e; e->ref++; err = nil; f = ewalk(e, name, &err); if(f == nil) e->ref--; else { *qid = eqid(f); s->e = f; } respond(r, err); } void serve(char *mount) { flashsrv.attach = flattach; flashsrv.clone = flclone; flashsrv.open = flopen; flashsrv.create = flcreate; flashsrv.read = flread; flashsrv.write = flwrite; flashsrv.remove = flremove; flashsrv.stat = flstat; flashsrv.wstat = flwstat; flashsrv.walk = flwalk; flashsrv.clunkaux = flclunkaux; postmountsrv(&flashsrv, "brzr", mount, MREPL|MCREATE); }