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