ref: 315776d60f1d50b7560c3d4e830c075a5d3e8828
dir: /fs.c/
#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);
}