#include #include #include #include #include #include <9p.h> enum { Qroot, Qtime, Qbintime, Nqid, }; enum { NUMSIZE = 12, VLNUMSIZE = 22, }; int bintimefd; vlong nsecdiff = 0; int fillstat(ulong qid, Dir *d) { memset(d, 0, sizeof(Dir)); d->uid = "marty"; d->gid = "mcfly"; d->muid = ""; d->qid = (Qid){qid, 0, 0}; d->atime = time(0); switch(qid) { case Qroot: d->name = "/"; d->qid.type = QTDIR; d->mode = DMDIR|0777; break; case Qtime: d->name = "time"; d->mode = 0666; break; case Qbintime: d->name = "bintime"; d->mode = 0666; break; } return 1; } int readtopdir(Fid*, uchar *buf, long off, int cnt, int blen) { int i, m, n; long pos; Dir d; n = 0; pos = 0; for (i = 1; i < Nqid; i++){ fillstat(i, &d); m = convD2M(&d, &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; n += m; cnt -= m; } pos += m; } return n; } static void fsattach(Req *r) { char *spec; spec = r->ifcall.aname; if(spec && spec[0]) { respond(r, "invalid attach specifier"); return; } r->fid->qid = (Qid){Qroot, 0, QTDIR}; r->ofcall.qid = r->fid->qid; respond(r, nil); } static void fsstat(Req *r) { fillstat((ulong)r->fid->qid.path, &r->d); r->d.name = estrdup9p(r->d.name); r->d.uid = estrdup9p(r->d.uid); r->d.gid = estrdup9p(r->d.gid); r->d.muid = estrdup9p(r->d.muid); respond(r, nil); } static char* fswalk1(Fid *fid, char *name, Qid *qid) { switch((ulong)fid->qid.path) { case Qroot: if (strcmp(name, "..") == 0) { *qid = (Qid){Qroot, 0, QTDIR}; fid->qid = *qid; return nil; } if (strcmp(name, "time") == 0) { *qid = (Qid){Qtime, 0, 0}; fid->qid = *qid; return nil; } if (strcmp(name, "bintime") == 0) { *qid = (Qid){Qbintime, 0, 0}; fid->qid = *qid; return nil; } return "file not found"; default: return "walk in non-directory"; } } static void fsopen(Req *r) { int omode; Fid *fid; ulong path; fid = r->fid; path = (ulong)fid->qid.path; omode = r->ifcall.mode; if(path == Qroot){ if (omode == OREAD) respond(r, nil); else respond(r, "permission denied"); return; } respond(r, nil); } static uvlong uvorder = 0x0001020304050607ULL; static uchar* le2vlong(vlong *to, uchar *f) { uchar *t, *o; int i; t = (uchar*)to; o = (uchar*)&uvorder; for(i = 0; i < sizeof(vlong); i++) t[o[i]] = f[i]; return f+sizeof(vlong); } static uchar* vlong2le(uchar *t, vlong from) { uchar *f, *o; int i; f = (uchar*)&from; o = (uchar*)&uvorder; for(i = 0; i < sizeof(vlong); i++) t[i] = f[o[i]]; return t+sizeof(vlong); } static void fsread(Req *r) { uchar *b; vlong x, t, h; int n, i; char str[7*NUMSIZE]; uchar buf[24]; if(pread(bintimefd, buf, sizeof(buf), 0) != sizeof(buf)){ responderror(r); return; } le2vlong(&x, buf); le2vlong(&t, buf+8); le2vlong(&h, buf+16); x -= nsecdiff; switch((ulong)r->fid->qid.path) { case Qroot: r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset, r->ifcall.count, r->ifcall.count); respond(r, nil); return; case Qtime: snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ", NUMSIZE-1, (long)(x/1000000000LL), VLNUMSIZE-1, x, VLNUMSIZE-1, t, VLNUMSIZE-1, h); readstr(r, str); respond(r, nil); return; case Qbintime: b = (uchar*)r->ofcall.data; n = r->ifcall.count; i = 0; if(n >= 3*sizeof(uvlong)){ vlong2le(b+2*sizeof(uvlong), h); i += sizeof(uvlong); } if(n >= 2*sizeof(uvlong)){ vlong2le(b+sizeof(uvlong), t); i += sizeof(uvlong); } if(n >= 8){ vlong2le(b, x); i += sizeof(vlong); } r->ofcall.count = i; respond(r, nil); return; } respond(r, "fixme"); } static void fswrite(Req *r) { char str[13]; uchar buf[8]; vlong x, now; int n; if(pread(bintimefd, buf, sizeof(buf), 0) != sizeof(buf)){ responderror(r); return; } le2vlong(&now, buf); n = r->ifcall.count; switch((ulong)r->fid->qid.path) { case Qtime: if(n >= sizeof(str)){ respond(r, "bad"); return; } strncpy(str, r->ifcall.data, n); str[n] = 0; x = strtol(str, 0, 0); if(x <= 0){ respond(r, "bad"); return; } x = x*1000000000LL; nsecdiff = now - x; r->ofcall.count = n; respond(r, nil); return; case Qbintime: respond(r, "not implemented"); return; } respond(r, "fixme"); } Srv fs = { .attach= fsattach, .walk1= fswalk1, .open= fsopen, .read= fsread, .write= fswrite, .stat= fsstat, }; void threadmain(int, char**) { bintimefd = open("/dev/bintime", OREAD); threadpostmountsrv(&fs, nil, "/dev", MBEFORE); }