ref: 50104ba72987b26febfa4e398458d47db20e9bea
dir: /fs.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "dat.h"
#include "fns.h"
#define Eexist "file does not exist"
#define Enodir "not a directory"
#define Enotyet "not yet implemented"
#define Eoffset "invalid offset"
#define Ewrite "write prohibited"
#define Ecreate "create prohibited"
#define Eremove "remove prohibited"
#define Einvalidname "invalid LPA name"
Qid qroot;
Qid qnew;
char *username;
enum {
Qroot,
Qnew,
Qsession,
Qctl,
Qcons,
Qlog,
Qmodules,
Qmodule,
Qthreads,
Qlpaobj
};
enum {
Fctl,
Fcons,
Flog,
Fmodules,
Fthreads,
};
enum {
Fnew,
Fsession,
};
typedef struct Aux Aux;
struct Aux
{
Session *session;
Module *module;
Symbol *symbol;
char *cachestr;
};
static Aux *
allocaux(void)
{
Aux *aux = alloc(DataAux);
setroot(aux, 1);
return aux;
}
#define QID_TYPE(qid) ((qid.path) & 0xFF)
#define QID_PATH(qid) (qid.path >> 8)
static Qid
mkqid(int type, uvlong id)
{
Qid qid;
qid.vers = 0;
qid.path = (type & 0xFF) | (id << 8);
switch(type){
case Qroot:
case Qsession:
case Qmodules:
case Qmodule:
case Qthreads:
qid.type = QTDIR;
break;
case Qnew:
case Qctl:
case Qcons:
case Qlog:
case Qlpaobj:
qid.type = QTFILE;
break;
}
if(type == Qcons)
qid.type |= QTAPPEND;
return qid;
}
Qid
freshobjqid(void)
{
static int id = 0;
Qid qid = mkqid(Qlpaobj, id);
id++;
return qid;
}
static void
mkfilestat(Dir *d, char *name, Qid qid, ulong mode)
{
d->uid = estrdup9p(username);
d->gid = estrdup9p(username);
d->muid = estrdup9p(username);
d->mode = mode;
d->name = estrdup9p(name);
d->qid = qid;
}
static void
mkdirstat(Dir *d, char *name, Qid qid)
{
d->uid = estrdup9p(username);
d->gid = estrdup9p(username);
d->muid = estrdup9p(username);
d->mode = 0555|DMDIR;
d->name = estrdup9p(name);
d->qid = qid;
}
static int
roottreegen(int n, Dir *d, void *aux)
{
Enumeration *sessions = aux;
int done = 0;
if(n == Fnew) /* new */
mkfilestat(d, "new", qnew, 0444);
else{
n -= Fsession;
if(n < sessions->count){
Session *s = sessions->items[n];
mkdirstat(d, s->name, s->qsession);
}else
done = 1;
}
return done ? -1 : 0;
}
static int
sessiongen(int n, Dir *d, void *aux)
{
Session *s = aux;
int done = 0;
switch(n){
case Fctl:
mkfilestat(d, "ctl", s->qctl, 0666);
break;
case Fcons:
mkfilestat(d, "cons", s->qctl, DMAPPEND|0555);
d->length = s->logsize;
break;
case Flog:
mkfilestat(d, "log", s->qlog, 0444);
d->length = s->logsize;
break;
case Fmodules:
mkdirstat(d, "modules", s->qmodules);
break;
/* case Fthreads:
mkdirstat(d, "threads", s->qthreads);
break;
*/
default:
done = 1;
}
return done ? -1 : 0;
}
static int
modulesgen(int n, Dir *d, void *aux)
{
Enumeration *modules = aux;
if(n == modules->count)
return -1;
Module *m = modules->items[n];
mkdirstat(d, m->name, m->qmodule);
return 0;
}
static int
symbolsgen(int n, Dir *d, void *aux)
{
Enumeration *symbols = aux;
if(n == symbols->count)
return -1;
Symbol *s = symbols->items[n];
mkfilestat(d, s->name, s->qsymbol, 0666);
return 0;
}
static char *
requeststr(Req *r)
{
char *buf;
r->ofcall.count = r->ifcall.count;
buf = emalloc9p(r->ifcall.count+1);
memcpy(buf, r->ifcall.data, r->ifcall.count);
buf[r->ifcall.count] = 0; /* make sure it is 0 terminated */
return buf;
}
static void
sessioncons(Req *r)
{
Aux *aux = r->fid->aux;
Session *s = aux->session;
srvrelease(r->srv);
if(r->ifcall.type == Tread){
qlock(&s->loglock);
if(r->ifcall.offset >= s->logsize)
rsleep(&s->logwait);
readbuf(r, s->log, s->logsize);
qunlock(&s->loglock);
}else{ /* Twrite */
char *buf = requeststr(r);
send(s->input, &buf);
}
srvacquire(r->srv);
}
static void
sessionlog(Req *r)
{
Aux *aux = r->fid->aux;
Session *s = aux->session;
srvrelease(r->srv);
qlock(&s->loglock);
readbuf(r, s->log, s->logsize);
qunlock(&s->loglock);
srvacquire(r->srv);
}
static void
sessionctl(Req *r)
{
Aux *aux = r->fid->aux;
Session *s = aux->session;
char *buf = requeststr(r);
srvrelease(r->srv);
systemcmd(s, buf, 1);
free(buf);
srvacquire(r->srv);
}
static char *
symbolrw(Req *r)
{
Aux *aux = r->fid->aux;
Symbol *s = aux->symbol;
char *err = nil;
if(r->ifcall.type == Tread){
/* Pretty print the value and readstr() it. */
if(aux->cachestr == nil)
aux->cachestr = printval(s->value);
readstr(r, aux->cachestr);
if(r->ofcall.count == 0){
free(aux->cachestr);
aux->cachestr = nil;
}
}else{ /* Twrite */
char *buf = requeststr(r);
void *v = parseval(buf, &err);
free(buf);
if(!err)
symset(s->table, s->id, v);
}
return err;
}
static void
fsattach(Req *r)
{
r->fid->qid = qroot;
r->ofcall.qid = r->fid->qid;
r->fid->aux = allocaux();
respond(r, nil);
}
static char *
fswalk1(Fid *fid, char *name, Qid *qid)
{
char *err = nil;
Enumeration *e = nil;
Aux *aux = fid->aux;
Session *s = aux->session;
Module *m = aux->module;
switch(QID_TYPE(fid->qid)){
case Qroot:
if(strcmp(name, "..") == 0)
*qid = fid->qid;
else if(strcmp(name, "new") == 0)
*qid = qnew;
else{
int found = 0;
e = enumsessions();
for(uvlong i = 0; i < e->count; i++){
Session *s = e->items[i];
if(strcmp(name, s->name) == 0){
*qid = s->qsession;
aux->session = s;
found = 1;
break;
}
}
if(!found)
err = Eexist;
}
break;
case Qsession:
if(strcmp(name, "..") == 0)
*qid = qroot;
else if(strcmp(name, "ctl") == 0)
*qid = s->qctl;
else if(strcmp(name, "cons") == 0)
*qid = s->qcons;
else if(strcmp(name, "log") == 0)
*qid = s->qlog;
else if(strcmp(name, "modules") == 0)
*qid = s->qmodules;
/* else if(strcmp(name, "threads") == 0)
*qid = s->qthreads;
*/
else
err = Eexist;
break;
case Qmodules:
if(strcmp(name, "..") == 0)
*qid = s->qsession;
else{
int found = 0;
e = enummodules(s);
for(uvlong i = 0; i < e->count && !found; i++){
Module *m = e->items[i];
if(strcmp(name, m->name) == 0){
*qid = m->qmodule;
aux->module = m;
found = 1;
}
}
if(!found)
err = Eexist;
}
break;
case Qmodule:
if(strcmp(name, "..") == 0)
*qid = m->qsession;
else{
int found = 0;
e = enumsymbols(m->symtab);
for(uvlong i = 0; i < e->count && !found; i++){
Symbol *symb = e->items[i];
if(strcmp(name, symb->name) == 0){
*qid = symb->qsymbol;
aux->symbol = symb;
found = 1;
}
}
if(!found)
err = Eexist;
}
break;
case Qthreads:
if(strcmp(name, "..") == 0)
*qid = s->qsession;
else
err = Enotyet;
break;
default:
err = Enodir;
break;
}
if(e != nil)
setroot(e, 0);
return err;
}
static char *
fsclone(Fid *old, Fid *new)
{
new->aux = allocaux();
Aux *oldaux = old->aux;
Aux *newaux = new->aux;
memcpy(newaux, oldaux, sizeof(Aux));
return nil;
}
static void
fsopen(Req *r)
{
/* TODO check permissions */
char *err = nil;
if(QID_TYPE(r->fid->qid) == Qnew){
/* Create a new session */
Session *s = allocsession();
Module *m = addmodule(s, "main");
qnew.vers = s->id;
r->fid->qid = qnew;
r->ofcall.qid = qnew;
s->qsession = mkqid(Qsession, s->id);
s->qctl = mkqid(Qctl, s->id);
s->qcons = mkqid(Qcons, s->id);
s->qlog = mkqid(Qlog, s->id);
s->qmodules = mkqid(Qmodules, s->id);
s->qthreads = mkqid(Qthreads, s->id);
m->qsession = s->qsession;
m->qmodule = mkqid(Qmodule, m->id);
}
respond(r, err);
}
static void
fsstat(Req *r)
{
Aux *aux = r->fid->aux;
Session *s = aux->session;
Module *m = aux->module;
Symbol *symb = aux->symbol;
char *err = nil;
switch(QID_TYPE(r->fid->qid)){
case Qroot:
mkdirstat(&r->d, "/", qroot);
break;
case Qnew:
roottreegen(Fnew, &r->d, nil);
break;
case Qsession:
mkdirstat(&r->d, s->name, s->qsession);
break;
case Qctl:
sessiongen(Fctl, &r->d, s);
break;
case Qcons:
sessiongen(Fcons, &r->d, s);
break;
case Qlog:
sessiongen(Flog, &r->d, s);
break;
case Qmodules:
sessiongen(Fmodules, &r->d, s);
break;
case Qmodule:
mkdirstat(&r->d, m->name, m->qmodule);
break;
case Qthreads:
sessiongen(Fthreads, &r->d, s);
break;
case Qlpaobj:
mkfilestat(&r->d, symb->name, symb->qsymbol, 0444);
break;
default:
err = Enotyet;
}
respond(r, err);
}
static void
fsread(Req *r)
{
char buf[256];
Enumeration *e = nil;
Aux *aux = r->fid->aux;
char *err = nil;
switch(QID_TYPE(r->fid->qid)){
case Qroot:
e = enumsessions();
dirread9p(r, roottreegen, e);
break;
case Qsession:
dirread9p(r, sessiongen, aux->session);
break;
case Qmodules:
e = enummodules(aux->session);
dirread9p(r, modulesgen, e);
break;
case Qmodule:
e = enumsymbols(aux->module->symtab);
dirread9p(r, symbolsgen, e);
break;
case Qnew:
snprint(buf, sizeof(buf), "%uld\n", r->fid->qid.vers);
readstr(r, buf);
break;
case Qcons:
sessioncons(r);
break;
case Qlog:
sessionlog(r);
break;
case Qlpaobj:
err = symbolrw(r);
break;
default:
err = Enotyet;
break;
}
if(e != nil)
setroot(e, 0);
respond(r, err);
}
static void
fswrite(Req *r)
{
char *err = nil;
switch(QID_TYPE(r->fid->qid)){
case Qctl:
sessionctl(r);
break;
case Qcons:
sessioncons(r);
break;
case Qlpaobj:
err = symbolrw(r);
break;
default:
err = Ewrite;
}
respond(r, err);
}
static void
fscreate(Req *r)
{
char *err = nil;
Aux *aux = r->fid->aux;
Module *m = aux->module;
uvlong symid;
Symbol *symb;
switch(QID_TYPE(r->fid->qid)){
case Qmodule: /* create a new symbol */
symid = sym(m->symtab, r->ifcall.name);
if(symid == -1)
err = Einvalidname;
symb = symptr(m->symtab, symid);
aux->symbol = symb;
r->fid->qid = r->ofcall.qid = symb->qsymbol;
break;
default:
err = Ecreate;
}
respond(r, err);
}
static void
fsremove(Req *r)
{
char *err;
switch(QID_TYPE(r->fid->qid)){
case Qlpaobj:
err = Enotyet;
break;
default:
err = Eremove;
}
respond(r, err);
}
static void
fsdestroyfid(Fid *fid)
{
if(fid->aux)
setroot(fid->aux, 0);
}
static Srv fs = {
.attach = fsattach,
.walk1 = fswalk1,
.clone = fsclone,
.open = fsopen,
.stat = fsstat,
.read = fsread,
.write = fswrite,
.create = fscreate,
.remove = fsremove,
.destroyfid = fsdestroyfid,
};
void
startfs(char *name, char *mtpt)
{
dataspecs[DataAux].size = sizeof(Aux);
username = getuser();
qroot = mkqid(Qroot, 0);
qnew = mkqid(Qnew, 0);
threadpostmountsrv(&fs, name, mtpt, MREPL);
}