xref: /plan9-contrib/sys/src/9k/port/chan.c (revision fe56f8278143226a24ec2546024e76738f2051d4)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier enum
99ef1f84bSDavid du Colombier {
109ef1f84bSDavid du Colombier 	PATHSLOP	= 20,
119ef1f84bSDavid du Colombier 	PATHMSLOP	= 20,
129ef1f84bSDavid du Colombier };
139ef1f84bSDavid du Colombier 
149ef1f84bSDavid du Colombier struct
159ef1f84bSDavid du Colombier {
169ef1f84bSDavid du Colombier 	Lock;
179ef1f84bSDavid du Colombier 	int	fid;
189ef1f84bSDavid du Colombier 	Chan	*free;
199ef1f84bSDavid du Colombier 	Chan	*list;
209ef1f84bSDavid du Colombier }chanalloc;
219ef1f84bSDavid du Colombier 
229ef1f84bSDavid du Colombier typedef struct Elemlist Elemlist;
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier struct Elemlist
259ef1f84bSDavid du Colombier {
269ef1f84bSDavid du Colombier 	char	*aname;	/* original name */
279ef1f84bSDavid du Colombier 	char	*name;	/* copy of name, so '/' can be overwritten */
289ef1f84bSDavid du Colombier 	int	nelems;
299ef1f84bSDavid du Colombier 	char	**elems;
309ef1f84bSDavid du Colombier 	int	*off;
319ef1f84bSDavid du Colombier 	int	mustbedir;
329ef1f84bSDavid du Colombier 	int	nerror;
339ef1f84bSDavid du Colombier 	int	prefix;
349ef1f84bSDavid du Colombier };
359ef1f84bSDavid du Colombier 
369ef1f84bSDavid du Colombier char*
chanpath(Chan * c)379ef1f84bSDavid du Colombier chanpath(Chan *c)
389ef1f84bSDavid du Colombier {
399ef1f84bSDavid du Colombier 	if(c == nil)
409ef1f84bSDavid du Colombier 		return "<nil chan>";
419ef1f84bSDavid du Colombier 	if(c->path == nil)
429ef1f84bSDavid du Colombier 		return "<nil path>";
439ef1f84bSDavid du Colombier 	if(c->path->s == nil)
449ef1f84bSDavid du Colombier 		return "<nil path.s>";
459ef1f84bSDavid du Colombier 	return c->path->s;
469ef1f84bSDavid du Colombier }
479ef1f84bSDavid du Colombier 
489ef1f84bSDavid du Colombier int
isdotdot(char * p)499ef1f84bSDavid du Colombier isdotdot(char *p)
509ef1f84bSDavid du Colombier {
519ef1f84bSDavid du Colombier 	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
529ef1f84bSDavid du Colombier }
539ef1f84bSDavid du Colombier 
549ef1f84bSDavid du Colombier /*
559ef1f84bSDavid du Colombier  * Rather than strncpy, which zeros the rest of the buffer, kstrcpy
569ef1f84bSDavid du Colombier  * truncates if necessary, always zero terminates, does not zero fill,
579ef1f84bSDavid du Colombier  * and puts ... at the end of the string if it's too long.  Usually used to
589ef1f84bSDavid du Colombier  * save a string in up->genbuf;
599ef1f84bSDavid du Colombier  */
609ef1f84bSDavid du Colombier void
kstrcpy(char * s,char * t,int ns)619ef1f84bSDavid du Colombier kstrcpy(char *s, char *t, int ns)
629ef1f84bSDavid du Colombier {
639ef1f84bSDavid du Colombier 	int nt;
649ef1f84bSDavid du Colombier 
659ef1f84bSDavid du Colombier 	nt = strlen(t);
669ef1f84bSDavid du Colombier 	if(nt+1 <= ns){
679ef1f84bSDavid du Colombier 		memmove(s, t, nt+1);
689ef1f84bSDavid du Colombier 		return;
699ef1f84bSDavid du Colombier 	}
709ef1f84bSDavid du Colombier 	/* too long */
719ef1f84bSDavid du Colombier 	if(ns < 4){
729ef1f84bSDavid du Colombier 		/* but very short! */
739ef1f84bSDavid du Colombier 		strncpy(s, t, ns);
749ef1f84bSDavid du Colombier 		return;
759ef1f84bSDavid du Colombier 	}
769ef1f84bSDavid du Colombier 	/* truncate with ... at character boundary (very rare case) */
779ef1f84bSDavid du Colombier 	memmove(s, t, ns-4);
789ef1f84bSDavid du Colombier 	ns -= 4;
799ef1f84bSDavid du Colombier 	s[ns] = '\0';
809ef1f84bSDavid du Colombier 	/* look for first byte of UTF-8 sequence by skipping continuation bytes */
819ef1f84bSDavid du Colombier 	while(ns>0 && (s[--ns]&0xC0)==0x80)
829ef1f84bSDavid du Colombier 		;
839ef1f84bSDavid du Colombier 	strcpy(s+ns, "...");
849ef1f84bSDavid du Colombier }
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier int
emptystr(char * s)879ef1f84bSDavid du Colombier emptystr(char *s)
889ef1f84bSDavid du Colombier {
899ef1f84bSDavid du Colombier 	if(s == nil)
909ef1f84bSDavid du Colombier 		return 1;
919ef1f84bSDavid du Colombier 	if(s[0] == '\0')
929ef1f84bSDavid du Colombier 		return 1;
939ef1f84bSDavid du Colombier 	return 0;
949ef1f84bSDavid du Colombier }
959ef1f84bSDavid du Colombier 
969ef1f84bSDavid du Colombier /*
979ef1f84bSDavid du Colombier  * Atomically replace *p with copy of s
989ef1f84bSDavid du Colombier  */
999ef1f84bSDavid du Colombier void
kstrdup(char ** p,char * s)1009ef1f84bSDavid du Colombier kstrdup(char **p, char *s)
1019ef1f84bSDavid du Colombier {
1029ef1f84bSDavid du Colombier 	int n;
1039ef1f84bSDavid du Colombier 	char *t, *prev;
1049ef1f84bSDavid du Colombier 
1059ef1f84bSDavid du Colombier 	n = strlen(s)+1;
1069ef1f84bSDavid du Colombier 	/* if it's a user, we can wait for memory; if not, something's very wrong */
1079ef1f84bSDavid du Colombier 	if(up){
1089ef1f84bSDavid du Colombier 		t = smalloc(n);
1099ef1f84bSDavid du Colombier 		setmalloctag(t, getcallerpc(&p));
1109ef1f84bSDavid du Colombier 	}else{
1119ef1f84bSDavid du Colombier 		t = malloc(n);
1129ef1f84bSDavid du Colombier 		if(t == nil)
1139ef1f84bSDavid du Colombier 			panic("kstrdup: no memory");
1149ef1f84bSDavid du Colombier 	}
1159ef1f84bSDavid du Colombier 	memmove(t, s, n);
1169ef1f84bSDavid du Colombier 	prev = *p;
1179ef1f84bSDavid du Colombier 	*p = t;
1189ef1f84bSDavid du Colombier 	free(prev);
1199ef1f84bSDavid du Colombier }
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier Chan*
newchan(void)1229ef1f84bSDavid du Colombier newchan(void)
1239ef1f84bSDavid du Colombier {
1249ef1f84bSDavid du Colombier 	Chan *c;
1259ef1f84bSDavid du Colombier 
1269ef1f84bSDavid du Colombier 	lock(&chanalloc);
1279ef1f84bSDavid du Colombier 	c = chanalloc.free;
1289ef1f84bSDavid du Colombier 	if(c != 0)
1299ef1f84bSDavid du Colombier 		chanalloc.free = c->next;
1309ef1f84bSDavid du Colombier 	unlock(&chanalloc);
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 	if(c == nil){
1339ef1f84bSDavid du Colombier 		c = smalloc(sizeof(Chan));
1349ef1f84bSDavid du Colombier 		lock(&chanalloc);
1359ef1f84bSDavid du Colombier 		c->fid = ++chanalloc.fid;
1369ef1f84bSDavid du Colombier 		c->link = chanalloc.list;
1379ef1f84bSDavid du Colombier 		chanalloc.list = c;
1389ef1f84bSDavid du Colombier 		unlock(&chanalloc);
1399ef1f84bSDavid du Colombier 	}
1409ef1f84bSDavid du Colombier 
1419ef1f84bSDavid du Colombier 	c->dev = nil;
1429ef1f84bSDavid du Colombier 	c->flag = 0;
1439ef1f84bSDavid du Colombier 	c->ref = 1;
1449ef1f84bSDavid du Colombier 	c->devno = 0;
1459ef1f84bSDavid du Colombier 	c->offset = 0;
1469ef1f84bSDavid du Colombier 	c->devoffset = 0;
1479ef1f84bSDavid du Colombier 	c->iounit = 0;
1489ef1f84bSDavid du Colombier 	c->umh = 0;
1499ef1f84bSDavid du Colombier 	c->uri = 0;
1509ef1f84bSDavid du Colombier 	c->dri = 0;
1519ef1f84bSDavid du Colombier 	c->aux = 0;
1529ef1f84bSDavid du Colombier 	c->mchan = 0;
1539ef1f84bSDavid du Colombier 	c->mc = 0;
1549ef1f84bSDavid du Colombier 	c->mux = 0;
1559ef1f84bSDavid du Colombier 	memset(&c->mqid, 0, sizeof(c->mqid));
1569ef1f84bSDavid du Colombier 	c->path = 0;
1579ef1f84bSDavid du Colombier 	c->ismtpt = 0;
1589ef1f84bSDavid du Colombier 
1599ef1f84bSDavid du Colombier 	return c;
1609ef1f84bSDavid du Colombier }
1619ef1f84bSDavid du Colombier 
1629ef1f84bSDavid du Colombier Ref npath;
1639ef1f84bSDavid du Colombier 
1649ef1f84bSDavid du Colombier Path*
newpath(char * s)1659ef1f84bSDavid du Colombier newpath(char *s)
1669ef1f84bSDavid du Colombier {
1679ef1f84bSDavid du Colombier 	int i;
1689ef1f84bSDavid du Colombier 	Path *p;
1699ef1f84bSDavid du Colombier 
1709ef1f84bSDavid du Colombier 	p = smalloc(sizeof(Path));
1719ef1f84bSDavid du Colombier 	i = strlen(s);
1729ef1f84bSDavid du Colombier 	p->len = i;
1739ef1f84bSDavid du Colombier 	p->alen = i+PATHSLOP;
1749ef1f84bSDavid du Colombier 	p->s = smalloc(p->alen);
1759ef1f84bSDavid du Colombier 	memmove(p->s, s, i+1);
1769ef1f84bSDavid du Colombier 	p->ref = 1;
1779ef1f84bSDavid du Colombier 	incref(&npath);
1789ef1f84bSDavid du Colombier 
1799ef1f84bSDavid du Colombier 	/*
1809ef1f84bSDavid du Colombier 	 * Cannot use newpath for arbitrary names because the mtpt
1819ef1f84bSDavid du Colombier 	 * array will not be populated correctly.  The names #/ and / are
1829ef1f84bSDavid du Colombier 	 * allowed, but other names with / in them draw warnings.
1839ef1f84bSDavid du Colombier 	 */
1849ef1f84bSDavid du Colombier 	if(strchr(s, '/') && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0)
1859ef1f84bSDavid du Colombier 		print("newpath: %s from %#p\n", s, getcallerpc(&s));
1869ef1f84bSDavid du Colombier 
1879ef1f84bSDavid du Colombier 	p->mlen = 1;
1889ef1f84bSDavid du Colombier 	p->malen = PATHMSLOP;
1899ef1f84bSDavid du Colombier 	p->mtpt = smalloc(p->malen*sizeof p->mtpt[0]);
1909ef1f84bSDavid du Colombier 	return p;
1919ef1f84bSDavid du Colombier }
1929ef1f84bSDavid du Colombier 
1939ef1f84bSDavid du Colombier static Path*
copypath(Path * p)1949ef1f84bSDavid du Colombier copypath(Path *p)
1959ef1f84bSDavid du Colombier {
1969ef1f84bSDavid du Colombier 	int i;
1979ef1f84bSDavid du Colombier 	Path *pp;
1989ef1f84bSDavid du Colombier 
1999ef1f84bSDavid du Colombier 	pp = smalloc(sizeof(Path));
2009ef1f84bSDavid du Colombier 	pp->ref = 1;
2019ef1f84bSDavid du Colombier 	incref(&npath);
2029ef1f84bSDavid du Colombier 	DBG("copypath %s %#p => %#p\n", p->s, p, pp);
2039ef1f84bSDavid du Colombier 
2049ef1f84bSDavid du Colombier 	pp->len = p->len;
2059ef1f84bSDavid du Colombier 	pp->alen = p->alen;
2069ef1f84bSDavid du Colombier 	pp->s = smalloc(p->alen);
2079ef1f84bSDavid du Colombier 	memmove(pp->s, p->s, p->len+1);
2089ef1f84bSDavid du Colombier 
2099ef1f84bSDavid du Colombier 	pp->mlen = p->mlen;
2109ef1f84bSDavid du Colombier 	pp->malen = p->malen;
2119ef1f84bSDavid du Colombier 	pp->mtpt = smalloc(p->malen*sizeof pp->mtpt[0]);
2129ef1f84bSDavid du Colombier 	for(i=0; i<pp->mlen; i++){
2139ef1f84bSDavid du Colombier 		pp->mtpt[i] = p->mtpt[i];
2149ef1f84bSDavid du Colombier 		if(pp->mtpt[i])
2159ef1f84bSDavid du Colombier 			incref(pp->mtpt[i]);
2169ef1f84bSDavid du Colombier 	}
2179ef1f84bSDavid du Colombier 
2189ef1f84bSDavid du Colombier 	return pp;
2199ef1f84bSDavid du Colombier }
2209ef1f84bSDavid du Colombier 
2219ef1f84bSDavid du Colombier void
pathclose(Path * p)2229ef1f84bSDavid du Colombier pathclose(Path *p)
2239ef1f84bSDavid du Colombier {
2249ef1f84bSDavid du Colombier 	int i;
2259ef1f84bSDavid du Colombier 
2269ef1f84bSDavid du Colombier 	if(p == nil)
2279ef1f84bSDavid du Colombier 		return;
2289ef1f84bSDavid du Colombier //XXX
2299ef1f84bSDavid du Colombier 	DBG("pathclose %#p %s ref=%d =>", p, p->s, p->ref);
2309ef1f84bSDavid du Colombier 	for(i=0; i<p->mlen; i++)
2319ef1f84bSDavid du Colombier 		DBG(" %#p", p->mtpt[i]);
2329ef1f84bSDavid du Colombier 	DBG("\n");
2339ef1f84bSDavid du Colombier 
2349ef1f84bSDavid du Colombier 	if(decref(p))
2359ef1f84bSDavid du Colombier 		return;
2369ef1f84bSDavid du Colombier 	decref(&npath);
2379ef1f84bSDavid du Colombier 	free(p->s);
2389ef1f84bSDavid du Colombier 	for(i=0; i<p->mlen; i++)
2399ef1f84bSDavid du Colombier 		if(p->mtpt[i])
2409ef1f84bSDavid du Colombier 			cclose(p->mtpt[i]);
2419ef1f84bSDavid du Colombier 	free(p->mtpt);
2429ef1f84bSDavid du Colombier 	free(p);
2439ef1f84bSDavid du Colombier }
2449ef1f84bSDavid du Colombier 
2459ef1f84bSDavid du Colombier /*
2469ef1f84bSDavid du Colombier  * In place, rewrite name to compress multiple /, eliminate ., and process ..
2479ef1f84bSDavid du Colombier  * (Really only called to remove a trailing .. that has been added.
2489ef1f84bSDavid du Colombier  * Otherwise would need to update n->mtpt as well.)
2499ef1f84bSDavid du Colombier  */
2509ef1f84bSDavid du Colombier static void
fixdotdotname(Path * p)2519ef1f84bSDavid du Colombier fixdotdotname(Path *p)
2529ef1f84bSDavid du Colombier {
2539ef1f84bSDavid du Colombier 	char *r;
2549ef1f84bSDavid du Colombier 
2559ef1f84bSDavid du Colombier 	if(p->s[0] == '#'){
2569ef1f84bSDavid du Colombier 		r = strchr(p->s, '/');
2579ef1f84bSDavid du Colombier 		if(r == nil)
2589ef1f84bSDavid du Colombier 			return;
2599ef1f84bSDavid du Colombier 		cleanname(r);
2609ef1f84bSDavid du Colombier 
2619ef1f84bSDavid du Colombier 		/*
2629ef1f84bSDavid du Colombier 		 * The correct name is #i rather than #i/,
2639ef1f84bSDavid du Colombier 		 * but the correct name of #/ is #/.
2649ef1f84bSDavid du Colombier 		 */
2659ef1f84bSDavid du Colombier 		if(strcmp(r, "/")==0 && p->s[1] != '/')
2669ef1f84bSDavid du Colombier 			*r = '\0';
2679ef1f84bSDavid du Colombier 	}else
2689ef1f84bSDavid du Colombier 		cleanname(p->s);
2699ef1f84bSDavid du Colombier 	p->len = strlen(p->s);
2709ef1f84bSDavid du Colombier }
2719ef1f84bSDavid du Colombier 
2729ef1f84bSDavid du Colombier static Path*
uniquepath(Path * p)2739ef1f84bSDavid du Colombier uniquepath(Path *p)
2749ef1f84bSDavid du Colombier {
2759ef1f84bSDavid du Colombier 	Path *new;
2769ef1f84bSDavid du Colombier 
2779ef1f84bSDavid du Colombier 	if(p->ref > 1){
2789ef1f84bSDavid du Colombier 		/* copy on write */
2799ef1f84bSDavid du Colombier 		new = copypath(p);
2809ef1f84bSDavid du Colombier 		pathclose(p);
2819ef1f84bSDavid du Colombier 		p = new;
2829ef1f84bSDavid du Colombier 	}
2839ef1f84bSDavid du Colombier 	return p;
2849ef1f84bSDavid du Colombier }
2859ef1f84bSDavid du Colombier 
2869ef1f84bSDavid du Colombier static Path*
addelem(Path * p,char * s,Chan * from)2879ef1f84bSDavid du Colombier addelem(Path *p, char *s, Chan *from)
2889ef1f84bSDavid du Colombier {
2899ef1f84bSDavid du Colombier 	char *t;
2909ef1f84bSDavid du Colombier 	int a, i;
2919ef1f84bSDavid du Colombier 	Chan *c, **tt;
2929ef1f84bSDavid du Colombier 
2939ef1f84bSDavid du Colombier 	if(s[0]=='.' && s[1]=='\0')
2949ef1f84bSDavid du Colombier 		return p;
2959ef1f84bSDavid du Colombier 
2969ef1f84bSDavid du Colombier 	p = uniquepath(p);
2979ef1f84bSDavid du Colombier 
2989ef1f84bSDavid du Colombier 	i = strlen(s);
2999ef1f84bSDavid du Colombier 	if(p->len+1+i+1 > p->alen){
3009ef1f84bSDavid du Colombier 		a = p->len+1+i+1 + PATHSLOP;
3019ef1f84bSDavid du Colombier 		t = smalloc(a);
3029ef1f84bSDavid du Colombier 		memmove(t, p->s, p->len+1);
3039ef1f84bSDavid du Colombier 		free(p->s);
3049ef1f84bSDavid du Colombier 		p->s = t;
3059ef1f84bSDavid du Colombier 		p->alen = a;
3069ef1f84bSDavid du Colombier 	}
3079ef1f84bSDavid du Colombier 	/* don't insert extra slash if one is present */
3089ef1f84bSDavid du Colombier 	if(p->len>0 && p->s[p->len-1]!='/' && s[0]!='/')
3099ef1f84bSDavid du Colombier 		p->s[p->len++] = '/';
3109ef1f84bSDavid du Colombier 	memmove(p->s+p->len, s, i+1);
3119ef1f84bSDavid du Colombier 	p->len += i;
3129ef1f84bSDavid du Colombier 	if(isdotdot(s)){
3139ef1f84bSDavid du Colombier 		fixdotdotname(p);
3149ef1f84bSDavid du Colombier 		DBG("addelem %s .. => rm %#p\n", p->s, p->mtpt[p->mlen-1]);
3159ef1f84bSDavid du Colombier 		if(p->mlen>1 && (c = p->mtpt[--p->mlen])){
3169ef1f84bSDavid du Colombier 			p->mtpt[p->mlen] = nil;
3179ef1f84bSDavid du Colombier 			cclose(c);
3189ef1f84bSDavid du Colombier 		}
3199ef1f84bSDavid du Colombier 	}else{
3209ef1f84bSDavid du Colombier 		if(p->mlen >= p->malen){
3219ef1f84bSDavid du Colombier 			p->malen = p->mlen+1+PATHMSLOP;
3229ef1f84bSDavid du Colombier 			tt = smalloc(p->malen*sizeof tt[0]);
3239ef1f84bSDavid du Colombier 			memmove(tt, p->mtpt, p->mlen*sizeof tt[0]);
3249ef1f84bSDavid du Colombier 			free(p->mtpt);
3259ef1f84bSDavid du Colombier 			p->mtpt = tt;
3269ef1f84bSDavid du Colombier 		}
3279ef1f84bSDavid du Colombier 		DBG("addelem %s %s => add %#p\n", p->s, s, from);
3289ef1f84bSDavid du Colombier 		p->mtpt[p->mlen++] = from;
3299ef1f84bSDavid du Colombier 		if(from)
3309ef1f84bSDavid du Colombier 			incref(from);
3319ef1f84bSDavid du Colombier 	}
3329ef1f84bSDavid du Colombier 	return p;
3339ef1f84bSDavid du Colombier }
3349ef1f84bSDavid du Colombier 
3359ef1f84bSDavid du Colombier void
chanfree(Chan * c)3369ef1f84bSDavid du Colombier chanfree(Chan *c)
3379ef1f84bSDavid du Colombier {
3389ef1f84bSDavid du Colombier 	c->flag = CFREE;
3399ef1f84bSDavid du Colombier 
3409ef1f84bSDavid du Colombier 	if(c->dirrock != nil){
3419ef1f84bSDavid du Colombier 		free(c->dirrock);
3429ef1f84bSDavid du Colombier 		c->dirrock = 0;
3439ef1f84bSDavid du Colombier 		c->nrock = 0;
3449ef1f84bSDavid du Colombier 		c->mrock = 0;
3459ef1f84bSDavid du Colombier 	}
3469ef1f84bSDavid du Colombier 	if(c->umh != nil){
3479ef1f84bSDavid du Colombier 		putmhead(c->umh);
3489ef1f84bSDavid du Colombier 		c->umh = nil;
3499ef1f84bSDavid du Colombier 	}
3509ef1f84bSDavid du Colombier 	if(c->umc != nil){
3519ef1f84bSDavid du Colombier 		cclose(c->umc);
3529ef1f84bSDavid du Colombier 		c->umc = nil;
3539ef1f84bSDavid du Colombier 	}
3549ef1f84bSDavid du Colombier 	if(c->mux != nil){
3559ef1f84bSDavid du Colombier 		muxclose(c->mux);
3569ef1f84bSDavid du Colombier 		c->mux = nil;
3579ef1f84bSDavid du Colombier 	}
3589ef1f84bSDavid du Colombier 	if(c->mchan != nil){
3599ef1f84bSDavid du Colombier 		cclose(c->mchan);
3609ef1f84bSDavid du Colombier 		c->mchan = nil;
3619ef1f84bSDavid du Colombier 	}
3629ef1f84bSDavid du Colombier 
3639ef1f84bSDavid du Colombier 	if(c->dev != nil){				//XDYNX
3649ef1f84bSDavid du Colombier 		//devtabdecr(c->dev);
3659ef1f84bSDavid du Colombier 		c->dev = nil;
3669ef1f84bSDavid du Colombier 	}
3679ef1f84bSDavid du Colombier 
3689ef1f84bSDavid du Colombier 	pathclose(c->path);
3699ef1f84bSDavid du Colombier 	c->path = nil;
3709ef1f84bSDavid du Colombier 
3719ef1f84bSDavid du Colombier 	lock(&chanalloc);
3729ef1f84bSDavid du Colombier 	c->next = chanalloc.free;
3739ef1f84bSDavid du Colombier 	chanalloc.free = c;
3749ef1f84bSDavid du Colombier 	unlock(&chanalloc);
3759ef1f84bSDavid du Colombier }
3769ef1f84bSDavid du Colombier 
3779ef1f84bSDavid du Colombier void
cclose(Chan * c)3789ef1f84bSDavid du Colombier cclose(Chan *c)
3799ef1f84bSDavid du Colombier {
3809ef1f84bSDavid du Colombier 	if(c->flag&CFREE)
3819ef1f84bSDavid du Colombier 		panic("cclose %#p", getcallerpc(&c));
3829ef1f84bSDavid du Colombier 
3839ef1f84bSDavid du Colombier 	DBG("cclose %#p name=%s ref=%d\n", c, c->path->s, c->ref);
3849ef1f84bSDavid du Colombier 	if(decref(c))
3859ef1f84bSDavid du Colombier 		return;
3869ef1f84bSDavid du Colombier 
3879ef1f84bSDavid du Colombier 	if(!waserror()){
3889ef1f84bSDavid du Colombier 		if(c->dev != nil)			//XDYNX
3899ef1f84bSDavid du Colombier 			c->dev->close(c);
3909ef1f84bSDavid du Colombier 		poperror();
3919ef1f84bSDavid du Colombier 	}
3929ef1f84bSDavid du Colombier 	chanfree(c);
3939ef1f84bSDavid du Colombier }
3949ef1f84bSDavid du Colombier 
3959ef1f84bSDavid du Colombier /*
3969ef1f84bSDavid du Colombier  * Queue a chan to be closed by one of the clunk procs.
3979ef1f84bSDavid du Colombier  */
3989ef1f84bSDavid du Colombier struct {
3999ef1f84bSDavid du Colombier 	Chan	*head;
4009ef1f84bSDavid du Colombier 	Chan	*tail;
4019ef1f84bSDavid du Colombier 	int	nqueued;
4029ef1f84bSDavid du Colombier 	int	nclosed;
4039ef1f84bSDavid du Colombier 	Lock	l;
4049ef1f84bSDavid du Colombier 	QLock	q;
4059ef1f84bSDavid du Colombier 	Rendez	r;
4069ef1f84bSDavid du Colombier } clunkq;
4079ef1f84bSDavid du Colombier 
4089ef1f84bSDavid du Colombier static void closeproc(void*);
4099ef1f84bSDavid du Colombier 
4109ef1f84bSDavid du Colombier void
ccloseq(Chan * c)4119ef1f84bSDavid du Colombier ccloseq(Chan *c)
4129ef1f84bSDavid du Colombier {
4139ef1f84bSDavid du Colombier 	if(c->flag&CFREE)
4149ef1f84bSDavid du Colombier 		panic("ccloseq %#p", getcallerpc(&c));
4159ef1f84bSDavid du Colombier 
4169ef1f84bSDavid du Colombier 	DBG("ccloseq %#p name=%s ref=%d\n", c, c->path->s, c->ref);
4179ef1f84bSDavid du Colombier 
4189ef1f84bSDavid du Colombier 	if(decref(c))
4199ef1f84bSDavid du Colombier 		return;
4209ef1f84bSDavid du Colombier 
4219ef1f84bSDavid du Colombier 	lock(&clunkq.l);
4229ef1f84bSDavid du Colombier 	clunkq.nqueued++;
4239ef1f84bSDavid du Colombier 	c->next = nil;
4249ef1f84bSDavid du Colombier 	if(clunkq.head)
4259ef1f84bSDavid du Colombier 		clunkq.tail->next = c;
4269ef1f84bSDavid du Colombier 	else
4279ef1f84bSDavid du Colombier 		clunkq.head = c;
4289ef1f84bSDavid du Colombier 	clunkq.tail = c;
4299ef1f84bSDavid du Colombier 	unlock(&clunkq.l);
4309ef1f84bSDavid du Colombier 
4319ef1f84bSDavid du Colombier 	if(!wakeup(&clunkq.r))
4329ef1f84bSDavid du Colombier 		kproc("closeproc", closeproc, nil);
4339ef1f84bSDavid du Colombier }
4349ef1f84bSDavid du Colombier 
4359ef1f84bSDavid du Colombier static int
clunkwork(void *)4369ef1f84bSDavid du Colombier clunkwork(void*)
4379ef1f84bSDavid du Colombier {
4389ef1f84bSDavid du Colombier 	return clunkq.head != nil;
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier 
4419ef1f84bSDavid du Colombier static void
closeproc(void *)4429ef1f84bSDavid du Colombier closeproc(void*)
4439ef1f84bSDavid du Colombier {
4449ef1f84bSDavid du Colombier 	Chan *c;
4459ef1f84bSDavid du Colombier 
4469ef1f84bSDavid du Colombier 	for(;;){
4479ef1f84bSDavid du Colombier 		qlock(&clunkq.q);
4489ef1f84bSDavid du Colombier 		if(clunkq.head == nil){
4499ef1f84bSDavid du Colombier 			if(!waserror()){
4509ef1f84bSDavid du Colombier 				tsleep(&clunkq.r, clunkwork, nil, 5000);
4519ef1f84bSDavid du Colombier 				poperror();
4529ef1f84bSDavid du Colombier 			}
4539ef1f84bSDavid du Colombier 			if(clunkq.head == nil){
4549ef1f84bSDavid du Colombier 				qunlock(&clunkq.q);
4559ef1f84bSDavid du Colombier 				pexit("no work", 1);
4569ef1f84bSDavid du Colombier 			}
4579ef1f84bSDavid du Colombier 		}
4589ef1f84bSDavid du Colombier 		lock(&clunkq.l);
4599ef1f84bSDavid du Colombier 		c = clunkq.head;
4609ef1f84bSDavid du Colombier 		clunkq.head = c->next;
4619ef1f84bSDavid du Colombier 		clunkq.nclosed++;
4629ef1f84bSDavid du Colombier 		unlock(&clunkq.l);
4639ef1f84bSDavid du Colombier 		qunlock(&clunkq.q);
4649ef1f84bSDavid du Colombier 		if(!waserror()){
4659ef1f84bSDavid du Colombier 			if(c->dev != nil)		//XDYNX
4669ef1f84bSDavid du Colombier 				c->dev->close(c);
4679ef1f84bSDavid du Colombier 			poperror();
4689ef1f84bSDavid du Colombier 		}
4699ef1f84bSDavid du Colombier 		chanfree(c);
4709ef1f84bSDavid du Colombier 	}
4719ef1f84bSDavid du Colombier }
4729ef1f84bSDavid du Colombier 
4739ef1f84bSDavid du Colombier /*
4749ef1f84bSDavid du Colombier  * Make sure we have the only copy of c.  (Copy on write.)
4759ef1f84bSDavid du Colombier  */
4769ef1f84bSDavid du Colombier Chan*
cunique(Chan * c)4779ef1f84bSDavid du Colombier cunique(Chan *c)
4789ef1f84bSDavid du Colombier {
4799ef1f84bSDavid du Colombier 	Chan *nc;
4809ef1f84bSDavid du Colombier 
4819ef1f84bSDavid du Colombier 	if(c->ref != 1){
4829ef1f84bSDavid du Colombier 		nc = cclone(c);
4839ef1f84bSDavid du Colombier 		cclose(c);
4849ef1f84bSDavid du Colombier 		c = nc;
4859ef1f84bSDavid du Colombier 	}
4869ef1f84bSDavid du Colombier 
4879ef1f84bSDavid du Colombier 	return c;
4889ef1f84bSDavid du Colombier }
4899ef1f84bSDavid du Colombier 
4909ef1f84bSDavid du Colombier int
eqqid(Qid a,Qid b)4919ef1f84bSDavid du Colombier eqqid(Qid a, Qid b)
4929ef1f84bSDavid du Colombier {
4939ef1f84bSDavid du Colombier 	return a.path == b.path && a.vers == b.vers;
4949ef1f84bSDavid du Colombier }
4959ef1f84bSDavid du Colombier 
4969ef1f84bSDavid du Colombier static int
eqchan(Chan * a,Chan * b,int skipvers)4979ef1f84bSDavid du Colombier eqchan(Chan *a, Chan *b, int skipvers)
4989ef1f84bSDavid du Colombier {
4999ef1f84bSDavid du Colombier 	if(a->qid.path != b->qid.path)
5009ef1f84bSDavid du Colombier 		return 0;
5019ef1f84bSDavid du Colombier 	if(!skipvers && a->qid.vers != b->qid.vers)
5029ef1f84bSDavid du Colombier 		return 0;
5039ef1f84bSDavid du Colombier 	if(a->dev->dc != b->dev->dc)
5049ef1f84bSDavid du Colombier 		return 0;
5059ef1f84bSDavid du Colombier 	if(a->devno != b->devno)
5069ef1f84bSDavid du Colombier 		return 0;
5079ef1f84bSDavid du Colombier 	return 1;
5089ef1f84bSDavid du Colombier }
5099ef1f84bSDavid du Colombier 
5109ef1f84bSDavid du Colombier int
eqchanddq(Chan * c,int dc,uint devno,Qid qid,int skipvers)5119ef1f84bSDavid du Colombier eqchanddq(Chan *c, int dc, uint devno, Qid qid, int skipvers)
5129ef1f84bSDavid du Colombier {
5139ef1f84bSDavid du Colombier 	if(c->qid.path != qid.path)
5149ef1f84bSDavid du Colombier 		return 0;
5159ef1f84bSDavid du Colombier 	if(!skipvers && c->qid.vers != qid.vers)
5169ef1f84bSDavid du Colombier 		return 0;
5179ef1f84bSDavid du Colombier 	if(c->dev->dc != dc)
5189ef1f84bSDavid du Colombier 		return 0;
5199ef1f84bSDavid du Colombier 	if(c->devno != devno)
5209ef1f84bSDavid du Colombier 		return 0;
5219ef1f84bSDavid du Colombier 	return 1;
5229ef1f84bSDavid du Colombier }
5239ef1f84bSDavid du Colombier 
5249ef1f84bSDavid du Colombier Mhead*
newmhead(Chan * from)5259ef1f84bSDavid du Colombier newmhead(Chan *from)
5269ef1f84bSDavid du Colombier {
5279ef1f84bSDavid du Colombier 	Mhead *mh;
5289ef1f84bSDavid du Colombier 
5299ef1f84bSDavid du Colombier 	mh = smalloc(sizeof(Mhead));
5309ef1f84bSDavid du Colombier 	mh->ref = 1;
5319ef1f84bSDavid du Colombier 	mh->from = from;
5329ef1f84bSDavid du Colombier 	incref(from);
5339ef1f84bSDavid du Colombier 	return mh;
5349ef1f84bSDavid du Colombier }
5359ef1f84bSDavid du Colombier 
5369ef1f84bSDavid du Colombier int
cmount(Chan ** newp,Chan * old,int flag,char * spec)5379ef1f84bSDavid du Colombier cmount(Chan **newp, Chan *old, int flag, char *spec)
5389ef1f84bSDavid du Colombier {
5399ef1f84bSDavid du Colombier 	int order, flg;
5409ef1f84bSDavid du Colombier 	Chan *new;
5419ef1f84bSDavid du Colombier 	Mhead *mhead, **l, *mh;
5429ef1f84bSDavid du Colombier 	Mount *nm, *f, *um, **h;
5439ef1f84bSDavid du Colombier 	Pgrp *pg;
5449ef1f84bSDavid du Colombier 
5459ef1f84bSDavid du Colombier 	if(QTDIR & (old->qid.type^(*newp)->qid.type))
5469ef1f84bSDavid du Colombier 		error(Emount);
5479ef1f84bSDavid du Colombier 
5489ef1f84bSDavid du Colombier 	if(old->umh)
5499ef1f84bSDavid du Colombier 		print("cmount: unexpected umh, caller %#p\n", getcallerpc(&newp));
5509ef1f84bSDavid du Colombier 
5519ef1f84bSDavid du Colombier 	order = flag&MORDER;
5529ef1f84bSDavid du Colombier 
5539ef1f84bSDavid du Colombier 	if(!(old->qid.type & QTDIR) && order != MREPL)
5549ef1f84bSDavid du Colombier 		error(Emount);
5559ef1f84bSDavid du Colombier 
5569ef1f84bSDavid du Colombier 	new = *newp;
5579ef1f84bSDavid du Colombier 	mh = new->umh;
5589ef1f84bSDavid du Colombier 
5599ef1f84bSDavid du Colombier 	/*
5609ef1f84bSDavid du Colombier 	 * Not allowed to bind when the old directory is itself a union.
5619ef1f84bSDavid du Colombier 	 * (Maybe it should be allowed, but I don't see what the semantics
5629ef1f84bSDavid du Colombier 	 * would be.)
5639ef1f84bSDavid du Colombier 	 *
5649ef1f84bSDavid du Colombier 	 * We need to check mh->mount->next to tell unions apart from
5659ef1f84bSDavid du Colombier 	 * simple mount points, so that things like
5669ef1f84bSDavid du Colombier 	 *	mount -c fd /root
5679ef1f84bSDavid du Colombier 	 *	bind -c /root /
5689ef1f84bSDavid du Colombier 	 * work.
5699ef1f84bSDavid du Colombier 	 *
5709ef1f84bSDavid du Colombier 	 * The check of mount->mflag allows things like
5719ef1f84bSDavid du Colombier 	 *	mount fd /root
5729ef1f84bSDavid du Colombier 	 *	bind -c /root /
5739ef1f84bSDavid du Colombier 	 *
5749ef1f84bSDavid du Colombier 	 * This is far more complicated than it should be, but I don't
5759ef1f84bSDavid du Colombier 	 * see an easier way at the moment.
5769ef1f84bSDavid du Colombier 	 */
5779ef1f84bSDavid du Colombier 	if((flag&MCREATE) && mh && mh->mount
5789ef1f84bSDavid du Colombier 	&& (mh->mount->next || !(mh->mount->mflag&MCREATE)))
5799ef1f84bSDavid du Colombier 		error(Emount);
5809ef1f84bSDavid du Colombier 
5819ef1f84bSDavid du Colombier 	pg = up->pgrp;
5829ef1f84bSDavid du Colombier 	wlock(&pg->ns);
5839ef1f84bSDavid du Colombier 
5849ef1f84bSDavid du Colombier 	l = &MOUNTH(pg, old->qid);
5859ef1f84bSDavid du Colombier 	for(mhead = *l; mhead; mhead = mhead->hash){
5869ef1f84bSDavid du Colombier 		if(eqchan(mhead->from, old, 1))
5879ef1f84bSDavid du Colombier 			break;
5889ef1f84bSDavid du Colombier 		l = &mhead->hash;
5899ef1f84bSDavid du Colombier 	}
5909ef1f84bSDavid du Colombier 
5919ef1f84bSDavid du Colombier 	if(mhead == nil){
5929ef1f84bSDavid du Colombier 		/*
5939ef1f84bSDavid du Colombier 		 *  nothing mounted here yet.  create a mount
5949ef1f84bSDavid du Colombier 		 *  head and add to the hash table.
5959ef1f84bSDavid du Colombier 		 */
5969ef1f84bSDavid du Colombier 		mhead = newmhead(old);
5979ef1f84bSDavid du Colombier 		*l = mhead;
5989ef1f84bSDavid du Colombier 
5999ef1f84bSDavid du Colombier 		/*
6009ef1f84bSDavid du Colombier 		 *  if this is a union mount, add the old
6019ef1f84bSDavid du Colombier 		 *  node to the mount chain.
6029ef1f84bSDavid du Colombier 		 */
6039ef1f84bSDavid du Colombier 		if(order != MREPL)
6049ef1f84bSDavid du Colombier 			mhead->mount = newmount(mhead, old, 0, 0);
6059ef1f84bSDavid du Colombier 	}
6069ef1f84bSDavid du Colombier 	wlock(&mhead->lock);
6079ef1f84bSDavid du Colombier 	if(waserror()){
6089ef1f84bSDavid du Colombier 		wunlock(&mhead->lock);
6099ef1f84bSDavid du Colombier 		nexterror();
6109ef1f84bSDavid du Colombier 	}
6119ef1f84bSDavid du Colombier 	wunlock(&pg->ns);
6129ef1f84bSDavid du Colombier 
6139ef1f84bSDavid du Colombier 	nm = newmount(mhead, new, flag, spec);
6149ef1f84bSDavid du Colombier 	if(mh != nil && mh->mount != nil){
6159ef1f84bSDavid du Colombier 		/*
6169ef1f84bSDavid du Colombier 		 *  copy a union when binding it onto a directory
6179ef1f84bSDavid du Colombier 		 */
6189ef1f84bSDavid du Colombier 		flg = order;
6199ef1f84bSDavid du Colombier 		if(order == MREPL)
6209ef1f84bSDavid du Colombier 			flg = MAFTER;
6219ef1f84bSDavid du Colombier 		h = &nm->next;
6229ef1f84bSDavid du Colombier 		um = mh->mount;
6239ef1f84bSDavid du Colombier 		for(um = um->next; um; um = um->next){
6249ef1f84bSDavid du Colombier 			f = newmount(mhead, um->to, flg, um->spec);
6259ef1f84bSDavid du Colombier 			*h = f;
6269ef1f84bSDavid du Colombier 			h = &f->next;
6279ef1f84bSDavid du Colombier 		}
6289ef1f84bSDavid du Colombier 	}
6299ef1f84bSDavid du Colombier 
6309ef1f84bSDavid du Colombier 	if(mhead->mount && order == MREPL){
6319ef1f84bSDavid du Colombier 		mountfree(mhead->mount);
6329ef1f84bSDavid du Colombier 		mhead->mount = 0;
6339ef1f84bSDavid du Colombier 	}
6349ef1f84bSDavid du Colombier 
6359ef1f84bSDavid du Colombier 	if(flag & MCREATE)
6369ef1f84bSDavid du Colombier 		nm->mflag |= MCREATE;
6379ef1f84bSDavid du Colombier 
6389ef1f84bSDavid du Colombier 	if(mhead->mount && order == MAFTER){
6399ef1f84bSDavid du Colombier 		for(f = mhead->mount; f->next; f = f->next)
6409ef1f84bSDavid du Colombier 			;
6419ef1f84bSDavid du Colombier 		f->next = nm;
6429ef1f84bSDavid du Colombier 	}else{
6439ef1f84bSDavid du Colombier 		for(f = nm; f->next; f = f->next)
6449ef1f84bSDavid du Colombier 			;
6459ef1f84bSDavid du Colombier 		f->next = mhead->mount;
6469ef1f84bSDavid du Colombier 		mhead->mount = nm;
6479ef1f84bSDavid du Colombier 	}
6489ef1f84bSDavid du Colombier 
6499ef1f84bSDavid du Colombier 	wunlock(&mhead->lock);
6509ef1f84bSDavid du Colombier 	poperror();
6519ef1f84bSDavid du Colombier 	return nm->mountid;
6529ef1f84bSDavid du Colombier }
6539ef1f84bSDavid du Colombier 
6549ef1f84bSDavid du Colombier void
cunmount(Chan * mnt,Chan * mounted)6559ef1f84bSDavid du Colombier cunmount(Chan *mnt, Chan *mounted)
6569ef1f84bSDavid du Colombier {
6579ef1f84bSDavid du Colombier 	Pgrp *pg;
6589ef1f84bSDavid du Colombier 	Mhead *mh, **l;
6599ef1f84bSDavid du Colombier 	Mount *f, **p;
6609ef1f84bSDavid du Colombier 
6619ef1f84bSDavid du Colombier 	if(mnt->umh)	/* should not happen */
6629ef1f84bSDavid du Colombier 		print("cunmount newp extra umh %#p has %#p\n", mnt, mnt->umh);
6639ef1f84bSDavid du Colombier 
6649ef1f84bSDavid du Colombier 	/*
6659ef1f84bSDavid du Colombier 	 * It _can_ happen that mounted->umh is non-nil,
6669ef1f84bSDavid du Colombier 	 * because mounted is the result of namec(Aopen)
6679ef1f84bSDavid du Colombier 	 * (see sysfile.c:/^sysunmount).
6689ef1f84bSDavid du Colombier 	 * If we open a union directory, it will have a umh.
6699ef1f84bSDavid du Colombier 	 * Although surprising, this is okay, since the
6709ef1f84bSDavid du Colombier 	 * cclose will take care of freeing the umh.
6719ef1f84bSDavid du Colombier 	 */
6729ef1f84bSDavid du Colombier 
6739ef1f84bSDavid du Colombier 	pg = up->pgrp;
6749ef1f84bSDavid du Colombier 	wlock(&pg->ns);
6759ef1f84bSDavid du Colombier 
6769ef1f84bSDavid du Colombier 	l = &MOUNTH(pg, mnt->qid);
6779ef1f84bSDavid du Colombier 	for(mh = *l; mh; mh = mh->hash){
6789ef1f84bSDavid du Colombier 		if(eqchan(mh->from, mnt, 1))
6799ef1f84bSDavid du Colombier 			break;
6809ef1f84bSDavid du Colombier 		l = &mh->hash;
6819ef1f84bSDavid du Colombier 	}
6829ef1f84bSDavid du Colombier 
6839ef1f84bSDavid du Colombier 	if(mh == 0){
6849ef1f84bSDavid du Colombier 		wunlock(&pg->ns);
6859ef1f84bSDavid du Colombier 		error(Eunmount);
6869ef1f84bSDavid du Colombier 	}
6879ef1f84bSDavid du Colombier 
6889ef1f84bSDavid du Colombier 	wlock(&mh->lock);
6899ef1f84bSDavid du Colombier 	if(mounted == 0){
6909ef1f84bSDavid du Colombier 		*l = mh->hash;
6919ef1f84bSDavid du Colombier 		wunlock(&pg->ns);
6929ef1f84bSDavid du Colombier 		mountfree(mh->mount);
6939ef1f84bSDavid du Colombier 		mh->mount = nil;
6949ef1f84bSDavid du Colombier 		cclose(mh->from);
6959ef1f84bSDavid du Colombier 		wunlock(&mh->lock);
6969ef1f84bSDavid du Colombier 		putmhead(mh);
6979ef1f84bSDavid du Colombier 		return;
6989ef1f84bSDavid du Colombier 	}
6999ef1f84bSDavid du Colombier 
7009ef1f84bSDavid du Colombier 	p = &mh->mount;
7019ef1f84bSDavid du Colombier 	for(f = *p; f; f = f->next){
7029ef1f84bSDavid du Colombier 		/* BUG: Needs to be 2 pass */
7039ef1f84bSDavid du Colombier 		if(eqchan(f->to, mounted, 1) ||
7049ef1f84bSDavid du Colombier 		  (f->to->mchan && eqchan(f->to->mchan, mounted, 1))){
7059ef1f84bSDavid du Colombier 			*p = f->next;
7069ef1f84bSDavid du Colombier 			f->next = 0;
7079ef1f84bSDavid du Colombier 			mountfree(f);
7089ef1f84bSDavid du Colombier 			if(mh->mount == nil){
7099ef1f84bSDavid du Colombier 				*l = mh->hash;
7109ef1f84bSDavid du Colombier 				cclose(mh->from);
7119ef1f84bSDavid du Colombier 				wunlock(&mh->lock);
7129ef1f84bSDavid du Colombier 				wunlock(&pg->ns);
7139ef1f84bSDavid du Colombier 				putmhead(mh);
7149ef1f84bSDavid du Colombier 				return;
7159ef1f84bSDavid du Colombier 			}
7169ef1f84bSDavid du Colombier 			wunlock(&mh->lock);
7179ef1f84bSDavid du Colombier 			wunlock(&pg->ns);
7189ef1f84bSDavid du Colombier 			return;
7199ef1f84bSDavid du Colombier 		}
7209ef1f84bSDavid du Colombier 		p = &f->next;
7219ef1f84bSDavid du Colombier 	}
7229ef1f84bSDavid du Colombier 	wunlock(&mh->lock);
7239ef1f84bSDavid du Colombier 	wunlock(&pg->ns);
7249ef1f84bSDavid du Colombier 	error(Eunion);
7259ef1f84bSDavid du Colombier }
7269ef1f84bSDavid du Colombier 
7279ef1f84bSDavid du Colombier Chan*
cclone(Chan * c)7289ef1f84bSDavid du Colombier cclone(Chan *c)
7299ef1f84bSDavid du Colombier {
7309ef1f84bSDavid du Colombier 	Chan *nc;
7319ef1f84bSDavid du Colombier 	Walkqid *wq;
7329ef1f84bSDavid du Colombier 
7339ef1f84bSDavid du Colombier 	wq = c->dev->walk(c, nil, nil, 0);		//XDYNX?
7349ef1f84bSDavid du Colombier 	if(wq == nil)
7359ef1f84bSDavid du Colombier 		error("clone failed");
7369ef1f84bSDavid du Colombier 	nc = wq->clone;
7379ef1f84bSDavid du Colombier 	free(wq);
7389ef1f84bSDavid du Colombier 	nc->path = c->path;
7399ef1f84bSDavid du Colombier 	if(c->path)
7409ef1f84bSDavid du Colombier 		incref(c->path);
7419ef1f84bSDavid du Colombier 	return nc;
7429ef1f84bSDavid du Colombier }
7439ef1f84bSDavid du Colombier 
7449ef1f84bSDavid du Colombier /* also used by sysfile.c:/^mountfix */
7459ef1f84bSDavid du Colombier int
findmount(Chan ** cp,Mhead ** mp,int dc,uint devno,Qid qid)7469ef1f84bSDavid du Colombier findmount(Chan **cp, Mhead **mp, int dc, uint devno, Qid qid)
7479ef1f84bSDavid du Colombier {
7489ef1f84bSDavid du Colombier 	Pgrp *pg;
7499ef1f84bSDavid du Colombier 	Mhead *mh;
7509ef1f84bSDavid du Colombier 
7519ef1f84bSDavid du Colombier 	pg = up->pgrp;
7529ef1f84bSDavid du Colombier 	rlock(&pg->ns);
7539ef1f84bSDavid du Colombier 	for(mh = MOUNTH(pg, qid); mh; mh = mh->hash){
7549ef1f84bSDavid du Colombier 		rlock(&mh->lock);
7559ef1f84bSDavid du Colombier 		if(mh->from == nil){
7569ef1f84bSDavid du Colombier 			print("mh %#p: mh->from nil\n", mh);
7579ef1f84bSDavid du Colombier 			runlock(&mh->lock);
7589ef1f84bSDavid du Colombier 			continue;
7599ef1f84bSDavid du Colombier 		}
7609ef1f84bSDavid du Colombier 		if(eqchanddq(mh->from, dc, devno, qid, 1)){
7619ef1f84bSDavid du Colombier 			runlock(&pg->ns);
7629ef1f84bSDavid du Colombier 			if(mp != nil){
7639ef1f84bSDavid du Colombier 				incref(mh);
7649ef1f84bSDavid du Colombier 				if(*mp != nil)
7659ef1f84bSDavid du Colombier 					putmhead(*mp);
7669ef1f84bSDavid du Colombier 				*mp = mh;
7679ef1f84bSDavid du Colombier 			}
7689ef1f84bSDavid du Colombier 			if(*cp != nil)
7699ef1f84bSDavid du Colombier 				cclose(*cp);
7709ef1f84bSDavid du Colombier 			incref(mh->mount->to);
7719ef1f84bSDavid du Colombier 			*cp = mh->mount->to;
7729ef1f84bSDavid du Colombier 			runlock(&mh->lock);
7739ef1f84bSDavid du Colombier 			return 1;
7749ef1f84bSDavid du Colombier 		}
7759ef1f84bSDavid du Colombier 		runlock(&mh->lock);
7769ef1f84bSDavid du Colombier 	}
7779ef1f84bSDavid du Colombier 
7789ef1f84bSDavid du Colombier 	runlock(&pg->ns);
7799ef1f84bSDavid du Colombier 	return 0;
7809ef1f84bSDavid du Colombier }
7819ef1f84bSDavid du Colombier 
7829ef1f84bSDavid du Colombier /*
7839ef1f84bSDavid du Colombier  * Calls findmount but also updates path.
7849ef1f84bSDavid du Colombier  */
7859ef1f84bSDavid du Colombier static int
domount(Chan ** cp,Mhead ** mp,Path ** path)7869ef1f84bSDavid du Colombier domount(Chan **cp, Mhead **mp, Path **path)
7879ef1f84bSDavid du Colombier {
7889ef1f84bSDavid du Colombier 	Chan **lc;
7899ef1f84bSDavid du Colombier 	Path *p;
7909ef1f84bSDavid du Colombier 
7919ef1f84bSDavid du Colombier 	if(findmount(cp, mp, (*cp)->dev->dc, (*cp)->devno, (*cp)->qid) == 0)
7929ef1f84bSDavid du Colombier 		return 0;
7939ef1f84bSDavid du Colombier 
7949ef1f84bSDavid du Colombier 	if(path){
7959ef1f84bSDavid du Colombier 		p = *path;
7969ef1f84bSDavid du Colombier 		p = uniquepath(p);
7979ef1f84bSDavid du Colombier 		if(p->mlen <= 0)
7989ef1f84bSDavid du Colombier 			print("domount: path %s has mlen==%d\n", p->s, p->mlen);
7999ef1f84bSDavid du Colombier 		else{
8009ef1f84bSDavid du Colombier 			lc = &p->mtpt[p->mlen-1];
8019ef1f84bSDavid du Colombier 			DBG("domount %#p %s => add %#p (was %#p)\n",
8029ef1f84bSDavid du Colombier 				p, p->s, (*mp)->from, p->mtpt[p->mlen-1]);
8039ef1f84bSDavid du Colombier 			incref((*mp)->from);
8049ef1f84bSDavid du Colombier 			if(*lc)
8059ef1f84bSDavid du Colombier 				cclose(*lc);
8069ef1f84bSDavid du Colombier 			*lc = (*mp)->from;
8079ef1f84bSDavid du Colombier 		}
8089ef1f84bSDavid du Colombier 		*path = p;
8099ef1f84bSDavid du Colombier 	}
8109ef1f84bSDavid du Colombier 	return 1;
8119ef1f84bSDavid du Colombier }
8129ef1f84bSDavid du Colombier 
8139ef1f84bSDavid du Colombier /*
8149ef1f84bSDavid du Colombier  * If c is the right-hand-side of a mount point, returns the left hand side.
8159ef1f84bSDavid du Colombier  * Changes name to reflect the fact that we've uncrossed the mountpoint,
8169ef1f84bSDavid du Colombier  * so name had better be ours to change!
8179ef1f84bSDavid du Colombier  */
8189ef1f84bSDavid du Colombier static Chan*
undomount(Chan * c,Path * path)8199ef1f84bSDavid du Colombier undomount(Chan *c, Path *path)
8209ef1f84bSDavid du Colombier {
8219ef1f84bSDavid du Colombier 	Chan *nc;
8229ef1f84bSDavid du Colombier 
8239ef1f84bSDavid du Colombier 	if(path->ref != 1 || path->mlen == 0)
8249ef1f84bSDavid du Colombier 		print("undomount: path %s ref %d mlen %d caller %#p\n",
8259ef1f84bSDavid du Colombier 			path->s, path->ref, path->mlen, getcallerpc(&c));
8269ef1f84bSDavid du Colombier 
8279ef1f84bSDavid du Colombier 	if(path->mlen>0 && (nc=path->mtpt[path->mlen-1]) != nil){
8289ef1f84bSDavid du Colombier 		DBG("undomount %#p %s => remove %p\n", path, path->s, nc);
8299ef1f84bSDavid du Colombier 		cclose(c);
8309ef1f84bSDavid du Colombier 		path->mtpt[path->mlen-1] = nil;
8319ef1f84bSDavid du Colombier 		c = nc;
8329ef1f84bSDavid du Colombier 	}
8339ef1f84bSDavid du Colombier 	return c;
8349ef1f84bSDavid du Colombier }
8359ef1f84bSDavid du Colombier 
8369ef1f84bSDavid du Colombier /*
8379ef1f84bSDavid du Colombier  * Call dev walk but catch errors.
8389ef1f84bSDavid du Colombier  */
8399ef1f84bSDavid du Colombier static Walkqid*
ewalk(Chan * c,Chan * nc,char ** name,int nname)8409ef1f84bSDavid du Colombier ewalk(Chan *c, Chan *nc, char **name, int nname)
8419ef1f84bSDavid du Colombier {
8429ef1f84bSDavid du Colombier 	Walkqid *wq;
8439ef1f84bSDavid du Colombier 
8449ef1f84bSDavid du Colombier 	if(waserror())
8459ef1f84bSDavid du Colombier 		return nil;
8469ef1f84bSDavid du Colombier 	wq = c->dev->walk(c, nc, name, nname);
8479ef1f84bSDavid du Colombier 	poperror();
8489ef1f84bSDavid du Colombier 	return wq;
8499ef1f84bSDavid du Colombier }
8509ef1f84bSDavid du Colombier 
8519ef1f84bSDavid du Colombier /*
8529ef1f84bSDavid du Colombier  * Either walks all the way or not at all.  No partial results in *cp.
8539ef1f84bSDavid du Colombier  * *nerror is the number of names to display in an error message.
8549ef1f84bSDavid du Colombier  */
8559ef1f84bSDavid du Colombier static char Edoesnotexist[] = "does not exist";
8569ef1f84bSDavid du Colombier int
walk(Chan ** cp,char ** names,int nnames,int nomount,int * nerror)8579ef1f84bSDavid du Colombier walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
8589ef1f84bSDavid du Colombier {
8599ef1f84bSDavid du Colombier 	int dc, devno, didmount, dotdot, i, n, nhave, ntry;
8609ef1f84bSDavid du Colombier 	Chan *c, *nc, *mtpt;
8619ef1f84bSDavid du Colombier 	Path *path;
8629ef1f84bSDavid du Colombier 	Mhead *mh, *nmh;
8639ef1f84bSDavid du Colombier 	Mount *f;
8649ef1f84bSDavid du Colombier 	Walkqid *wq;
8659ef1f84bSDavid du Colombier 
8669ef1f84bSDavid du Colombier 	c = *cp;
8679ef1f84bSDavid du Colombier 	incref(c);
8689ef1f84bSDavid du Colombier 	path = c->path;
8699ef1f84bSDavid du Colombier 	incref(path);
8709ef1f84bSDavid du Colombier 	mh = nil;
8719ef1f84bSDavid du Colombier 
8729ef1f84bSDavid du Colombier 	/*
8739ef1f84bSDavid du Colombier 	 * While we haven't gotten all the way down the path:
8749ef1f84bSDavid du Colombier 	 *    1. step through a mount point, if any
8759ef1f84bSDavid du Colombier 	 *    2. send a walk request for initial dotdot or initial prefix without dotdot
8769ef1f84bSDavid du Colombier 	 *    3. move to the first mountpoint along the way.
8779ef1f84bSDavid du Colombier 	 *    4. repeat.
8789ef1f84bSDavid du Colombier 	 *
8799ef1f84bSDavid du Colombier 	 * Each time through the loop:
8809ef1f84bSDavid du Colombier 	 *
8819ef1f84bSDavid du Colombier 	 *	If didmount==0, c is on the undomount side of the mount point.
8829ef1f84bSDavid du Colombier 	 *	If didmount==1, c is on the domount side of the mount point.
8839ef1f84bSDavid du Colombier 	 * 	Either way, c's full path is path.
8849ef1f84bSDavid du Colombier 	 */
8859ef1f84bSDavid du Colombier 	didmount = 0;
8869ef1f84bSDavid du Colombier 	for(nhave=0; nhave<nnames; nhave+=n){
8879ef1f84bSDavid du Colombier 		if(!(c->qid.type & QTDIR)){
8889ef1f84bSDavid du Colombier 			if(nerror)
8899ef1f84bSDavid du Colombier 				*nerror = nhave;
8909ef1f84bSDavid du Colombier 			pathclose(path);
8919ef1f84bSDavid du Colombier 			cclose(c);
8929ef1f84bSDavid du Colombier 			strcpy(up->errstr, Enotdir);
8939ef1f84bSDavid du Colombier 			if(mh != nil)
8949ef1f84bSDavid du Colombier 				putmhead(mh);
8959ef1f84bSDavid du Colombier 			return -1;
8969ef1f84bSDavid du Colombier 		}
8979ef1f84bSDavid du Colombier 		ntry = nnames - nhave;
8989ef1f84bSDavid du Colombier 		if(ntry > MAXWELEM)
8999ef1f84bSDavid du Colombier 			ntry = MAXWELEM;
9009ef1f84bSDavid du Colombier 		dotdot = 0;
9019ef1f84bSDavid du Colombier 		for(i=0; i<ntry; i++){
9029ef1f84bSDavid du Colombier 			if(isdotdot(names[nhave+i])){
9039ef1f84bSDavid du Colombier 				if(i==0){
9049ef1f84bSDavid du Colombier 					dotdot = 1;
9059ef1f84bSDavid du Colombier 					ntry = 1;
9069ef1f84bSDavid du Colombier 				}else
9079ef1f84bSDavid du Colombier 					ntry = i;
9089ef1f84bSDavid du Colombier 				break;
9099ef1f84bSDavid du Colombier 			}
9109ef1f84bSDavid du Colombier 		}
9119ef1f84bSDavid du Colombier 
9129ef1f84bSDavid du Colombier 		if(!dotdot && !nomount && !didmount)
9139ef1f84bSDavid du Colombier 			domount(&c, &mh, &path);
9149ef1f84bSDavid du Colombier 
9159ef1f84bSDavid du Colombier 		dc = c->dev->dc;
9169ef1f84bSDavid du Colombier 		devno = c->devno;
9179ef1f84bSDavid du Colombier 
9189ef1f84bSDavid du Colombier 		if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){
9199ef1f84bSDavid du Colombier 			/* try a union mount, if any */
9209ef1f84bSDavid du Colombier 			if(mh && !nomount){
9219ef1f84bSDavid du Colombier 				/*
9229ef1f84bSDavid du Colombier 				 * mh->mount->to == c, so start at mh->mount->next
9239ef1f84bSDavid du Colombier 				 */
9249ef1f84bSDavid du Colombier 				rlock(&mh->lock);
9259ef1f84bSDavid du Colombier 				for(f = mh->mount->next; f; f = f->next)
9269ef1f84bSDavid du Colombier 					if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil)
9279ef1f84bSDavid du Colombier 						break;
9289ef1f84bSDavid du Colombier 				runlock(&mh->lock);
9299ef1f84bSDavid du Colombier 				if(f != nil){
9309ef1f84bSDavid du Colombier 					dc = f->to->dev->dc;
9319ef1f84bSDavid du Colombier 					devno = f->to->devno;
9329ef1f84bSDavid du Colombier 				}
9339ef1f84bSDavid du Colombier 			}
9349ef1f84bSDavid du Colombier 			if(wq == nil){
9359ef1f84bSDavid du Colombier 				cclose(c);
9369ef1f84bSDavid du Colombier 				pathclose(path);
9379ef1f84bSDavid du Colombier 				if(nerror)
9389ef1f84bSDavid du Colombier 					*nerror = nhave+1;
9399ef1f84bSDavid du Colombier 				if(mh != nil)
9409ef1f84bSDavid du Colombier 					putmhead(mh);
9419ef1f84bSDavid du Colombier 				return -1;
9429ef1f84bSDavid du Colombier 			}
9439ef1f84bSDavid du Colombier 		}
9449ef1f84bSDavid du Colombier 
9459ef1f84bSDavid du Colombier 		nmh = nil;
9469ef1f84bSDavid du Colombier 		didmount = 0;
9479ef1f84bSDavid du Colombier 		if(dotdot){
9489ef1f84bSDavid du Colombier 			assert(wq->nqid == 1);
9499ef1f84bSDavid du Colombier 			assert(wq->clone != nil);
9509ef1f84bSDavid du Colombier 
9519ef1f84bSDavid du Colombier 			path = addelem(path, "..", nil);
9529ef1f84bSDavid du Colombier 			nc = undomount(wq->clone, path);
9539ef1f84bSDavid du Colombier 			n = 1;
9549ef1f84bSDavid du Colombier 		}else{
9559ef1f84bSDavid du Colombier 			nc = nil;
9569ef1f84bSDavid du Colombier 			if(!nomount){
9579ef1f84bSDavid du Colombier 				for(i=0; i<wq->nqid && i<ntry-1; i++){
9589ef1f84bSDavid du Colombier 					if(findmount(&nc, &nmh, dc, devno, wq->qid[i])){
9599ef1f84bSDavid du Colombier 						didmount = 1;
9609ef1f84bSDavid du Colombier 						break;
9619ef1f84bSDavid du Colombier 					}
9629ef1f84bSDavid du Colombier 				}
9639ef1f84bSDavid du Colombier 			}
9649ef1f84bSDavid du Colombier 			if(nc == nil){	/* no mount points along path */
9659ef1f84bSDavid du Colombier 				if(wq->clone == nil){
9669ef1f84bSDavid du Colombier 					cclose(c);
9679ef1f84bSDavid du Colombier 					pathclose(path);
9689ef1f84bSDavid du Colombier 					if(wq->nqid==0 || (wq->qid[wq->nqid-1].type & QTDIR)){
9699ef1f84bSDavid du Colombier 						if(nerror)
9709ef1f84bSDavid du Colombier 							*nerror = nhave+wq->nqid+1;
9719ef1f84bSDavid du Colombier 						strcpy(up->errstr, Edoesnotexist);
9729ef1f84bSDavid du Colombier 					}else{
9739ef1f84bSDavid du Colombier 						if(nerror)
9749ef1f84bSDavid du Colombier 							*nerror = nhave+wq->nqid;
9759ef1f84bSDavid du Colombier 						strcpy(up->errstr, Enotdir);
9769ef1f84bSDavid du Colombier 					}
9779ef1f84bSDavid du Colombier 					free(wq);
9789ef1f84bSDavid du Colombier 					if(mh != nil)
9799ef1f84bSDavid du Colombier 						putmhead(mh);
9809ef1f84bSDavid du Colombier 					return -1;
9819ef1f84bSDavid du Colombier 				}
9829ef1f84bSDavid du Colombier 				n = wq->nqid;
9839ef1f84bSDavid du Colombier 				nc = wq->clone;
9849ef1f84bSDavid du Colombier 			}else{		/* stopped early, at a mount point */
9859ef1f84bSDavid du Colombier 				didmount = 1;
9869ef1f84bSDavid du Colombier 				if(wq->clone != nil){
9879ef1f84bSDavid du Colombier 					cclose(wq->clone);
9889ef1f84bSDavid du Colombier 					wq->clone = nil;
9899ef1f84bSDavid du Colombier 				}
9909ef1f84bSDavid du Colombier 				n = i+1;
9919ef1f84bSDavid du Colombier 			}
9929ef1f84bSDavid du Colombier 			for(i=0; i<n; i++){
9939ef1f84bSDavid du Colombier 				mtpt = nil;
9949ef1f84bSDavid du Colombier 				if(i==n-1 && nmh)
9959ef1f84bSDavid du Colombier 					mtpt = nmh->from;
9969ef1f84bSDavid du Colombier 				path = addelem(path, names[nhave+i], mtpt);
9979ef1f84bSDavid du Colombier 			}
9989ef1f84bSDavid du Colombier 		}
9999ef1f84bSDavid du Colombier 		cclose(c);
10009ef1f84bSDavid du Colombier 		c = nc;
10019ef1f84bSDavid du Colombier 		putmhead(mh);
10029ef1f84bSDavid du Colombier 		mh = nmh;
10039ef1f84bSDavid du Colombier 		free(wq);
10049ef1f84bSDavid du Colombier 	}
10059ef1f84bSDavid du Colombier 
10069ef1f84bSDavid du Colombier 	putmhead(mh);
10079ef1f84bSDavid du Colombier 
10089ef1f84bSDavid du Colombier 	c = cunique(c);
10099ef1f84bSDavid du Colombier 
10109ef1f84bSDavid du Colombier 	if(c->umh != nil){	//BUG
10119ef1f84bSDavid du Colombier 		print("walk umh\n");
10129ef1f84bSDavid du Colombier 		putmhead(c->umh);
10139ef1f84bSDavid du Colombier 		c->umh = nil;
10149ef1f84bSDavid du Colombier 	}
10159ef1f84bSDavid du Colombier 
10169ef1f84bSDavid du Colombier 	pathclose(c->path);
10179ef1f84bSDavid du Colombier 	c->path = path;
10189ef1f84bSDavid du Colombier 
10199ef1f84bSDavid du Colombier 	cclose(*cp);
10209ef1f84bSDavid du Colombier 	*cp = c;
10219ef1f84bSDavid du Colombier 	if(nerror)
10229ef1f84bSDavid du Colombier 		*nerror = nhave;
10239ef1f84bSDavid du Colombier 	return 0;
10249ef1f84bSDavid du Colombier }
10259ef1f84bSDavid du Colombier 
10269ef1f84bSDavid du Colombier /*
10279ef1f84bSDavid du Colombier  * c is a mounted non-creatable directory.  find a creatable one.
10289ef1f84bSDavid du Colombier  */
10299ef1f84bSDavid du Colombier Chan*
createdir(Chan * c,Mhead * mh)10309ef1f84bSDavid du Colombier createdir(Chan *c, Mhead *mh)
10319ef1f84bSDavid du Colombier {
10329ef1f84bSDavid du Colombier 	Chan *nc;
10339ef1f84bSDavid du Colombier 	Mount *f;
10349ef1f84bSDavid du Colombier 
10359ef1f84bSDavid du Colombier 	rlock(&mh->lock);
10369ef1f84bSDavid du Colombier 	if(waserror()){
10379ef1f84bSDavid du Colombier 		runlock(&mh->lock);
10389ef1f84bSDavid du Colombier 		nexterror();
10399ef1f84bSDavid du Colombier 	}
10409ef1f84bSDavid du Colombier 	for(f = mh->mount; f; f = f->next){
10419ef1f84bSDavid du Colombier 		if(f->mflag&MCREATE){
10429ef1f84bSDavid du Colombier 			nc = cclone(f->to);
10439ef1f84bSDavid du Colombier 			runlock(&mh->lock);
10449ef1f84bSDavid du Colombier 			poperror();
10459ef1f84bSDavid du Colombier 			cclose(c);
10469ef1f84bSDavid du Colombier 			return nc;
10479ef1f84bSDavid du Colombier 		}
10489ef1f84bSDavid du Colombier 	}
10499ef1f84bSDavid du Colombier 	error(Enocreate);
10509ef1f84bSDavid du Colombier 	return 0;
10519ef1f84bSDavid du Colombier }
10529ef1f84bSDavid du Colombier 
10539ef1f84bSDavid du Colombier static void
growparse(Elemlist * e)10549ef1f84bSDavid du Colombier growparse(Elemlist *e)
10559ef1f84bSDavid du Colombier {
10569ef1f84bSDavid du Colombier 	char **new;
10579ef1f84bSDavid du Colombier 	int *inew;
10589ef1f84bSDavid du Colombier 	enum { Delta = 8 };
10599ef1f84bSDavid du Colombier 
10609ef1f84bSDavid du Colombier 	if(e->nelems % Delta == 0){
10619ef1f84bSDavid du Colombier 		new = smalloc((e->nelems+Delta) * sizeof(char*));
10629ef1f84bSDavid du Colombier 		memmove(new, e->elems, e->nelems*sizeof(char*));
10639ef1f84bSDavid du Colombier 		free(e->elems);
10649ef1f84bSDavid du Colombier 		e->elems = new;
10659ef1f84bSDavid du Colombier 		inew = smalloc((e->nelems+Delta+1) * sizeof(int));
10669ef1f84bSDavid du Colombier 		memmove(inew, e->off, (e->nelems+1)*sizeof(int));
10679ef1f84bSDavid du Colombier 		free(e->off);
10689ef1f84bSDavid du Colombier 		e->off = inew;
10699ef1f84bSDavid du Colombier 	}
10709ef1f84bSDavid du Colombier }
10719ef1f84bSDavid du Colombier 
10729ef1f84bSDavid du Colombier /*
10739ef1f84bSDavid du Colombier  * The name is known to be valid.
10749ef1f84bSDavid du Colombier  * Copy the name so slashes can be overwritten.
10759ef1f84bSDavid du Colombier  * An empty string will set nelem=0.
10769ef1f84bSDavid du Colombier  * A path ending in / or /. or /.//./ etc. will have
10779ef1f84bSDavid du Colombier  * e.mustbedir = 1, so that we correctly
10789ef1f84bSDavid du Colombier  * reject, e.g., "/adm/users/." when /adm/users is a file
10799ef1f84bSDavid du Colombier  * rather than a directory.
10809ef1f84bSDavid du Colombier  */
10819ef1f84bSDavid du Colombier static void
parsename(char * aname,Elemlist * e)10829ef1f84bSDavid du Colombier parsename(char *aname, Elemlist *e)
10839ef1f84bSDavid du Colombier {
10849ef1f84bSDavid du Colombier 	char *name, *slash;
10859ef1f84bSDavid du Colombier 
10869ef1f84bSDavid du Colombier 	kstrdup(&e->name, aname);
10879ef1f84bSDavid du Colombier 	name = e->name;
10889ef1f84bSDavid du Colombier 	e->nelems = 0;
10899ef1f84bSDavid du Colombier 	e->elems = nil;
10909ef1f84bSDavid du Colombier 	e->off = smalloc(sizeof(int));
10919ef1f84bSDavid du Colombier 	e->off[0] = skipslash(name) - name;
10929ef1f84bSDavid du Colombier 	for(;;){
10939ef1f84bSDavid du Colombier 		name = skipslash(name);
10949ef1f84bSDavid du Colombier 		if(*name == '\0'){
10959ef1f84bSDavid du Colombier 			e->off[e->nelems] = name+strlen(name) - e->name;
10969ef1f84bSDavid du Colombier 			e->mustbedir = 1;
10979ef1f84bSDavid du Colombier 			break;
10989ef1f84bSDavid du Colombier 		}
10999ef1f84bSDavid du Colombier 		growparse(e);
11009ef1f84bSDavid du Colombier 		e->elems[e->nelems++] = name;
11019ef1f84bSDavid du Colombier 		slash = utfrune(name, '/');
11029ef1f84bSDavid du Colombier 		if(slash == nil){
11039ef1f84bSDavid du Colombier 			e->off[e->nelems] = name+strlen(name) - e->name;
11049ef1f84bSDavid du Colombier 			e->mustbedir = 0;
11059ef1f84bSDavid du Colombier 			break;
11069ef1f84bSDavid du Colombier 		}
11079ef1f84bSDavid du Colombier 		e->off[e->nelems] = slash - e->name;
11089ef1f84bSDavid du Colombier 		*slash++ = '\0';
11099ef1f84bSDavid du Colombier 		name = slash;
11109ef1f84bSDavid du Colombier 	}
11119ef1f84bSDavid du Colombier 
11129ef1f84bSDavid du Colombier 	if(DBGFLG > 1){
11139ef1f84bSDavid du Colombier 		int i;
11149ef1f84bSDavid du Colombier 
11159ef1f84bSDavid du Colombier 		DBG("parsename %s:", e->name);
11169ef1f84bSDavid du Colombier 		for(i=0; i<=e->nelems; i++)
11179ef1f84bSDavid du Colombier 			DBG(" %d", e->off[i]);
11189ef1f84bSDavid du Colombier 		DBG("\n");
11199ef1f84bSDavid du Colombier 	}
11209ef1f84bSDavid du Colombier }
11219ef1f84bSDavid du Colombier 
11229ef1f84bSDavid du Colombier static void*
memrchr(void * va,int c,long n)11239ef1f84bSDavid du Colombier memrchr(void *va, int c, long n)
11249ef1f84bSDavid du Colombier {
11259ef1f84bSDavid du Colombier 	uchar *a, *e;
11269ef1f84bSDavid du Colombier 
11279ef1f84bSDavid du Colombier 	a = va;
11289ef1f84bSDavid du Colombier 	for(e=a+n-1; e>a; e--)
11299ef1f84bSDavid du Colombier 		if(*e == c)
11309ef1f84bSDavid du Colombier 			return e;
11319ef1f84bSDavid du Colombier 	return nil;
11329ef1f84bSDavid du Colombier }
11339ef1f84bSDavid du Colombier 
11349ef1f84bSDavid du Colombier static void
namelenerror(char * aname,int len,char * err)11359ef1f84bSDavid du Colombier namelenerror(char *aname, int len, char *err)
11369ef1f84bSDavid du Colombier {
11379ef1f84bSDavid du Colombier 	char *ename, *name, *next;
11389ef1f84bSDavid du Colombier 	int i, errlen;
11399ef1f84bSDavid du Colombier 
11409ef1f84bSDavid du Colombier 	/*
11419ef1f84bSDavid du Colombier 	 * If the name is short enough, just use the whole thing.
11429ef1f84bSDavid du Colombier 	 */
11439ef1f84bSDavid du Colombier 	errlen = strlen(err);
11449ef1f84bSDavid du Colombier 	if(len < ERRMAX/3 || len+errlen < 2*ERRMAX/3)
11459ef1f84bSDavid du Colombier 		snprint(up->genbuf, sizeof up->genbuf, "%.*s",
11469ef1f84bSDavid du Colombier 			utfnlen(aname, len), aname);
11479ef1f84bSDavid du Colombier 	else{
11489ef1f84bSDavid du Colombier 		/*
11499ef1f84bSDavid du Colombier 		 * Print a suffix of the name, but try to get a little info.
11509ef1f84bSDavid du Colombier 		 */
11519ef1f84bSDavid du Colombier 		ename = aname+len;
11529ef1f84bSDavid du Colombier 		next = ename;
11539ef1f84bSDavid du Colombier 		do{
11549ef1f84bSDavid du Colombier 			name = next;
11559ef1f84bSDavid du Colombier 			next = memrchr(aname, '/', name-aname);
11569ef1f84bSDavid du Colombier 			if(next == nil)
11579ef1f84bSDavid du Colombier 				next = aname;
11589ef1f84bSDavid du Colombier 			len = ename-next;
11599ef1f84bSDavid du Colombier 		}while(len < ERRMAX/3 || len + errlen < 2*ERRMAX/3);
11609ef1f84bSDavid du Colombier 
11619ef1f84bSDavid du Colombier 		/*
11629ef1f84bSDavid du Colombier 		 * If the name is ridiculously long, chop it.
11639ef1f84bSDavid du Colombier 		 */
11649ef1f84bSDavid du Colombier 		if(name == ename){
11659ef1f84bSDavid du Colombier 			name = ename-ERRMAX/4;
11669ef1f84bSDavid du Colombier 			if(name <= aname)
11679ef1f84bSDavid du Colombier 				panic("bad math in namelenerror");
11689ef1f84bSDavid du Colombier 			/* walk out of current UTF sequence */
1169406c76faSDavid du Colombier 			for(i=0; (*name&0xC0)==0x80 && i<UTFmax; i++)
11709ef1f84bSDavid du Colombier 				name++;
11719ef1f84bSDavid du Colombier 		}
11729ef1f84bSDavid du Colombier 		snprint(up->genbuf, sizeof up->genbuf, "...%.*s",
11739ef1f84bSDavid du Colombier 			utfnlen(name, ename-name), name);
11749ef1f84bSDavid du Colombier 	}
11759ef1f84bSDavid du Colombier 	snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
11769ef1f84bSDavid du Colombier 	nexterror();
11779ef1f84bSDavid du Colombier }
11789ef1f84bSDavid du Colombier 
11799ef1f84bSDavid du Colombier void
nameerror(char * name,char * err)11809ef1f84bSDavid du Colombier nameerror(char *name, char *err)
11819ef1f84bSDavid du Colombier {
11829ef1f84bSDavid du Colombier 	namelenerror(name, strlen(name), err);
11839ef1f84bSDavid du Colombier }
11849ef1f84bSDavid du Colombier 
11859ef1f84bSDavid du Colombier /*
11869ef1f84bSDavid du Colombier  * Turn a name into a channel.
11879ef1f84bSDavid du Colombier  * &name[0] is known to be a valid address.  It may be a kernel address.
11889ef1f84bSDavid du Colombier  *
11899ef1f84bSDavid du Colombier  * Opening with amode Aopen, Acreate, Aremove, or Aaccess guarantees
11909ef1f84bSDavid du Colombier  * that the result will be the only reference to that particular fid.
11919ef1f84bSDavid du Colombier  * This is necessary since we might pass the result to
11929ef1f84bSDavid du Colombier  * devtab[]->remove().
11939ef1f84bSDavid du Colombier  *
11949ef1f84bSDavid du Colombier  * Opening Atodir or Amount does not guarantee this.
11959ef1f84bSDavid du Colombier  *
11969ef1f84bSDavid du Colombier  * Under certain circumstances, opening Aaccess will cause
11979ef1f84bSDavid du Colombier  * an unnecessary clone in order to get a cunique Chan so it
11989ef1f84bSDavid du Colombier  * can attach the correct name.  Sysstat and sys_stat need the
11999ef1f84bSDavid du Colombier  * correct name so they can rewrite the stat info.
12009ef1f84bSDavid du Colombier  */
12019ef1f84bSDavid du Colombier Chan*
namec(char * aname,int amode,int omode,int perm)12029ef1f84bSDavid du Colombier namec(char *aname, int amode, int omode, int perm)
12039ef1f84bSDavid du Colombier {
12049ef1f84bSDavid du Colombier 	int len, n, nomount;
12059ef1f84bSDavid du Colombier 	Chan *c, *cnew;
12069ef1f84bSDavid du Colombier 	Path *path;
12079ef1f84bSDavid du Colombier 	Elemlist e;
12089ef1f84bSDavid du Colombier 	Rune r;
12099ef1f84bSDavid du Colombier 	Mhead *mh;
12109ef1f84bSDavid du Colombier 	char *createerr, tmperrbuf[ERRMAX];
12119ef1f84bSDavid du Colombier 	char *name;
12129ef1f84bSDavid du Colombier 	Dev *dev;
12139ef1f84bSDavid du Colombier 
12149ef1f84bSDavid du Colombier 	if(aname[0] == '\0')
12159ef1f84bSDavid du Colombier 		error("empty file name");
12169ef1f84bSDavid du Colombier 	aname = validnamedup(aname, 1);
12179ef1f84bSDavid du Colombier 	if(waserror()){
12189ef1f84bSDavid du Colombier 		free(aname);
12199ef1f84bSDavid du Colombier 		nexterror();
12209ef1f84bSDavid du Colombier 	}
12219ef1f84bSDavid du Colombier 	DBG("namec %s %d %d\n", aname, amode, omode);
12229ef1f84bSDavid du Colombier 	name = aname;
12239ef1f84bSDavid du Colombier 
12249ef1f84bSDavid du Colombier 	/*
12259ef1f84bSDavid du Colombier 	 * Find the starting off point (the current slash, the root of
12269ef1f84bSDavid du Colombier 	 * a device tree, or the current dot) as well as the name to
12279ef1f84bSDavid du Colombier 	 * evaluate starting there.
12289ef1f84bSDavid du Colombier 	 */
12299ef1f84bSDavid du Colombier 	nomount = 0;
12309ef1f84bSDavid du Colombier 	switch(name[0]){
12319ef1f84bSDavid du Colombier 	case '/':
12329ef1f84bSDavid du Colombier 		c = up->slash;
12339ef1f84bSDavid du Colombier 		incref(c);
12349ef1f84bSDavid du Colombier 		break;
12359ef1f84bSDavid du Colombier 
12369ef1f84bSDavid du Colombier 	case '#':
12379ef1f84bSDavid du Colombier 		nomount = 1;
12389ef1f84bSDavid du Colombier 		up->genbuf[0] = '\0';
12399ef1f84bSDavid du Colombier 		n = 0;
12409ef1f84bSDavid du Colombier 		while(*name != '\0' && (*name != '/' || n < 2)){
12419ef1f84bSDavid du Colombier 			if(n >= sizeof(up->genbuf)-1)
12429ef1f84bSDavid du Colombier 				error(Efilename);
12439ef1f84bSDavid du Colombier 			up->genbuf[n++] = *name++;
12449ef1f84bSDavid du Colombier 		}
12459ef1f84bSDavid du Colombier 		up->genbuf[n] = '\0';
12469ef1f84bSDavid du Colombier 		/*
12479ef1f84bSDavid du Colombier 		 *  noattach is sandboxing.
12489ef1f84bSDavid du Colombier 		 *
12499ef1f84bSDavid du Colombier 		 *  the OK exceptions are:
12509ef1f84bSDavid du Colombier 		 *	|  it only gives access to pipes you create
12519ef1f84bSDavid du Colombier 		 *	d  this process's file descriptors
12529ef1f84bSDavid du Colombier 		 *	e  this process's environment
12539ef1f84bSDavid du Colombier 		 *  the iffy exceptions are:
12549ef1f84bSDavid du Colombier 		 *	c  time and pid, but also cons and consctl
12559ef1f84bSDavid du Colombier 		 *	p  control of your own processes (and unfortunately
12569ef1f84bSDavid du Colombier 		 *	   any others left unprotected)
12579ef1f84bSDavid du Colombier 		 */
12589ef1f84bSDavid du Colombier 		n = chartorune(&r, up->genbuf+1)+1;
12599ef1f84bSDavid du Colombier 		/* actually / is caught by parsing earlier */
12609ef1f84bSDavid du Colombier 		if(utfrune("M", r))
12619ef1f84bSDavid du Colombier 			error(Enoattach);
12629ef1f84bSDavid du Colombier 		if(up->pgrp->noattach && utfrune("|decp", r)==nil)
12639ef1f84bSDavid du Colombier 			error(Enoattach);
12649ef1f84bSDavid du Colombier 		dev = devtabget(r, 1);			//XDYNX
12659ef1f84bSDavid du Colombier 		if(dev == nil)
12669ef1f84bSDavid du Colombier 			error(Ebadsharp);
12679ef1f84bSDavid du Colombier 		//if(waserror()){
12689ef1f84bSDavid du Colombier 		//	devtabdecr(dev);
12699ef1f84bSDavid du Colombier 		//	nexterror();
12709ef1f84bSDavid du Colombier 		//}
12719ef1f84bSDavid du Colombier 		c = dev->attach(up->genbuf+n);
12729ef1f84bSDavid du Colombier 		//poperror();
12739ef1f84bSDavid du Colombier 		//devtabdecr(dev);
12749ef1f84bSDavid du Colombier 		break;
12759ef1f84bSDavid du Colombier 
12769ef1f84bSDavid du Colombier 	default:
12779ef1f84bSDavid du Colombier 		c = up->dot;
12789ef1f84bSDavid du Colombier 		incref(c);
12799ef1f84bSDavid du Colombier 		break;
12809ef1f84bSDavid du Colombier 	}
12819ef1f84bSDavid du Colombier 
12829ef1f84bSDavid du Colombier 	e.aname = aname;
12839ef1f84bSDavid du Colombier 	e.prefix = name - aname;
12849ef1f84bSDavid du Colombier 	e.name = nil;
12859ef1f84bSDavid du Colombier 	e.elems = nil;
12869ef1f84bSDavid du Colombier 	e.off = nil;
12879ef1f84bSDavid du Colombier 	e.nelems = 0;
12889ef1f84bSDavid du Colombier 	e.nerror = 0;
12899ef1f84bSDavid du Colombier 	if(waserror()){
12909ef1f84bSDavid du Colombier 		cclose(c);
12919ef1f84bSDavid du Colombier 		free(e.name);
12929ef1f84bSDavid du Colombier 		free(e.elems);
12939ef1f84bSDavid du Colombier 		/*
12949ef1f84bSDavid du Colombier 		 * Prepare nice error, showing first e.nerror elements of name.
12959ef1f84bSDavid du Colombier 		 */
12969ef1f84bSDavid du Colombier 		if(e.nerror == 0)
12979ef1f84bSDavid du Colombier 			nexterror();
12989ef1f84bSDavid du Colombier 		strcpy(tmperrbuf, up->errstr);
12999ef1f84bSDavid du Colombier 		if(e.off[e.nerror]==0)
13009ef1f84bSDavid du Colombier 			print("nerror=%d but off=%d\n",
13019ef1f84bSDavid du Colombier 				e.nerror, e.off[e.nerror]);
13029ef1f84bSDavid du Colombier 		if(DBGFLG > 0){
13039ef1f84bSDavid du Colombier 			DBG("showing %d+%d/%d (of %d) of %s (%d %d)\n",
13049ef1f84bSDavid du Colombier 				e.prefix, e.off[e.nerror], e.nerror,
13059ef1f84bSDavid du Colombier 				e.nelems, aname, e.off[0], e.off[1]);
13069ef1f84bSDavid du Colombier 		}
13079ef1f84bSDavid du Colombier 		len = e.prefix+e.off[e.nerror];
13089ef1f84bSDavid du Colombier 		free(e.off);
13099ef1f84bSDavid du Colombier 		namelenerror(aname, len, tmperrbuf);
13109ef1f84bSDavid du Colombier 	}
13119ef1f84bSDavid du Colombier 
13129ef1f84bSDavid du Colombier 	/*
13139ef1f84bSDavid du Colombier 	 * Build a list of elements in the name.
13149ef1f84bSDavid du Colombier 	 */
13159ef1f84bSDavid du Colombier 	parsename(name, &e);
13169ef1f84bSDavid du Colombier 
13179ef1f84bSDavid du Colombier 	/*
13189ef1f84bSDavid du Colombier 	 * On create, ....
13199ef1f84bSDavid du Colombier 	 */
13209ef1f84bSDavid du Colombier 	if(amode == Acreate){
13219ef1f84bSDavid du Colombier 		/* perm must have DMDIR if last element is / or /. */
13229ef1f84bSDavid du Colombier 		if(e.mustbedir && !(perm&DMDIR)){
13239ef1f84bSDavid du Colombier 			e.nerror = e.nelems;
13249ef1f84bSDavid du Colombier 			error("create without DMDIR");
13259ef1f84bSDavid du Colombier 		}
13269ef1f84bSDavid du Colombier 
13279ef1f84bSDavid du Colombier 		/* don't try to walk the last path element just yet. */
13289ef1f84bSDavid du Colombier 		if(e.nelems == 0)
13299ef1f84bSDavid du Colombier 			error(Eexist);
13309ef1f84bSDavid du Colombier 		e.nelems--;
13319ef1f84bSDavid du Colombier 	}
13329ef1f84bSDavid du Colombier 
13339ef1f84bSDavid du Colombier 	if(walk(&c, e.elems, e.nelems, nomount, &e.nerror) < 0){
13349ef1f84bSDavid du Colombier 		if(e.nerror < 0 || e.nerror > e.nelems){
13359ef1f84bSDavid du Colombier 			print("namec %s walk error nerror=%d\n", aname, e.nerror);
13369ef1f84bSDavid du Colombier 			e.nerror = 0;
13379ef1f84bSDavid du Colombier 		}
13389ef1f84bSDavid du Colombier 		nexterror();
13399ef1f84bSDavid du Colombier 	}
13409ef1f84bSDavid du Colombier 
13419ef1f84bSDavid du Colombier 	if(e.mustbedir && !(c->qid.type & QTDIR))
13429ef1f84bSDavid du Colombier 		error("not a directory");
13439ef1f84bSDavid du Colombier 
13449ef1f84bSDavid du Colombier 	if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type & QTDIR))
13459ef1f84bSDavid du Colombier 		error("cannot exec directory");
13469ef1f84bSDavid du Colombier 
13479ef1f84bSDavid du Colombier 	switch(amode){
13489ef1f84bSDavid du Colombier 	case Abind:
13499ef1f84bSDavid du Colombier 		/* no need to maintain path - cannot dotdot an Abind */
13509ef1f84bSDavid du Colombier 		mh = nil;
13519ef1f84bSDavid du Colombier 		if(!nomount)
13529ef1f84bSDavid du Colombier 			domount(&c, &mh, nil);
13539ef1f84bSDavid du Colombier 		if(c->umh != nil)
13549ef1f84bSDavid du Colombier 			putmhead(c->umh);
13559ef1f84bSDavid du Colombier 		c->umh = mh;
13569ef1f84bSDavid du Colombier 		break;
13579ef1f84bSDavid du Colombier 
13589ef1f84bSDavid du Colombier 	case Aaccess:
13599ef1f84bSDavid du Colombier 	case Aremove:
13609ef1f84bSDavid du Colombier 	case Aopen:
13619ef1f84bSDavid du Colombier 	Open:
13629ef1f84bSDavid du Colombier 		/* save&update the name; domount might change c */
13639ef1f84bSDavid du Colombier 		path = c->path;
13649ef1f84bSDavid du Colombier 		incref(path);
13659ef1f84bSDavid du Colombier 		mh = nil;
13669ef1f84bSDavid du Colombier 		if(!nomount)
13679ef1f84bSDavid du Colombier 			domount(&c, &mh, &path);
13689ef1f84bSDavid du Colombier 
13699ef1f84bSDavid du Colombier 		/* our own copy to open or remove */
13709ef1f84bSDavid du Colombier 		c = cunique(c);
13719ef1f84bSDavid du Colombier 
13729ef1f84bSDavid du Colombier 		/* now it's our copy anyway, we can put the name back */
13739ef1f84bSDavid du Colombier 		pathclose(c->path);
13749ef1f84bSDavid du Colombier 		c->path = path;
13759ef1f84bSDavid du Colombier 
13769ef1f84bSDavid du Colombier 		/* record whether c is on a mount point */
13779ef1f84bSDavid du Colombier 		c->ismtpt = mh!=nil;
13789ef1f84bSDavid du Colombier 
13799ef1f84bSDavid du Colombier 		switch(amode){
13809ef1f84bSDavid du Colombier 		case Aaccess:
13819ef1f84bSDavid du Colombier 		case Aremove:
13829ef1f84bSDavid du Colombier 			putmhead(mh);
13839ef1f84bSDavid du Colombier 			break;
13849ef1f84bSDavid du Colombier 
13859ef1f84bSDavid du Colombier 		case Aopen:
13869ef1f84bSDavid du Colombier 		case Acreate:
13879ef1f84bSDavid du Colombier if(c->umh != nil){
13889ef1f84bSDavid du Colombier 	print("cunique umh Open\n");
13899ef1f84bSDavid du Colombier 	putmhead(c->umh);
13909ef1f84bSDavid du Colombier 	c->umh = nil;
13919ef1f84bSDavid du Colombier }
13929ef1f84bSDavid du Colombier 			/* only save the mount head if it's a multiple element union */
13939ef1f84bSDavid du Colombier 			if(mh && mh->mount && mh->mount->next)
13949ef1f84bSDavid du Colombier 				c->umh = mh;
13959ef1f84bSDavid du Colombier 			else
13969ef1f84bSDavid du Colombier 				putmhead(mh);
13979ef1f84bSDavid du Colombier 
13989ef1f84bSDavid du Colombier 			if(omode == OEXEC)
13999ef1f84bSDavid du Colombier 				c->flag &= ~CCACHE;
14009ef1f84bSDavid du Colombier 
14019ef1f84bSDavid du Colombier 
14029ef1f84bSDavid du Colombier //open:							//XDYNX
14039ef1f84bSDavid du Colombier // get dev
14049ef1f84bSDavid du Colombier // open
14059ef1f84bSDavid du Colombier // if no error and read/write
14069ef1f84bSDavid du Colombier // then fill in c->dev and
14079ef1f84bSDavid du Colombier // don't put
14089ef1f84bSDavid du Colombier 			c = c->dev->open(c, omode&~OCEXEC);
14099ef1f84bSDavid du Colombier 
14109ef1f84bSDavid du Colombier 			if(omode & OCEXEC)
14119ef1f84bSDavid du Colombier 				c->flag |= CCEXEC;
14129ef1f84bSDavid du Colombier 			if(omode & ORCLOSE)
14139ef1f84bSDavid du Colombier 				c->flag |= CRCLOSE;
14149ef1f84bSDavid du Colombier 			break;
14159ef1f84bSDavid du Colombier 		}
14169ef1f84bSDavid du Colombier 		break;
14179ef1f84bSDavid du Colombier 
14189ef1f84bSDavid du Colombier 	case Atodir:
14199ef1f84bSDavid du Colombier 		/*
14209ef1f84bSDavid du Colombier 		 * Directories (e.g. for cd) are left before the mount point,
14219ef1f84bSDavid du Colombier 		 * so one may mount on / or . and see the effect.
14229ef1f84bSDavid du Colombier 		 */
14239ef1f84bSDavid du Colombier 		if(!(c->qid.type & QTDIR))
14249ef1f84bSDavid du Colombier 			error(Enotdir);
14259ef1f84bSDavid du Colombier 		break;
14269ef1f84bSDavid du Colombier 
14279ef1f84bSDavid du Colombier 	case Amount:
14289ef1f84bSDavid du Colombier 		/*
14299ef1f84bSDavid du Colombier 		 * When mounting on an already mounted upon directory,
14309ef1f84bSDavid du Colombier 		 * one wants subsequent mounts to be attached to the
14319ef1f84bSDavid du Colombier 		 * original directory, not the replacement.  Don't domount.
14329ef1f84bSDavid du Colombier 		 */
14339ef1f84bSDavid du Colombier 		break;
14349ef1f84bSDavid du Colombier 
14359ef1f84bSDavid du Colombier 	case Acreate:
14369ef1f84bSDavid du Colombier 		/*
14379ef1f84bSDavid du Colombier 		 * We've already walked all but the last element.
14389ef1f84bSDavid du Colombier 		 * If the last exists, try to open it OTRUNC.
14399ef1f84bSDavid du Colombier 		 * If omode&OEXCL is set, just give up.
14409ef1f84bSDavid du Colombier 		 */
14419ef1f84bSDavid du Colombier 		e.nelems++;
14429ef1f84bSDavid du Colombier 		e.nerror++;
14439ef1f84bSDavid du Colombier 		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
14449ef1f84bSDavid du Colombier 			if(omode&OEXCL)
14459ef1f84bSDavid du Colombier 				error(Eexist);
14469ef1f84bSDavid du Colombier 			omode |= OTRUNC;
14479ef1f84bSDavid du Colombier 			goto Open;
14489ef1f84bSDavid du Colombier 		}
14499ef1f84bSDavid du Colombier 
14509ef1f84bSDavid du Colombier 		/*
14519ef1f84bSDavid du Colombier 		 * The semantics of the create(2) system call are that if the
14529ef1f84bSDavid du Colombier 		 * file exists and can be written, it is to be opened with truncation.
14539ef1f84bSDavid du Colombier 		 * On the other hand, the create(5) message fails if the file exists.
14549ef1f84bSDavid du Colombier 		 * If we get two create(2) calls happening simultaneously,
14559ef1f84bSDavid du Colombier 		 * they might both get here and send create(5) messages, but only
14569ef1f84bSDavid du Colombier 		 * one of the messages will succeed.  To provide the expected create(2)
14579ef1f84bSDavid du Colombier 		 * semantics, the call with the failed message needs to try the above
14589ef1f84bSDavid du Colombier 		 * walk again, opening for truncation.  This correctly solves the
14599ef1f84bSDavid du Colombier 		 * create/create race, in the sense that any observable outcome can
14609ef1f84bSDavid du Colombier 		 * be explained as one happening before the other.
14619ef1f84bSDavid du Colombier 		 * The create/create race is quite common.  For example, it happens
14629ef1f84bSDavid du Colombier 		 * when two rc subshells simultaneously update the same
14639ef1f84bSDavid du Colombier 		 * environment variable.
14649ef1f84bSDavid du Colombier 		 *
14659ef1f84bSDavid du Colombier 		 * The implementation still admits a create/create/remove race:
14669ef1f84bSDavid du Colombier 		 * (A) walk to file, fails
14679ef1f84bSDavid du Colombier 		 * (B) walk to file, fails
14689ef1f84bSDavid du Colombier 		 * (A) create file, succeeds, returns
14699ef1f84bSDavid du Colombier 		 * (B) create file, fails
14709ef1f84bSDavid du Colombier 		 * (A) remove file, succeeds, returns
14719ef1f84bSDavid du Colombier 		 * (B) walk to file, return failure.
14729ef1f84bSDavid du Colombier 		 *
14739ef1f84bSDavid du Colombier 		 * This is hardly as common as the create/create race, and is really
14749ef1f84bSDavid du Colombier 		 * not too much worse than what might happen if (B) got a hold of a
14759ef1f84bSDavid du Colombier 		 * file descriptor and then the file was removed -- either way (B) can't do
14769ef1f84bSDavid du Colombier 		 * anything with the result of the create call.  So we don't care about this race.
14779ef1f84bSDavid du Colombier 		 *
14789ef1f84bSDavid du Colombier 		 * Applications that care about more fine-grained decision of the races
14799ef1f84bSDavid du Colombier 		 * can use the OEXCL flag to get at the underlying create(5) semantics;
14809ef1f84bSDavid du Colombier 		 * by default we provide the common case.
14819ef1f84bSDavid du Colombier 		 *
14829ef1f84bSDavid du Colombier 		 * We need to stay behind the mount point in case we
14839ef1f84bSDavid du Colombier 		 * need to do the first walk again (should the create fail).
14849ef1f84bSDavid du Colombier 		 *
14859ef1f84bSDavid du Colombier 		 * We also need to cross the mount point and find the directory
14869ef1f84bSDavid du Colombier 		 * in the union in which we should be creating.
14879ef1f84bSDavid du Colombier 		 *
14889ef1f84bSDavid du Colombier 		 * The channel staying behind is c, the one moving forward is cnew.
14899ef1f84bSDavid du Colombier 		 */
14909ef1f84bSDavid du Colombier 		mh = nil;
14919ef1f84bSDavid du Colombier 		cnew = nil;		/* is this assignment necessary? */
14929ef1f84bSDavid du Colombier 		if(!waserror()){	/* try create */
14939ef1f84bSDavid du Colombier 			if(!nomount && findmount(&cnew, &mh, c->dev->dc, c->devno, c->qid))
14949ef1f84bSDavid du Colombier 				cnew = createdir(cnew, mh);
14959ef1f84bSDavid du Colombier 			else{
14969ef1f84bSDavid du Colombier 				cnew = c;
14979ef1f84bSDavid du Colombier 				incref(cnew);
14989ef1f84bSDavid du Colombier 			}
14999ef1f84bSDavid du Colombier 
15009ef1f84bSDavid du Colombier 			/*
15019ef1f84bSDavid du Colombier 			 * We need our own copy of the Chan because we're
15029ef1f84bSDavid du Colombier 			 * about to send a create, which will move it.  Once we have
15039ef1f84bSDavid du Colombier 			 * our own copy, we can fix the name, which might be wrong
15049ef1f84bSDavid du Colombier 			 * if findmount gave us a new Chan.
15059ef1f84bSDavid du Colombier 			 */
15069ef1f84bSDavid du Colombier 			cnew = cunique(cnew);
15079ef1f84bSDavid du Colombier 			pathclose(cnew->path);
15089ef1f84bSDavid du Colombier 			cnew->path = c->path;
15099ef1f84bSDavid du Colombier 			incref(cnew->path);
15109ef1f84bSDavid du Colombier 
15119ef1f84bSDavid du Colombier //create:						//XDYNX
15129ef1f84bSDavid du Colombier // like open regarding read/write?
15139ef1f84bSDavid du Colombier 
15149ef1f84bSDavid du Colombier 			cnew->dev->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
15159ef1f84bSDavid du Colombier 			poperror();
15169ef1f84bSDavid du Colombier 			if(omode & OCEXEC)
15179ef1f84bSDavid du Colombier 				cnew->flag |= CCEXEC;
15189ef1f84bSDavid du Colombier 			if(omode & ORCLOSE)
15199ef1f84bSDavid du Colombier 				cnew->flag |= CRCLOSE;
15209ef1f84bSDavid du Colombier 			if(mh)
15219ef1f84bSDavid du Colombier 				putmhead(mh);
15229ef1f84bSDavid du Colombier 			cclose(c);
15239ef1f84bSDavid du Colombier 			c = cnew;
15249ef1f84bSDavid du Colombier 			c->path = addelem(c->path, e.elems[e.nelems-1], nil);
15259ef1f84bSDavid du Colombier 			break;
15269ef1f84bSDavid du Colombier 		}
15279ef1f84bSDavid du Colombier 		/* create failed */
15289ef1f84bSDavid du Colombier 		cclose(cnew);
15299ef1f84bSDavid du Colombier 		if(mh)
15309ef1f84bSDavid du Colombier 			putmhead(mh);
15319ef1f84bSDavid du Colombier 		if(omode & OEXCL)
15329ef1f84bSDavid du Colombier 			nexterror();
15339ef1f84bSDavid du Colombier 		/* save error */
15349ef1f84bSDavid du Colombier 		createerr = up->errstr;
15359ef1f84bSDavid du Colombier 		up->errstr = tmperrbuf;
15369ef1f84bSDavid du Colombier 		/* note: we depend that walk does not error */
15379ef1f84bSDavid du Colombier 		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
15389ef1f84bSDavid du Colombier 			up->errstr = createerr;
15399ef1f84bSDavid du Colombier 			error(createerr);	/* report true error */
15409ef1f84bSDavid du Colombier 		}
15419ef1f84bSDavid du Colombier 		up->errstr = createerr;
15429ef1f84bSDavid du Colombier 		omode |= OTRUNC;
15439ef1f84bSDavid du Colombier 		goto Open;
15449ef1f84bSDavid du Colombier 
15459ef1f84bSDavid du Colombier 	default:
15469ef1f84bSDavid du Colombier 		panic("unknown namec access %d\n", amode);
15479ef1f84bSDavid du Colombier 	}
15489ef1f84bSDavid du Colombier 
15499ef1f84bSDavid du Colombier 	/* place final element in genbuf for e.g. exec */
15509ef1f84bSDavid du Colombier 	if(e.nelems > 0)
15519ef1f84bSDavid du Colombier 		kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
15529ef1f84bSDavid du Colombier 	else
15539ef1f84bSDavid du Colombier 		kstrcpy(up->genbuf, ".", sizeof up->genbuf);
15549ef1f84bSDavid du Colombier 	free(e.name);
15559ef1f84bSDavid du Colombier 	free(e.elems);
15569ef1f84bSDavid du Colombier 	free(e.off);
15579ef1f84bSDavid du Colombier 	poperror();	/* e c */
15589ef1f84bSDavid du Colombier 	free(aname);
15599ef1f84bSDavid du Colombier 	poperror();	/* aname */
15609ef1f84bSDavid du Colombier 
15619ef1f84bSDavid du Colombier 	return c;
15629ef1f84bSDavid du Colombier }
15639ef1f84bSDavid du Colombier 
15649ef1f84bSDavid du Colombier /*
15659ef1f84bSDavid du Colombier  * name is valid. skip leading / and ./ as much as possible
15669ef1f84bSDavid du Colombier  */
15679ef1f84bSDavid du Colombier char*
skipslash(char * name)15689ef1f84bSDavid du Colombier skipslash(char *name)
15699ef1f84bSDavid du Colombier {
15709ef1f84bSDavid du Colombier 	while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))
15719ef1f84bSDavid du Colombier 		name++;
15729ef1f84bSDavid du Colombier 	return name;
15739ef1f84bSDavid du Colombier }
15749ef1f84bSDavid du Colombier 
15759ef1f84bSDavid du Colombier char isfrog[256]={
15769ef1f84bSDavid du Colombier 	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
15779ef1f84bSDavid du Colombier 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
15789ef1f84bSDavid du Colombier 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
15799ef1f84bSDavid du Colombier 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
15809ef1f84bSDavid du Colombier 	['/']	1,
15819ef1f84bSDavid du Colombier 	[0x7f]	1,
15829ef1f84bSDavid du Colombier };
15839ef1f84bSDavid du Colombier 
15849ef1f84bSDavid du Colombier /*
15859ef1f84bSDavid du Colombier  * Check that the name
15869ef1f84bSDavid du Colombier  *  a) is in valid memory.
15879ef1f84bSDavid du Colombier  *  b) is shorter than 2^16 bytes, so it can fit in a 9P string field.
15889ef1f84bSDavid du Colombier  *  c) contains no frogs.
15899ef1f84bSDavid du Colombier  * The first byte is known to be addressable by the requester, so the
15909ef1f84bSDavid du Colombier  * routine works for kernel and user memory both.
15919ef1f84bSDavid du Colombier  * The parameter slashok flags whether a slash character is an error
15929ef1f84bSDavid du Colombier  * or a valid character.
15939ef1f84bSDavid du Colombier  *
15949ef1f84bSDavid du Colombier  * The parameter dup flags whether the string should be copied
15959ef1f84bSDavid du Colombier  * out of user space before being scanned the second time.
15969ef1f84bSDavid du Colombier  * (Otherwise a malicious thread could remove the NUL, causing us
15979ef1f84bSDavid du Colombier  * to access unchecked addresses.)
15989ef1f84bSDavid du Colombier  */
15999ef1f84bSDavid du Colombier static char*
validname0(char * aname,int slashok,int dup,uintptr pc)16009ef1f84bSDavid du Colombier validname0(char *aname, int slashok, int dup, uintptr pc)
16019ef1f84bSDavid du Colombier {
16029ef1f84bSDavid du Colombier 	char *ename, *name, *s;
16039ef1f84bSDavid du Colombier 	int c, n;
16049ef1f84bSDavid du Colombier 	Rune r;
16059ef1f84bSDavid du Colombier 
16069ef1f84bSDavid du Colombier 	name = aname;
1607*fe56f827SDavid du Colombier 	if(!iskaddr(name)){
16089ef1f84bSDavid du Colombier 		if(!dup)
16099ef1f84bSDavid du Colombier 			print("warning: validname* called from %#p with user pointer", pc);
16109ef1f84bSDavid du Colombier 		ename = vmemchr(name, 0, (1<<16));
16119ef1f84bSDavid du Colombier 	}else
16129ef1f84bSDavid du Colombier 		ename = memchr(name, 0, (1<<16));
16139ef1f84bSDavid du Colombier 
16149ef1f84bSDavid du Colombier 	if(ename==nil || ename-name>=(1<<16))
16159ef1f84bSDavid du Colombier 		error("name too long");
16169ef1f84bSDavid du Colombier 
16179ef1f84bSDavid du Colombier 	s = nil;
16189ef1f84bSDavid du Colombier 	if(dup){
16199ef1f84bSDavid du Colombier 		n = ename-name;
16209ef1f84bSDavid du Colombier 		s = smalloc(n+1);
16219ef1f84bSDavid du Colombier 		memmove(s, name, n);
16229ef1f84bSDavid du Colombier 		s[n] = 0;
16239ef1f84bSDavid du Colombier 		aname = s;
16249ef1f84bSDavid du Colombier 		name = s;
16259ef1f84bSDavid du Colombier 		setmalloctag(s, pc);
16269ef1f84bSDavid du Colombier 	}
16279ef1f84bSDavid du Colombier 
16289ef1f84bSDavid du Colombier 	while(*name){
16299ef1f84bSDavid du Colombier 		/* all characters above '~' are ok */
16309ef1f84bSDavid du Colombier 		c = *(uchar*)name;
16319ef1f84bSDavid du Colombier 		if(c >= Runeself)
16329ef1f84bSDavid du Colombier 			name += chartorune(&r, name);
16339ef1f84bSDavid du Colombier 		else{
16349ef1f84bSDavid du Colombier 			if(isfrog[c])
16359ef1f84bSDavid du Colombier 				if(!slashok || c!='/'){
16369ef1f84bSDavid du Colombier 					snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
16379ef1f84bSDavid du Colombier 					free(s);
16389ef1f84bSDavid du Colombier 					error(up->genbuf);
16399ef1f84bSDavid du Colombier 			}
16409ef1f84bSDavid du Colombier 			name++;
16419ef1f84bSDavid du Colombier 		}
16429ef1f84bSDavid du Colombier 	}
16439ef1f84bSDavid du Colombier 	return s;
16449ef1f84bSDavid du Colombier }
16459ef1f84bSDavid du Colombier 
16469ef1f84bSDavid du Colombier void
validname(char * aname,int slashok)16479ef1f84bSDavid du Colombier validname(char *aname, int slashok)
16489ef1f84bSDavid du Colombier {
16499ef1f84bSDavid du Colombier 	validname0(aname, slashok, 0, getcallerpc(&aname));
16509ef1f84bSDavid du Colombier }
16519ef1f84bSDavid du Colombier 
16529ef1f84bSDavid du Colombier char*
validnamedup(char * aname,int slashok)16539ef1f84bSDavid du Colombier validnamedup(char *aname, int slashok)
16549ef1f84bSDavid du Colombier {
16559ef1f84bSDavid du Colombier 	return validname0(aname, slashok, 1, getcallerpc(&aname));
16569ef1f84bSDavid du Colombier }
16579ef1f84bSDavid du Colombier 
16589ef1f84bSDavid du Colombier void
isdir(Chan * c)16599ef1f84bSDavid du Colombier isdir(Chan *c)
16609ef1f84bSDavid du Colombier {
16619ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
16629ef1f84bSDavid du Colombier 		return;
16639ef1f84bSDavid du Colombier 	error(Enotdir);
16649ef1f84bSDavid du Colombier }
16659ef1f84bSDavid du Colombier 
16669ef1f84bSDavid du Colombier /*
16679ef1f84bSDavid du Colombier  * This is necessary because there are many
16689ef1f84bSDavid du Colombier  * pointers to the top of a given mount list:
16699ef1f84bSDavid du Colombier  *
16709ef1f84bSDavid du Colombier  *	- the mhead in the namespace hash table
16719ef1f84bSDavid du Colombier  *	- the mhead in chans returned from findmount:
16729ef1f84bSDavid du Colombier  *	  used in namec and then by unionread.
16739ef1f84bSDavid du Colombier  *	- the mhead in chans returned from createdir:
16749ef1f84bSDavid du Colombier  *	  used in the open/create race protect, which is gone.
16759ef1f84bSDavid du Colombier  *
16769ef1f84bSDavid du Colombier  * The RWlock in the Mhead protects the mount list it contains.
16779ef1f84bSDavid du Colombier  * The mount list is deleted when we cunmount.
16789ef1f84bSDavid du Colombier  * The RWlock ensures that nothing is using the mount list at that time.
16799ef1f84bSDavid du Colombier  *
16809ef1f84bSDavid du Colombier  * It is okay to replace c->mh with whatever you want as
16819ef1f84bSDavid du Colombier  * long as you are sure you have a unique reference to it.
16829ef1f84bSDavid du Colombier  *
16839ef1f84bSDavid du Colombier  * This comment might belong somewhere else.
16849ef1f84bSDavid du Colombier  */
16859ef1f84bSDavid du Colombier void
putmhead(Mhead * mh)16869ef1f84bSDavid du Colombier putmhead(Mhead *mh)
16879ef1f84bSDavid du Colombier {
16889ef1f84bSDavid du Colombier 	if(mh && decref(mh) == 0){
16899ef1f84bSDavid du Colombier 		mh->mount = (Mount*)0xCafeBeef;
16909ef1f84bSDavid du Colombier 		free(mh);
16919ef1f84bSDavid du Colombier 	}
16929ef1f84bSDavid du Colombier }
16939ef1f84bSDavid du Colombier 
1694