From 68576f51196972e8a7f3d7db89244fd7278c2bbd Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Mon, 22 Aug 2011 03:05:01 +0200 Subject: nusb/ptp: fix memory leaks, use libthread/ioprocs, cleanup --- sys/src/cmd/nusb/ptp/mkfile | 2 +- sys/src/cmd/nusb/ptp/ptp.c | 1014 +++++++++++++++++++++++++++++++++++++++++ sys/src/cmd/nusb/ptp/usbptp.c | 987 --------------------------------------- 3 files changed, 1015 insertions(+), 988 deletions(-) create mode 100644 sys/src/cmd/nusb/ptp/ptp.c delete mode 100644 sys/src/cmd/nusb/ptp/usbptp.c diff --git a/sys/src/cmd/nusb/ptp/mkfile b/sys/src/cmd/nusb/ptp/mkfile index e8e8a73ae..3bdd3c8f1 100644 --- a/sys/src/cmd/nusb/ptp/mkfile +++ b/sys/src/cmd/nusb/ptp/mkfile @@ -5,7 +5,7 @@ LIB=../lib/usb.a$O TARG=ptp HFILES= -OFILES=usbptp.$O +OFILES=ptp.$O +#include +#include +#include +#include +#include +#include <9p.h> + +#include "usb.h" + +enum +{ + Qroot, + Qstore, + Qobj, + Qthumb, +}; + +enum { + /* flags */ + DataSend = 0x00010000, + DataRecv = 0x00020000, + OutParam = 0x00040000, + + /* rpc codes */ + OpenSession = 0x1002, + CloseSession = 0x1003, + GetStorageIds = 0x1004, + GetStorageInfo = 0x1005, + GetObjectHandles = 0x1007, + GetObjectInfo = 0x1008, + GetObject = 0x1009, + GetThumb = 0x100A, + DeleteObject = 0x100B, +}; + +typedef struct Ptprpc Ptprpc; +typedef struct Node Node; +typedef struct Ioflush Ioflush; + +struct Ptprpc +{ + uchar length[4]; + uchar type[2]; + uchar code[2]; + uchar transid[4]; + union { + uchar p[5][4]; + uchar d[500]; + }; +}; + +struct Node +{ + Dir d; + + Node *parent; + Node *next; + Node *child; + + int store; + int handle; + int format; + + void *data; + int ndata; +}; + +struct Ioflush +{ + Channel *c; + Ioproc *io; +}; + + +enum { + In, + Out, +}; + +static Dev *usbep[2]; + +static int debug; +static ulong time0; +static int maxpacket = 64; +static int sessionId = 0; +static int transId = 0; + +static Node **nodes; +static int nnodes; + +static Channel *iochan; + +char Eperm[] = "permission denied"; +char Einterrupt[] = "interrupted"; + +#define PATH(type, n) ((uvlong)(type)|((uvlong)(n)<<4)) +#define TYPE(path) ((int)((path)&0xF)) +#define NUM(path) ((int)((path)>>4)) + +static void +hexdump(char *prefix, uchar *p, int n) +{ + char *s; + int i; + int m; + + m = 12; + s = emalloc9p(1+((n+1)*((m*6)+7))); + s[0] = '\0'; + for(i=0; i= 32 && p[i]<=127); + sprint(x, "%.2x %c ", (int)p[i], printable ? p[i] : '.'); + strcat(s, x); + } + fprint(2, "%20-s: %6d bytes %s\n", prefix, n, s); + free(s); +} + +static int +wasinterrupt(void) +{ + char err[ERRMAX]; + + rerrstr(err, sizeof(err)); + if(strstr(err, Einterrupt) || strstr(err, "timed out")){ + werrstr(Einterrupt); + return 1; + } + return 0; +} + +static char * +ptperrstr(int code) +{ + static char *a[] = { + "undefined", + nil , + "general error" , + "session not open" , + "invalid transaction id" , + "operation not supported" , + "parameter not supported" , + "incomplete transfer" , + "invalid storage id" , + "invalid object handle" , + "device prop not supported" , + "invalid object format code" , + "storage full" , + "object write protected" , + "store read only" , + "access denied" , + "no thumbnail present" , + "self test failed" , + "partial deletion" , + "store not available" , + "specification by format unsupported" , + "no valid object info" , + "invalid code format" , + "unknown vendor code", + "capture already terminated", + "device busy", + "invalid parent object", + "invalid device prop format", + "invalid device prop value", + "invalid parameter", + "session already opend", + "transaction canceld", + "specification of destination unsupported" + }; + + code -= 0x2000; + if(code < 0) + return nil; + if(code >= nelem(a)) + return "invalid error number"; + return a[code]; +} + +static int +ptpcheckerr(Ptprpc *rpc, int type, int transid, int length) +{ + char *s; + + if(length < 4+2+2+4){ + werrstr("short response: %d < %d", length, 4+2+2+4); + return 1; + } + if(GET4(rpc->length) < length){ + werrstr("unexpected response length 0x%x < 0x%x", GET4(rpc->length), length); + return 1; + } + if(GET4(rpc->transid) != transid){ + werrstr("unexpected transaction id 0x%x != 0x%x", GET4(rpc->transid), transid); + return 1; + } + if(GET2(rpc->type) != type){ + werrstr("unexpected response type 0x%x != 0x%x", GET2(rpc->type), type); + return 1; + } + if(s = ptperrstr(GET2(rpc->code))){ + werrstr("%s", s); + return -GET2(rpc->code); + } + return 0; +} + +static int +vptprpc(Ioproc *io, int code, int flags, va_list a) +{ + Ptprpc rpc; + int np, n, t, i, l; + uchar *b, *p, *e; + + np = flags & 0xF; + n = 4+2+2+4+4*np; + t = transId++; + + PUT4(rpc.length, n); + PUT2(rpc.type, 1); + PUT2(rpc.code, code); + PUT4(rpc.transid, t); + + for(i=0; i", (uchar*)&rpc, n); + + werrstr(""); + if(iowrite(io, usbep[Out]->dfd, &rpc, n) != n){ + wasinterrupt(); + return -1; + } + + if(flags & DataSend){ + void *sdata; + int sdatalen; + + sdata = va_arg(a, void*); + sdatalen = va_arg(a, int); + + b = (uchar*)sdata; + p = b; + e = b + sdatalen; + + l = 4+2+2+4+sdatalen; + PUT4(rpc.length, l); + PUT2(rpc.type, 2); + + if((n = sdatalen) > sizeof(rpc.d)) + n = sizeof(rpc.d); + memmove(rpc.d, p, n); + p += n; + n += (4+2+2+4); + + if(debug) + hexdump("data>", (uchar*)&rpc, n); + if(iowrite(io, usbep[Out]->dfd, &rpc, n) != n){ + wasinterrupt(); + return -1; + } + while(p < e){ + if((n = iowrite(io, usbep[Out]->dfd, p, e-p)) < 0){ + if(!wasinterrupt()) + return -1; + } + p += n; + } + } + + if(flags & DataRecv){ + void **prdata; + int *prdatalen; + + prdata = va_arg(a, void**); + prdatalen = va_arg(a, int*); + + *prdata = nil; + *prdatalen = 0; + + do{ + if((n = ioread(io, usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){ + wasinterrupt(); + return -1; + } + if(debug) + hexdump("data<", (uchar*)&rpc, n); + if((l = ptpcheckerr(&rpc, 2, t, n)) < 0) + return -1; + } while(l); + + l = GET4(rpc.length); + if((l < 4+2+2+4) || (l < n)){ + werrstr("invalid recvdata length"); + return -1; + } + + l -= (4+2+2+4); + n -= (4+2+2+4); + + b = emalloc9p(l); + p = b; + e = b+l; + memmove(p, rpc.d, n); + p += n; + + while(p < e){ + if((n = ioread(io, usbep[In]->dfd, p, e-p)) < 0){ + wasinterrupt(); + free(b); + return -1; + } + p += n; + } + *prdata = b; + *prdatalen = e-b; + } + + do { + if((n = ioread(io, usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){ + wasinterrupt(); + return -1; + } + if(debug) + hexdump("resp<", (uchar*)&rpc, n); + if((l = ptpcheckerr(&rpc, 3, t, n)) < 0) + return -1; + } while(l); + + if(flags & OutParam){ + int *pp; + + for(i=0; iaux = f.c; + srvrelease(r->srv); + } else + a[1].op = CHANEND; + if(alt(a) == 0){ + ioflush(f.io); + if(f.c) + threadcreate(ioflusher, &f, 4*1024); + va_start(va, flags); + i = vptprpc(f.io, code, flags, va); + va_end(va); + } else + werrstr("%s", m); + if(r){ + srvacquire(r->srv); + r->aux = nil; + } + if(f.io){ + if(f.c) + sendp(f.c, nil); + sendp(iochan, f.io); + } else if(f.c) + chanfree(f.c); + return i; +} + +static int* +ptparray4(uchar *d, uchar *e) +{ + int *a, i, n; + + if(d + 4 > e) + return nil; + n = GET4(d); + d += 4; + if(d + n*4 > e) + return nil; + a = emalloc9p((1+n) * sizeof(int)); + a[0] = n; + for(i=0; i e) + return nil; + n = *d; + d++; + if(d + n*2 > e) + return nil; + p = s = emalloc9p((n+1)*UTFmax); + for(i=0; iname); + free(d->uid); + free(d->gid); + free(d->muid); + memset(d, 0, sizeof(*d)); +} + +static void +copydir(Dir *d, Dir *s) +{ + memmove(d, s, sizeof(*d)); + if(d->name) + d->name = estrdup9p(d->name); + if(d->uid) + d->uid = estrdup9p(d->uid); + if(d->gid) + d->gid = estrdup9p(d->gid); + if(d->muid) + d->muid = estrdup9p(d->muid); +} + +static Node* +cachednode(uvlong path, Node ***pf) +{ + Node *x; + int i; + + if(pf) + *pf = nil; + for(i=0; id.qid.path == path) + return x; + } + return nil; +} + +static Node* +getnode(Req *r, uvlong path) +{ + Node *x, *y, **f; + uchar *p; + int np; + char *s; + + if(x = cachednode(path, &f)) + return x; + + y = nil; + x = emalloc9p(sizeof(*x)); + memset(x, 0, sizeof(*x)); + x->d.qid.path = path; + x->d.uid = estrdup9p("ptp"); + x->d.gid = estrdup9p("usb"); + x->d.atime = x->d.mtime = time0; + + p = nil; + np = 0; + switch(TYPE(path)){ + case Qroot: + x->d.qid.type = QTDIR; + x->d.mode = DMDIR|0777; + x->d.name = estrdup9p("/"); + goto Addnode; + + case Qstore: + x->store = NUM(path); + x->handle = 0xffffffff; + x->d.qid.type = QTDIR; + x->d.mode = DMDIR|0777; + x->d.name = emalloc9p(10); + sprint(x->d.name, "%x", x->store); + goto Addnode; + + case Qobj: + case Qthumb: + if(ptprpc(r, GetObjectInfo, 1|DataRecv, NUM(path), &p, &np) < 0) + break; + if(debug) + hexdump("objectinfo", p, np); + if(np < 52){ + werrstr("bad objectinfo"); + break; + } + + /* + * another proc migh'v come in and done it for us, + * so check the cache again. + */ + if(y = cachednode(path, &f)) + break; + + if((x->d.name = ptpstring2(p+52, p+np)) == nil){ + werrstr("bad objectinfo"); + break; + } + x->handle = NUM(path); + x->store = GET4(p); + x->format = GET2(p+4); + if(x->format == 0x3001 && GET2(p+42) == 1){ + x->d.qid.type = QTDIR; + x->d.mode = DMDIR|0777; + } else { + x->d.mode = 0666; + if(TYPE(path) == Qthumb){ + char *t; + + t = emalloc9p(8 + strlen(x->d.name)); + sprint(t, "thumb_%s", x->d.name); + free(x->d.name); + x->d.name = t; + + x->d.length = GET4(p+14); + } else { + x->d.length = GET4(p+8); + } + } + if(s = ptpstring2(p+(53+p[52]*2), p+np)){ + if(strlen(s) >= 15){ + Tm t; + + // 0123 45 67 8 9A BC DF + // 2008 12 26 T 00 21 18 + memset(&t, 0, sizeof(t)); + + s[0x10] = 0; + t.sec = atoi(s+0xD); + s[0xD] = 0; + t.min = atoi(s+0xB); + s[0xB] = 0; + t.hour = atoi(s+0x9); + s[0x8] = 0; + t.mday = atoi(s+0x6); + s[0x6] = 0; + t.mon = atoi(s+0x4) - 1; + s[0x4] = 0; + t.year = atoi(s) - 1900; + + x->d.atime = x->d.mtime = tm2sec(&t); + } + free(s); + } + free(p); + Addnode: + if(f == nil){ + if(nnodes % 64 == 0) + nodes = erealloc9p(nodes, sizeof(nodes[0]) * (nnodes + 64)); + f = &nodes[nnodes++]; + } + return *f = x; + } + + cleardir(&x->d); + free(x); + free(p); + return y; +} + +static void +freenode(Node *nod) +{ + int i; + + /* remove the node from the tree */ + for(i=0; id); + free(nod->data); + free(nod); +} + +static int +readchilds(Req *r, Node *nod) +{ + int e, i; + int *a; + uchar *p; + int np; + Node *x, **xx; + + e = 0; + switch(TYPE(nod->d.qid.path)){ + case Qroot: + if(ptprpc(r, GetStorageIds, 0|DataRecv, &p, &np) < 0) + return -1; + a = ptparray4(p, p+np); + free(p); + xx = &nod->child; + *xx = nil; + for(i=0; a && iparent = nod; + *xx = x; + xx = &x->next; + *xx = nil; + } + free(a); + break; + + case Qstore: + case Qobj: + if(ptprpc(r, GetObjectHandles, 3|DataRecv, nod->store, 0, nod->handle, &p, &np) < 0) + return -1; + a = ptparray4(p, p+np); + free(p); + xx = &nod->child; + *xx = nil; + for(i=0; a && iparent = nod; + *xx = x; + xx = &x->next; + *xx = nil; + + /* skip thumb when not image format */ + if((x->format & 0xFF00) != 0x3800) + continue; + if((x = getnode(r, PATH(Qthumb, a[i+1]))) == nil){ + e = -1; + break; + } + x->parent = nod; + *xx = x; + xx = &x->next; + *xx = nil; + } + free(a); + break; + } + + return e; +} + +static void +fsattach(Req *r) +{ + if(r->ifcall.aname && r->ifcall.aname[0]){ + respond(r, "invalid attach specifier"); + return; + } + r->fid->qid.path = PATH(Qroot, 0); + r->fid->qid.type = QTDIR; + r->fid->qid.vers = 0; + r->ofcall.qid = r->fid->qid; + respond(r, nil); +} + +static void +fsstat(Req *r) +{ + Node *nod; + + if((nod = getnode(r, r->fid->qid.path)) == nil){ + responderror(r); + return; + } + copydir(&r->d, &nod->d); + respond(r, nil); +} + +static int +nodegen(int i, Dir *d, void *aux) +{ + Node *nod = aux; + + for(nod=nod->child; nod && i; nod=nod->next, i--) + ; + if(i==0 && nod){ + copydir(d, &nod->d); + return 0; + } + return -1; +} + +static char* +fswalk1(Req *r, char *name, Qid *qid) +{ + static char buf[ERRMAX]; + uvlong path; + Node *nod; + Fid *fid; + + fid = r->newfid; + path = fid->qid.path; + if(!(fid->qid.type&QTDIR)) + return "walk in non-directory"; + if(nod = getnode(r, path)){ + if(strcmp(name, "..") == 0){ + if(nod = nod->parent) + *qid = nod->d.qid; + return nil; + } + if(readchilds(r, nod) == 0){ + for(nod=nod->child; nod; nod=nod->next){ + if(strcmp(nod->d.name, name) == 0){ + *qid = nod->d.qid; + return nil; + } + } + return "directory entry not found"; + } + } + rerrstr(buf, sizeof(buf)); + return buf; +} + +static char* +oldwalk1(Fid *fid, char *name, void *arg) +{ + Qid qid; + char *e; + Req *r; + + r = arg; + assert(fid == r->newfid); + if(e = fswalk1(r, name, &qid)) + return e; + fid->qid = qid; + return nil; +} + +static char* +oldclone(Fid *, Fid *, void *) +{ + return nil; +} + +static void +fswalk(Req *r) +{ + walkandclone(r, oldwalk1, oldclone, r); +} + +static void +fsread(Req *r) +{ + uvlong path; + Node *nod; + uchar *p; + int np; + + np = 0; + p = nil; + path = r->fid->qid.path; + if(nod = getnode(r, path)){ + switch(TYPE(path)){ + case Qroot: + case Qstore: + case Qobj: + if(nod->d.qid.type & QTDIR){ + if(readchilds(r, nod) < 0) + break; + dirread9p(r, nodegen, nod); + respond(r, nil); + return; + } + /* no break */ + case Qthumb: + if(nod->data == nil){ + if(ptprpc(r, TYPE(path)==Qthumb ? GetThumb : GetObject, + 1|DataRecv, nod->handle, &p, &np) < 0) + break; + nod->data = p; + nod->ndata = np; + } + readbuf(r, nod->data, nod->ndata); + respond(r, nil); + return; + } + } + free(p); + responderror(r); +} + +static void +fsremove(Req *r) +{ + Node *nod; + uvlong path; + + path = r->fid->qid.path; + if(nod = getnode(r, path)){ + switch(TYPE(path)){ + default: + werrstr(Eperm); + break; + case Qobj: + if(ptprpc(r, DeleteObject, 2, nod->handle, 0) < 0) + break; + /* no break */ + case Qthumb: + if(nod = cachednode(path, nil)) + freenode(nod); + respond(r, nil); + return; + } + } + responderror(r); +} + +static void +fsopen(Req *r) +{ + if(r->ifcall.mode != OREAD){ + respond(r, Eperm); + return; + } + respond(r, nil); +} + +static void +fsflush(Req *r) +{ + Channel *c; + + if(c = r->oldreq->aux) + sendp(c, Einterrupt); + respond(r, nil); +} + +static void +fsdestroyfid(Fid *fid) +{ + Node *nod; + uvlong path; + + path = fid->qid.path; + switch(TYPE(path)){ + case Qobj: + case Qthumb: + if(nod = cachednode(path, nil)){ + free(nod->data); + nod->data = nil; + nod->ndata = 0; + } + break; + } +} + +static void +fsend(Srv *) +{ + ptprpc(nil, CloseSession, 0); + closeioproc(recvp(iochan)); +} + +static int +findendpoints(Dev *d, int *epin, int *epout) +{ + int i; + Ep *ep; + Usbdev *ud; + + ud = d->usb; + *epin = *epout = -1; + for(i=0; iep); i++){ + if((ep = ud->ep[i]) == nil) + continue; + if(ep->type != Ebulk) + continue; + if(ep->dir == Eboth || ep->dir == Ein) + if(*epin == -1) + *epin = ep->id; + if(ep->dir == Eboth || ep->dir == Eout) + if(*epout == -1) + *epout = ep->id; + if(*epin >= 0 && *epout >= 0) + return 0; + } + return -1; +} + +Srv fs = +{ + .attach = fsattach, + .destroyfid = fsdestroyfid, + .walk = fswalk, + .open = fsopen, + .read = fsread, + .remove = fsremove, + .stat = fsstat, + .flush = fsflush, + .end = fsend, +}; + +static void +usage(void) +{ + fprint(2, "usage: %s [-dD] devid\n", argv0); + threadexits("usage"); +} + +void +threadmain(int argc, char **argv) +{ + char name[64], desc[64]; + int epin, epout; + Dev *d; + + ARGBEGIN { + case 'd': + debug++; + break; + case 'D': + chatty9p++; + break; + default: + usage(); + } ARGEND; + + if(argc == 0) + usage(); + if((d = getdev(atoi(*argv))) == nil) + sysfatal("opendev: %r"); + if(findendpoints(d, &epin, &epout) < 0) + sysfatal("findendpoints: %r"); + + usbep[In] = openep(d, epin); + if(epin == epout){ + incref(usbep[In]); + usbep[Out] = usbep[In]; + opendevdata(usbep[In], ORDWR); + } else { + usbep[Out] = openep(d, epout); + opendevdata(usbep[In], OREAD); + opendevdata(usbep[Out], OWRITE); + } + if(usbep[In]->dfd < 0 || usbep[Out]->dfd < 0) + sysfatal("open endpoints: %r"); + + iochan = chancreate(sizeof(Ioproc*), 1); + sendp(iochan, ioproc()); + + sessionId = getpid(); + if(ptprpc(nil, OpenSession, 1, sessionId) < 0) + sysfatal("open session: %r"); + + time0 = time(0); + + snprint(name, sizeof name, "sdU%d.0", d->id); + snprint(desc, sizeof desc, "%d.ptp", d->id); + threadpostsharesrv(&fs, nil, name, desc); + + threadexits(0); +} diff --git a/sys/src/cmd/nusb/ptp/usbptp.c b/sys/src/cmd/nusb/ptp/usbptp.c deleted file mode 100644 index 955205717..000000000 --- a/sys/src/cmd/nusb/ptp/usbptp.c +++ /dev/null @@ -1,987 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include <9p.h> - -#include "usb.h" - -enum -{ - Qroot, - Qstore, - Qobj, - Qthumb, -}; - -enum { - /* flags */ - DataSend = 0x00010000, - DataRecv = 0x00020000, - OutParam = 0x00040000, - - /* rpc codes */ - OpenSession = 0x1002, - CloseSession = 0x1003, - GetStorageIds = 0x1004, - GetStorageInfo = 0x1005, - GetObjectHandles = 0x1007, - GetObjectInfo = 0x1008, - GetObject = 0x1009, - GetThumb = 0x100A, - DeleteObject = 0x100B, -}; - -typedef struct Ptprpc Ptprpc; -struct Ptprpc -{ - uchar length[4]; - uchar type[2]; - uchar code[2]; - uchar transid[4]; - union { - uchar p[5][4]; - uchar d[500]; - }; -}; - -typedef struct Node Node; -struct Node -{ - Dir d; - - Node *parent; - Node *next; - Node *child; - - int store; - int handle; - int format; - - void *data; - int ndata; -}; - -int debug; - -enum { - In, - Out, -}; -static Dev *usbep[2]; - -static ulong time0; -static int maxpacket = 64; -static int sessionId = 0; -static int transId = 0; - -static Node **nodes; -static int nnodes; - -static char *uname; - -#define PATH(type, n) ((uvlong)(type)|((uvlong)(n)<<4)) -#define TYPE(path) ((int)((path)&0xF)) -#define NUM(path) ((int)((path)>>4)) - -static void -hexdump(char *prefix, uchar *p, int n) -{ - char *s; - int i; - int m; - - m = 12; - s = emalloc9p(1+((n+1)*((m*6)+7))); - s[0] = '\0'; - for(i=0; i= 32 && p[i]<=127); - sprint(x, "%.2x %c ", (int)p[i], printable ? p[i] : '.'); - strcat(s, x); - } - fprint(2, "%20-s: %6d bytes %s\n", prefix, n, s); - free(s); -} - -static int -wasinterrupt(void) -{ - char err[ERRMAX]; - - rerrstr(err, sizeof(err)); - if(strstr(err, "interrupted") || strstr(err, "request timed out")){ - werrstr("interrupted"); - return 1; - } - return 0; -} - -static char * -ptperrstr(int code) -{ - static char *a[] = { - "undefined", - nil , - "general error" , - "session not open" , - "invalid transaction id" , - "operation not supported" , - "parameter not supported" , - "incomplete transfer" , - "invalid storage id" , - "invalid object handle" , - "device prop not supported" , - "invalid object format code" , - "storage full" , - "object write protected" , - "store read only" , - "access denied" , - "no thumbnail present" , - "self test failed" , - "partial deletion" , - "store not available" , - "specification by format unsupported" , - "no valid object info" , - "invalid code format" , - "unknown vendor code", - "capture already terminated", - "device busy", - "invalid parent object", - "invalid device prop format", - "invalid device prop value", - "invalid parameter", - "session already opend", - "transaction canceld", - "specification of destination unsupported" - }; - - code -= 0x2000; - if(code < 0) - return nil; - if(code >= nelem(a)) - return "invalid error number"; - return a[code]; -} - -static int -ptpcheckerr(Ptprpc *rpc, int type, int transid, int length) -{ - char *s; - - if(length < 4+2+2+4){ - werrstr("short response: %d < %d", length, 4+2+2+4); - return 1; - } - if(GET4(rpc->length) < length){ - werrstr("unexpected response length 0x%x < 0x%x", GET4(rpc->length), length); - return 1; - } - if(GET4(rpc->transid) != transid){ - werrstr("unexpected transaction id 0x%x != 0x%x", GET4(rpc->transid), transid); - return 1; - } - if(GET2(rpc->type) != type){ - werrstr("unexpected response type 0x%x != 0x%x", GET2(rpc->type), type); - return 1; - } - if(s = ptperrstr(GET2(rpc->code))){ - werrstr("%s", s); - return -GET2(rpc->code); - } - return 0; -} - -static int -vptprpc(int code, int flags, va_list a) -{ - Ptprpc rpc; - int np, n, t, i, l; - uchar *b, *p, *e; - - np = flags & 0xF; - n = 4+2+2+4+4*np; - t = transId++; - - PUT4(rpc.length, n); - PUT2(rpc.type, 1); - PUT2(rpc.code, code); - PUT4(rpc.transid, t); - - for(i=0; i", (uchar*)&rpc, n); - - werrstr(""); - if(write(usbep[Out]->dfd, &rpc, n) != n){ - wasinterrupt(); - return -1; - } - - if(flags & DataSend){ - void *sdata; - int sdatalen; - - sdata = va_arg(a, void*); - sdatalen = va_arg(a, int); - - b = (uchar*)sdata; - p = b; - e = b + sdatalen; - - l = 4+2+2+4+sdatalen; - PUT4(rpc.length, l); - PUT2(rpc.type, 2); - - if((n = sdatalen) > sizeof(rpc.d)) - n = sizeof(rpc.d); - memmove(rpc.d, p, n); - p += n; - n += (4+2+2+4); - - if(debug) - hexdump("data>", (uchar*)&rpc, n); - if(write(usbep[Out]->dfd, &rpc, n) != n){ - wasinterrupt(); - return -1; - } - while(p < e){ - if((n = write(usbep[Out]->dfd, p, e-p)) < 0){ - wasinterrupt(); - break; - } - p += n; - } - } - - if(flags & DataRecv){ - void **prdata; - int *prdatalen; - - prdata = va_arg(a, void**); - prdatalen = va_arg(a, int*); - - *prdata = nil; - *prdatalen = 0; - - do{ - if((n = read(usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){ - wasinterrupt(); - return -1; - } - if(debug > 1) - hexdump("data<", (uchar*)&rpc, n); - if((l = ptpcheckerr(&rpc, 2, t, n)) < 0) - return -1; - } while(l); - - l = GET4(rpc.length); - if((l < 4+2+2+4) || (l < n)){ - werrstr("invalid recvdata length"); - return -1; - } - - l -= (4+2+2+4); - n -= (4+2+2+4); - - b = emalloc9p(l); - p = b; - e = b+l; - memmove(p, rpc.d, n); - p += n; - - while(p < e){ - if((n = read(usbep[In]->dfd, p, e-p)) < 0){ - wasinterrupt(); - free(b); - return -1; - } - p += n; - } - *prdata = b; - *prdatalen = e-b; - } - - do { - if((n = read(usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){ - wasinterrupt(); - return -1; - } - if(debug > 1) - hexdump("resp<", (uchar*)&rpc, n); - if((l = ptpcheckerr(&rpc, 3, t, n)) < 0) - return -1; - } while(l); - - if(flags & OutParam){ - int *pp; - - for(i=0; iaux = (void*)getpid(); - srvrelease(r->srv); - } - i = semacquire(&ptpsem, 1); - if(i == 1){ - va_start(a, flags); - i = vptprpc(code, flags, a); - va_end(a); - semrelease(&ptpsem, 1); - } - if(i < 0 && debug) - fprint(2, "ptprpc: req=%p %r\n", r); - if(r != nil){ - srvacquire(r->srv); - r->aux = (void*)-1; - } - return i; -} - -static int* -ptparray4(uchar *d, uchar *e) -{ - int *a, i, n; - - if(d + 4 > e) - return nil; - n = GET4(d); - d += 4; - if(d + n*4 > e) - return nil; - a = emalloc9p((1+n) * sizeof(int)); - a[0] = n; - for(i=0; i e) - return nil; - n = *d; - d++; - if(d + n*2 > e) - return nil; - p = s = emalloc9p((n+1)*UTFmax); - for(i=0; iname); - free(d->uid); - free(d->gid); - free(d->muid); - memset(d, 0, sizeof(*d)); -} - -static void -copydir(Dir *d, Dir *s) -{ - memmove(d, s, sizeof(*d)); - if(d->name) - d->name = estrdup9p(d->name); - if(d->uid) - d->uid = estrdup9p(d->uid); - if(d->gid) - d->gid = estrdup9p(d->gid); - if(d->muid) - d->muid = estrdup9p(d->muid); -} - -static Node* -getnode(uvlong path, Req *r) -{ - int i, j; - Node *x; - uchar *p; - int np; - char *s; - - j = -1; - for(i=0; id.qid.path == path) - return x; - } - - x = emalloc9p(sizeof(*x)); - - memset(x, 0, sizeof(*x)); - - x->d.qid.path = path; - x->d.uid = estrdup9p(uname); - x->d.gid = estrdup9p(uname); - x->d.atime = x->d.mtime = time0; - - p = nil; - np = 0; - switch(TYPE(path)){ - case Qroot: - x->d.qid.type = QTDIR; - x->d.mode = DMDIR|0777; - x->d.name = estrdup9p("/"); - break; - - case Qstore: - x->store = NUM(path); - x->handle = 0xffffffff; - x->d.qid.type = QTDIR; - x->d.mode = DMDIR|0777; - x->d.name = emalloc9p(10); - sprint(x->d.name, "%x", x->store); - break; - - case Qobj: - case Qthumb: - if(ptprpc(r, GetObjectInfo, 1|DataRecv, NUM(path), &p, &np) < 0) - goto err; - if(debug > 1) - hexdump("objectinfo", p, np); - if(np < 52){ - werrstr("bad objectinfo"); - goto err; - } - - j = -1; - for(i=0; id.qid.path == path){ - /* never mind */ - cleardir(&x->d); - free(x); - return nodes[i]; - } - } - - if((x->d.name = ptpstring2(p+52, p+np)) == nil){ - werrstr("bad objectinfo"); - goto err; - } - x->handle = NUM(path); - x->store = GET4(p); - x->format = GET2(p+4); - if(x->format == 0x3001 && GET2(p+42) == 1){ - x->d.qid.type = QTDIR; - x->d.mode = DMDIR|0777; - } else { - x->d.mode = 0666; - if(TYPE(path) == Qthumb){ - char *t; - - t = emalloc9p(8 + strlen(x->d.name)); - sprint(t, "thumb_%s", x->d.name); - free(x->d.name); - x->d.name = t; - - x->d.length = GET4(p+14); - } else { - x->d.length = GET4(p+8); - } - } - if(s = ptpstring2(p+(53+p[52]*2), p+np)){ - if(strlen(s) >= 15){ - Tm t; - - // 0123 45 67 8 9A BC DF - // 2008 12 26 T 00 21 18 - memset(&t, 0, sizeof(t)); - - s[0x10] = 0; - t.sec = atoi(s+0xD); - s[0xD] = 0; - t.min = atoi(s+0xB); - s[0xB] = 0; - t.hour = atoi(s+0x9); - s[0x8] = 0; - t.mday = atoi(s+0x6); - s[0x6] = 0; - t.mon = atoi(s+0x4) - 1; - s[0x4] = 0; - t.year = atoi(s) - 1900; - - x->d.atime = x->d.mtime = tm2sec(&t); - } - free(s); - } - free(p); - break; - } - - if(j < 0){ - if(nnodes % 64 == 0) - nodes = erealloc9p(nodes, sizeof(nodes[0]) * (nnodes + 64)); - j = nnodes++; - } - return nodes[j] = x; - -err: - cleardir(&x->d); - free(x); - free(p); - - return nil; -} - -static void -freenode(Node *nod) -{ - int i; - - /* remove the node from the tree */ - for(i=0; id); - free(nod->data); - free(nod); -} - -static int -readchilds(Node *nod, Req *r) -{ - int i; - int *a; - uchar *p; - int np; - Node *x, **xx; - - switch(TYPE(nod->d.qid.path)){ - case Qroot: - if(ptprpc(r, GetStorageIds, 0|DataRecv, &p, &np) < 0) - return -1; - a = ptparray4(p, p+np); - free(p); - xx = &nod->child; - for(i=0; a && iparent = nod; - *xx = x; - xx = &x->next; - } - } - *xx = nil; - free(a); - break; - - case Qstore: - case Qobj: - if(ptprpc(r, GetObjectHandles, 3|DataRecv, nod->store, 0, nod->handle, &p, &np) < 0) - return -1; - a = ptparray4(p, p+np); - free(p); - xx = &nod->child; - for(i=0; a && iparent = nod; - *xx = x; - xx = &x->next; - - /* skip thumb when not image format */ - if((x->format & 0xFF00) != 0x3800) - continue; - } - if(x = getnode(PATH(Qthumb, a[i+1]), r)){ - x->parent = nod; - *xx = x; - xx = &x->next; - } - } - *xx = nil; - free(a); - break; - } - - return 0; -} - -static void -fsattach(Req *r) -{ - if(r->ifcall.aname && r->ifcall.aname[0]){ - respond(r, "invalid attach specifier"); - return; - } - if(uname == nil) - uname = estrdup9p(r->ifcall.uname); - r->fid->qid.path = PATH(Qroot, 0); - r->fid->qid.type = QTDIR; - r->fid->qid.vers = 0; - r->ofcall.qid = r->fid->qid; - respond(r, nil); -} - -static void -fsstat(Req *r) -{ - Node *nod; - - if((nod = getnode(r->fid->qid.path, r)) == nil){ - responderror(r); - return; - } - copydir(&r->d, &nod->d); - respond(r, nil); -} - -static int -nodegen(int i, Dir *d, void *aux) -{ - Node *nod = aux; - - for(nod=nod->child; nod && i; nod=nod->next, i--) - ; - if(i==0 && nod){ - copydir(d, &nod->d); - return 0; - } - return -1; -} - -static char* -fswalk1(Req *r, char *name, Qid *qid) -{ - static char buf[ERRMAX]; - uvlong path; - Node *nod; - Fid *fid; - - fid = r->newfid; - path = fid->qid.path; - if(!(fid->qid.type&QTDIR)) - return "walk in non-directory"; - - if((nod = getnode(path, r)) == nil) - goto err; - - if(strcmp(name, "..") == 0){ - if(nod = nod->parent) - *qid = nod->d.qid; - return nil; - } - if(readchilds(nod, r) < 0) - goto err; - for(nod=nod->child; nod; nod=nod->next){ - if(strcmp(nod->d.name, name) == 0){ - *qid = nod->d.qid; - return nil; - } - } - return "directory entry not found"; - -err: - rerrstr(buf, sizeof(buf)); - return buf; -} - -static char* -oldwalk1(Fid *fid, char *name, void *arg) -{ - Qid qid; - char *e; - Req *r; - - r = arg; - assert(fid == r->newfid); - if(e = fswalk1(r, name, &qid)) - return e; - fid->qid = qid; - return nil; -} - -static char* -oldclone(Fid *, Fid *, void *) -{ - return nil; -} - -static void -fswalk(Req *r) -{ - walkandclone(r, oldwalk1, oldclone, r); -} - -static void -fsread(Req *r) -{ - uvlong path; - Node *nod; - uchar *p; - int np; - - np = 0; - p = nil; - path = r->fid->qid.path; - if((nod = getnode(path, r)) == nil) - goto err; - - if(nod->d.qid.type & QTDIR){ - if(readchilds(nod, r) < 0) - goto err; - dirread9p(r, nodegen, nod); - respond(r, nil); - return; - } - - switch(TYPE(path)){ - default: - werrstr("bug in fsread path=%llux", path); - break; - - case Qobj: - case Qthumb: - if(nod->data == nil){ - if(TYPE(path)==Qthumb){ - if(ptprpc(r, GetThumb, 1|DataRecv, nod->handle, &p, &np) < 0) - goto err; - } else { - if(ptprpc(r, GetObject, 1|DataRecv, nod->handle, &p, &np) < 0) - goto err; - } - nod->data = p; - nod->ndata = np; - } - readbuf(r, nod->data, nod->ndata); - respond(r, nil); - return; - } -err: - free(p); - responderror(r); -} - -static void -fsremove(Req *r) -{ - Node *nod; - uvlong path; - - path = r->fid->qid.path; - if((nod = getnode(path, r)) == nil) - goto err; - - switch(TYPE(path)){ - default: - werrstr("bug in fsremove path=%llux", path); - break; - case Qobj: - if(ptprpc(r, DeleteObject, 2, nod->handle, 0) < 0) - goto err; - case Qthumb: - freenode(nod); - respond(r, nil); - return; - } -err: - responderror(r); -} - -static void -fsopen(Req *r) -{ - if(r->ifcall.mode != OREAD){ - respond(r, "permission denied"); - return; - } - respond(r, nil); -} - -static void -fsflush(Req *r) -{ - Req *o; - - if(o = r->oldreq){ - if(debug) - fprint(2, "fsflush: req=%p\n", o); - int pid = (int)o->aux; - if(pid != -1 && pid != 0){ - o->aux = (void*)-1; - postnote(PNPROC, pid, "interrupt"); - } - } - respond(r, nil); -} - -static void -fsdestroyfid(Fid *fid) -{ - Node *nod; - uvlong path; - - path = fid->qid.path; - switch(TYPE(path)){ - case Qobj: - case Qthumb: - if(nod = getnode(path, nil)){ - free(nod->data); - nod->data = nil; - nod->ndata = 0; - } - break; - } -} - -static void -fsend(Srv *) -{ - ptprpc(nil, CloseSession, 0); -} - -static int -findendpoints(Dev *d, int *epin, int *epout) -{ - int i; - Ep *ep; - Usbdev *ud; - - ud = d->usb; - *epin = *epout = -1; - for(i=0; iep); i++){ - if((ep = ud->ep[i]) == nil) - continue; - if(ep->type != Ebulk) - continue; - if(ep->dir == Eboth || ep->dir == Ein) - if(*epin == -1) - *epin = ep->id; - if(ep->dir == Eboth || ep->dir == Eout) - if(*epout == -1) - *epout = ep->id; - if(*epin >= 0 && *epout >= 0) - return 0; - } - return -1; -} - -static int -inote(void *, char *msg) -{ - if(strstr(msg, "interrupt")) - return 1; - return 0; -} - -Srv fs = -{ -.attach= fsattach, -.destroyfid= fsdestroyfid, -.walk= fswalk, -.open= fsopen, -.read= fsread, -.remove= fsremove, -.stat= fsstat, -.flush= fsflush, -.end= fsend, -}; - -static void -usage(void) -{ - fprint(2, "usage: %s [-dD] devid\n", argv0); - exits("usage"); -} - -void -main(int argc, char **argv) -{ - int epin, epout; - char name[64], desc[64]; - Dev *d; - - ARGBEGIN { - case 'd': - debug++; - break; - case 'D': - chatty9p++; - break; - default: - usage(); - } ARGEND; - - if(argc == 0) - usage(); - if((d = getdev(atoi(*argv))) == nil) - sysfatal("opendev: %r"); - if(findendpoints(d, &epin, &epout) < 0) - sysfatal("findendpoints: %r"); - - usbep[In] = openep(d, epin); - if(epin == epout){ - incref(usbep[In]); - usbep[Out] = usbep[In]; - opendevdata(usbep[In], ORDWR); - } else { - usbep[Out] = openep(d, epout); - opendevdata(usbep[In], OREAD); - opendevdata(usbep[Out], OWRITE); - } - if(usbep[In]->dfd < 0 || usbep[Out]->dfd < 0) - sysfatal("open endpoints: %r"); - - sessionId = getpid(); - if(ptprpc(nil, OpenSession, 1, sessionId) < 0) - return; - - atnotify(inote, 1); - time0 = time(0); - - snprint(name, sizeof name, "sdU%d.0", d->id); - snprint(desc, sizeof desc, "%d.ptp", d->id); - postsharesrv(&fs, nil, name, desc); - - exits(0); -} -- cgit v1.2.3