827 lines · 13.3 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" enum {	Qroot,	Qcroot,	Qshr,	Qcshr,	Qcmpt,}; typedef struct Ent Ent;typedef struct Shr Shr;typedef struct Mpt Mpt;typedef struct Sch Sch; struct Ent{	Ref;	int	id;	char	*name;	char	*owner;	ulong	perm;}; struct Shr{	Ent;	Mhead	umh;	Shr	*next;}; struct Mpt{	Ent;	Mount	m;}; struct Sch{	int	level; 	Shr	*shr;	Mpt	*mpt; 	Chan	*chan;}; static QLock	shrslk;static Shr	*shrs; static int	shrid;static int	mptid; static Mpt*tompt(Mount *m){	return (Mpt*)((char*)m - (char*)&((Mpt*)0)->m);} static Sch*tosch(Chan *c){	Sch *sch; 	if(c == nil)		error("nil chan");	sch = c->aux;	if(sch == nil)		error("nil chan aux");	if(sch->chan != c)		error("bad chan");	return sch;} static voidshrinit(void){	shrid = 1;	mptid = 1;} static voidputmpt(Mpt *mpt){	if(decref(mpt))		return;	if(mpt->m.to != nil)		cclose(mpt->m.to);	free(mpt->name);	free(mpt->owner);	free(mpt);} static voidputshr(Shr *shr){	if(decref(shr))		return;	free(shr->name);	free(shr->owner);	free(shr);} static Qidshrqid(int level, int id){	Qid q; 	q.type = (level == Qcmpt) ? QTFILE : QTDIR;	q.path = (uvlong)id<<4 | level;	q.vers = 0;	return q;} static Chan*shrattach(char *spec){	Sch *sch;	Chan *c;		if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))		error(Enoattach);	c = devattach(L'σ', spec); 	sch = smalloc(sizeof(*sch));	sch->level = spec[0] == 'c' ? Qcroot : Qroot;	sch->mpt = nil;	sch->shr = nil;	sch->chan = c;	c->aux = sch;	c->qid = shrqid(sch->level, 0); 	return c;} static Chan*shrclone(Chan *c){	Chan *nc;	Sch *sch, *och; 	och = tosch(c);	nc = devclone(c);	sch = smalloc(sizeof(*sch));	memmove(sch, och, sizeof(*sch));	if(sch->shr != nil)		incref(sch->shr);	if(sch->mpt != nil)		incref(sch->mpt);	sch->chan = nc;	nc->aux = sch;	return nc;} static voidshrclunk(Chan *c){	Sch *sch; 	sch = tosch(c);	c->aux = nil;	sch->chan = nil;	if(sch->mpt != nil)		putmpt(sch->mpt);	if(sch->shr != nil)		putshr(sch->shr);	free(sch);	} static Walkqid*shrwalk(Chan *c, Chan *nc, char **name, int nname){	Walkqid *wq, *wq2;	int alloc, j;	char *nam;	Sch *sch;	Shr *shr;	Mpt *mpt;	Mount *m;	Mhead *h;		alloc = 0;	if(nc == nil){		nc = shrclone(c);		alloc = 1;	}	wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));	wq->nqid = 0;	wq->clone = nc;	if(waserror()){		if(alloc)			cclose(wq->clone);		if(wq->nqid > 0)			wq->clone = nil;		else {			free(wq);			wq = nil;		}		return wq;	}	sch = tosch(nc);	for(j = 0; j < nname; j++){		if(nc->qid.type != QTDIR)			error(Enotdir); 		nam = name[j];		if(nam[0] == '.' && nam[1] == 0) {			/* nop */		} else if(nam[0] == '.' && nam[1] == '.' && nam[2] == 0) {			switch(sch->level){			default:				error(Egreg);			case Qshr:				nc->qid = shrqid(sch->level = Qroot, 0);				break;			case Qcshr:				nc->qid = shrqid(sch->level = Qcroot, 0);				break;			}			putshr(sch->shr);			sch->shr = nil;		} else if(sch->level == Qcroot || sch->level == Qroot) {			qlock(&shrslk);			for(shr = shrs; shr != nil; shr = shr->next)				if(strcmp(nam, shr->name) == 0){					incref(shr);					break;				}			qunlock(&shrslk);			if(shr == nil)				error(Enonexist);			sch->level = sch->level == Qcroot ? Qcshr : Qshr;			sch->shr = shr;			nc->qid = shrqid(sch->level, shr->id);		} else if(sch->level == Qcshr) {			mpt = nil;			shr = sch->shr;			h = &shr->umh;			rlock(&h->lock);			for(m = h->mount; m != nil; m = m->next){				mpt = tompt(m);				if(strcmp(nam, mpt->name) == 0){					incref(mpt);					break;				}			}			runlock(&h->lock);			if(m == nil)				error(Enonexist);			sch->mpt = mpt;			nc->qid = shrqid(sch->level = Qcmpt, mpt->id);		} else if(sch->level == Qshr) {			shr = sch->shr;			h = &shr->umh;			wq2 = nil;			rlock(&h->lock);			for(m = h->mount; m != nil && wq2 == nil; m = m->next){				if(m->to == nil)					continue;				if(waserror())					continue;				wq2 = devtab[m->to->type]->walk(m->to, nil, name + j, nname - j);				poperror();			}			runlock(&h->lock);			if(wq2 == nil)				error(Enonexist);			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;		} else			error(Egreg);		wq->qid[wq->nqid++] = nc->qid;	}	poperror();	return wq;} static intshrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp){	Mpt *mpt;	Sch *sch;	Shr *shr;	Mhead *h;	Mount *m; 	sch = tosch(c);	switch(sch->level){	default:		return -1;	case Qroot:	case Qcroot:		qlock(&shrslk);		for(shr = shrs; shr != nil && s > 0; shr = shr->next)			s--;		if(shr == nil){			qunlock(&shrslk);			return -1;		}		kstrcpy(up->genbuf, shr->name, sizeof up->genbuf);		if(sch->level == Qroot)			devdir(c, shrqid(Qshr, shr->id), up->genbuf, 0, shr->owner,				shr->perm & ~0222, dp);		else			devdir(c, shrqid(Qcshr, shr->id), up->genbuf, 0, shr->owner,				shr->perm, dp);		qunlock(&shrslk);		return 1;	case Qcshr:		shr = sch->shr;		h = &shr->umh;		rlock(&h->lock);		for(m = h->mount; m != nil && s > 0; m = m->next)			s--;		if(m == nil){			runlock(&h->lock);			return -1;		}		mpt = tompt(m);		kstrcpy(up->genbuf, mpt->name, sizeof up->genbuf);		devdir(c, shrqid(Qcmpt, mpt->id), up->genbuf, 0, mpt->owner, mpt->perm, dp);		runlock(&h->lock);		return 1;	}} static intshrstat(Chan *c, uchar *db, int n){	Sch *sch;	Dir dir;	int rc; 	sch = tosch(c);	switch(sch->level){	default:		error(Egreg);	case Qroot:		devdir(c, c->qid, "#σ", 0, eve, 0555, &dir);		break;	case Qcroot:		devdir(c, c->qid, "#σc", 0, eve, 0777, &dir);		break;	case Qshr:		devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm & ~0222, &dir);		break;	case Qcshr:		devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm, &dir);		break;	case Qcmpt:		devdir(c, c->qid, sch->mpt->name, 0, sch->mpt->owner, sch->mpt->perm, &dir);		break;	}	rc = convD2M(&dir, db, n);	if(rc == 0)		error(Ebadarg);	return rc;} static Chan*shropen(Chan *c, int omode){	Chan *nc;	Sch *sch;	Shr *shr;	Mpt *mpt;	int mode; 	if(c->qid.type == QTDIR && omode != OREAD)		error(Eisdir); 	mode = openmode(omode);	sch = tosch(c);	switch(sch->level){	default:		error(Egreg);	case Qroot:	case Qcroot:		break;	case Qshr:	case Qcshr:		shr = sch->shr;		devpermcheck(shr->owner, shr->perm, mode);		break;	case Qcmpt:		if(omode&OTRUNC)			error(Eexist);		shr = sch->shr;		mpt = sch->mpt;		devpermcheck(mpt->owner, mpt->perm, mode);		rlock(&shr->umh.lock);		if(mpt->m.to == nil || mpt->m.to->mchan == nil){			runlock(&shr->umh.lock);			error(Eshutdown);		}		nc = mpt->m.to->mchan;		incref(nc);		runlock(&shr->umh.lock);		if(mode != nc->mode){			cclose(nc);			error(Eperm);		}		cclose(c);		return nc;	}	c->mode = mode;	c->flag |= COPEN;	c->offset = 0;	return c;} /* chan.c */Chan* createdir(Chan *c, Mhead *m); static Chan*shrcreate(Chan *c, char *name, int omode, ulong perm){	Sch *sch;	Shr *shr;	Mpt *mpt;	Mhead *h;	Mount *m;	Chan *nc;	int mode; 	mode = openmode(omode);	sch = tosch(c);	switch(sch->level){	case Qcroot:	case Qcshr:		if(strcmp(up->user, "none") == 0)			error(Eperm);	}	switch(sch->level){	default:		error(Eperm);	case Qshr:		incref(c);		if(waserror()){			cclose(c);			nexterror();		}		nc = createdir(c, &sch->shr->umh);		poperror();		if(waserror()){			cclose(nc);			nexterror();		}		nc = devtab[nc->type]->create(nc, name, omode, perm);		poperror();		cclose(c);		return nc;		case Qcroot:		if(up->pgrp->noattach)			error(Enoattach);		if((perm & DMDIR) == 0 || mode != OREAD)			error(Eperm);		if(strlen(name) >= sizeof(up->genbuf))			error(Etoolong);		qlock(&shrslk);		if(waserror()){			qunlock(&shrslk);			nexterror();		}		for(shr = shrs; shr != nil; shr = shr->next)			if(strcmp(name, shr->name) == 0)				error(Eexist); 		shr = smalloc(sizeof(*shr));		incref(shr);		shr->id = shrid++; 		kstrdup(&shr->name, name);		kstrdup(&shr->owner, up->user);		shr->perm = perm; 		incref(shr);		shr->next = shrs;		shrs = shr; 		poperror();		qunlock(&shrslk); 		c->qid = shrqid(sch->level = Qcshr, shr->id);		sch->shr = shr;		break;	case Qcshr:		if(up->pgrp->noattach)			error(Enoattach);

Lines 1–500 of 827.