shithub: riscv

Download patch

ref: 8784d2d0ea623b3a6ea77ffb3559b2a6985ee5a5
parent: 4636a1e21adfe395c2afdce2145da497b913d1d3
author: aiju <[email protected]>
date: Sun Jul 24 18:12:01 EDT 2011

added devshr

--- /dev/null
+++ b/sys/src/9/port/devshr.c
@@ -1,0 +1,597 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"../port/error.h"
+
+typedef struct Shr Shr;
+
+struct Shr
+{
+	Ref;
+	char	*name;
+	char	*owner;
+	ulong	perm;
+	Shr	*link;
+	ulong	path;
+	Mhead	umh; /* only lock and mount are used */
+	char	*desc; /* contents of file; nil if invalid, rebuild if necessary */
+	QLock	desclock;
+};
+
+static QLock	shrlk;
+static Shr	*shr;
+static int	qidpath;
+static int	mntid;
+
+static void
+shrdecref(Shr *sp)
+{
+	Mount *m, *mm;
+
+	if(decref(sp) != 0)
+		return;
+	
+	for(m = sp->umh.mount; m != nil; m = mm) {
+		cclose(m->to);
+		mm = m->next;
+		free(m);
+	}
+	free(sp->owner);
+	free(sp->name);
+	free(sp);
+}
+
+static int
+shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
+{
+	Shr *sp;
+	Qid q;
+
+	if(s == DEVDOTDOT){
+		devdir(c, c->qid, "#σ", 0, eve, 0555, dp);
+		return 1;
+	}
+
+	qlock(&shrlk);
+	for(sp = shr; sp && s; sp = sp->link)
+		s--;
+
+	if(sp == 0) {
+		qunlock(&shrlk);
+		return -1;
+	}
+
+	mkqid(&q, sp->path, 0, c->dev ? QTFILE : QTDIR);
+	/* make sure name string continues to exist after we release lock */
+	kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
+	devdir(c, q, up->genbuf, 0, sp->owner, sp->perm & (c->dev ? ~0111 : ~0), dp);
+	qunlock(&shrlk);
+	return 1;
+}
+
+static void
+shrinit(void)
+{
+	qidpath = 1;
+}
+
+static Chan*
+shrattach(char *spec)
+{
+	Chan *c;
+	
+	if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))
+		error(Enoattach);
+
+	c = devattach(L'σ', spec);
+	if(spec[0] == 'c')
+		c->dev = 1;
+	else
+		c->dev = 0;
+	return c;
+}
+
+static Shr*
+shrlookup(char *name, ulong qidpath)
+{
+	Shr *sp;
+	for(sp = shr; sp; sp = sp->link)
+		if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
+			return sp;
+	return nil;
+}
+
+static Walkqid*
+shrwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	Walkqid *wq, *wq2;
+	Shr *sp;
+	int alloc, j;
+	char *n;
+	Mount *f;
+	
+	if(nname > 0)
+		isdir(c);
+
+	alloc = 0;
+	wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
+	if(waserror()){
+		if(alloc && wq->clone != nil)
+			cclose(wq->clone);
+		free(wq);
+		return nil;
+	}
+	if(nc == nil){
+		nc = devclone(c);
+		nc->type = 0;
+		alloc = 1;
+	}
+	nc->aux = nil;
+	wq->clone = nc;
+	for(j = 0; j < nname; j++){
+		if(!(nc->qid.type & QTDIR)){
+			if(j == 0)
+				error(Enotdir);
+			kstrcpy(up->errstr, Enotdir, ERRMAX);
+			goto Done;
+		}
+		n = name[j];
+		if(n[0] == '.' && n[1] == 0)
+			USED(n);
+		else if(n[0] == '.' && n[1] == '.' && n[2] == 0){
+			if(nc->qid.path != 0)
+				nc->qid.path = 0;
+			nc->qid.type = QTDIR;
+		} else if(nc->qid.path == 0) {
+			qlock(&shrlk);
+			sp = shrlookup(n, -1);
+			if(sp != nil){
+				if(waserror()){
+					qunlock(&shrlk);
+					if(j == 0)
+						nexterror();
+					goto Done;
+				}
+				devpermcheck(sp->owner, sp->perm, OEXEC);
+				poperror();
+				mkqid(&nc->qid, sp->path, 0, c->dev ? QTFILE : QTDIR);
+			}
+			qunlock(&shrlk);
+			if(sp == nil)
+				goto Error;
+		} else {
+			qlock(&shrlk);
+			sp = shrlookup(nil, nc->qid.path);
+			if(sp != nil)
+				incref(sp);
+			qunlock(&shrlk);
+			if(sp == nil)
+				goto Error;
+			wq2 = nil;
+			rlock(&sp->umh.lock);
+			for(f = sp->umh.mount; f != nil && wq2 == nil; f = f->next) {
+				if(waserror())
+					continue;
+				wq2 = devtab[f->to->type]->walk(f->to, nil, name + j, nname - j);
+				poperror();
+			}
+			runlock(&sp->umh.lock);
+			shrdecref(sp);
+			if(wq2 == nil)
+				goto Error;
+			memmove(wq->qid + wq->nqid, wq2->qid, wq2->nqid);
+			wq->nqid += wq2->nqid;
+			if(alloc)
+				cclose(wq->clone);
+			wq->clone = wq2->clone;
+			free(wq2);
+			poperror();
+			return wq;
+		}
+		wq->qid[wq->nqid++] = nc->qid;
+	}
+
+	goto Done;
+Error:
+	if(j == 0)
+		error(Enonexist);
+	kstrcpy(up->errstr, Enonexist, ERRMAX);
+Done:
+	poperror();
+	if(wq->nqid < nname) {
+		if(alloc)
+			cclose(wq->clone);
+		wq->clone = nil;
+	} else if(wq->clone)
+		wq->clone->type = c->type;
+	return wq;
+}
+
+static int
+shrstat(Chan *c, uchar *db, int n)
+{
+	return devstat(c, db, n, 0, 0, shrgen);
+}
+
+static Chan*
+shropen(Chan *c, int omode)
+{
+	Shr *sp;
+
+	if(c->qid.type == QTDIR && omode != OREAD)
+		error(Eisdir);
+	if(c->qid.path != 0){
+		qlock(&shrlk);
+		if(waserror()){
+			qunlock(&shrlk);
+			nexterror();
+		}
+		sp = shrlookup(nil, c->qid.path);
+		if(sp == nil)
+			error(Enonexist);
+		if(c->qid.type == QTDIR)
+			c->umh = &sp->umh;
+		devpermcheck(sp->owner, sp->perm, openmode(omode));
+		qunlock(&shrlk);
+		poperror();
+	}
+	if(omode & ORCLOSE)
+		error(Eperm);
+	c->mode = openmode(omode);
+	c->flag |= COPEN;
+	c->offset = 0;
+	return c;
+}
+
+static void
+shrunioncreate(Chan *c, char *name, int omode, ulong perm)
+{
+	Shr *sp;
+	Mount *m;
+	Walkqid *wq;
+	
+	error(Enocreate); /* code below is broken */
+	
+	qlock(&shrlk);
+	sp = shrlookup(nil, c->qid.path);
+	if(sp != nil)
+		incref(sp);
+	qunlock(&shrlk);
+	if(sp == nil)
+		error(Enonexist);
+	if(waserror()){
+		shrdecref(sp);
+		nexterror();
+	}
+	for(m = sp->umh.mount; m != nil; m = m->next)
+		if(m->mflag & MCREATE)
+			break;
+	if(m == nil)
+		error(Enocreate);
+
+	wq = devtab[m->to->type]->walk(m->to, c, nil, 0);
+	if(wq == nil)
+		error(Egreg);
+	if(wq->clone != c){
+		cclose(wq->clone);
+		free(wq);
+		error(Egreg);
+	}
+	free(wq);
+	devtab[c->type]->create(c, name, omode, perm);
+	shrdecref(sp);
+	poperror();
+}
+
+static void
+shrcreate(Chan *c, char *name, int omode, ulong perm)
+{
+	char *sname;
+	Shr *sp;
+	
+	if(c->qid.path != 0) {
+		shrunioncreate(c, name, omode, perm);
+		return;
+	}
+	
+	if(c->dev != 1)
+		error(Eperm);
+
+	if(omode & OCEXEC)	/* can't happen */
+		panic("someone broke namec");
+
+	sp = smalloc(sizeof *sp);
+	sname = smalloc(strlen(name)+1);
+
+	qlock(&shrlk);
+	if(waserror()){
+		free(sp);
+		free(sname);
+		qunlock(&shrlk);
+		nexterror();
+	}
+	if(sp == nil || sname == nil)
+		error(Enomem);
+	if(shrlookup(name, -1))
+		error(Eexist);
+
+	sp->path = qidpath++;
+	sp->link = shr;
+	strcpy(sname, name);
+	sp->name = sname;
+	incref(sp);
+	c->qid.type = QTFILE;
+	c->qid.path = sp->path;
+	shr = sp;
+	qunlock(&shrlk);
+	poperror();
+
+	kstrdup(&sp->owner, up->user);
+	sp->perm = (perm&0777) | ((perm&0444)>>2);
+
+	c->flag |= COPEN;
+	c->mode = OWRITE;
+}
+
+static void
+shrremove(Chan *c)
+{
+	Shr *sp, **l;
+
+	if(c->qid.path == 0)
+		error(Eperm);
+
+	qlock(&shrlk);
+	if(waserror()){
+		qunlock(&shrlk);
+		nexterror();
+	}
+	l = &shr;
+	for(sp = *l; sp; sp = sp->link) {
+		if(sp->path == c->qid.path)
+			break;
+
+		l = &sp->link;
+	}
+	if(sp == 0)
+		error(Enonexist);
+
+	if(strcmp(sp->owner, eve) == 0 && !iseve())
+		error(Eperm);
+	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
+		error(Eperm);
+
+	*l = sp->link;
+	qunlock(&shrlk);
+	poperror();
+
+	shrdecref(sp);
+}
+
+static int
+shrwstat(Chan *c, uchar *dp, int n)
+{
+	char *strs;
+	Dir d;
+	Shr *sp;
+
+	if(c->qid.path == 0)
+		error(Eperm);
+
+	strs = nil;
+	qlock(&shrlk);
+	if(waserror()){
+		qunlock(&shrlk);
+		free(strs);
+		nexterror();
+	}
+
+	sp = shrlookup(nil, c->qid.path);
+	if(sp == 0)
+		error(Enonexist);
+
+	if(strcmp(sp->owner, up->user) != 0 && !iseve())
+		error(Eperm);
+
+	strs = smalloc(n);
+	n = convM2D(dp, n, &d, strs);
+	if(n == 0)
+		error(Eshortstat);
+	if(d.mode != ~0UL)
+		sp->perm = d.mode & 0777;
+	if(d.uid && *d.uid)
+		kstrdup(&sp->owner, d.uid);
+	if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
+		if(strchr(d.name, '/') != nil)
+			error(Ebadchar);
+		kstrdup(&sp->name, d.name);
+	}
+	qunlock(&shrlk);
+	free(strs);
+	poperror();
+	return n;
+}
+
+static void
+shrclose(Chan *c)
+{
+	c->umh = nil;
+	if(c->flag & CRCLOSE){
+		if(waserror())
+			return;
+		shrremove(c);
+		poperror();
+	}
+}
+
+static long
+shrread(Chan *c, void *va, long n, vlong off)
+{
+	Shr *sp;
+	long ret;
+	int nn;
+	Mount *f;
+	char *s, *e;
+
+	if(c->qid.path == 0)
+		return devdirread(c, va, n, 0, 0, shrgen);
+	
+	if(c->qid.type & QTDIR)
+		return unionread(c, va, n);
+	
+	qlock(&shrlk);
+	sp = shrlookup(nil, c->qid.path);
+	if(sp != nil)
+		incref(sp);
+	qunlock(&shrlk);
+	if(sp == nil)
+		error(Enonexist);
+	qlock(&sp->desclock);
+	if(sp->desc == nil){
+		nn = 0;
+		rlock(&sp->umh.lock);
+		for(f = sp->umh.mount; f != nil; f = f->next)
+			nn += 32 + strlen((char*)(f + 1));
+		s = sp->desc = smalloc(nn);
+		e = s + nn;
+		for(f = sp->umh.mount; f != nil; f = f->next)
+			s = seprint(s, e, "%lud %s %C %lud %lld\n", f->mountid, (char*)(f + 1), devtab[f->to->mchan->type]->dc, f->to->mchan->dev, f->to->qid.path);
+		runlock(&sp->umh.lock);
+	}
+	ret = readstr(off, va, n, sp->desc);
+	qunlock(&sp->desclock);
+	return ret;
+}
+
+static long
+shrwrite(Chan *c, void *va, long n, vlong)
+{
+	Shr *sp;
+	char *buf, *p, *desc, *aname;
+	int mode, fd;
+	Chan *bc, *c0;
+	Mount *m, *mm;
+	struct{
+		Chan	*chan;
+		Chan	*authchan;
+		char	*spec;
+		int	flags;
+	}bogus;
+	
+	qlock(&shrlk);
+	sp = shrlookup(nil, c->qid.path);
+	if(sp == nil) {
+		qunlock(&shrlk);
+		error(Enonexist);
+	}
+	incref(sp);
+	qunlock(&shrlk);
+	if(waserror()){
+		shrdecref(sp);
+		nexterror();
+	}
+
+	buf = smalloc(n+1);
+	if(waserror()){
+		free(buf);
+		nexterror();
+	}
+	memmove(buf, va, n);
+	buf[n] = 0;
+	
+	p = buf;
+	mode = 0;
+	for(; *p > ' '; p++)
+		switch(*p) {
+		case 'a': mode |= MAFTER; break;
+		case 'b': mode |= MBEFORE; break;
+		case 'c': mode |= MCREATE; break;
+		case 'C': mode |= MCACHE; break;
+		default: error(Ebadarg);
+		}
+
+	if((mode & (MAFTER|MBEFORE)) == 0 || (mode & (MAFTER|MBEFORE)) == (MAFTER|MBEFORE))
+		error(Ebadarg);
+	while(*p <= ' ')
+		p++;
+	if(*p == 0)
+		error(Ebadarg);
+	fd = strtol(p, &p, 10);
+	while(*p <= ' ' && *p != '\n')
+		p++;
+	if(*p != 0 && *p != '\n') {
+		desc = p;
+		p = strchr(desc, '\n');
+		if(p != nil)
+			*p = 0;
+	} else
+		desc = "";
+	aname = strchr(buf, '\n') + 1;
+	if(aname != nil && *aname == 0)
+		aname = nil;
+	if(strlen(desc) > 128)
+		error(Ebadarg);
+
+	bc = fdtochan(fd, ORDWR, 0, 1);
+	if(waserror()) {
+		cclose(bc);
+		nexterror();
+	}
+	bogus.flags = mode & MCACHE;
+	bogus.chan = bc;
+	bogus.authchan = nil;
+	bogus.spec = aname;
+	c0 = devtab[devno('M', 0)]->attach((char*)&bogus);
+	cclose(bc);
+	poperror();
+
+	m = smalloc(sizeof(Mount) + strlen(desc) + 1);
+	strcpy((char*)(m + 1), desc);
+	m->to = c0;
+	m->mflag = mode;
+	qlock(&shrlk);
+	m->mountid = ++mntid;
+	qunlock(&shrlk);
+	wlock(&sp->umh.lock);
+	if((mode & MAFTER) != 0 && sp->umh.mount != nil) {
+		for(mm = sp->umh.mount; mm->next != nil; mm = mm->next)
+			;
+		mm->next = m;
+	} else {
+		m->next = sp->umh.mount;
+		sp->umh.mount = m;
+	}
+	wunlock(&sp->umh.lock);
+	qlock(&sp->desclock);
+	free(sp->desc);
+	sp->desc = nil;
+	qunlock(&sp->desclock);
+	shrdecref(sp);
+	free(buf);
+	poperror();
+	poperror();
+	return n;
+}
+
+Dev shrdevtab = {
+	L'σ',
+	"shr",
+
+	devreset,
+	shrinit,	
+	devshutdown,
+	shrattach,
+	shrwalk,
+	shrstat,
+	shropen,
+	shrcreate,
+	shrclose,
+	shrread,
+	devbread,
+	shrwrite,
+	devbwrite,
+	shrremove,
+	shrwstat,
+};