#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>

uint time0;

enum
{
	Qroot = 0,
	Qkid,
};

char *kidname;
uint kidmode;

void
fsattach(Req *r)
{
	char *spec;

	spec = r->ifcall.aname;
	if(spec && spec[0]){
		respond(r, "invalid attach specifier");
		return;
	}
	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
	r->fid->qid = r->ofcall.qid;
	respond(r, nil);
}

char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
	switch((int)fid->qid.path){
	default:
		return "path not found";
	case Qroot:
		if(strcmp(name, "..") == 0)
			break;
		if(strcmp(name, kidname) == 0){
			fid->qid = (Qid){Qkid, 0, kidmode>>24};
			break;
		}
		return "path not found";
	case Qkid:
		if(strcmp(name, "..") == 0){
			fid->qid = (Qid){Qroot, 0, QTDIR};
			break;
		}
		return "path not found";
	}
	*qid = fid->qid;
	return nil;
}

void
fsstat(Req *r)
{
	int q;
	Dir *d;

	d = &r->d;
	memset(d, 0, sizeof *d);
	q = r->fid->qid.path;
	d->qid = r->fid->qid;
	switch(q){
	case Qroot:
		d->name = estrdup9p("/");
		d->mode = DMDIR|0777;
		break;

	case Qkid:
		d->name = estrdup9p(kidname);
		d->mode = kidmode;
		break;
	}

	d->atime = d->mtime = time0;
	d->uid = estrdup9p("stub");
	d->gid = estrdup9p("stub");
	d->muid = estrdup9p("");
	respond(r, nil);
}

int
dirgen(int off, Dir *d, void*)
{
	if(off != 0)
		return -1;

	memset(d, 0, sizeof *d);
	d->atime = d->mtime = time0;
	d->name = estrdup9p(kidname);
	d->mode = kidmode;
	d->qid = (Qid){Qkid, 0, kidmode>>24};
	d->qid.type = d->mode>>24;
	d->uid = estrdup9p("stub");
	d->gid = estrdup9p("stub");
	d->muid = estrdup9p("");
	return 0;
}

void
fsread(Req *r)
{
	int q;

	q = r->fid->qid.path;
	switch(q){
	default:
		respond(r, "bug");
		return;

	case Qroot:
		dirread9p(r, dirgen, nil);
		respond(r, nil);
		return;
	}
}

void
fswrite(Req *r)
{
	respond(r, "no writing");
}

void
fsopen(Req *r)
{
	if(r->fid->qid.path != Qroot){
		respond(r, "permission denied");
		return;
	}

	if(r->ifcall.mode != OREAD)
		respond(r, "permission denied");
	else
		respond(r, nil);
}

Srv fs = {
	.attach=	fsattach,
	.open=	fsopen,
	.read=	fsread,
	.write=	fswrite,
	.stat=	fsstat,
	.walk1=	fswalk1,
};

void
usage(void)
{
	fprint(2, "usage: aux/stub [-Dd] path/name\n");
	exits("usage");
}

void
main(int argc, char **argv)
{
	char *p, *mtpt;

	quotefmtinstall();

	time0 = time(0);
	ARGBEGIN{
	case 'D':
		chatty9p++;
		break;
	case 'd':
		kidmode = DMDIR;
		break;
	default:
		usage();
	}ARGEND

	if(argc != 1)
		usage();

	if((p = strrchr(argv[0], '/')) == 0){
		mtpt = ".";
		kidname = argv[0];
	}else if(p == argv[0]){
		mtpt = "/";
		kidname = argv[0]+1;
	}else{
		mtpt = argv[0];
		*p++ = '\0';
		kidname = p;
	}
	/* don't leave standard descriptors open to confuse mk */
	close(0);
	close(1);
	close(2);
	postmountsrv(&fs, nil, mtpt, MBEFORE);
	exits(nil);
}
