plan 9 kernel history: overview | file list | diff list

1999/0629/port/chan.c (diff list | history)

port/chan.c on 1990/0227
1990/0227    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0227    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0227    
 
1999/0629    
enum 
{ 
	CNAMESLOP	= 20 
}; 
 
1992/0620    
struct 
{ 
1990/0227    
	Lock; 
1992/0620    
	int	fid; 
1993/0501    
	Chan	*free; 
	Chan	*list; 
1990/0227    
}chanalloc; 
 
1999/0629    
#define SEP(c) ((c) == 0 || (c) == '/') 
 
1990/0227    
int 
incref(Ref *r) 
{ 
1990/1104    
	int x; 
 
1990/0227    
	lock(r); 
1990/1104    
	x = ++r->ref; 
1990/0227    
	unlock(r); 
1990/1104    
	return x; 
1990/0227    
} 
 
int 
decref(Ref *r) 
{ 
1990/1104    
	int x; 
 
1990/0227    
	lock(r); 
1990/1104    
	x = --r->ref; 
1990/0227    
	unlock(r); 
1998/0512    
	if(x < 0) 
1991/0705    
		panic("decref"); 
1991/0723    
 
1990/1104    
	return x; 
1990/0227    
} 
 
void 
1993/0501    
chanrec(Mnt *m) 
{ 
	Chan *c; 
 
	lock(&chanalloc); 
	for(c = chanalloc.list; c; c = c->link) 
		if(c->mntptr == m) 
			c->flag |= CRECOV; 
	unlock(&chanalloc); 
} 
 
void 
1990/0227    
chandevreset(void) 
{ 
	int i; 
 
1997/0408    
	for(i=0; devtab[i] != nil; i++) 
1997/0327    
		devtab[i]->reset(); 
1990/0227    
} 
 
void 
chandevinit(void) 
{ 
	int i; 
 
1997/0408    
	for(i=0; devtab[i] != nil; i++) 
1997/0327    
		devtab[i]->init(); 
1990/0227    
} 
 
Chan* 
newchan(void) 
{ 
	Chan *c; 
 
1992/0620    
	lock(&chanalloc); 
	c = chanalloc.free; 
1993/0501    
	if(c != 0) 
1992/0620    
		chanalloc.free = c->next; 
	unlock(&chanalloc); 
 
	if(c == 0) { 
		c = smalloc(sizeof(Chan)); 
1993/0501    
		lock(&chanalloc); 
		c->fid = ++chanalloc.fid; 
		c->link = chanalloc.list; 
		chanalloc.list = c; 
		unlock(&chanalloc); 
1990/0227    
	} 
1992/0620    
 
	/* if you get an error before associating with a dev, 
	   close calls rootclose, a nop */ 
	c->type = 0; 
	c->flag = 0; 
	c->ref = 1; 
	c->dev = 0; 
	c->offset = 0; 
1998/0829    
	c->mh = 0; 
	c->xmh = 0; 
	c->uri = 0; 
1992/0620    
	c->aux = 0; 
	c->mchan = 0; 
1993/1013    
	c->mcp = 0; 
1992/0620    
	c->mqid = (Qid){0, 0}; 
1999/0629    
	c->name = 0; 
1992/0620    
	return c; 
1990/0227    
} 
 
1999/0629    
static Ref ncname; 
 
Cname* 
newcname(char *s) 
{ 
	Cname *n; 
	int i; 
 
	n = smalloc(sizeof(Cname)); 
	i = strlen(s); 
	n->len = i; 
	n->alen = i+CNAMESLOP; 
	n->s = smalloc(n->alen); 
	memmove(n->s, s, i+1); 
	n->ref = 1; 
	incref(&ncname); 
	return n; 
} 
 
1997/1210    
void 
1999/0629    
cnameclose(Cname *n) 
{ 
	if(n == 0) 
		return; 
	if(decref(n)) 
		return; 
	decref(&ncname); 
	free(n->s); 
	free(n); 
} 
 
