19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * Web file system. Conventionally mounted at /mnt/web
39a747e4fSDavid du Colombier *
49a747e4fSDavid du Colombier * ctl send control messages (might go away)
59a747e4fSDavid du Colombier * cookies list of cookies, editable
69a747e4fSDavid du Colombier * clone open and read to obtain new connection
79a747e4fSDavid du Colombier * n connection directory
89a747e4fSDavid du Colombier * ctl control messages (like get url)
99a747e4fSDavid du Colombier * body retrieved data
109a747e4fSDavid du Colombier * content-type mime content-type of body
119a747e4fSDavid du Colombier * postbody data to be posted
129a747e4fSDavid du Colombier * parsed parsed version of url
139a747e4fSDavid du Colombier * url entire url
149a747e4fSDavid du Colombier * scheme http, ftp, etc.
159a747e4fSDavid du Colombier * host hostname
169a747e4fSDavid du Colombier * path path on host
179a747e4fSDavid du Colombier * query query after path
189a747e4fSDavid du Colombier * fragment #foo anchor reference
199a747e4fSDavid du Colombier * user user name (ftp)
209a747e4fSDavid du Colombier * password password (ftp)
219a747e4fSDavid du Colombier * ftptype transfer mode (ftp)
229a747e4fSDavid du Colombier */
239a747e4fSDavid du Colombier
249a747e4fSDavid du Colombier #include <u.h>
259a747e4fSDavid du Colombier #include <libc.h>
269a747e4fSDavid du Colombier #include <bio.h>
279a747e4fSDavid du Colombier #include <ip.h>
289a747e4fSDavid du Colombier #include <plumb.h>
299a747e4fSDavid du Colombier #include <thread.h>
309a747e4fSDavid du Colombier #include <fcall.h>
319a747e4fSDavid du Colombier #include <9p.h>
329a747e4fSDavid du Colombier #include "dat.h"
339a747e4fSDavid du Colombier #include "fns.h"
349a747e4fSDavid du Colombier
359a747e4fSDavid du Colombier int fsdebug;
369a747e4fSDavid du Colombier
379a747e4fSDavid du Colombier enum
389a747e4fSDavid du Colombier {
399a747e4fSDavid du Colombier Qroot,
409a747e4fSDavid du Colombier Qrootctl,
419a747e4fSDavid du Colombier Qclone,
429a747e4fSDavid du Colombier Qcookies,
439a747e4fSDavid du Colombier Qclient,
449a747e4fSDavid du Colombier Qctl,
459a747e4fSDavid du Colombier Qbody,
469a747e4fSDavid du Colombier Qbodyext,
479a747e4fSDavid du Colombier Qcontenttype,
489a747e4fSDavid du Colombier Qpostbody,
499a747e4fSDavid du Colombier Qparsed,
509a747e4fSDavid du Colombier Qurl,
519a747e4fSDavid du Colombier Qscheme,
529a747e4fSDavid du Colombier Qschemedata,
539a747e4fSDavid du Colombier Quser,
549a747e4fSDavid du Colombier Qpasswd,
559a747e4fSDavid du Colombier Qhost,
569a747e4fSDavid du Colombier Qport,
579a747e4fSDavid du Colombier Qpath,
589a747e4fSDavid du Colombier Qquery,
599a747e4fSDavid du Colombier Qfragment,
609a747e4fSDavid du Colombier Qftptype,
619a747e4fSDavid du Colombier Qend,
629a747e4fSDavid du Colombier };
639a747e4fSDavid du Colombier
649a747e4fSDavid du Colombier #define PATH(type, n) ((type)|((n)<<8))
659a747e4fSDavid du Colombier #define TYPE(path) ((int)(path) & 0xFF)
669a747e4fSDavid du Colombier #define NUM(path) ((uint)(path)>>8)
679a747e4fSDavid du Colombier
689a747e4fSDavid du Colombier Channel *creq;
699a747e4fSDavid du Colombier Channel *creqwait;
709a747e4fSDavid du Colombier Channel *cclunk;
719a747e4fSDavid du Colombier Channel *cclunkwait;
729a747e4fSDavid du Colombier
739a747e4fSDavid du Colombier typedef struct Tab Tab;
749a747e4fSDavid du Colombier struct Tab
759a747e4fSDavid du Colombier {
769a747e4fSDavid du Colombier char *name;
779a747e4fSDavid du Colombier ulong mode;
789a747e4fSDavid du Colombier int offset;
799a747e4fSDavid du Colombier };
809a747e4fSDavid du Colombier
819a747e4fSDavid du Colombier Tab tab[] =
829a747e4fSDavid du Colombier {
839a747e4fSDavid du Colombier "/", DMDIR|0555, 0,
849a747e4fSDavid du Colombier "ctl", 0666, 0,
859a747e4fSDavid du Colombier "clone", 0666, 0,
869a747e4fSDavid du Colombier "cookies", 0666, 0,
879a747e4fSDavid du Colombier "XXX", DMDIR|0555, 0,
889a747e4fSDavid du Colombier "ctl", 0666, 0,
899a747e4fSDavid du Colombier "body", 0444, 0,
909a747e4fSDavid du Colombier "XXX", 0444, 0,
919a747e4fSDavid du Colombier "contenttype", 0444, 0,
929a747e4fSDavid du Colombier "postbody", 0666, 0,
939a747e4fSDavid du Colombier "parsed", DMDIR|0555, 0,
949a747e4fSDavid du Colombier "url", 0444, offsetof(Url, url),
959a747e4fSDavid du Colombier "scheme", 0444, offsetof(Url, scheme),
969a747e4fSDavid du Colombier "schemedata", 0444, offsetof(Url, schemedata),
979a747e4fSDavid du Colombier "user", 0444, offsetof(Url, user),
989a747e4fSDavid du Colombier "passwd", 0444, offsetof(Url, passwd),
999a747e4fSDavid du Colombier "host", 0444, offsetof(Url, host),
1009a747e4fSDavid du Colombier "port", 0444, offsetof(Url, port),
1019a747e4fSDavid du Colombier "path", 0444, offsetof(Url, path),
1029a747e4fSDavid du Colombier "query", 0444, offsetof(Url, query),
1039a747e4fSDavid du Colombier "fragment", 0444, offsetof(Url, fragment),
1049a747e4fSDavid du Colombier "ftptype", 0444, offsetof(Url, ftp.type),
1059a747e4fSDavid du Colombier };
1069a747e4fSDavid du Colombier
1079a747e4fSDavid du Colombier ulong time0;
1089a747e4fSDavid du Colombier
1099a747e4fSDavid du Colombier static void
fillstat(Dir * d,uvlong path,ulong length,char * ext)1109a747e4fSDavid du Colombier fillstat(Dir *d, uvlong path, ulong length, char *ext)
1119a747e4fSDavid du Colombier {
1129a747e4fSDavid du Colombier Tab *t;
1139a747e4fSDavid du Colombier int type;
1149a747e4fSDavid du Colombier char buf[32];
1159a747e4fSDavid du Colombier
1169a747e4fSDavid du Colombier memset(d, 0, sizeof(*d));
1179a747e4fSDavid du Colombier d->uid = estrdup("web");
1189a747e4fSDavid du Colombier d->gid = estrdup("web");
1199a747e4fSDavid du Colombier d->qid.path = path;
1209a747e4fSDavid du Colombier d->atime = d->mtime = time0;
1219a747e4fSDavid du Colombier d->length = length;
1229a747e4fSDavid du Colombier type = TYPE(path);
1239a747e4fSDavid du Colombier t = &tab[type];
1249a747e4fSDavid du Colombier if(type == Qbodyext) {
1259a747e4fSDavid du Colombier snprint(buf, sizeof buf, "body.%s", ext == nil ? "xxx" : ext);
1269a747e4fSDavid du Colombier d->name = estrdup(buf);
1279a747e4fSDavid du Colombier }
1289a747e4fSDavid du Colombier else if(t->name)
1299a747e4fSDavid du Colombier d->name = estrdup(t->name);
1309a747e4fSDavid du Colombier else{ /* client directory */
1319a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%ud", NUM(path));
1329a747e4fSDavid du Colombier d->name = estrdup(buf);
1339a747e4fSDavid du Colombier }
1349a747e4fSDavid du Colombier d->qid.type = t->mode>>24;
1359a747e4fSDavid du Colombier d->mode = t->mode;
1369a747e4fSDavid du Colombier }
1379a747e4fSDavid du Colombier
1389a747e4fSDavid du Colombier static void
fsstat(Req * r)1399a747e4fSDavid du Colombier fsstat(Req *r)
1409a747e4fSDavid du Colombier {
1419a747e4fSDavid du Colombier fillstat(&r->d, r->fid->qid.path, 0, nil);
1429a747e4fSDavid du Colombier respond(r, nil);
1439a747e4fSDavid du Colombier }
1449a747e4fSDavid du Colombier
1459a747e4fSDavid du Colombier static int
rootgen(int i,Dir * d,void *)1469a747e4fSDavid du Colombier rootgen(int i, Dir *d, void*)
1479a747e4fSDavid du Colombier {
1489a747e4fSDavid du Colombier char buf[32];
1499a747e4fSDavid du Colombier
1509a747e4fSDavid du Colombier i += Qroot+1;
1519a747e4fSDavid du Colombier if(i < Qclient){
1529a747e4fSDavid du Colombier fillstat(d, i, 0, nil);
1539a747e4fSDavid du Colombier return 0;
1549a747e4fSDavid du Colombier }
1559a747e4fSDavid du Colombier i -= Qclient;
1569a747e4fSDavid du Colombier if(i < nclient){
1579a747e4fSDavid du Colombier fillstat(d, PATH(Qclient, i), 0, nil);
1589a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%d", i);
1599a747e4fSDavid du Colombier free(d->name);
1609a747e4fSDavid du Colombier d->name = estrdup(buf);
1619a747e4fSDavid du Colombier return 0;
1629a747e4fSDavid du Colombier }
1639a747e4fSDavid du Colombier return -1;
1649a747e4fSDavid du Colombier }
1659a747e4fSDavid du Colombier
1669a747e4fSDavid du Colombier static int
clientgen(int i,Dir * d,void * aux)1679a747e4fSDavid du Colombier clientgen(int i, Dir *d, void *aux)
1689a747e4fSDavid du Colombier {
1699a747e4fSDavid du Colombier Client *c;
1709a747e4fSDavid du Colombier
1719a747e4fSDavid du Colombier c = aux;
1729a747e4fSDavid du Colombier i += Qclient+1;
1739a747e4fSDavid du Colombier if(i <= Qparsed){
1749a747e4fSDavid du Colombier fillstat(d, PATH(i, c->num), 0, c->ext);
1759a747e4fSDavid du Colombier return 0;
1769a747e4fSDavid du Colombier }
1779a747e4fSDavid du Colombier return -1;
1789a747e4fSDavid du Colombier }
1799a747e4fSDavid du Colombier
1809a747e4fSDavid du Colombier static int
parsedgen(int i,Dir * d,void * aux)1819a747e4fSDavid du Colombier parsedgen(int i, Dir *d, void *aux)
1829a747e4fSDavid du Colombier {
1839a747e4fSDavid du Colombier Client *c;
1849a747e4fSDavid du Colombier
1859a747e4fSDavid du Colombier c = aux;
1869a747e4fSDavid du Colombier i += Qparsed+1;
1879a747e4fSDavid du Colombier if(i < Qend){
1889a747e4fSDavid du Colombier fillstat(d, PATH(i, c->num), 0, nil);
1899a747e4fSDavid du Colombier return 0;
1909a747e4fSDavid du Colombier }
1919a747e4fSDavid du Colombier return -1;
1929a747e4fSDavid du Colombier }
1939a747e4fSDavid du Colombier
1949a747e4fSDavid du Colombier static void
fsread(Req * r)1959a747e4fSDavid du Colombier fsread(Req *r)
1969a747e4fSDavid du Colombier {
1979a747e4fSDavid du Colombier char *s;
1989a747e4fSDavid du Colombier char e[ERRMAX];
1999a747e4fSDavid du Colombier Client *c;
2009a747e4fSDavid du Colombier ulong path;
2019a747e4fSDavid du Colombier
2029a747e4fSDavid du Colombier path = r->fid->qid.path;
2039a747e4fSDavid du Colombier switch(TYPE(path)){
2049a747e4fSDavid du Colombier default:
2059a747e4fSDavid du Colombier snprint(e, sizeof e, "bug in webfs path=%lux\n", path);
2069a747e4fSDavid du Colombier respond(r, e);
2079a747e4fSDavid du Colombier break;
2089a747e4fSDavid du Colombier
2099a747e4fSDavid du Colombier case Qroot:
2109a747e4fSDavid du Colombier dirread9p(r, rootgen, nil);
2119a747e4fSDavid du Colombier respond(r, nil);
2129a747e4fSDavid du Colombier break;
2139a747e4fSDavid du Colombier
2149a747e4fSDavid du Colombier case Qrootctl:
2159a747e4fSDavid du Colombier globalctlread(r);
2169a747e4fSDavid du Colombier break;
2179a747e4fSDavid du Colombier
2189a747e4fSDavid du Colombier case Qcookies:
2199a747e4fSDavid du Colombier cookieread(r);
2209a747e4fSDavid du Colombier break;
2219a747e4fSDavid du Colombier
2229a747e4fSDavid du Colombier case Qclient:
2239a747e4fSDavid du Colombier dirread9p(r, clientgen, client[NUM(path)]);
2249a747e4fSDavid du Colombier respond(r, nil);
2259a747e4fSDavid du Colombier break;
2269a747e4fSDavid du Colombier
2279a747e4fSDavid du Colombier case Qctl:
2289a747e4fSDavid du Colombier ctlread(r, client[NUM(path)]);
2299a747e4fSDavid du Colombier break;
2309a747e4fSDavid du Colombier
2319a747e4fSDavid du Colombier case Qcontenttype:
2329a747e4fSDavid du Colombier c = client[NUM(path)];
2339a747e4fSDavid du Colombier if(c->contenttype == nil)
2349a747e4fSDavid du Colombier r->ofcall.count = 0;
2359a747e4fSDavid du Colombier else
2369a747e4fSDavid du Colombier readstr(r, c->contenttype);
2379a747e4fSDavid du Colombier respond(r, nil);
2389a747e4fSDavid du Colombier break;
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier case Qpostbody:
2419a747e4fSDavid du Colombier c = client[NUM(path)];
2429a747e4fSDavid du Colombier readbuf(r, c->postbody, c->npostbody);
2439a747e4fSDavid du Colombier respond(r, nil);
2449a747e4fSDavid du Colombier break;
2459a747e4fSDavid du Colombier
2469a747e4fSDavid du Colombier case Qbody:
2479a747e4fSDavid du Colombier case Qbodyext:
2489a747e4fSDavid du Colombier c = client[NUM(path)];
2499a747e4fSDavid du Colombier if(c->iobusy){
2509a747e4fSDavid du Colombier respond(r, "already have i/o pending");
2519a747e4fSDavid du Colombier break;
2529a747e4fSDavid du Colombier }
2539a747e4fSDavid du Colombier c->iobusy = 1;
2549a747e4fSDavid du Colombier sendp(c->creq, r);
2559a747e4fSDavid du Colombier break;
2569a747e4fSDavid du Colombier
2579a747e4fSDavid du Colombier case Qparsed:
2589a747e4fSDavid du Colombier dirread9p(r, parsedgen, client[NUM(path)]);
2599a747e4fSDavid du Colombier respond(r, nil);
2609a747e4fSDavid du Colombier break;
2619a747e4fSDavid du Colombier
2629a747e4fSDavid du Colombier case Qurl:
2639a747e4fSDavid du Colombier case Qscheme:
2649a747e4fSDavid du Colombier case Qschemedata:
2659a747e4fSDavid du Colombier case Quser:
2669a747e4fSDavid du Colombier case Qpasswd:
2679a747e4fSDavid du Colombier case Qhost:
2689a747e4fSDavid du Colombier case Qport:
2699a747e4fSDavid du Colombier case Qpath:
2709a747e4fSDavid du Colombier case Qquery:
2719a747e4fSDavid du Colombier case Qfragment:
2729a747e4fSDavid du Colombier case Qftptype:
2739a747e4fSDavid du Colombier c = client[NUM(path)];
2749a747e4fSDavid du Colombier r->ofcall.count = 0;
275d9306527SDavid du Colombier if(c->url != nil
276*9dfc0cb2SDavid du Colombier && (s = *(char**)((uintptr)c->url+tab[TYPE(path)].offset)) != nil)
2779a747e4fSDavid du Colombier readstr(r, s);
2789a747e4fSDavid du Colombier respond(r, nil);
2799a747e4fSDavid du Colombier break;
2809a747e4fSDavid du Colombier }
2819a747e4fSDavid du Colombier }
2829a747e4fSDavid du Colombier
2839a747e4fSDavid du Colombier static void
fswrite(Req * r)2849a747e4fSDavid du Colombier fswrite(Req *r)
2859a747e4fSDavid du Colombier {
2869a747e4fSDavid du Colombier int m;
2879a747e4fSDavid du Colombier ulong path;
2889a747e4fSDavid du Colombier char e[ERRMAX], *buf, *cmd, *arg;
2899a747e4fSDavid du Colombier Client *c;
2909a747e4fSDavid du Colombier
2919a747e4fSDavid du Colombier path = r->fid->qid.path;
2929a747e4fSDavid du Colombier switch(TYPE(path)){
2939a747e4fSDavid du Colombier default:
2949a747e4fSDavid du Colombier snprint(e, sizeof e, "bug in webfs path=%lux\n", path);
2959a747e4fSDavid du Colombier respond(r, e);
2969a747e4fSDavid du Colombier break;
2979a747e4fSDavid du Colombier
2989a747e4fSDavid du Colombier case Qcookies:
2999a747e4fSDavid du Colombier cookiewrite(r);
3009a747e4fSDavid du Colombier break;
3019a747e4fSDavid du Colombier
3029a747e4fSDavid du Colombier case Qrootctl:
3039a747e4fSDavid du Colombier case Qctl:
3049a747e4fSDavid du Colombier if(r->ifcall.count >= 1024){
3059a747e4fSDavid du Colombier respond(r, "ctl message too long");
3069a747e4fSDavid du Colombier return;
3079a747e4fSDavid du Colombier }
3089a747e4fSDavid du Colombier buf = estredup(r->ifcall.data, (char*)r->ifcall.data+r->ifcall.count);
3099a747e4fSDavid du Colombier cmd = buf;
3109a747e4fSDavid du Colombier arg = strpbrk(cmd, "\t ");
3119a747e4fSDavid du Colombier if(arg){
3129a747e4fSDavid du Colombier *arg++ = '\0';
3139a747e4fSDavid du Colombier arg += strspn(arg, "\t ");
3149a747e4fSDavid du Colombier }else
3159a747e4fSDavid du Colombier arg = "";
3169a747e4fSDavid du Colombier r->ofcall.count = r->ifcall.count;
3179a747e4fSDavid du Colombier if(TYPE(path)==Qrootctl){
3189a747e4fSDavid du Colombier if(!ctlwrite(r, &globalctl, cmd, arg)
3199a747e4fSDavid du Colombier && !globalctlwrite(r, cmd, arg))
3209a747e4fSDavid du Colombier respond(r, "unknown control command");
3219a747e4fSDavid du Colombier }else{
3229a747e4fSDavid du Colombier c = client[NUM(path)];
3239a747e4fSDavid du Colombier if(!ctlwrite(r, &c->ctl, cmd, arg)
3249a747e4fSDavid du Colombier && !clientctlwrite(r, c, cmd, arg))
3259a747e4fSDavid du Colombier respond(r, "unknown control command");
3269a747e4fSDavid du Colombier }
3279a747e4fSDavid du Colombier free(buf);
3289a747e4fSDavid du Colombier break;
3299a747e4fSDavid du Colombier
3309a747e4fSDavid du Colombier case Qpostbody:
3319a747e4fSDavid du Colombier c = client[NUM(path)];
3329a747e4fSDavid du Colombier if(c->bodyopened){
3339a747e4fSDavid du Colombier respond(r, "cannot write postbody after opening body");
3349a747e4fSDavid du Colombier break;
3359a747e4fSDavid du Colombier }
3369a747e4fSDavid du Colombier if(r->ifcall.offset >= 128*1024*1024){ /* >128MB is probably a mistake */
3379a747e4fSDavid du Colombier respond(r, "offset too large");
3389a747e4fSDavid du Colombier break;
3399a747e4fSDavid du Colombier }
3409a747e4fSDavid du Colombier m = r->ifcall.offset + r->ifcall.count;
3419a747e4fSDavid du Colombier if(c->npostbody < m){
3429a747e4fSDavid du Colombier c->postbody = erealloc(c->postbody, m);
3439a747e4fSDavid du Colombier memset(c->postbody+c->npostbody, 0, m-c->npostbody);
3449a747e4fSDavid du Colombier c->npostbody = m;
3459a747e4fSDavid du Colombier }
3469a747e4fSDavid du Colombier memmove(c->postbody+r->ifcall.offset, r->ifcall.data, r->ifcall.count);
3479a747e4fSDavid du Colombier r->ofcall.count = r->ifcall.count;
3489a747e4fSDavid du Colombier respond(r, nil);
3499a747e4fSDavid du Colombier break;
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier }
3529a747e4fSDavid du Colombier
3539a747e4fSDavid du Colombier static void
fsopen(Req * r)3549a747e4fSDavid du Colombier fsopen(Req *r)
3559a747e4fSDavid du Colombier {
3569a747e4fSDavid du Colombier static int need[4] = { 4, 2, 6, 1 };
3579a747e4fSDavid du Colombier ulong path;
3589a747e4fSDavid du Colombier int n;
3599a747e4fSDavid du Colombier Client *c;
3609a747e4fSDavid du Colombier Tab *t;
3619a747e4fSDavid du Colombier
3629a747e4fSDavid du Colombier /*
3639a747e4fSDavid du Colombier * lib9p already handles the blatantly obvious.
3649a747e4fSDavid du Colombier * we just have to enforce the permissions we have set.
3659a747e4fSDavid du Colombier */
3669a747e4fSDavid du Colombier path = r->fid->qid.path;
3679a747e4fSDavid du Colombier t = &tab[TYPE(path)];
3689a747e4fSDavid du Colombier n = need[r->ifcall.mode&3];
3699a747e4fSDavid du Colombier if((n&t->mode) != n){
3709a747e4fSDavid du Colombier respond(r, "permission denied");
3719a747e4fSDavid du Colombier return;
3729a747e4fSDavid du Colombier }
3739a747e4fSDavid du Colombier
3749a747e4fSDavid du Colombier switch(TYPE(path)){
3759a747e4fSDavid du Colombier case Qcookies:
3769a747e4fSDavid du Colombier cookieopen(r);
3779a747e4fSDavid du Colombier break;
3789a747e4fSDavid du Colombier
3799a747e4fSDavid du Colombier case Qpostbody:
3809a747e4fSDavid du Colombier c = client[NUM(path)];
3819a747e4fSDavid du Colombier c->havepostbody++;
3829a747e4fSDavid du Colombier c->ref++;
3839a747e4fSDavid du Colombier respond(r, nil);
3849a747e4fSDavid du Colombier break;
3859a747e4fSDavid du Colombier
3869a747e4fSDavid du Colombier case Qbody:
3879a747e4fSDavid du Colombier case Qbodyext:
3889a747e4fSDavid du Colombier c = client[NUM(path)];
3899a747e4fSDavid du Colombier if(c->url == nil){
3909a747e4fSDavid du Colombier respond(r, "url is not yet set");
3919a747e4fSDavid du Colombier break;
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier c->bodyopened = 1;
3949a747e4fSDavid du Colombier c->ref++;
3959a747e4fSDavid du Colombier sendp(c->creq, r);
3969a747e4fSDavid du Colombier break;
3979a747e4fSDavid du Colombier
3989a747e4fSDavid du Colombier case Qclone:
3999a747e4fSDavid du Colombier n = newclient(0);
4009a747e4fSDavid du Colombier path = PATH(Qctl, n);
4019a747e4fSDavid du Colombier r->fid->qid.path = path;
4029a747e4fSDavid du Colombier r->ofcall.qid.path = path;
4039a747e4fSDavid du Colombier if(fsdebug)
4049a747e4fSDavid du Colombier fprint(2, "open clone => path=%lux\n", path);
4059a747e4fSDavid du Colombier t = &tab[Qctl];
4069a747e4fSDavid du Colombier /* fall through */
4079a747e4fSDavid du Colombier default:
4089a747e4fSDavid du Colombier if(t-tab >= Qclient)
4099a747e4fSDavid du Colombier client[NUM(path)]->ref++;
4109a747e4fSDavid du Colombier respond(r, nil);
4119a747e4fSDavid du Colombier break;
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier }
4149a747e4fSDavid du Colombier
4159a747e4fSDavid du Colombier static void
fsdestroyfid(Fid * fid)4169a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
4179a747e4fSDavid du Colombier {
4189a747e4fSDavid du Colombier sendp(cclunk, fid);
4199a747e4fSDavid du Colombier recvp(cclunkwait);
4209a747e4fSDavid du Colombier }
4219a747e4fSDavid du Colombier
4229a747e4fSDavid du Colombier static void
fsattach(Req * r)4239a747e4fSDavid du Colombier fsattach(Req *r)
4249a747e4fSDavid du Colombier {
4259a747e4fSDavid du Colombier if(r->ifcall.aname && r->ifcall.aname[0]){
4269a747e4fSDavid du Colombier respond(r, "invalid attach specifier");
4279a747e4fSDavid du Colombier return;
4289a747e4fSDavid du Colombier }
4299a747e4fSDavid du Colombier r->fid->qid.path = PATH(Qroot, 0);
4309a747e4fSDavid du Colombier r->fid->qid.type = QTDIR;
4319a747e4fSDavid du Colombier r->fid->qid.vers = 0;
4329a747e4fSDavid du Colombier r->ofcall.qid = r->fid->qid;
4339a747e4fSDavid du Colombier respond(r, nil);
4349a747e4fSDavid du Colombier }
4359a747e4fSDavid du Colombier
4369a747e4fSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)4379a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
4389a747e4fSDavid du Colombier {
4399a747e4fSDavid du Colombier int i, n;
4409a747e4fSDavid du Colombier ulong path;
4419a747e4fSDavid du Colombier char buf[32], *ext;
4429a747e4fSDavid du Colombier
4439a747e4fSDavid du Colombier path = fid->qid.path;
4449a747e4fSDavid du Colombier if(!(fid->qid.type&QTDIR))
4459a747e4fSDavid du Colombier return "walk in non-directory";
4469a747e4fSDavid du Colombier
4479a747e4fSDavid du Colombier if(strcmp(name, "..") == 0){
4489a747e4fSDavid du Colombier switch(TYPE(path)){
4499a747e4fSDavid du Colombier case Qparsed:
4509a747e4fSDavid du Colombier qid->path = PATH(Qclient, NUM(path));
4519a747e4fSDavid du Colombier qid->type = tab[Qclient].mode>>24;
4529a747e4fSDavid du Colombier return nil;
4539a747e4fSDavid du Colombier case Qclient:
4549a747e4fSDavid du Colombier case Qroot:
4559a747e4fSDavid du Colombier qid->path = PATH(Qroot, 0);
4569a747e4fSDavid du Colombier qid->type = tab[Qroot].mode>>24;
4579a747e4fSDavid du Colombier return nil;
4589a747e4fSDavid du Colombier default:
4599a747e4fSDavid du Colombier return "bug in fswalk1";
4609a747e4fSDavid du Colombier }
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier
4639a747e4fSDavid du Colombier i = TYPE(path)+1;
4649a747e4fSDavid du Colombier for(; i<nelem(tab); i++){
4659a747e4fSDavid du Colombier if(i==Qclient){
4669a747e4fSDavid du Colombier n = atoi(name);
4679a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%d", n);
4689a747e4fSDavid du Colombier if(n < nclient && strcmp(buf, name) == 0){
4699a747e4fSDavid du Colombier qid->path = PATH(i, n);
4709a747e4fSDavid du Colombier qid->type = tab[i].mode>>24;
4719a747e4fSDavid du Colombier return nil;
4729a747e4fSDavid du Colombier }
4739a747e4fSDavid du Colombier break;
4749a747e4fSDavid du Colombier }
4759a747e4fSDavid du Colombier if(i==Qbodyext){
4769a747e4fSDavid du Colombier ext = client[NUM(path)]->ext;
4779a747e4fSDavid du Colombier snprint(buf, sizeof buf, "body.%s", ext == nil ? "xxx" : ext);
4789a747e4fSDavid du Colombier if(strcmp(buf, name) == 0){
4799a747e4fSDavid du Colombier qid->path = PATH(i, NUM(path));
4809a747e4fSDavid du Colombier qid->type = tab[i].mode>>24;
4819a747e4fSDavid du Colombier return nil;
4829a747e4fSDavid du Colombier }
4839a747e4fSDavid du Colombier }
4849a747e4fSDavid du Colombier else if(strcmp(name, tab[i].name) == 0){
4859a747e4fSDavid du Colombier qid->path = PATH(i, NUM(path));
4869a747e4fSDavid du Colombier qid->type = tab[i].mode>>24;
4879a747e4fSDavid du Colombier return nil;
4889a747e4fSDavid du Colombier }
4899a747e4fSDavid du Colombier if(tab[i].mode&DMDIR)
4909a747e4fSDavid du Colombier break;
4919a747e4fSDavid du Colombier }
4929a747e4fSDavid du Colombier return "directory entry not found";
4939a747e4fSDavid du Colombier }
4949a747e4fSDavid du Colombier
4959a747e4fSDavid du Colombier static void
fsflush(Req * r)4969a747e4fSDavid du Colombier fsflush(Req *r)
4979a747e4fSDavid du Colombier {
4989a747e4fSDavid du Colombier Req *or;
4999a747e4fSDavid du Colombier int t;
5009a747e4fSDavid du Colombier Client *c;
5019a747e4fSDavid du Colombier ulong path;
5029a747e4fSDavid du Colombier
5039a747e4fSDavid du Colombier or=r;
5049a747e4fSDavid du Colombier while(or->ifcall.type==Tflush)
5059a747e4fSDavid du Colombier or = or->oldreq;
5069a747e4fSDavid du Colombier
5079a747e4fSDavid du Colombier if(or->ifcall.type != Tread && or->ifcall.type != Topen)
5089a747e4fSDavid du Colombier abort();
5099a747e4fSDavid du Colombier
5109a747e4fSDavid du Colombier path = or->fid->qid.path;
5119a747e4fSDavid du Colombier t = TYPE(path);
5129a747e4fSDavid du Colombier if(t != Qbody && t != Qbodyext)
5139a747e4fSDavid du Colombier abort();
5149a747e4fSDavid du Colombier
5159a747e4fSDavid du Colombier c = client[NUM(path)];
5169a747e4fSDavid du Colombier sendp(c->creq, r);
5173ff48bf5SDavid du Colombier iointerrupt(c->io);
5189a747e4fSDavid du Colombier }
5199a747e4fSDavid du Colombier
5209a747e4fSDavid du Colombier static void
fsthread(void *)5219a747e4fSDavid du Colombier fsthread(void*)
5229a747e4fSDavid du Colombier {
5239a747e4fSDavid du Colombier ulong path;
5249a747e4fSDavid du Colombier Alt a[3];
5259a747e4fSDavid du Colombier Fid *fid;
5269a747e4fSDavid du Colombier Req *r;
5279a747e4fSDavid du Colombier
5289a747e4fSDavid du Colombier threadsetname("fsthread");
5299a747e4fSDavid du Colombier plumbstart();
5309a747e4fSDavid du Colombier
5319a747e4fSDavid du Colombier a[0].op = CHANRCV;
5329a747e4fSDavid du Colombier a[0].c = cclunk;
5339a747e4fSDavid du Colombier a[0].v = &fid;
5349a747e4fSDavid du Colombier a[1].op = CHANRCV;
5359a747e4fSDavid du Colombier a[1].c = creq;
5369a747e4fSDavid du Colombier a[1].v = &r;
5379a747e4fSDavid du Colombier a[2].op = CHANEND;
5389a747e4fSDavid du Colombier
5399a747e4fSDavid du Colombier for(;;){
5409a747e4fSDavid du Colombier switch(alt(a)){
5419a747e4fSDavid du Colombier case 0:
5429a747e4fSDavid du Colombier path = fid->qid.path;
5439a747e4fSDavid du Colombier if(TYPE(path)==Qcookies)
5449a747e4fSDavid du Colombier cookieclunk(fid);
5459a747e4fSDavid du Colombier if(fid->omode != -1 && TYPE(path) >= Qclient)
5469a747e4fSDavid du Colombier closeclient(client[NUM(path)]);
5479a747e4fSDavid du Colombier sendp(cclunkwait, nil);
5489a747e4fSDavid du Colombier break;
5499a747e4fSDavid du Colombier case 1:
5509a747e4fSDavid du Colombier switch(r->ifcall.type){
5519a747e4fSDavid du Colombier case Tattach:
5529a747e4fSDavid du Colombier fsattach(r);
5539a747e4fSDavid du Colombier break;
5549a747e4fSDavid du Colombier case Topen:
5559a747e4fSDavid du Colombier fsopen(r);
5569a747e4fSDavid du Colombier break;
5579a747e4fSDavid du Colombier case Tread:
5589a747e4fSDavid du Colombier fsread(r);
5599a747e4fSDavid du Colombier break;
5609a747e4fSDavid du Colombier case Twrite:
5619a747e4fSDavid du Colombier fswrite(r);
5629a747e4fSDavid du Colombier break;
5639a747e4fSDavid du Colombier case Tstat:
5649a747e4fSDavid du Colombier fsstat(r);
5659a747e4fSDavid du Colombier break;
5669a747e4fSDavid du Colombier case Tflush:
5679a747e4fSDavid du Colombier fsflush(r);
5689a747e4fSDavid du Colombier break;
5699a747e4fSDavid du Colombier default:
5709a747e4fSDavid du Colombier respond(r, "bug in fsthread");
5719a747e4fSDavid du Colombier break;
5729a747e4fSDavid du Colombier }
5739a747e4fSDavid du Colombier sendp(creqwait, 0);
5749a747e4fSDavid du Colombier break;
5759a747e4fSDavid du Colombier }
5769a747e4fSDavid du Colombier }
5779a747e4fSDavid du Colombier }
5789a747e4fSDavid du Colombier
5799a747e4fSDavid du Colombier static void
fssend(Req * r)5809a747e4fSDavid du Colombier fssend(Req *r)
5819a747e4fSDavid du Colombier {
5829a747e4fSDavid du Colombier sendp(creq, r);
5839a747e4fSDavid du Colombier recvp(creqwait); /* avoids need to deal with spurious flushes */
5849a747e4fSDavid du Colombier }
5859a747e4fSDavid du Colombier
5869a747e4fSDavid du Colombier void
initfs(void)5879a747e4fSDavid du Colombier initfs(void)
5889a747e4fSDavid du Colombier {
5899a747e4fSDavid du Colombier time0 = time(0);
5909a747e4fSDavid du Colombier creq = chancreate(sizeof(void*), 0);
5919a747e4fSDavid du Colombier creqwait = chancreate(sizeof(void*), 0);
5929a747e4fSDavid du Colombier cclunk = chancreate(sizeof(void*), 0);
5939a747e4fSDavid du Colombier cclunkwait = chancreate(sizeof(void*), 0);
5949a747e4fSDavid du Colombier procrfork(fsthread, nil, STACK, RFNAMEG);
5959a747e4fSDavid du Colombier }
5969a747e4fSDavid du Colombier
5979a747e4fSDavid du Colombier void
takedown(Srv *)5989a747e4fSDavid du Colombier takedown(Srv*)
5999a747e4fSDavid du Colombier {
6009a747e4fSDavid du Colombier closecookies();
6019a747e4fSDavid du Colombier threadexitsall("done");
6029a747e4fSDavid du Colombier }
6039a747e4fSDavid du Colombier
6049a747e4fSDavid du Colombier Srv fs =
6059a747e4fSDavid du Colombier {
6069a747e4fSDavid du Colombier .attach= fssend,
6079a747e4fSDavid du Colombier .destroyfid= fsdestroyfid,
6089a747e4fSDavid du Colombier .walk1= fswalk1,
6099a747e4fSDavid du Colombier .open= fssend,
6109a747e4fSDavid du Colombier .read= fssend,
6119a747e4fSDavid du Colombier .write= fssend,
6129a747e4fSDavid du Colombier .stat= fssend,
6139a747e4fSDavid du Colombier .flush= fssend,
6149a747e4fSDavid du Colombier .end= takedown,
6159a747e4fSDavid du Colombier };
6169a747e4fSDavid du Colombier
617