#include #include #include #include #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); }