Cname* 
addelem(Cname *n, char *s) 
{ 
	int i, a; 
	char *t; 
	Cname *new; 
 
	if(n->ref > 1){ 
		/* copy on write */ 
		new = newcname(n->s); 
		cnameclose(n); 
		n = new; 
	} 
 
	i = strlen(s); 
	if(n->len+1+i+1 < n->alen){ 
		a = n->len+1+i+1 + CNAMESLOP; 
		t = smalloc(a); 
		memmove(t, n->s, n->len+1); 
		free(n->s); 
		n->s = t; 
		n->alen = a; 
	} 
	n->s[n->len++] = '/'; 
	memmove(n->s+n->len, s, i+1); 
	n->len += i; 
	return n; 
} 
 
void 
1992/0320    
chanfree(Chan *c) 
{ 
	c->flag = CFREE; 
1993/0501    
 
1993/0330    
	if(c->session){ 
		freesession(c->session); 
		c->session = 0; 
	} 
1993/0501    
 
1998/0829    
	if(c->mh != nil){ 
		putmhead(c->mh); 
		c->mh = nil; 
	} 
 
1999/0629    
	cnameclose(c->name); 
1993/0501    
 
1992/0320    
	lock(&chanalloc); 
	c->next = chanalloc.free; 
	chanalloc.free = c; 
	unlock(&chanalloc); 
} 
 
void 
1997/0327    
cclose(Chan *c) 
1990/0227    
{ 
1994/0813    
	if(c->flag&CFREE) 
1999/0501    
		panic("cclose %lux", getcallerpc(&c)); 
1993/0501    
	if(decref(c)) 
		return; 
 
	if(!waserror()) { 
1997/0327    
		devtab[c->type]->close(c); 
1993/0501    
		poperror(); 
1990/0227    
	} 
1993/0501    
 
	chanfree(c); 
} 
1990/0227    
 
int 
1990/11211    
eqqid(Qid a, Qid b) 
1990/0227    
{ 
1990/11211    
	return a.path==b.path && a.vers==b.vers; 
} 
 
int 
eqchan(Chan *a, Chan *b, int pathonly) 
{ 
	if(a->qid.path != b->qid.path) 
1990/0227    
		return 0; 
1990/11211    
	if(!pathonly && a->qid.vers!=b->qid.vers) 
		return 0; 
1990/0227    
	if(a->type != b->type) 
		return 0; 
	if(a->dev != b->dev) 
		return 0; 
	return 1; 
} 
 
int 
1997/0327    
cmount(Chan *new, Chan *old, int flag, char *spec) 
1990/0227    
{ 
	Pgrp *pg; 
1993/1115    
	int order, flg; 
1991/1011    
	Mhead *m, **l; 
1993/1115    
	Mount *nm, *f, *um, **h; 
1990/0227    
 
1990/11211    
	if(CHDIR & (old->qid.path^new->qid.path)) 
		error(Emount); 
1991/1011    
 
	order = flag&MORDER; 
 
	if((old->qid.path&CHDIR)==0 && order != MREPL) 
1990/11211    
		error(Emount); 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	wlock(&pg->ns); 
 
	l = &MOUNTH(pg, old); 
	for(m = *l; m; m = m->hash) { 
		if(eqchan(m->from, old, 1)) 
			break; 
		l = &m->hash; 
1990/0227    
	} 
1991/1011    
 
	if(m == 0) { 
1993/1217    
		/* 
		 *  nothing mounted here yet.  create a mount 
		 *  head and add to the hash table. 
		 */ 
1992/0619    
		m = smalloc(sizeof(Mhead)); 
1998/0829    
		m->ref = 1; 
1991/1011    
		m->from = old; 
		incref(old); 
		m->hash = *l; 
		*l = m; 
1993/1217    
 
		/* 
		 *  if this is a union mount, add the old 
		 *  node to the mount chain. 
		 */ 
1998/0512    
		if(order != MREPL) 
1993/0501    
			m->mount = newmount(m, old, 0, 0); 
1990/0227    
	} 
1998/0829    
	wlock(&m->lock); 
	if(waserror()){ 
		wunlock(&m->lock); 
		nexterror(); 
	} 
	wunlock(&pg->ns); 
1990/0227    
 
1993/0501    
	nm = newmount(m, new, flag, spec); 
1998/0829    
	if(new->mh != nil && new->mh->mount != nil) { 
1993/1216    
		/* 
		 *  copy a union when binding it onto a directory 
		 */ 
		flg = order; 
		if(order == MREPL) 
			flg = MAFTER; 
1993/1115    
		h = &nm->next; 
1998/0829    
		um = new->mh->mount; 
		for(um = um->next; um; um = um->next) { 
1993/1115    
			f = newmount(m, um->to, flg, um->spec); 
			*h = f; 
			h = &f->next; 
		} 
1993/1216    
	} 
 
	if(m->mount && order == MREPL) { 
		mountfree(m->mount); 
		m->mount = 0; 
1993/1115    
	} 
1993/0501    
 
1990/0227    
	if(flag & MCREATE) 
		new->flag |= CCREATE; 
 
1991/1011    
	if(m->mount && order == MAFTER) { 
		for(f = m->mount; f->next; f = f->next) 
			; 
		f->next = nm; 
	} 
	else { 
1993/1115    
		for(f = nm; f->next; f = f->next) 
			; 
		f->next = m->mount; 
1991/1011    
		m->mount = nm; 
	} 
1990/0227    
 
1998/0829    
	wunlock(&m->lock); 
1991/1011    
	poperror(); 
	return nm->mountid; 
} 
1990/0227    
 
