Plan 9 from Bell Labs’s /usr/web/sources/contrib/pdt/gphrfs/fs.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


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

#include "dat.h"
#include "fns.h"

enum
{
	Qroot = 0,
	Qctl,
	Qdata,
	QEND,
};

#define PATH(type, n) ((type)|((n)<<8))
#define TYPE(path) ((int)(path) & 0xFF)
#define NUM(path) ((uint)(path)>>8)

typedef struct Tab Tab;
struct Tab
{
	char* name;
	ulong mode;
} tab[] = {
	"/",		DMDIR|0555,
	"ctl",		0666,
	"data",	0444,
};

Conn conn;

static char* fillstat(Dir* d, uvlong path);
static int rootgen(int i, Dir* d, void* aux);
static void ctlread(Req* r);
static void ctlwrite(Req* r);
static void dataread(Req* r);

static void
fsattach(Req* r)
{
	Conn* c;

	c = &conn;

	if(r->ifcall.aname && *r->ifcall.aname){
		respond(r, "fsattach: invalid attach specifier");
		return;
	}

	memset(c, 0, sizeof(Conn));

	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)
{
	respond(r, fillstat(&r->d, r->fid->qid.path));
}

static void
fsdestroyfid(Fid*)
{
	Conn* c;

	c = &conn;

	free(c->datbuf);
	c->datbuf = nil;
}


static void
fsopen(Req* r)
{
	static int need[4] = { 4, 2, 6, 1 };
	Conn* c;
	Tab* t;
	uvlong path;
	int n, fd;

	path = r->fid->qid.path;
	c = &conn;

	t = &tab[TYPE(path)];
	n = need[r->ifcall.mode&3];
	if((n&t->mode) != n){
		respond(r, "fsopen: permission denied");
		return;
	}

	switch(TYPE(path)){
	default:
		break;
	case Qdata:
		if((fd = gphrdial(c->host, c->net, c->service)) < 0){
			c->error = "fsopen: dial failed";
			respond(r, c->error);
			return;
		}
		free(c->datbuf);
		c->datbuf = nil;
		if((c->n = gphrget(fd, c->selector, &c->datbuf)) < 0){
			c->error = "fsopen: get failed";
			respond(r, c->error);
			return;
		}
	}
	respond(r, nil);
}

static void
fsread(Req* r)
{
	Conn* c;

	c = &conn;

	switch(TYPE(r->fid->qid.path)){
	default:
		c->error = "fsread: invalid file type";
		respond(r, c->error);
		return;
	case Qroot:
		dirread9p(r, rootgen, nil);
		respond(r, nil);
		break;
	case Qctl:
		ctlread(r);
		break;
	case Qdata:
		dataread(r);
		break;
	}
}

static void
fswrite(Req* r)
{
	static int need[4] = { 4, 2, 6, 1 };
	Conn* c;
	uvlong path;

	path = r->fid->qid.path;
	c = &conn;

	switch(TYPE(path)){
	default:
		c->error = "fswrite: invalid file type";
		respond(r, c->error);
		return;
	case Qctl:
		ctlwrite(r);
		break;
	}
}

char*
fswalk1(Fid* fid, char* name, Qid* qid)
{
	Conn* c;
	uvlong path;
	Tab* t;
	int i;

	path = fid->qid.path;
	c = &conn;

	if(!(fid->qid.type&QTDIR)){
		c->error = "fswalk1: walk in non-directory";
		return c->error;
	}

	if(strcmp(name, "..") == 0){
		switch(TYPE(path)){
		default:
			c->error = "fswalk1: should not happen";
			return c->error;
		case Qroot:
			qid->path = PATH(Qroot, 0);
			qid->type = tab[Qroot].mode>>24;
			fid->qid = *qid;
			return nil;
		}
	}

	for(i=TYPE(path)+1, t=&tab[i]; i<nelem(tab); i++, t++)
		if(strcmp(name, t->name) == 0){
			qid->path = PATH(i, NUM(path));
			qid->type = t->mode>>24;
			fid->qid = *qid;
			return nil;
		}

	c->error = "fswalk1: cannot find directory entry";
	return c->error;
}

