#include #include #include #include #include <9p.h> #include "tag.h" typedef struct Box Box; typedef struct Boxclass Boxclass; typedef enum Class { Crecord, Cbox, Cfullbox, Cdata, Cunknown, } Class; struct Box { vlong offset; u32int length; char type[4*UTFmax + 1]; Class class; u8int version; u32int flags; vlong data; u32int dlength; }; struct Boxclass { char *type; Class class; }; enum { Qroot = 1, QPRAW = 1ULL<<63, }; Boxclass bclasstab[] = { {"aART", Cbox}, {"covr", Cbox}, {"cpil", Cbox}, {"data", Cdata}, {"dinf", Cbox}, {"disk", Cbox}, {"edts", Cbox}, {"ilst", Cbox}, {"mdia", Cbox}, {"meta", Cfullbox}, {"mfra", Cbox}, {"minf", Cbox}, {"moof", Cbox}, {"moov", Cbox}, {"mvex", Cbox}, {"pgap", Cbox}, {"root", Cbox}, {"stbl", Cbox}, {"tmpo", Cbox}, {"traf", Cbox}, {"trak", Cbox}, {"trkn", Cbox}, {"udta", Cbox}, {"©ART", Cbox}, {"©alb", Cbox}, {"©day", Cbox}, {"©gen", Cbox}, {"©nam", Cbox}, {"©too", Cbox}, }; int srcfd; Dir *srcdir; char *filename; void * emalloc(ulong n) { void *p; if((p = malloc(n)) == nil) sysfatal("malloc: %r"); setmalloctag(p, getcallerpc(&n)); return p; } #define tabend(tab) tab + nelem(tab) Class boxclass(char *type) { Boxclass *bc; for(bc=bclasstab; bc < tabend(bclasstab); bc++) { if(strcmp(type, bc->type) == 0) return bc->class; } return Crecord; } uvlong boxpath(Box *box) { return (strcmp(box->type, "root") == 0) ? Qroot : box->offset; } void readtype(uchar **p, char *s) { int i; Rune r; for(i=0; i < 4; i++) { r = (*p)[i]; /* convert from 8859-1 */ s += runetochar(s, &r); } *s = '\0'; } int readbox(int fd, Box *box, vlong offset) { uchar buf[12], *p; int n; n = pread(fd, buf, sizeof buf, offset); if(n < 0) return -1; /* pass errstr unmodified */ if(n < 8) { werrstr("short read: %d/8", n); return -1; } p = buf; box->offset = offset; box->length = g32(&p); readtype(&p, box->type); box->class = boxclass(box->type); switch(box->class) { case Cunknown: case Crecord: case Cbox: box->data = box->offset + 8; box->dlength = box->length - 8; break; case Cfullbox: if(n < 12) { werrstr("short read: %d/12", n); return -1; } box->version = g8(&p); box->flags = g24(&p); box->data = box->offset + 12; box->dlength = box->length - 12; break; case Cdata: if(n < 8) { werrstr("short read: %d/8", n); return -1; } box->data = box->offset + 16; box->dlength = box->length - 16; break; default: abort(); } return 0; } void fsattach(Req *r) { Box *box; box = emalloc(sizeof(*box)); box->offset = 0; box->length = srcdir->length; strcpy(box->type, "root"); box->class = Cbox; box->data = box->offset; box->dlength = box->length; r->fid->qid = (Qid){Qroot|0, 0, QTDIR}; r->fid->aux = box; r->ofcall.qid = r->fid->qid; respond(r, nil); } char * strnop(char *s) { return s; } void filldir(Dir *d, Box *box, int raw, int mode) { char *(*dup)(char *); dup = mode ? estrdup9p : strnop; d->mode = (raw || box->class == Crecord || box->class == Cdata) ? 0444 : DMDIR|0555; d->qid.path = boxpath(box) | (raw ? QPRAW : 0); d->qid.vers = 0; d->qid.type = d->mode >> 24; d->atime = 0; d->mtime = srcdir->mtime; d->length = (d->qid.type & QTDIR) ? 0 : box->length; d->name = dup(raw ? "raw" : box->type); d->uid = dup("qt"); d->gid = dup("qt"); d->muid = dup(""); } void fsdirread(Req *r) { Box *box, subbox; int start; uchar *p, *ep; Dir d; vlong offset, end; uint rv; box = r->fid->aux; start = r->ifcall.offset == 0 ? 0 : r->fid->dirindex; p = (uchar *)r->ofcall.data; ep = p + r->ifcall.count; if(r->ifcall.offset == 0) { filldir(&d, box, 1, 0); p += convD2M(&d, p, ep-p); // FIXME -- handle errors } offset = box->data; end = offset + box->dlength; // FIXME -- seek to start while(offset < end && p < ep) { if(r->ifcall.offset > 0) break; readbox(srcfd, &subbox, offset); // FIXME -- handle errors filldir(&d, &subbox, 0, 0); if((rv = convD2M(&d, p, ep-p)) < BIT16SZ) break; p += rv; offset += subbox.length; start++; } r->fid->dirindex = start; r->ofcall.count = p - (uchar *)r->ofcall.data; } void fsread(Req *r) { Qid qid; Box *box; vlong offset; u32int count, size; long n; qid = r->fid->qid; if(qid.type & QTDIR) { fsdirread(r); respond(r, nil); return; } box = r->fid->aux; offset = r->ifcall.offset; count = r->ifcall.count; size = box->dlength; offset = (offset > size) ? size : offset; count = (count > size-offset ? size-offset : count); n = pread(srcfd, r->ofcall.data, count, box->data + offset); if(n < 0) { respond(r, "read: %r"); return; } r->ofcall.count = n; respond(r, nil); } void fsstat(Req *r) { Qid qid; Box *box; qid = r->fid->qid; box = r->fid->aux; filldir(&r->d, box, (qid.path & QPRAW) != 0, 1); respond(r, nil); } Box * findbox(Box *box, char *type) { vlong offset, end; Box b, *ans; offset = box->data; end = offset + box->dlength; while(offset < end) { readbox(srcfd, &b, offset); // FIXME -- handle errors if(strcmp(type, b.type) == 0) { ans = emalloc(sizeof(Box)); setmalloctag(ans, getcallerpc(&box)); *ans = b; return ans; } offset += b.length; } return nil; } /* http://9fans.net/archive/2012/03/266 */ char * fswalk1(Fid *fid, char *name, Qid *qid) { Box *box, *subbox; box = fid->aux; if(strcmp(name, "raw") == 0) { subbox = emalloc(sizeof(*subbox)); *subbox = *box; fid->aux = subbox; qid->path = boxpath(box) | QPRAW; } else { subbox = findbox(box, name); if(subbox == nil) return "no such box"; fid->aux = subbox; qid->path = subbox->offset; } qid->vers = 0; qid->type = ((qid->path & QPRAW) || subbox->class == Crecord || subbox->class == Cdata) ? QTFILE : QTDIR; free(box); fid->qid = *qid; return nil; } char * fsclone(Fid *ofid, Fid *fid) { fid->aux = emalloc(sizeof(Box)); *(Box *)fid->aux = *(Box *)ofid->aux; return nil; } void fsdestroyfid(Fid *fid) { free(fid->aux); } Srv fs = { .attach = fsattach, .read = fsread, .stat = fsstat, .walk1 = fswalk1, .clone = fsclone, .destroyfid = fsdestroyfid, }; void usage(void) { fprint(2, "usage: %s file [mntpt]\n", argv0); exits("usage"); } void main(int argc, char **argv) { char *mntpt = "/n/qt"; ARGBEGIN { default: usage(); } ARGEND if(argc < 1 || argc > 2) usage(); if(argc == 2) mntpt = argv[1]; if((srcfd = open(argv[0], OREAD)) < 0) sysfatal("open %s: %r", argv[0]); if((srcdir = dirfstat(srcfd)) == nil) sysfatal("dirfstat %s: %r", argv[0]); filename = argv[0]; postmountsrv(&fs, nil, mntpt, MREPL); exits(nil); }