1991/1011    
void 
1997/0327    
cunmount(Chan *mnt, Chan *mounted) 
1991/1011    
{ 
	Pgrp *pg; 
	Mhead *m, **l; 
	Mount *f, **p; 
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	wlock(&pg->ns); 
 
	l = &MOUNTH(pg, mnt); 
	for(m = *l; m; m = m->hash) { 
		if(eqchan(m->from, mnt, 1)) 
			break; 
		l = &m->hash; 
1990/0227    
	} 
 
1991/1011    
	if(m == 0) { 
		wunlock(&pg->ns); 
1992/0111    
		error(Eunmount); 
1990/0321    
	} 
1991/1011    
 
1998/0829    
	wlock(&m->lock); 
1991/1011    
	if(mounted == 0) { 
		*l = m->hash; 
		wunlock(&pg->ns); 
		mountfree(m->mount); 
1998/0829    
		m->mount = nil; 
1997/0327    
		cclose(m->from); 
1998/0829    
		wunlock(&m->lock); 
		putmhead(m); 
1991/1011    
		return; 
	} 
1998/0829    
	wunlock(&pg->ns); 
1991/1011    
 
	p = &m->mount; 
	for(f = *p; f; f = f->next) { 
1994/0115    
		/* BUG: Needs to be 2 pass */ 
1994/0509    
		if(eqchan(f->to, mounted, 1) || 
		  (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) { 
1991/1011    
			*p = f->next; 
			f->next = 0; 
			mountfree(f); 
1998/0829    
			if(m->mount == nil) { 
1991/1011    
				*l = m->hash; 
				wunlock(&pg->ns); 
1997/0327    
				cclose(m->from); 
1998/0829    
				wunlock(&m->lock); 
				putmhead(m); 
1991/1011    
				return; 
			} 
1998/0829    
			wunlock(&m->lock); 
1991/1011    
			return; 
		} 
		p = &f->next; 
	} 
1998/0829    
	wunlock(&m->lock); 
1992/0111    
	error(Eunion); 
1990/0227    
} 
 
Chan* 
1997/0327    
cclone(Chan *c, Chan *nc) 
1990/0227    
{ 
1999/0629    
	nc = devtab[c->type]->clone(c, nc); 
	if(nc != nil){ 
		nc->name = c->name; 
		if(c->name) 
			incref(c->name); 
	} 
	return nc; 
1990/0227    
} 
 
1991/0427    
Chan* 
domount(Chan *c) 
1990/0227    
{ 
	Pgrp *pg; 
1991/1011    
	Chan *nc; 
	Mhead *m; 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	rlock(&pg->ns); 
1998/0829    
	if(c->mh){ 
		putmhead(c->mh); 
		c->mh = 0; 
1991/0427    
	} 
1991/1011    
 
1998/0829    
	for(m = MOUNTH(pg, c); m; m = m->hash){ 
		rlock(&m->lock); 
1991/1011    
		if(eqchan(m->from, c, 1)) { 
1998/0829    
			if(waserror()) { 
				runlock(&m->lock); 
				nexterror(); 
			} 
			runlock(&pg->ns); 
1997/0327    
			nc = cclone(m->mount->to, 0); 
1998/0829    
			if(nc->mh != nil) 
				putmhead(nc->mh); 
			nc->mh = m; 
			nc->xmh = m; 
			incref(m); 
1997/0327    
			cclose(c); 
1998/0512    
			c = nc; 
1998/0829    
			poperror(); 
			runlock(&m->lock); 
			return c; 
1991/1011    
		} 
1998/0829    
		runlock(&m->lock); 
	} 
1991/1011    
 
	runlock(&pg->ns); 
	return c; 
1990/0227    
} 
 
1991/0427    
Chan* 
1991/1011    
undomount(Chan *c) 
1990/0227    
{ 
1997/1121    
	Chan *nc; 
1991/1011    
	Pgrp *pg; 
	Mount *t; 
1997/1121    
	Mhead **h, **he, *f; 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
		nexterror(); 
1991/0427    
	} 
 
1991/1011    
	he = &pg->mnthash[MNTHASH]; 
	for(h = pg->mnthash; h < he; h++) { 
		for(f = *h; f; f = f->hash) { 
1992/0825    
			for(t = f->mount; t; t = t->next) { 
1991/1011    
				if(eqchan(c, t->to, 1)) { 
1997/1121    
					nc = cclone(t->head->from, 0); 
1997/0327    
					cclose(c); 
1997/1121    
					c = nc; 
1991/1011    
					break; 
				} 
1992/0825    
			} 
1991/0427    
		} 
1990/0914    
	} 
1991/1011    
	poperror(); 
	runlock(&pg->ns); 
	return c; 
} 
1990/0914    
 