static char*
fsclone(Fid *ofid, Fid *fid)
{
	if(chatty9p) fprint(2, "fsclone: %d -> %d\n", TYPE(ofid->qid.path), TYPE(fid->qid.path));

	return nil;
}

static char*
fillstat(Dir* d, uvlong path)
{
	Tab* t;

	t = &tab[TYPE(path)];
	memset(d, 0, sizeof(Dir));
	if((d->uid = strdup("gphr")) == nil)
		goto statoom;
	if((d->gid = strdup("gphr")) == nil)
		goto statoom;
	if((d->name = strdup(t->name)) == nil)
		goto statoom;
	d->qid.path = path;
	d->qid.type = t->mode>>24;
	d->mode = t->mode;
	/* XXX time should be set to match last update (happens at open or write) */
	d->atime = d->mtime = time(0);

	return nil;

statoom:
	free(d->uid);
	free(d->gid);
	free(d->name);
	return "fillstat: out of memory";
}

static int
rootgen(int i, Dir* d, void*)
{
	i += Qroot+1;
	if(i >= QEND) return -1;
	fillstat(d, i);
	return 0;
}

static void
ctlread(Req* r)
{
	Conn* c;
	char buf[1024];

	c = &conn;
	snprint(buf, 1024, "addr\t%s!%s!%s\nselector\t%s\n", c->net, c->host, c->service, c->selector);
	readstr(r, buf);
	respond(r, nil);
}

static void
ctlwrite(Req* r)
{
	Conn* c;
	char *buf, *cmd, *arg;

	c = &conn;

	if(r->ifcall.count >= 1024){
		c->error = "ctlwrite: message too long";
		respond(r, c->error);
		return;
	}
	if((buf = stredup(r->ifcall.data, (char*)r->ifcall.data+r->ifcall.count)) == nil){
		c->error = "ctlwrite: out of memory";
		respond(r, c->error);
		return;
	}
	r->ofcall.count = r->ifcall.count;

	if(r->ifcall.count >= 1 && buf[r->ifcall.count-1] == '\n')
		buf[r->ifcall.count-1] = '\0';
	cmd = buf;
	arg = strpbrk(cmd, "\t ");
	if(arg){
		*arg++ = '\0';
		arg += strspn(arg, "\t ");
	}else
		arg = "";
	if(strcmp(cmd, "addr") == 0){
		free(c->addrbuf);
		c->addrbuf = buf;
		c->net = nil;
		c->host = nil;
		c->service = nil;
		if(strncmp(arg, "tcp!", 4) == 0){
			arg[3] = '\0';
			c->net = arg;
			arg+=4;
		}else{
			c->net = "tcp";
		}
		c->host = arg;
		c->service = strpbrk(arg, "!");
		if(c->service) *c->service++ = '\0';
		else c->service = "70";
		if(chatty9p) fprint(2, "net: %s, host: %s, service: %s", c->net, c->host, c->service);
	}else if(strcmp(cmd, "selector") == 0){
		free(c->selbuf);
		c->selbuf = buf;
		c->selector = arg;
		if(chatty9p) fprint(2, "selector: %s", c->selector);
	}else{
		c->error = "ctlwrite: invalid command";
		respond(r, c->error);
		return;
	}

	respond(r, nil);
}

static void
dataread(Req* r)
{
	Conn* c;
	long count, offset;

	c = &conn;

	count = r->ifcall.count;
	offset = r->ifcall.offset;
	offset = offset > c->n ? c->n : offset;
	count = offset+count > c->n ? c->n-offset : count;
	r->ifcall.count = count;
	r->ifcall.offset = offset;
	readbuf(r, c->datbuf, c->n);
	c->offset = offset;
	respond(r, nil);
}

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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.