#include #include #include #include #include #include #include <9p.h> ulong messagesize = IOHDRSZ+8192; char statbuf[IOHDRSZ+8192]; int subfd; int editfd = -1; int tidefd = -1; int old9p = -1; uchar* rxbuf; uchar* txbuf; char Ewstatbuffer[] = "bogus wstat buffer"; void usage(void) { fprint(2, "usage: substfs [...] /srv/service | -c command | -n networkaddress [remote2local local2remote]\n"); exits("usage"); } void* emalloc(ulong n) { void *p; p = malloc(n); if(p == 0) sysfatal("malloc(%ld) fails", (long)n); memset(p, 0, n); return p; } void getfcallnew(int fd, Fcall *fc, int have) { int len; if(have > BIT32SZ) sysfatal("cannot happen: %r"); if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) sysfatal("couldn't read message: %r"); len = GBIT32(rxbuf); if(len <= BIT32SZ) sysfatal("bogus message"); len -= BIT32SZ; if(readn(fd, rxbuf+BIT32SZ, len) != len) sysfatal("short message: %r"); if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) sysfatal("badly sized message type %d: %r", rxbuf[0]); } void putfcallnew(int wfd, Fcall *tx) { ulong n; if((n = convS2M(tx, txbuf, messagesize)) == 0) sysfatal("couldn't format message type %d: %r", tx->type); fprint(2, "substfs: %F\n", tx); if(write(wfd, txbuf, n) != n) sysfatal("couldn't send message: %r"); } void getfcall(int fd, Fcall *fc) { //getfcallnew(fd, fc, 0); int res; res = read9pmsg(fd, rxbuf, messagesize); if (res < 0) { // fprint(2, "%us", rxbuf); sysfatal("couldn't read message: %r"); } if (res == 0) sysfatal("end of file on fd"); if(convM2S(rxbuf, messagesize, fc) == 0) sysfatal("badly sized message type %d: %r", rxbuf[0]); fprint(2, "substfs: %F\n", fc); } static long dirpackage(uchar *buf, long ts, Dir **d) { char *s; long ss, i, n, nn, m; *d = nil; if(ts <= 0) return 0; /* * first find number of all stats, check they look like stats, & size all associated strings */ ss = 0; n = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(statcheck(&buf[i], m) < 0) break; ss += m; n++; } if(i != ts) return -1; *d = malloc(n * sizeof(Dir) + ss); if(*d == nil) return -1; /* * then convert all buffers */ s = (char*)*d + n * sizeof(Dir); nn = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16((uchar*)&buf[i]); if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ free(*d); *d = nil; return -1; } nn++; s += m; } return nn; } void mydirread9p(Fcall *rx, Fcall *tx, Dir* d, long ndir) { int start; uchar *p, *ep; uint rv; if(rx->offset == 0) start = 0; else // start = r->fid->dirindex; start = 0; p = (uchar*)tx->data; ep = p+rx->count; while((p < ep) && (start < ndir)){ rv = convD2M(&d[start], p, ep-p); if(rv <= BIT16SZ) break; p += rv; start++; } // r->fid->dirindex = start; tx->count = p - (uchar*)tx->data; } static char* do_edit(int fd, char *src, char *fn) { char buf[1024]; if (fd >= 0) { fprint(2, "substfs: %swrite... %s\n", fn, src); write(fd, src, strlen(src)+1); fprint(2, "substfs: %swrite... done\n", fn); fprint(2, "substfs: %sread... \n", fn); read(fd, buf, sizeof(buf)); fprint(2, "substfs: %sread... %s\n", fn, buf); if (strcmp(src, buf) != 0) { return strdup(buf); } } return src; } static char* do_tide(int fd, char *src, char *fn) { char buf[1024]; char *p; if (fd >= 0) { fprint(2, "substfs: %swrite... %s\n", fn, src); fprint(fd, "%s\n", src); fprint(2, "substfs: %swrite... done\n", fn); fprint(2, "substfs: %sread... \n", fn); read(fd, buf, sizeof(buf)); if (p = strchr(buf, '\n')) *p = '\0'; fprint(2, "substfs: %sread... %s\n", fn, buf); if (strcmp(src, buf) != 0) { return strdup(buf); } } return src; } static char* edit(char *src) { return do_edit(editfd, src, "edit"); } static char* tide(char *src) { return do_tide(tidefd, src, "tide"); } static void handle(Fcall *rx, Fcall *tx) { fprint(2, "substfs: putfcallnew...\n"); putfcallnew(subfd, rx); fprint(2, "substfs: putfcallnew... done\n"); fprint(2, "substfs: getfcall... \n"); getfcall(subfd, tx); fprint(2, "substfs: getfcall... done\n"); } void seterror(Fcall *f, char *error) { f->type = Rerror; f->ename = error ? error : "programmer error"; } void rversion(Fcall *rx, Fcall *tx, Fidpool *fp) { USED(fp); handle(rx, tx); } void rauth(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f = allocfid(fp, rx->afid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); f->qid = tx->qid; closefid(f); } void rattach(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f = allocfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); f->qid = tx->qid; closefid(f); } void rwalk(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f; long i; for (i = 0; i < rx->nwname; i++) { rx->wname[i] = tide(rx->wname[i]); } handle(rx, tx); if ((rx->nwname == tx->nwqid)) { f= allocfid(fp, rx->newfid); fprint(2, "substfs: fid: %ld\n", f->fid); f->qid = tx->wqid[tx->nwqid-1]; closefid(f); } else { fprint(2, "substfs: walk failed\n"); } } void ropen(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f= lookupfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); f->qid = tx->qid; closefid(f); } void rcreate(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f; handle(rx, tx); if (tx->type != Rerror) { f= allocfid(fp, rx->fid); fprint(2, "substfs: fid: %ld\n", f->fid); f->qid = tx->qid; closefid(f); } else { fprint(2, "substfs: create failed\n"); } } void rread(Fcall *rx, Fcall *tx, Fidpool *fp) { Dir *d; long nd; long i; Fid *f= lookupfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); fprint(2, "substfs: qid.type: %x\n", f->qid.type); if (f->qid.type&QTDIR) { fprint(2, "substfs: directory!\n"); nd = dirpackage((uchar*)tx->data, tx->count, &d); for (i=0; i < nd; i++) { fprint(2, "substfs-rread[%ld]: %D\n", i, &d[i]); d[i].name = edit(d[i].name); } mydirread9p(rx, tx, d, nd); } else { fprint(2, "substfs: NO directory!\n"); } closefid(f); } void rwrite(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f= lookupfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); closefid(f); } void rclunk(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f= lookupfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); removefid(fp, rx->fid); } void rremove(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f= lookupfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); closefid(f); } void rstat(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f= lookupfid(fp, rx->fid); Dir d; handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); if (convM2D(tx->stat, tx->nstat, &d, statbuf) <= BIT16SZ){ seterror(tx, Ewstatbuffer); fprint(2, "substfs-rstat: Ewstatbuffer\n"); } else { fprint(2, "substfs-rstat: %D\n", &d); } closefid(f); } void rwstat(Fcall *rx, Fcall *tx, Fidpool *fp) { Fid *f= lookupfid(fp, rx->fid); handle(rx, tx); fprint(2, "substfs: fid: %ld\n", f->fid); closefid(f); } void fidnop(Fid*) { } void serve(int rfd, int wfd) { Fcall rx, tx; Fidpool* fp; fp = allocfidpool(fidnop); for(;;){ getfcall(rfd, &rx); if(chatty9p) fprint(2, "<- %F\n", &rx); memset(&tx, 0, sizeof tx); tx.type = rx.type+1; tx.tag = rx.tag; switch(rx.type){ case Tflush: break; case Tversion: rversion(&rx, &tx, fp); break; case Tauth: rauth(&rx, &tx, fp); break; case Tattach: rattach(&rx, &tx, fp); break; case Twalk: rwalk(&rx, &tx, fp); break; case Tstat: // tx.stat = databuf; rstat(&rx, &tx, fp); break; case Twstat: rwstat(&rx, &tx, fp); break; case Topen: ropen(&rx, &tx, fp); break; case Tcreate: rcreate(&rx, &tx, fp); break; case Tread: // tx.data = databuf; rread(&rx, &tx, fp); break; case Twrite: rwrite(&rx, &tx, fp); break; case Tclunk: rclunk(&rx, &tx, fp); break; case Tremove: rremove(&rx, &tx, fp); break; default: fprint(2, "unknown message %F\n", &rx); seterror(&tx, "bad message"); break; } if(chatty9p) fprint(2, "-> %F\n", &tx); putfcallnew(wfd, &tx); } } int connectcmd(char *cmd) { int p[2]; if(pipe(p) < 0) return -1; switch(fork()){ case -1: fprint(2, "fork failed: %r\n"); _exits("exec"); case 0: dup(p[0], 0); dup(p[0], 1); close(p[1]); execl("/bin/rc", "rc", "-c", cmd, nil); fprint(2, "exec failed: %r\n"); _exits("exec"); default: close(p[0]); return p[1]; } } void main(int argc, char **argv) { char *mtpt, *service; int cmd, net; int sfd[2]; mtpt = nil; service = nil; cmd = 0; net = 0; ARGBEGIN{ case 'D': chatty9p++; break; case 's': service = EARGF(usage()); break; case 'm': mtpt = EARGF(usage()); break; case 'c': cmd = 1; break; case 'n': net = 1; break; default: usage(); }ARGEND if(argc < 1) usage(); fmtinstall('D', dirfmt); fmtinstall('M', dirmodefmt); fmtinstall('F', fcallfmt); rxbuf = emalloc(messagesize); txbuf = emalloc(messagesize); if(cmd && net) usage(); if(cmd) subfd = connectcmd(argv[0]); else if(net){ subfd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0); if(subfd < 0) sysfatal("dial: %r"); }else{ subfd = open(argv[0], ORDWR); if(subfd < 0) sysfatal("open: %r"); } //postmountsrv(&substsrv, service, mtpt, MREPL); //exits(nil); if (argc == 3) { editfd = connectcmd(argv[1]); tidefd = connectcmd(argv[2]); } if(pipe(sfd) < 0) sysfatal("pipe: %r"); if(service) if(postfd(service, sfd[0]) < 0) sysfatal("postfd %s: %r", service); serve(sfd[1], sfd[1]); }