1998/0224    
int 
1999/0629    
walkname(Chan **cp, char *name, int domnt) 
{ 
	Chan *c; 
 
	if(walk(cp, name, domnt) < 0) 
		return -1; 
	c = *cp; 
	if(c->name == nil) 
		c->name = newcname(name); 
	else 
		c->name = addelem(c->name, name); 
	return 0; 
} 
 
int 
1998/0224    
walk(Chan **cp, char *name, int domnt) 
1991/1011    
{ 
1998/0224    
	Chan *c, *ac; 
1991/1011    
	Mount *f; 
	int dotdot; 
1990/0227    
 
1998/0224    
	ac = *cp; 
 
1993/0501    
	if(name[0] == '\0') 
1998/0224    
		return 0; 
1990/0914    
 
1991/1011    
	dotdot = 0; 
1993/0501    
	if(name[0] == '.' && name[1] == '.' && name[2] == '\0') { 
1998/0224    
		*cp = ac = undomount(ac); 
1991/1011    
		dotdot = 1; 
	} 
1991/0427    
 
1997/0813    
	ac->flag &= ~CCREATE;	/* not inherited through a walk */ 
1997/0327    
	if(devtab[ac->type]->walk(ac, name) != 0) { 
1991/1011    
		if(dotdot) 
1998/0224    
			*cp = undomount(*cp); 
1991/1011    
		if(domnt) 
1998/0224    
			*cp = domount(*cp); 
		return 0; 
1991/1011    
	} 
 
1998/0829    
	if(ac->mh == nil) 
1998/0224    
		return -1; 
1991/1011    
 
1998/0224    
	c = nil; 
1993/0501    
 
1998/0829    
	rlock(&ac->mh->lock); 
1991/1011    
	if(waserror()) { 
1998/0829    
		runlock(&ac->mh->lock); 
1991/1011    
		if(c) 
1997/0327    
			cclose(c); 
1991/1011    
		nexterror(); 
	} 
1998/0829    
	for(f = ac->mh->mount; f; f = f->next) { 
1997/0327    
		c = cclone(f->to, 0); 
1997/0813    
		c->flag &= ~CCREATE;	/* not inherited through a walk */ 
1997/0327    
		if(devtab[c->type]->walk(c, name) != 0) 
1991/1011    
			break; 
1997/0327    
		cclose(c); 
1998/0224    
		c = nil; 
1991/1011    
	} 
	poperror(); 
1998/0829    
	runlock(&ac->mh->lock); 
1991/1011    
 
1998/0224    
	if(c == nil) 
		return -1; 
1993/0501    
 
	if(dotdot) 
		c = undomount(c); 
 
1998/0829    
	if(c->mh){ 
		putmhead(c->mh); 
		c->mh = nil; 
	} 
1993/0501    
	if(domnt) { 
		if(waserror()) { 
1997/0327    
			cclose(c); 
1993/0501    
			nexterror(); 
1991/1011    
		} 
1993/0501    
		c = domount(c); 
		poperror(); 
1991/1011    
	} 
1997/0327    
	cclose(ac); 
1998/0224    
	*cp = c; 
1998/0512    
	return 0; 
1990/0227    
} 
 
