#include #include #include #include #include "usb.h" #include "usbfs.h" typedef struct Rpc Rpc; enum { Incr = 3, /* increments for fs array */ Dtop = 0, /* high 32 bits for / */ Qdir = 0, /* low 32 bits for /devdir */ }; QLock fslck; static Usbfs** fs; static int nfs; static int fsused; static int exitonclose = 1; void usbfsexits(int y) { exitonclose = y; } static int qiddev(uvlong path) { return (int)(path>>32) & 0xFF; } static int qidfile(uvlong path) { return (int)(path & 0xFFFFFFFFULL); } static uvlong mkqid(int qd, int qf) { return ((uvlong)qd << 32) | (uvlong)qf; } void usbfsdirdump(void) { int i; qlock(&fslck); fprint(2, "%s: fs list: (%d used %d total)\n", argv0, fsused, nfs); for(i = 1; i < nfs; i++) if(fs[i] != nil) if(fs[i]->dev != nil) fprint(2, "%s\t%s dev %#p refs %ld\n", argv0, fs[i]->name, fs[i]->dev, fs[i]->dev->ref); else fprint(2, "%s:\t%s\n", argv0, fs[i]->name); qunlock(&fslck); } void usbfsadd(Usbfs *dfs) { int i, j; dprint(2, "%s: fsadd %s\n", argv0, dfs->name); qlock(&fslck); for(i = 1; i < nfs; i++) if(fs[i] == nil) break; if(i >= nfs){ if((nfs%Incr) == 0){ fs = realloc(fs, sizeof(Usbfs*) * (nfs+Incr)); if(fs == nil) sysfatal("realloc: %r"); for(j = nfs; j < nfs+Incr; j++) fs[j] = nil; } if(nfs == 0) /* do not use entry 0 */ nfs++; fs[nfs++] = dfs; }else fs[i] = dfs; dfs->qid = mkqid(i, 0); fsused++; qunlock(&fslck); } static void usbfsdelnth(int i) { if(fs[i] != nil){ dprint(2, "%s: fsdel %s", argv0, fs[i]->name); if(fs[i]->dev != nil){ dprint(2, " dev %#p ref %ld\n", fs[i]->dev, fs[i]->dev->ref); }else dprint(2, "no dev\n"); if(fs[i]->end != nil) fs[i]->end(fs[i]); closedev(fs[i]->dev); fsused--; } fs[i] = nil; if(fsused == 0 && exitonclose != 0){ fprint(2, "%s: all file systems gone: exiting\n", argv0); threadexitsall(nil); } } void usbfsdel(Usbfs *dfs) { int i; qlock(&fslck); for(i = 0; i < nfs; i++) if(dfs == nil || fs[i] == dfs){ usbfsdelnth(i); if(dfs != nil) break; } qunlock(&fslck); } static void fsend(Usbfs*) { dprint(2, "%s: fsend\n", argv0); usbfsdel(nil); } void usbfsgone(char *dir) { int i; qlock(&fslck); /* devices may have more than one fs */ for(i = 0; i < nfs; i++) if(fs[i] != nil && fs[i]->dev != nil) if(strcmp(fs[i]->dev->dir, dir) == 0) usbfsdelnth(i); qunlock(&fslck); } static void fsclone(Usbfs*, Fid *o, Fid *n) { int qd; Dev *dev; void (*xfsclone)(Usbfs *fs, Fid *of, Fid *nf); xfsclone = nil; dev = nil; qd = qiddev(o->qid.path); qlock(&fslck); if(qd != Dtop && fs[qd] != nil && fs[qd]->clone != nil){ dev = fs[qd]->dev; if(dev != nil) incref(dev); xfsclone = fs[qd]->clone; } qunlock(&fslck); if(xfsclone != nil){ xfsclone(fs[qd], o, n); } if(dev != nil) closedev(dev); } static int fswalk(Usbfs*, Fid *fid, char *name) { Qid q; int qd, qf; int i; int rc; Dev *dev; Dir d; int (*xfswalk)(Usbfs *fs, Fid *f, char *name); q = fid->qid; qd = qiddev(q.path); qf = qidfile(q.path); q.type = QTDIR; q.vers = 0; if(strcmp(name, "..") == 0) if(qd == Dtop || qf == Qdir){ q.path = mkqid(Dtop, Qdir); fid->qid = q; return 0; } if(qd != 0){ qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfswalk = fs[qd]->walk; qunlock(&fslck); rc = xfswalk(fs[qd], fid, name); if(dev != nil) closedev(dev); return rc; } qlock(&fslck); for(i = 0; i < nfs; i++) if(fs[i] != nil && strcmp(name, fs[i]->name) == 0){ q.path = mkqid(i, Qdir); fs[i]->stat(fs[i], q, &d); /* may be a file */ fid->qid = d.qid; qunlock(&fslck); return 0; } qunlock(&fslck); werrstr(Enotfound); return -1; } static int fsopen(Usbfs*, Fid *fid, int mode) { int qd; int rc; Dev *dev; int (*xfsopen)(Usbfs *fs, Fid *f, int mode); qd = qiddev(fid->qid.path); if(qd == Dtop) return 0; qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfsopen = fs[qd]->open; qunlock(&fslck); if(xfsopen != nil) rc = xfsopen(fs[qd], fid, mode); else rc = 0; if(dev != nil) closedev(dev); return rc; } static int dirgen(Usbfs*, Qid, int n, Dir *d, void *) { int i; Dev *dev; char *nm; qlock(&fslck); for(i = 0; i < nfs; i++) if(fs[i] != nil && n-- == 0){ d->qid.type = QTDIR; d->qid.path = mkqid(i, Qdir); d->qid.vers = 0; dev = fs[i]->dev; if(dev != nil) incref(dev); nm = d->name; fs[i]->stat(fs[i], d->qid, d); d->name = nm; strncpy(d->name, fs[i]->name, Namesz); if(dev != nil) closedev(dev); qunlock(&fslck); return 0; } qunlock(&fslck); return -1; } static long fsread(Usbfs*, Fid *fid, void *data, long cnt, vlong off) { int qd; int rc; Dev *dev; Qid q; long (*xfsread)(Usbfs *fs, Fid *f, void *data, long count, vlong ); q = fid->qid; qd = qiddev(q.path); if(qd == Dtop) return usbdirread(nil, q, data, cnt, off, dirgen, nil); qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfsread = fs[qd]->read; qunlock(&fslck); rc = xfsread(fs[qd], fid, data, cnt, off); if(dev != nil) closedev(dev); return rc; } static long fswrite(Usbfs*, Fid *fid, void *data, long cnt, vlong off) { int qd; int rc; Dev *dev; long (*xfswrite)(Usbfs *fs, Fid *f, void *data, long count, vlong ); qd = qiddev(fid->qid.path); if(qd == Dtop) sysfatal("fswrite: not for usbd /"); qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfswrite = fs[qd]->write; qunlock(&fslck); rc = xfswrite(fs[qd], fid, data, cnt, off); if(dev != nil) closedev(dev); return rc; } static void fsclunk(Usbfs*, Fid* fid) { int qd; Dev *dev; void (*xfsclunk)(Usbfs *fs, Fid *f); dev = nil; qd = qiddev(fid->qid.path); qlock(&fslck); if(qd != Dtop && fs[qd] != nil){ dev=fs[qd]->dev; if(dev != nil) incref(dev); xfsclunk = fs[qd]->clunk; }else xfsclunk = nil; qunlock(&fslck); if(xfsclunk != nil){ xfsclunk(fs[qd], fid); } if(dev != nil) closedev(dev); } static int fsstat(Usbfs*, Qid qid, Dir *d) { int qd; int rc; Dev *dev; int (*xfsstat)(Usbfs *fs, Qid q, Dir *d); qd = qiddev(qid.path); if(qd == Dtop){ d->qid = qid; d->name = "usb"; d->length = 0; d->mode = 0555|DMDIR; return 0; } qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } xfsstat = fs[qd]->stat; dev = fs[qd]->dev; if(dev != nil) incref(dev); qunlock(&fslck); rc = xfsstat(fs[qd], qid, d); if(dev != nil) closedev(dev); return rc; } Usbfs usbdirfs = { .walk = fswalk, .clone = fsclone, .clunk = fsclunk, .open = fsopen, .read = fsread, .write = fswrite, .stat = fsstat, .end = fsend, };