#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#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);
}
|