/* 
1991/0427    
 * c is a mounted non-creatable directory.  find a creatable one. 
1990/0227    
 */ 
1991/0427    
Chan* 
createdir(Chan *c) 
1990/0227    
{ 
1991/1011    
	Chan *nc; 
	Mount *f; 
1990/0227    
 
1998/0829    
	rlock(&c->mh->lock); 
1991/1011    
	if(waserror()) { 
1998/0829    
		runlock(&c->mh->lock); 
1990/0227    
		nexterror(); 
	} 
1998/0829    
	for(f = c->mh->mount; f; f = f->next) { 
1991/1011    
		if(f->to->flag&CCREATE) { 
1997/0327    
			nc = cclone(f->to, 0); 
1998/0829    
			if(nc->mh != nil) 
				putmhead(nc->mh); 
			nc->mh = c->mh; 
			incref(c->mh); 
			runlock(&c->mh->lock); 
1991/1126    
			poperror(); 
1997/0327    
			cclose(c); 
1991/1011    
			return nc; 
		} 
1990/0227    
	} 
1991/1011    
	error(Enocreate); 
1997/0327    
	return 0; 
1990/0227    
} 
 
1993/0501    
Chan* 
1995/0208    
mchan(char *id, int walkname) 
1993/0501    
{ 
	Chan *c; 
	Pgrp *pg; 
	Mount *t; 
	int mdev; 
	ulong mountid; 
	Mhead **h, **he, *f; 
 
	mountid = strtoul(id, 0, 0); 
	mdev = devno('M', 0); 
 
	pg = up->pgrp; 
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
		nexterror(); 
	} 
 
	he = &pg->mnthash[MNTHASH]; 
	for(h = pg->mnthash; h < he; h++) { 
		for(f = *h; f; f = f->hash) { 
			for(t = f->mount; t; t = t->next) { 
				c = t->to; 
				if(c->type == mdev && c->mntptr->id == mountid) { 
1995/0208    
					if(walkname == 0) { 
						c = c->mntptr->c; 
						incref(c); 
					} 
					else 
1997/0327    
						c = cclone(c, 0); 
1993/0501    
					runlock(&pg->ns); 
					poperror(); 
					return c; 
				} 
			} 
		} 
	} 
	error(Enonexist); 
	return 0; 
} 
 
1990/0914    
void 
saveregisters(void) 
{ 
} 
 
1990/0227    
/* 
1999/0629    
 * In place, rewrite name to compress multiple /, eliminate ., and process .. 
 */ 
