diff options
Diffstat (limited to 'fs.c')
-rw-r--r-- | fs.c | 336 |
1 files changed, 336 insertions, 0 deletions
@@ -0,0 +1,336 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <thread.h> +#include <draw.h> +#include <memdraw.h> +#include <fcall.h> +#include <9p.h> + +typedef struct Dirtab Dirtab; + +struct Dirtab +{ + char *name; + uchar type; + uint qidpath; + uint perm; +}; + +enum { + Qroot, + Qctl, + Qframe, +}; + +char Ebotch[] = "9P protocol botch"; +char Enotfound[] = "file not found"; +char Enotdir[] = "not a directory"; +char Eperm[] = "permission denied"; + +Dirtab dirtab[] = { + "/", QTDIR, Qroot, 0555|DMDIR, + "ctl", QTFILE, Qctl, 0600, + "frame", QTFILE, Qframe, 0444, +}; +char *jefe = "Pablo R. Picasso"; +Memimage *fb; + +static int +mode2perm(int m) +{ + static int perms[4] = {4, 2, 6, 1}; + + return perms[m&OMASK]; +} + +static void +fillstat(Dir *dir, Dirtab *d) +{ + dir->name = estrdup9p(d->name); + dir->uid = estrdup9p(jefe); + dir->gid = estrdup9p(jefe); + dir->mode = d->perm; + dir->length = 0; + dir->qid = (Qid){d->qidpath, 0, d->type}; + dir->atime = time(0); + dir->mtime = time(0); + dir->muid = estrdup9p(""); +} + +static int +dirgen(int n, Dir *dir, void*) +{ + if(++n >= nelem(dirtab)) + return -1; + fillstat(dir, &dirtab[n]); + return 0; +} + +static int +readimg(Memimage *i, char *t, Rectangle r, int offset, int n) +{ + int ww, oo, y, m; + uchar *tt; + + ww = bytesperline(r, i->depth); + r.min.y += offset/ww; + if(r.min.y >= r.max.y) + return 0; + + y = r.min.y + (n + ww-1)/ww; + if(y < r.max.y) + r.max.y = y; + + m = ww * Dy(r); + oo = offset % ww; + if(oo == 0 && n >= m) + return unloadmemimage(i, r, (uchar*)t, n); + + if((tt = malloc(m)) == nil) + return -1; + + m = unloadmemimage(i, r, tt, m) - oo; + if(m > 0){ + if(n < m) m = n; + memmove(t, tt + oo, m); + } + + free(tt); + return m; +} + +void +fsattach(Req *r) +{ + if(r->ifcall.aname && r->ifcall.aname[0]){ + respond(r, "invalid attach specifier"); + return; + } + + r->ofcall.qid = (Qid){Qroot, 0, QTDIR}; + r->fid->qid = r->ofcall.qid; + r->fid->aux = nil; + respond(r, nil); +} + +void +fsopen(Req *r) +{ + int i, perm, want; + + for(i = 0; i < nelem(dirtab); i++) + if(r->fid->qid.path == dirtab[i].qidpath) + break; + + if(i < nelem(dirtab)){ + if(strcmp(r->fid->uid, jefe) == 0) + perm = dirtab[i].perm>>6; + else + perm = dirtab[i].perm; + }else{ + respond(r, Ebotch); + return; + }; + + if((r->ifcall.mode & (OTRUNC|OCEXEC|ORCLOSE)) != 0) + goto deny; + want = mode2perm(r->ifcall.mode); + if((want & perm) != want){ +deny: + respond(r, Eperm); + return; + } + respond(r, nil); +} + +void +fsread(Req *r) +{ + Memimage *i; + char buf[128], cbuf[30], *t; + ulong off, cnt; + int n; + + off = r->ifcall.offset; + cnt = r->ifcall.count; + + switch(r->fid->qid.path){ + default: + respond(r, "bug in fsread"); + break; + case Qroot: + dirread9p(r, dirgen, nil); + respond(r, nil); + break; + case Qctl: + respond(r, nil); + break; + case Qframe: + i = fb; + if(off < 5*12){ + n = snprint(buf, sizeof buf, "%11s %11d %11d %11d %11d ", + chantostr(cbuf, i->chan), + i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y); + t = estrdup9p(buf); + + if(off > n){ + off = n; + cnt = 0; + } + + if(off+cnt > n) + cnt = n-off; + + r->ofcall.data = t+off; + r->ofcall.count = cnt; + respond(r, nil); + free(t); + break; + } + + off -= 5*12; + n = -1; + t = malloc(cnt); + if(t != nil){ + r->ofcall.data = t; + n = readimg(i, t, i->r, off, cnt); + } + + if(n < 0){ + buf[0] = 0; + errstr(buf, sizeof buf); + respond(r, buf); + }else{ + r->ofcall.count = n; + respond(r, nil); + } + free(t); + break; + } +} + +void +fswrite(Req *r) +{ + char *msg, *f[10]; + ulong cnt, nf; + int i; + + cnt = r->ifcall.count; + + switch(r->fid->qid.path){ + default: + respond(r, "bug in fswrite"); + break; + case Qctl: + msg = emalloc9p(cnt+1); + memmove(msg, r->ifcall.data, cnt); + msg[cnt] = 0; + nf = tokenize(msg, f, nelem(f)); + for(i = 0; i < nf; i++) + fprint(2, "%s[%d]%s%s", i == 0? "": " ", i, f[i], i == nf-1? "\n": ""); + free(msg); + r->ofcall.count = cnt; + respond(r, nil); + break; + } +} + +void +fsstat(Req *r) +{ + int i; + + for(i = 0; i < nelem(dirtab); i++) + if(r->fid->qid.path == dirtab[i].qidpath){ + fillstat(&r->d, &dirtab[i]); + respond(r, nil); + return; + } + respond(r, Enotfound); +} + +char * +fswalk1(Fid *f, char *name, Qid *qid) +{ + int i; + + switch(f->qid.path){ + case Qroot: + if(strcmp(name, "..") == 0){ + *qid = f->qid; + return nil; + } + for(i = 1; i < nelem(dirtab); i++) + if(strcmp(name, dirtab[i].name) == 0){ + *qid = (Qid){dirtab[i].qidpath, 0, 0}; + f->qid = *qid; + return nil; + } + return Enotfound; + default: + return Enotdir; + } +} + +char * +fsclone(Fid *old, Fid *new) +{ + USED(old, new); + return nil; +} + +Srv fs = { + .attach = fsattach, + .open = fsopen, + .read = fsread, + .write = fswrite, + .stat = fsstat, + .walk1 = fswalk1, + .clone = fsclone, +}; + +void +usage(void) +{ + fprint(2, "usage: %s [-D] [-s srvname] [-m mtpt]\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + char *srvname, *mtpt; + int fd; + + srvname = "render"; + mtpt = "/mnt/render"; + ARGBEGIN{ + case 'D': + chatty9p++; + break; + case 's': + srvname = EARGF(usage()); + break; + case 'm': + mtpt = EARGF(usage()); + break; + default: usage(); + }ARGEND + if(argc != 0) + usage(); + + jefe = getuser(); + + fd = open("/dev/window", OREAD); + if(fd < 0) + sysfatal("open: %r"); + fb = readmemimage(fd); + if(fb == nil) + sysfatal("readmemimage: %r"); + close(fd); + + threadpostmountsrv(&fs, srvname, mtpt, MREPL|MCREATE); + exits(nil); +} |