#include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <9p.h> enum { Xpath, Xreader, Xfilter,}; typedef struct Aux Aux;typedef struct Data Data; struct Aux { Reqqueue *reader; Reqqueue *filter; Channel *data; Aux *path; int fd; int type;}; struct Data { int n; u8int p[1];}; #define FAUX(r) ((Aux*)r->fid->file->aux) static voidfsopen(Req *r){ Aux *a; char *e; if(FAUX(r) == nil){ respond(r, nil); return; } e = nil; switch(r->ifcall.mode){ case OREAD: if(FAUX(r)->reader != nil){ e = "only one reader allowed"; }else{ a = calloc(1, sizeof(Aux)); a->type = Xreader; a->path = FAUX(r); a->path->reader = reqqueuecreate(); r->fid->aux = a; } break; case ORDWR: /* FIXME chain multiple filters together */ if(FAUX(r)->filter != nil){ e = "only one filter allowed"; }else{ a = calloc(1, sizeof(Aux)); a->type = Xfilter; a->path = FAUX(r); a->path->filter = reqqueuecreate(); a->fd = a->path->fd; r->fid->aux = a; } break; default: e = "invalid mode"; break; } respond(r, e);} static voidfilterread(Req *r){ int n; if((n = read(FAUX(r)->fd, r->ofcall.data, r->ifcall.count)) >= 0){ r->ofcall.count = n; respond(r, nil); }else{ respond(r, "%r"); }} static voidreaderread(Req *r){ Data *d; if((d = recvp(FAUX(r)->data)) != nil){ r->ofcall.count = d->n; memmove(r->ofcall.data, d->p, d->n); free(d); respond(r, nil); }else{ filterread(r); }} static voidfsread(Req *r){ Aux *a; a = r->fid->aux; switch(a->type){ case Xreader: reqqueuepush(a->path->reader, r, readerread); break; case Xfilter: reqqueuepush(a->path->filter, r, filterread); break; }} static voidfilterwrite(Req *r){ Data *d; d = malloc(sizeof(*d)+r->ifcall.count); d->n = r->ifcall.count; memmove(d->p, r->ifcall.data, d->n); sendp(FAUX(r)->data, d); respond(r, nil);} static voidfswrite(Req *r){ Aux *a; a = r->fid->aux; switch(a->type){ case Xfilter: reqqueuepush(a->path->filter, r, filterwrite); break; default: respond(r, "invalid op"); }} static voidfsflush(Req *r){ Aux *a; Req *o; o = r->oldreq; a = o->fid->aux; if(o->ifcall.type == Tread && a != nil){ if(a->type == Xreader) reqqueueflush(FAUX(o)->reader, o); if(a->type == Xfilter) reqqueueflush(FAUX(o)->filter, o); } respond(r, nil);} static voidfsdestroyfid(Fid *fid){ Aux *a; a = fid->aux; if(a == nil) return; switch(a->type){ case Xreader: if(a->path->reader != nil) reqqueuefree(a->path->reader); a->path->reader = nil; free(a); break; case Xfilter: if(a->path->filter != nil) reqqueuefree(a->path->filter); a->path->filter = nil; free(a); break; }} static Srv fs = { .open = fsopen, .read = fsread, .write = fswrite, .flush = fsflush, .destroyfid = fsdestroyfid,}; static voidusage(void){ print("usage: %s [-s srv] [-m mtpt] file ...\n", argv0); threadexitsall("usage");} voidthreadmain(int argc, char **argv){ Aux *a; char *srv, *mtpt, *file; int i, fd; srv = nil; mtpt = nil; ARGBEGIN{ case 'D': chatty9p++; break; case 's': srv = EARGF(usage()); break; case 'm': mtpt = EARGF(usage()); break; default: usage(); }ARGEND fs.tree = alloctree(nil, nil, DMDIR|0775, nil); for(i = 0; i < argc; i++){ if((fd = open(argv[i], OREAD)) < 0) sysfatal("%r"); if((file = utfrrune(argv[i], '/')) != nil) file++; else file = argv[i]; if((a = calloc(1, sizeof(*a))) == nil) sysfatal("no memory"); a->type = Xpath; a->fd = fd; a->data = chancreate(sizeof(Data*), 32); closefile(createfile(fs.tree->root, file, nil, 0600, a)); } threadpostmountsrv(&fs, srv, mtpt, MREPL); threadexits(nil);}
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
enum {
Xpath,
Xreader,
Xfilter,
};
typedef struct Aux Aux;
typedef struct Data Data;
struct Aux {
Reqqueue *reader;
Reqqueue *filter;
Channel *data;
Aux *path;
int fd;
int type;
};
struct Data {
int n;
u8int p[1];
};
#define FAUX(r) ((Aux*)r->fid->file->aux)
static void
fsopen(Req *r)
{
Aux *a;
char *e;
if(FAUX(r) == nil){
respond(r, nil);
return;
}
e = nil;
switch(r->ifcall.mode){
case OREAD:
if(FAUX(r)->reader != nil){
e = "only one reader allowed";
}else{
a = calloc(1, sizeof(Aux));
a->type = Xreader;
a->path = FAUX(r);
a->path->reader = reqqueuecreate();
r->fid->aux = a;
}
break;
case ORDWR:
/* FIXME chain multiple filters together */
if(FAUX(r)->filter != nil){
e = "only one filter allowed";
}else{
a = calloc(1, sizeof(Aux));
a->type = Xfilter;
a->path = FAUX(r);
a->path->filter = reqqueuecreate();
a->fd = a->path->fd;
r->fid->aux = a;
}
break;
default:
e = "invalid mode";
break;
}
respond(r, e);
}
static void
filterread(Req *r)
{
int n;
if((n = read(FAUX(r)->fd, r->ofcall.data, r->ifcall.count)) >= 0){
r->ofcall.count = n;
respond(r, nil);
}else{
respond(r, "%r");
}
}
static void
readerread(Req *r)
{
Data *d;
if((d = recvp(FAUX(r)->data)) != nil){
r->ofcall.count = d->n;
memmove(r->ofcall.data, d->p, d->n);
free(d);
respond(r, nil);
}else{
filterread(r);
}
}
static void
fsread(Req *r)
{
Aux *a;
a = r->fid->aux;
switch(a->type){
case Xreader:
reqqueuepush(a->path->reader, r, readerread);
break;
case Xfilter:
reqqueuepush(a->path->filter, r, filterread);
break;
}
}
static void
filterwrite(Req *r)
{
Data *d;
d = malloc(sizeof(*d)+r->ifcall.count);
d->n = r->ifcall.count;
memmove(d->p, r->ifcall.data, d->n);
sendp(FAUX(r)->data, d);
respond(r, nil);
}
static void
fswrite(Req *r)
{
Aux *a;
a = r->fid->aux;
switch(a->type){
case Xfilter:
reqqueuepush(a->path->filter, r, filterwrite);
break;
default:
respond(r, "invalid op");
}
}
static void
fsflush(Req *r)
{
Aux *a;
Req *o;
o = r->oldreq;
a = o->fid->aux;
if(o->ifcall.type == Tread && a != nil){
if(a->type == Xreader)
reqqueueflush(FAUX(o)->reader, o);
if(a->type == Xfilter)
reqqueueflush(FAUX(o)->filter, o);
}
respond(r, nil);
}
static void
fsdestroyfid(Fid *fid)
{
Aux *a;
a = fid->aux;
if(a == nil)
return;
switch(a->type){
case Xreader:
if(a->path->reader != nil)
reqqueuefree(a->path->reader);
a->path->reader = nil;
free(a);
break;
case Xfilter:
if(a->path->filter != nil)
reqqueuefree(a->path->filter);
a->path->filter = nil;
free(a);
break;
}
}
static Srv fs = {
.open = fsopen,
.read = fsread,
.write = fswrite,
.flush = fsflush,
.destroyfid = fsdestroyfid,
};
static void
usage(void)
{
print("usage: %s [-s srv] [-m mtpt] file ...\n", argv0);
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
Aux *a;
char *srv, *mtpt, *file;
int i, fd;
srv = nil;
mtpt = nil;
ARGBEGIN{
case 'D':
chatty9p++;
break;
case 's':
srv = EARGF(usage());
break;
case 'm':
mtpt = EARGF(usage());
break;
default:
usage();
}ARGEND
fs.tree = alloctree(nil, nil, DMDIR|0775, nil);
for(i = 0; i < argc; i++){
if((fd = open(argv[i], OREAD)) < 0)
sysfatal("%r");
if((file = utfrrune(argv[i], '/')) != nil)
file++;
else
file = argv[i];
if((a = calloc(1, sizeof(*a))) == nil)
sysfatal("no memory");
a->type = Xpath;
a->fd = fd;
a->data = chancreate(sizeof(Data*), 32);
closefile(createfile(fs.tree->root, file, nil, 0600, a));
}
threadpostmountsrv(&fs, srv, mtpt, MREPL);
threadexits(nil);
}