void 
cleanname(Cname *n, int offset) 
{ 
	char *p, *q, *dotdot, *name; 
	int rooted; 
 
	name = n->s+offset; 
	rooted = name[0] == '/'; 
 
	/* 
	 * invariants: 
	 *	p points at beginning of path element we're considering. 
	 *	q points just past the last path element we wrote (no slash). 
	 *	dotdot points just past the point where .. cannot backtrack 
	 *		any further (no slash). 
	 */ 
	p = q = dotdot = name+rooted; 
	while(*p) { 
		if(p[0] == '/')	/* null element */ 
			p++; 
		else if(p[0] == '.' && SEP(p[1])) 
			p += 1;	/* don't count the separator in case it is nul */ 
		else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { 
			p += 2; 
			if(q > dotdot) {	/* can backtrack */ 
				while(--q > dotdot && *q != '/') 
					; 
			} else if(!rooted) {	/* ``/..'' ≡ ``/'', but ``./../'' ≡ ``..'' */ 
				if(q != name) 
					*q++ = '/'; 
				*q++ = '.'; 
				*q++ = '.'; 
				dotdot = q; 
			} 
		} else {	/* real path element */ 
			if(q != name+rooted) 
				*q++ = '/'; 
			while((*q = *p) != '/' && *q != 0) 
				p++, q++; 
		} 
	} 
	if(q == name)	/* empty string is really ``.'' */ 
		*q++ = '.'; 
	*q = 0; 
	n->len = (q-name) + offset; 
} 
 
/* 
1990/0227    
 * Turn a name into a channel. 
 * &name[0] is known to be a valid address.  It may be a kernel address. 
 */ 
Chan* 
namec(char *name, int amode, int omode, ulong perm) 
{ 
1992/1217    
	Rune r; 
1990/0821    
	char *p; 
1992/0711    
	char *elem; 
1999/0629    
	Cname *cname; 
	int t, n, newname; 
1993/0501    
	int mntok, isdot; 
1998/0224    
	Chan *c, *cc; 
1991/1105    
	char createerr[ERRLEN]; 
1990/0227    
 
	if(name[0] == 0) 
1990/11211    
		error(Enonexist); 
1990/0821    
 
1993/0501    
	if(!((ulong)name & KZERO)) { 
1990/0821    
		p = name; 
		t = BY2PG-((ulong)p&(BY2PG-1)); 
1993/0501    
		while(vmemchr(p, 0, t) == 0) { 
1990/0821    
			p += t; 
			t = BY2PG; 
		} 
	} 
 
1999/0629    
	newname = 1; 
	cname = nil; 
	if(waserror()){ 
		cnameclose(cname); 
		nexterror(); 
	} 
 
1993/0501    
	elem = up->elem; 
1990/0227    
	mntok = 1; 
1990/0820    
	isdot = 0; 
1993/0501    
	switch(name[0]) { 
	case '/': 
1999/0629    
		cname = newcname(name);	/* save this before advancing */ 
1990/0227    
		name = skipslash(name); 
1999/0629    
		c = cclone(up->slash, 0); 
1993/0501    
		break; 
	case '#': 
1999/0629    
		cname = newcname(name);	/* save this before advancing */ 
1990/0227    
		mntok = 0; 
1993/0501    
		elem[0] = 0; 
		n = 0; 
		while(*name && (*name != '/' || n < 2)) 
			elem[n++] = *name++; 
		elem[n] = '\0'; 
		n = chartorune(&r, elem+1)+1; 
		if(r == 'M') { 
1995/0208    
			if(elem[n] == 'c') { 
				c = mchan(elem+n+1, 0); 
				name = skipslash(name); 
				if(*name) 
					error(Efilename); 
1999/0629    
				poperror(); 
				cnameclose(cname); 
1995/0208    
				return c; 
			} 
			else { 
				c = mchan(elem+n, 1); 
				name = skipslash(name); 
			} 
1994/1212    
			break; 
1993/0501    
		} 
1992/1217    
		t = devno(r, 1); 
1990/0227    
		if(t == -1) 
1990/11211    
			error(Ebadsharp); 
1993/0501    
 
1997/0327    
		c = devtab[t]->attach(elem+n); 
1993/0501    
		name = skipslash(name); 
		break; 
	default: 
1999/0629    
		cname = newcname(up->dot->name->s); 
		cname = addelem(cname, name); 
1997/0327    
		c = cclone(up->dot, 0); 
1993/0501    
		name = skipslash(name); 
1990/0820    
		if(*name == 0) 
			isdot = 1; 
	} 
1990/0227    
 
	if(waserror()){ 
1997/0327    
		cclose(c); 
1990/0227    
		nexterror(); 
	} 
 
	name = nextelem(name, elem); 
1990/0820    
 
1991/0416    
	/* 
	 *  If mounting, don't follow the mount entry for root or the 
	 *  current directory. 
	 */ 
	if(mntok && !isdot && !(amode==Amount && elem[0]==0)) 
1991/0427    
		c = domount(c);			/* see case Atodir below */ 
1990/0227    
 
1993/0501    
	while(*name) { 
1998/0224    
		if(walk(&c, elem, mntok) < 0) 
1990/11211    
			error(Enonexist); 
1990/0227    
		name = nextelem(name, elem); 
	} 
1990/0820    
 
1993/1007    
	switch(amode) { 
1990/0227    
	case Aaccess: 
1993/1007    
		if(isdot) { 
1991/0427    
			c = domount(c); 
1993/1007    
			break; 
1990/0820    
		} 
1998/0224    
		if(walk(&c, elem, mntok) < 0) 
1993/1007    
			error(Enonexist); 
1990/0227    
		break; 
 
	case Atodir: 
		/* 
		 * Directories (e.g. for cd) are left before the mount point, 
		 * so one may mount on / or . and see the effect. 
		 */ 
1998/0224    
		if(walk(&c, elem, 0) < 0) 
1990/11211    
			error(Enonexist); 
1991/0427    
		if(!(c->qid.path & CHDIR)) 
1990/11211    
			error(Enotdir); 
1990/0227    
		break; 
 
	case Aopen: 
1990/0820    
		if(isdot) 
1991/0427    
			c = domount(c); 
1993/0501    
		else { 
1998/0224    
			if(walk(&c, elem, mntok) < 0) 
1990/11211    
				error(Enonexist); 
1990/0820    
		} 
1990/0227    
	Open: 
1991/1011    
		/* else error() in open has wrong value of c saved */ 
1993/1018    
		saveregisters(); 
 
1993/1017    
		if(omode == OEXEC) 
1993/1018    
			c->flag &= ~CCACHE; 
1998/0512    
 
1999/0629    
		cc = c; 
1999/0122    
		c = devtab[c->type]->open(c, omode&~OCEXEC); 
1999/0629    
		if(cc != c) 
			newname = 0; 
1993/1018    
 
1990/08141    
		if(omode & OCEXEC) 
1991/0427    
			c->flag |= CCEXEC; 
1992/0811    
		if(omode & ORCLOSE) 
			c->flag |= CRCLOSE; 
1990/0227    
		break; 
 
	case Amount: 
		/* 
1993/0501    
		 * When mounting on an already mounted upon directory, 
1998/0512    
		 * one wants subsequent mounts to be attached to the 
1993/0501    
		 * original directory, not the replacement. 
1990/0227    
		 */ 
1998/0224    
		if(walk(&c, elem, 0) < 0) 
1990/11211    
			error(Enonexist); 
1990/0227    
		break; 
 
	case Acreate: 
1990/0820    
		if(isdot) 
1990/11211    
			error(Eisdir); 
1991/0427    
 
		/* 
		 *  Walk the element before trying to create it 
		 *  to see if it exists.  We clone the channel 
		 *  first, just in case someone is trying to 
		 *  use clwalk outside the kernel. 
		 */ 
1997/0327    
		cc = cclone(c, 0); 
1991/0427    
		if(waserror()){ 
1997/0327    
			cclose(cc); 
1991/0427    
			nexterror(); 
		} 
1991/0727    
		nameok(elem); 
1998/0224    
		if(walk(&cc, elem, 1) == 0){ 
1991/0427    
			poperror(); 
1997/0327    
			cclose(c); 
1998/0224    
			c = cc; 
1990/0227    
			omode |= OTRUNC; 
			goto Open; 
		} 
1997/0327    
		cclose(cc); 
1991/0427    
		poperror(); 
 
		/* 
		 *  the file didn't exist, try the create 
		 */ 
1998/0829    
		if(c->mh != nil && !(c->flag&CCREATE)) 
1991/0427    
			c = createdir(c); 
1991/1105    
 
		/* 
1993/0501    
		 * protect against the open/create race. 
		 * This is not a complete fix. It just reduces the window. 
1991/1105    
		 */ 
		if(waserror()) { 
1993/0501    
			strcpy(createerr, up->error); 
1998/0224    
			if(walk(&c, elem, 1) < 0) 
1992/0111    
				error(createerr); 
1991/1105    
			omode |= OTRUNC; 
			goto Open; 
		} 
1999/0122    
		devtab[c->type]->create(c, elem, omode&~OCEXEC, perm); 
1990/08141    
		if(omode & OCEXEC) 
1991/0427    
			c->flag |= CCEXEC; 
1996/0730    
		if(omode & ORCLOSE) 
			c->flag |= CRCLOSE; 
1991/1105    
		poperror(); 
1990/0227    
		break; 
 
	default: 
		panic("unknown namec access %d\n", amode); 
	} 
1999/0629    
 
	poperror(); 
 
	/* peculiar workaround for #/ */ 
	if(newname){ 
		if(cname->s[0]=='#' && cname->s[1]=='/') 
			cleanname(cname, 2); 
		else 
			cleanname(cname, 0); 
		cnameclose(c->name); 
		c->name = cname; 
	}else 
		cnameclose(cname); 
 
1990/0227    
	poperror(); 
1991/0427    
	return c; 
1990/0227    
} 
 
/* 
 * name[0] is addressable. 
 */ 
char* 
skipslash(char *name) 
{ 
1990/0820    
    Again: 
1990/0821    
	while(*name == '/') 
1990/0227    
		name++; 
1990/0821    
	if(*name=='.' && (name[1]==0 || name[1]=='/')){ 
		name++; 
		goto Again; 
1990/0820    
	} 
1990/0227    
	return name; 
} 
 
1992/0101    
char isfrog[256]={ 
1990/0227    
	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1, 
	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1, 
	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1, 
	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1, 
1999/0323    
/*	[' ']	1,	rob - let's try this out */ 
1990/0227    
	['/']	1, 
	[0x7f]	1, 
}; 
1991/0727    
 
void 
nameok(char *elem) 
{ 
1991/1107    
	char *eelem; 
 
	eelem = elem+NAMELEN; 
1991/0727    
	while(*elem) { 
1992/0101    
		if(isfrog[*(uchar*)elem]) 
1991/0727    
			error(Ebadchar); 
		elem++; 
1991/1107    
		if(elem >= eelem) 
			error(Efilename); 
1991/0727    
	} 
} 
1990/0227    
 
/* 
 * name[0] should not be a slash. 
 */ 
char* 
nextelem(char *name, char *elem) 
{ 
1992/0711    
	int w; 
1993/0501    
	char *end; 
1992/0213    
	Rune r; 
1990/0227    
 
	if(*name == '/') 
1990/11211    
		error(Efilename); 
1993/0501    
	end = utfrune(name, '/'); 
	if(end == 0) 
		end = strchr(name, 0); 
	w = end-name; 
1992/0213    
	if(w >= NAMELEN) 
		error(Efilename); 
	memmove(elem, name, w); 
	elem[w] = 0; 
1993/0501    
	while(name < end){ 
1992/0213    
		name += chartorune(&r, name); 
		if(r<sizeof(isfrog) && isfrog[r]) 
1990/11211    
			error(Ebadchar); 
1990/0227    
	} 
	return skipslash(name); 
} 
 
void 
isdir(Chan *c) 
{ 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0227    
		return; 
1990/11211    
	error(Enotdir); 
1998/0829    
} 
 
void 
putmhead(Mhead *m) 
{ 
	if(decref(m) == 0) 
		free(m); 
1990/0227    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)