1*8ccd4a63SDavid du Colombier #include "u.h" 2*8ccd4a63SDavid du Colombier #include "lib.h" 3*8ccd4a63SDavid du Colombier #include "dat.h" 4*8ccd4a63SDavid du Colombier #include "fns.h" 5*8ccd4a63SDavid du Colombier #include "error.h" 6*8ccd4a63SDavid du Colombier 7*8ccd4a63SDavid du Colombier int chandebug=0; /* toggled by sysr1 */ 8*8ccd4a63SDavid du Colombier QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */ 9*8ccd4a63SDavid du Colombier 10*8ccd4a63SDavid du Colombier int domount(Chan**, Mhead**); 11*8ccd4a63SDavid du Colombier 12*8ccd4a63SDavid du Colombier void 13*8ccd4a63SDavid du Colombier dumpmount(void) /* DEBUGGING */ 14*8ccd4a63SDavid du Colombier { 15*8ccd4a63SDavid du Colombier Pgrp *pg; 16*8ccd4a63SDavid du Colombier Mount *t; 17*8ccd4a63SDavid du Colombier Mhead **h, **he, *f; 18*8ccd4a63SDavid du Colombier 19*8ccd4a63SDavid du Colombier if(up == nil){ 20*8ccd4a63SDavid du Colombier print("no process for dumpmount\n"); 21*8ccd4a63SDavid du Colombier return; 22*8ccd4a63SDavid du Colombier } 23*8ccd4a63SDavid du Colombier pg = up->pgrp; 24*8ccd4a63SDavid du Colombier if(pg == nil){ 25*8ccd4a63SDavid du Colombier print("no pgrp for dumpmount\n"); 26*8ccd4a63SDavid du Colombier return; 27*8ccd4a63SDavid du Colombier } 28*8ccd4a63SDavid du Colombier rlock(&pg->ns); 29*8ccd4a63SDavid du Colombier if(waserror()) { 30*8ccd4a63SDavid du Colombier runlock(&pg->ns); 31*8ccd4a63SDavid du Colombier nexterror(); 32*8ccd4a63SDavid du Colombier } 33*8ccd4a63SDavid du Colombier 34*8ccd4a63SDavid du Colombier he = &pg->mnthash[MNTHASH]; 35*8ccd4a63SDavid du Colombier for(h = pg->mnthash; h < he; h++) { 36*8ccd4a63SDavid du Colombier for(f = *h; f; f = f->hash) { 37*8ccd4a63SDavid du Colombier print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f, 38*8ccd4a63SDavid du Colombier f->from->name->s, f->from->qid.path, 39*8ccd4a63SDavid du Colombier f->from->qid.vers, devtab[f->from->type]->dc, 40*8ccd4a63SDavid du Colombier f->from->dev); 41*8ccd4a63SDavid du Colombier for(t = f->mount; t; t = t->next) 42*8ccd4a63SDavid du Colombier print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev); 43*8ccd4a63SDavid du Colombier } 44*8ccd4a63SDavid du Colombier } 45*8ccd4a63SDavid du Colombier poperror(); 46*8ccd4a63SDavid du Colombier runlock(&pg->ns); 47*8ccd4a63SDavid du Colombier } 48*8ccd4a63SDavid du Colombier 49*8ccd4a63SDavid du Colombier 50*8ccd4a63SDavid du Colombier char* 51*8ccd4a63SDavid du Colombier c2name(Chan *c) /* DEBUGGING */ 52*8ccd4a63SDavid du Colombier { 53*8ccd4a63SDavid du Colombier if(c == nil) 54*8ccd4a63SDavid du Colombier return "<nil chan>"; 55*8ccd4a63SDavid du Colombier if(c->name == nil) 56*8ccd4a63SDavid du Colombier return "<nil name>"; 57*8ccd4a63SDavid du Colombier if(c->name->s == nil) 58*8ccd4a63SDavid du Colombier return "<nil name.s>"; 59*8ccd4a63SDavid du Colombier return c->name->s; 60*8ccd4a63SDavid du Colombier } 61*8ccd4a63SDavid du Colombier 62*8ccd4a63SDavid du Colombier enum 63*8ccd4a63SDavid du Colombier { 64*8ccd4a63SDavid du Colombier CNAMESLOP = 20 65*8ccd4a63SDavid du Colombier }; 66*8ccd4a63SDavid du Colombier 67*8ccd4a63SDavid du Colombier struct 68*8ccd4a63SDavid du Colombier { 69*8ccd4a63SDavid du Colombier Lock lk; 70*8ccd4a63SDavid du Colombier int fid; 71*8ccd4a63SDavid du Colombier Chan *free; 72*8ccd4a63SDavid du Colombier Chan *list; 73*8ccd4a63SDavid du Colombier }chanalloc; 74*8ccd4a63SDavid du Colombier 75*8ccd4a63SDavid du Colombier typedef struct Elemlist Elemlist; 76*8ccd4a63SDavid du Colombier 77*8ccd4a63SDavid du Colombier struct Elemlist 78*8ccd4a63SDavid du Colombier { 79*8ccd4a63SDavid du Colombier char *name; /* copy of name, so '/' can be overwritten */ 80*8ccd4a63SDavid du Colombier int nelems; 81*8ccd4a63SDavid du Colombier char **elems; 82*8ccd4a63SDavid du Colombier int *off; 83*8ccd4a63SDavid du Colombier int mustbedir; 84*8ccd4a63SDavid du Colombier }; 85*8ccd4a63SDavid du Colombier 86*8ccd4a63SDavid du Colombier #define SEP(c) ((c) == 0 || (c) == '/') 87*8ccd4a63SDavid du Colombier void cleancname(Cname*); 88*8ccd4a63SDavid du Colombier 89*8ccd4a63SDavid du Colombier int 90*8ccd4a63SDavid du Colombier isdotdot(char *p) 91*8ccd4a63SDavid du Colombier { 92*8ccd4a63SDavid du Colombier return p[0]=='.' && p[1]=='.' && p[2]=='\0'; 93*8ccd4a63SDavid du Colombier } 94*8ccd4a63SDavid du Colombier 95*8ccd4a63SDavid du Colombier int 96*8ccd4a63SDavid du Colombier incref(Ref *r) 97*8ccd4a63SDavid du Colombier { 98*8ccd4a63SDavid du Colombier int x; 99*8ccd4a63SDavid du Colombier 100*8ccd4a63SDavid du Colombier lock(&r->lk); 101*8ccd4a63SDavid du Colombier x = ++r->ref; 102*8ccd4a63SDavid du Colombier unlock(&r->lk); 103*8ccd4a63SDavid du Colombier return x; 104*8ccd4a63SDavid du Colombier } 105*8ccd4a63SDavid du Colombier 106*8ccd4a63SDavid du Colombier int 107*8ccd4a63SDavid du Colombier decref(Ref *r) 108*8ccd4a63SDavid du Colombier { 109*8ccd4a63SDavid du Colombier int x; 110*8ccd4a63SDavid du Colombier 111*8ccd4a63SDavid du Colombier lock(&r->lk); 112*8ccd4a63SDavid du Colombier x = --r->ref; 113*8ccd4a63SDavid du Colombier unlock(&r->lk); 114*8ccd4a63SDavid du Colombier if(x < 0) 115*8ccd4a63SDavid du Colombier panic("decref, pc=0x%lux", getcallerpc(&r)); 116*8ccd4a63SDavid du Colombier 117*8ccd4a63SDavid du Colombier return x; 118*8ccd4a63SDavid du Colombier } 119*8ccd4a63SDavid du Colombier 120*8ccd4a63SDavid du Colombier /* 121*8ccd4a63SDavid du Colombier * Rather than strncpy, which zeros the rest of the buffer, kstrcpy 122*8ccd4a63SDavid du Colombier * truncates if necessary, always zero terminates, does not zero fill, 123*8ccd4a63SDavid du Colombier * and puts ... at the end of the string if it's too long. Usually used to 124*8ccd4a63SDavid du Colombier * save a string in up->genbuf; 125*8ccd4a63SDavid du Colombier */ 126*8ccd4a63SDavid du Colombier void 127*8ccd4a63SDavid du Colombier kstrcpy(char *s, char *t, int ns) 128*8ccd4a63SDavid du Colombier { 129*8ccd4a63SDavid du Colombier int nt; 130*8ccd4a63SDavid du Colombier 131*8ccd4a63SDavid du Colombier nt = strlen(t); 132*8ccd4a63SDavid du Colombier if(nt+1 <= ns){ 133*8ccd4a63SDavid du Colombier memmove(s, t, nt+1); 134*8ccd4a63SDavid du Colombier return; 135*8ccd4a63SDavid du Colombier } 136*8ccd4a63SDavid du Colombier /* too long */ 137*8ccd4a63SDavid du Colombier if(ns < 4){ 138*8ccd4a63SDavid du Colombier /* but very short! */ 139*8ccd4a63SDavid du Colombier strncpy(s, t, ns); 140*8ccd4a63SDavid du Colombier return; 141*8ccd4a63SDavid du Colombier } 142*8ccd4a63SDavid du Colombier /* truncate with ... at character boundary (very rare case) */ 143*8ccd4a63SDavid du Colombier memmove(s, t, ns-4); 144*8ccd4a63SDavid du Colombier ns -= 4; 145*8ccd4a63SDavid du Colombier s[ns] = '\0'; 146*8ccd4a63SDavid du Colombier /* look for first byte of UTF-8 sequence by skipping continuation bytes */ 147*8ccd4a63SDavid du Colombier while(ns>0 && (s[--ns]&0xC0)==0x80) 148*8ccd4a63SDavid du Colombier ; 149*8ccd4a63SDavid du Colombier strcpy(s+ns, "..."); 150*8ccd4a63SDavid du Colombier } 151*8ccd4a63SDavid du Colombier 152*8ccd4a63SDavid du Colombier int 153*8ccd4a63SDavid du Colombier emptystr(char *s) 154*8ccd4a63SDavid du Colombier { 155*8ccd4a63SDavid du Colombier if(s == nil) 156*8ccd4a63SDavid du Colombier return 1; 157*8ccd4a63SDavid du Colombier if(s[0] == '\0') 158*8ccd4a63SDavid du Colombier return 1; 159*8ccd4a63SDavid du Colombier return 0; 160*8ccd4a63SDavid du Colombier } 161*8ccd4a63SDavid du Colombier 162*8ccd4a63SDavid du Colombier /* 163*8ccd4a63SDavid du Colombier * Atomically replace *p with copy of s 164*8ccd4a63SDavid du Colombier */ 165*8ccd4a63SDavid du Colombier void 166*8ccd4a63SDavid du Colombier kstrdup(char **p, char *s) 167*8ccd4a63SDavid du Colombier { 168*8ccd4a63SDavid du Colombier int n; 169*8ccd4a63SDavid du Colombier char *t, *prev; 170*8ccd4a63SDavid du Colombier 171*8ccd4a63SDavid du Colombier n = strlen(s)+1; 172*8ccd4a63SDavid du Colombier /* if it's a user, we can wait for memory; if not, something's very wrong */ 173*8ccd4a63SDavid du Colombier if(up){ 174*8ccd4a63SDavid du Colombier t = smalloc(n); 175*8ccd4a63SDavid du Colombier setmalloctag(t, getcallerpc(&p)); 176*8ccd4a63SDavid du Colombier }else{ 177*8ccd4a63SDavid du Colombier t = malloc(n); 178*8ccd4a63SDavid du Colombier if(t == nil) 179*8ccd4a63SDavid du Colombier panic("kstrdup: no memory"); 180*8ccd4a63SDavid du Colombier } 181*8ccd4a63SDavid du Colombier memmove(t, s, n); 182*8ccd4a63SDavid du Colombier prev = *p; 183*8ccd4a63SDavid du Colombier *p = t; 184*8ccd4a63SDavid du Colombier free(prev); 185*8ccd4a63SDavid du Colombier } 186*8ccd4a63SDavid du Colombier 187*8ccd4a63SDavid du Colombier void 188*8ccd4a63SDavid du Colombier chandevreset(void) 189*8ccd4a63SDavid du Colombier { 190*8ccd4a63SDavid du Colombier int i; 191*8ccd4a63SDavid du Colombier 192*8ccd4a63SDavid du Colombier for(i=0; devtab[i] != nil; i++) 193*8ccd4a63SDavid du Colombier devtab[i]->reset(); 194*8ccd4a63SDavid du Colombier } 195*8ccd4a63SDavid du Colombier 196*8ccd4a63SDavid du Colombier void 197*8ccd4a63SDavid du Colombier chandevinit(void) 198*8ccd4a63SDavid du Colombier { 199*8ccd4a63SDavid du Colombier int i; 200*8ccd4a63SDavid du Colombier 201*8ccd4a63SDavid du Colombier for(i=0; devtab[i] != nil; i++) 202*8ccd4a63SDavid du Colombier devtab[i]->init(); 203*8ccd4a63SDavid du Colombier } 204*8ccd4a63SDavid du Colombier 205*8ccd4a63SDavid du Colombier void 206*8ccd4a63SDavid du Colombier chandevshutdown(void) 207*8ccd4a63SDavid du Colombier { 208*8ccd4a63SDavid du Colombier int i; 209*8ccd4a63SDavid du Colombier 210*8ccd4a63SDavid du Colombier /* shutdown in reverse order */ 211*8ccd4a63SDavid du Colombier for(i=0; devtab[i] != nil; i++) 212*8ccd4a63SDavid du Colombier ; 213*8ccd4a63SDavid du Colombier for(i--; i >= 0; i--) 214*8ccd4a63SDavid du Colombier devtab[i]->shutdown(); 215*8ccd4a63SDavid du Colombier } 216*8ccd4a63SDavid du Colombier 217*8ccd4a63SDavid du Colombier Chan* 218*8ccd4a63SDavid du Colombier newchan(void) 219*8ccd4a63SDavid du Colombier { 220*8ccd4a63SDavid du Colombier Chan *c; 221*8ccd4a63SDavid du Colombier 222*8ccd4a63SDavid du Colombier lock(&chanalloc.lk); 223*8ccd4a63SDavid du Colombier c = chanalloc.free; 224*8ccd4a63SDavid du Colombier if(c != 0) 225*8ccd4a63SDavid du Colombier chanalloc.free = c->next; 226*8ccd4a63SDavid du Colombier unlock(&chanalloc.lk); 227*8ccd4a63SDavid du Colombier 228*8ccd4a63SDavid du Colombier if(c == nil) { 229*8ccd4a63SDavid du Colombier c = smalloc(sizeof(Chan)); 230*8ccd4a63SDavid du Colombier lock(&chanalloc.lk); 231*8ccd4a63SDavid du Colombier c->fid = ++chanalloc.fid; 232*8ccd4a63SDavid du Colombier c->link = chanalloc.list; 233*8ccd4a63SDavid du Colombier chanalloc.list = c; 234*8ccd4a63SDavid du Colombier unlock(&chanalloc.lk); 235*8ccd4a63SDavid du Colombier } 236*8ccd4a63SDavid du Colombier 237*8ccd4a63SDavid du Colombier /* if you get an error before associating with a dev, 238*8ccd4a63SDavid du Colombier close calls rootclose, a nop */ 239*8ccd4a63SDavid du Colombier c->type = 0; 240*8ccd4a63SDavid du Colombier c->flag = 0; 241*8ccd4a63SDavid du Colombier c->ref.ref = 1; 242*8ccd4a63SDavid du Colombier c->dev = 0; 243*8ccd4a63SDavid du Colombier c->offset = 0; 244*8ccd4a63SDavid du Colombier c->iounit = 0; 245*8ccd4a63SDavid du Colombier c->umh = 0; 246*8ccd4a63SDavid du Colombier c->uri = 0; 247*8ccd4a63SDavid du Colombier c->dri = 0; 248*8ccd4a63SDavid du Colombier c->aux = 0; 249*8ccd4a63SDavid du Colombier c->mchan = 0; 250*8ccd4a63SDavid du Colombier c->mcp = 0; 251*8ccd4a63SDavid du Colombier c->mux = 0; 252*8ccd4a63SDavid du Colombier memset(&c->mqid, 0, sizeof(c->mqid)); 253*8ccd4a63SDavid du Colombier c->name = 0; 254*8ccd4a63SDavid du Colombier return c; 255*8ccd4a63SDavid du Colombier } 256*8ccd4a63SDavid du Colombier 257*8ccd4a63SDavid du Colombier static Ref ncname; 258*8ccd4a63SDavid du Colombier 259*8ccd4a63SDavid du Colombier Cname* 260*8ccd4a63SDavid du Colombier newcname(char *s) 261*8ccd4a63SDavid du Colombier { 262*8ccd4a63SDavid du Colombier Cname *n; 263*8ccd4a63SDavid du Colombier int i; 264*8ccd4a63SDavid du Colombier 265*8ccd4a63SDavid du Colombier n = smalloc(sizeof(Cname)); 266*8ccd4a63SDavid du Colombier i = strlen(s); 267*8ccd4a63SDavid du Colombier n->len = i; 268*8ccd4a63SDavid du Colombier n->alen = i+CNAMESLOP; 269*8ccd4a63SDavid du Colombier n->s = smalloc(n->alen); 270*8ccd4a63SDavid du Colombier memmove(n->s, s, i+1); 271*8ccd4a63SDavid du Colombier n->ref.ref = 1; 272*8ccd4a63SDavid du Colombier incref(&ncname); 273*8ccd4a63SDavid du Colombier return n; 274*8ccd4a63SDavid du Colombier } 275*8ccd4a63SDavid du Colombier 276*8ccd4a63SDavid du Colombier void 277*8ccd4a63SDavid du Colombier cnameclose(Cname *n) 278*8ccd4a63SDavid du Colombier { 279*8ccd4a63SDavid du Colombier if(n == nil) 280*8ccd4a63SDavid du Colombier return; 281*8ccd4a63SDavid du Colombier if(decref(&n->ref)) 282*8ccd4a63SDavid du Colombier return; 283*8ccd4a63SDavid du Colombier decref(&ncname); 284*8ccd4a63SDavid du Colombier free(n->s); 285*8ccd4a63SDavid du Colombier free(n); 286*8ccd4a63SDavid du Colombier } 287*8ccd4a63SDavid du Colombier 288*8ccd4a63SDavid du Colombier Cname* 289*8ccd4a63SDavid du Colombier addelem(Cname *n, char *s) 290*8ccd4a63SDavid du Colombier { 291*8ccd4a63SDavid du Colombier int i, a; 292*8ccd4a63SDavid du Colombier char *t; 293*8ccd4a63SDavid du Colombier Cname *new; 294*8ccd4a63SDavid du Colombier 295*8ccd4a63SDavid du Colombier if(s[0]=='.' && s[1]=='\0') 296*8ccd4a63SDavid du Colombier return n; 297*8ccd4a63SDavid du Colombier 298*8ccd4a63SDavid du Colombier if(n->ref.ref > 1){ 299*8ccd4a63SDavid du Colombier /* copy on write */ 300*8ccd4a63SDavid du Colombier new = newcname(n->s); 301*8ccd4a63SDavid du Colombier cnameclose(n); 302*8ccd4a63SDavid du Colombier n = new; 303*8ccd4a63SDavid du Colombier } 304*8ccd4a63SDavid du Colombier 305*8ccd4a63SDavid du Colombier i = strlen(s); 306*8ccd4a63SDavid du Colombier if(n->len+1+i+1 > n->alen){ 307*8ccd4a63SDavid du Colombier a = n->len+1+i+1 + CNAMESLOP; 308*8ccd4a63SDavid du Colombier t = smalloc(a); 309*8ccd4a63SDavid du Colombier memmove(t, n->s, n->len+1); 310*8ccd4a63SDavid du Colombier free(n->s); 311*8ccd4a63SDavid du Colombier n->s = t; 312*8ccd4a63SDavid du Colombier n->alen = a; 313*8ccd4a63SDavid du Colombier } 314*8ccd4a63SDavid du Colombier if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */ 315*8ccd4a63SDavid du Colombier n->s[n->len++] = '/'; 316*8ccd4a63SDavid du Colombier memmove(n->s+n->len, s, i+1); 317*8ccd4a63SDavid du Colombier n->len += i; 318*8ccd4a63SDavid du Colombier if(isdotdot(s)) 319*8ccd4a63SDavid du Colombier cleancname(n); 320*8ccd4a63SDavid du Colombier return n; 321*8ccd4a63SDavid du Colombier } 322*8ccd4a63SDavid du Colombier 323*8ccd4a63SDavid du Colombier void 324*8ccd4a63SDavid du Colombier chanfree(Chan *c) 325*8ccd4a63SDavid du Colombier { 326*8ccd4a63SDavid du Colombier c->flag = CFREE; 327*8ccd4a63SDavid du Colombier 328*8ccd4a63SDavid du Colombier if(c->umh != nil){ 329*8ccd4a63SDavid du Colombier putmhead(c->umh); 330*8ccd4a63SDavid du Colombier c->umh = nil; 331*8ccd4a63SDavid du Colombier } 332*8ccd4a63SDavid du Colombier if(c->umc != nil){ 333*8ccd4a63SDavid du Colombier cclose(c->umc); 334*8ccd4a63SDavid du Colombier c->umc = nil; 335*8ccd4a63SDavid du Colombier } 336*8ccd4a63SDavid du Colombier if(c->mux != nil){ 337*8ccd4a63SDavid du Colombier muxclose(c->mux); 338*8ccd4a63SDavid du Colombier c->mux = nil; 339*8ccd4a63SDavid du Colombier } 340*8ccd4a63SDavid du Colombier if(c->mchan != nil){ 341*8ccd4a63SDavid du Colombier cclose(c->mchan); 342*8ccd4a63SDavid du Colombier c->mchan = nil; 343*8ccd4a63SDavid du Colombier } 344*8ccd4a63SDavid du Colombier 345*8ccd4a63SDavid du Colombier cnameclose(c->name); 346*8ccd4a63SDavid du Colombier 347*8ccd4a63SDavid du Colombier lock(&chanalloc.lk); 348*8ccd4a63SDavid du Colombier c->next = chanalloc.free; 349*8ccd4a63SDavid du Colombier chanalloc.free = c; 350*8ccd4a63SDavid du Colombier unlock(&chanalloc.lk); 351*8ccd4a63SDavid du Colombier } 352*8ccd4a63SDavid du Colombier 353*8ccd4a63SDavid du Colombier void 354*8ccd4a63SDavid du Colombier cclose(Chan *c) 355*8ccd4a63SDavid du Colombier { 356*8ccd4a63SDavid du Colombier if(c->flag&CFREE) 357*8ccd4a63SDavid du Colombier panic("cclose %lux", getcallerpc(&c)); 358*8ccd4a63SDavid du Colombier 359*8ccd4a63SDavid du Colombier if(decref(&c->ref)) 360*8ccd4a63SDavid du Colombier return; 361*8ccd4a63SDavid du Colombier 362*8ccd4a63SDavid du Colombier if(!waserror()){ 363*8ccd4a63SDavid du Colombier devtab[c->type]->close(c); 364*8ccd4a63SDavid du Colombier poperror(); 365*8ccd4a63SDavid du Colombier } 366*8ccd4a63SDavid du Colombier chanfree(c); 367*8ccd4a63SDavid du Colombier } 368*8ccd4a63SDavid du Colombier 369*8ccd4a63SDavid du Colombier /* 370*8ccd4a63SDavid du Colombier * Make sure we have the only copy of c. (Copy on write.) 371*8ccd4a63SDavid du Colombier */ 372*8ccd4a63SDavid du Colombier Chan* 373*8ccd4a63SDavid du Colombier cunique(Chan *c) 374*8ccd4a63SDavid du Colombier { 375*8ccd4a63SDavid du Colombier Chan *nc; 376*8ccd4a63SDavid du Colombier 377*8ccd4a63SDavid du Colombier if(c->ref.ref != 1) { 378*8ccd4a63SDavid du Colombier nc = cclone(c); 379*8ccd4a63SDavid du Colombier cclose(c); 380*8ccd4a63SDavid du Colombier c = nc; 381*8ccd4a63SDavid du Colombier } 382*8ccd4a63SDavid du Colombier 383*8ccd4a63SDavid du Colombier return c; 384*8ccd4a63SDavid du Colombier } 385*8ccd4a63SDavid du Colombier 386*8ccd4a63SDavid du Colombier int 387*8ccd4a63SDavid du Colombier eqqid(Qid a, Qid b) 388*8ccd4a63SDavid du Colombier { 389*8ccd4a63SDavid du Colombier return a.path==b.path && a.vers==b.vers; 390*8ccd4a63SDavid du Colombier } 391*8ccd4a63SDavid du Colombier 392*8ccd4a63SDavid du Colombier int 393*8ccd4a63SDavid du Colombier eqchan(Chan *a, Chan *b, int pathonly) 394*8ccd4a63SDavid du Colombier { 395*8ccd4a63SDavid du Colombier if(a->qid.path != b->qid.path) 396*8ccd4a63SDavid du Colombier return 0; 397*8ccd4a63SDavid du Colombier if(!pathonly && a->qid.vers!=b->qid.vers) 398*8ccd4a63SDavid du Colombier return 0; 399*8ccd4a63SDavid du Colombier if(a->type != b->type) 400*8ccd4a63SDavid du Colombier return 0; 401*8ccd4a63SDavid du Colombier if(a->dev != b->dev) 402*8ccd4a63SDavid du Colombier return 0; 403*8ccd4a63SDavid du Colombier return 1; 404*8ccd4a63SDavid du Colombier } 405*8ccd4a63SDavid du Colombier 406*8ccd4a63SDavid du Colombier int 407*8ccd4a63SDavid du Colombier eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly) 408*8ccd4a63SDavid du Colombier { 409*8ccd4a63SDavid du Colombier if(a->qid.path != qid.path) 410*8ccd4a63SDavid du Colombier return 0; 411*8ccd4a63SDavid du Colombier if(!pathonly && a->qid.vers!=qid.vers) 412*8ccd4a63SDavid du Colombier return 0; 413*8ccd4a63SDavid du Colombier if(a->type != type) 414*8ccd4a63SDavid du Colombier return 0; 415*8ccd4a63SDavid du Colombier if(a->dev != dev) 416*8ccd4a63SDavid du Colombier return 0; 417*8ccd4a63SDavid du Colombier return 1; 418*8ccd4a63SDavid du Colombier } 419*8ccd4a63SDavid du Colombier 420*8ccd4a63SDavid du Colombier Mhead* 421*8ccd4a63SDavid du Colombier newmhead(Chan *from) 422*8ccd4a63SDavid du Colombier { 423*8ccd4a63SDavid du Colombier Mhead *mh; 424*8ccd4a63SDavid du Colombier 425*8ccd4a63SDavid du Colombier mh = smalloc(sizeof(Mhead)); 426*8ccd4a63SDavid du Colombier mh->ref.ref = 1; 427*8ccd4a63SDavid du Colombier mh->from = from; 428*8ccd4a63SDavid du Colombier incref(&from->ref); 429*8ccd4a63SDavid du Colombier 430*8ccd4a63SDavid du Colombier /* 431*8ccd4a63SDavid du Colombier n = from->name->len; 432*8ccd4a63SDavid du Colombier if(n >= sizeof(mh->fromname)) 433*8ccd4a63SDavid du Colombier n = sizeof(mh->fromname)-1; 434*8ccd4a63SDavid du Colombier memmove(mh->fromname, from->name->s, n); 435*8ccd4a63SDavid du Colombier mh->fromname[n] = 0; 436*8ccd4a63SDavid du Colombier */ 437*8ccd4a63SDavid du Colombier return mh; 438*8ccd4a63SDavid du Colombier } 439*8ccd4a63SDavid du Colombier 440*8ccd4a63SDavid du Colombier int 441*8ccd4a63SDavid du Colombier cmount(Chan **newp, Chan *old, int flag, char *spec) 442*8ccd4a63SDavid du Colombier { 443*8ccd4a63SDavid du Colombier Pgrp *pg; 444*8ccd4a63SDavid du Colombier int order, flg; 445*8ccd4a63SDavid du Colombier Mhead *m, **l, *mh; 446*8ccd4a63SDavid du Colombier Mount *nm, *f, *um, **h; 447*8ccd4a63SDavid du Colombier Chan *new; 448*8ccd4a63SDavid du Colombier 449*8ccd4a63SDavid du Colombier if(QTDIR & (old->qid.type^(*newp)->qid.type)) 450*8ccd4a63SDavid du Colombier error(Emount); 451*8ccd4a63SDavid du Colombier 452*8ccd4a63SDavid du Colombier if(old->umh)print("cmount old extra umh\n"); 453*8ccd4a63SDavid du Colombier 454*8ccd4a63SDavid du Colombier order = flag&MORDER; 455*8ccd4a63SDavid du Colombier 456*8ccd4a63SDavid du Colombier if((old->qid.type&QTDIR)==0 && order != MREPL) 457*8ccd4a63SDavid du Colombier error(Emount); 458*8ccd4a63SDavid du Colombier 459*8ccd4a63SDavid du Colombier new = *newp; 460*8ccd4a63SDavid du Colombier mh = new->umh; 461*8ccd4a63SDavid du Colombier 462*8ccd4a63SDavid du Colombier /* 463*8ccd4a63SDavid du Colombier * Not allowed to bind when the old directory 464*8ccd4a63SDavid du Colombier * is itself a union. (Maybe it should be allowed, but I don't see 465*8ccd4a63SDavid du Colombier * what the semantics would be.) 466*8ccd4a63SDavid du Colombier * 467*8ccd4a63SDavid du Colombier * We need to check mh->mount->next to tell unions apart from 468*8ccd4a63SDavid du Colombier * simple mount points, so that things like 469*8ccd4a63SDavid du Colombier * mount -c fd /root 470*8ccd4a63SDavid du Colombier * bind -c /root / 471*8ccd4a63SDavid du Colombier * work. The check of mount->mflag catches things like 472*8ccd4a63SDavid du Colombier * mount fd /root 473*8ccd4a63SDavid du Colombier * bind -c /root / 474*8ccd4a63SDavid du Colombier * 475*8ccd4a63SDavid du Colombier * This is far more complicated than it should be, but I don't 476*8ccd4a63SDavid du Colombier * see an easier way at the moment. -rsc 477*8ccd4a63SDavid du Colombier */ 478*8ccd4a63SDavid du Colombier if((flag&MCREATE) && mh && mh->mount 479*8ccd4a63SDavid du Colombier && (mh->mount->next || !(mh->mount->mflag&MCREATE))) 480*8ccd4a63SDavid du Colombier error(Emount); 481*8ccd4a63SDavid du Colombier 482*8ccd4a63SDavid du Colombier pg = up->pgrp; 483*8ccd4a63SDavid du Colombier wlock(&pg->ns); 484*8ccd4a63SDavid du Colombier 485*8ccd4a63SDavid du Colombier l = &MOUNTH(pg, old->qid); 486*8ccd4a63SDavid du Colombier for(m = *l; m; m = m->hash) { 487*8ccd4a63SDavid du Colombier if(eqchan(m->from, old, 1)) 488*8ccd4a63SDavid du Colombier break; 489*8ccd4a63SDavid du Colombier l = &m->hash; 490*8ccd4a63SDavid du Colombier } 491*8ccd4a63SDavid du Colombier 492*8ccd4a63SDavid du Colombier if(m == nil) { 493*8ccd4a63SDavid du Colombier /* 494*8ccd4a63SDavid du Colombier * nothing mounted here yet. create a mount 495*8ccd4a63SDavid du Colombier * head and add to the hash table. 496*8ccd4a63SDavid du Colombier */ 497*8ccd4a63SDavid du Colombier m = newmhead(old); 498*8ccd4a63SDavid du Colombier *l = m; 499*8ccd4a63SDavid du Colombier 500*8ccd4a63SDavid du Colombier /* 501*8ccd4a63SDavid du Colombier * if this is a union mount, add the old 502*8ccd4a63SDavid du Colombier * node to the mount chain. 503*8ccd4a63SDavid du Colombier */ 504*8ccd4a63SDavid du Colombier if(order != MREPL) 505*8ccd4a63SDavid du Colombier m->mount = newmount(m, old, 0, 0); 506*8ccd4a63SDavid du Colombier } 507*8ccd4a63SDavid du Colombier wlock(&m->lock); 508*8ccd4a63SDavid du Colombier if(waserror()){ 509*8ccd4a63SDavid du Colombier wunlock(&m->lock); 510*8ccd4a63SDavid du Colombier nexterror(); 511*8ccd4a63SDavid du Colombier } 512*8ccd4a63SDavid du Colombier wunlock(&pg->ns); 513*8ccd4a63SDavid du Colombier 514*8ccd4a63SDavid du Colombier nm = newmount(m, new, flag, spec); 515*8ccd4a63SDavid du Colombier if(mh != nil && mh->mount != nil) { 516*8ccd4a63SDavid du Colombier /* 517*8ccd4a63SDavid du Colombier * copy a union when binding it onto a directory 518*8ccd4a63SDavid du Colombier */ 519*8ccd4a63SDavid du Colombier flg = order; 520*8ccd4a63SDavid du Colombier if(order == MREPL) 521*8ccd4a63SDavid du Colombier flg = MAFTER; 522*8ccd4a63SDavid du Colombier h = &nm->next; 523*8ccd4a63SDavid du Colombier um = mh->mount; 524*8ccd4a63SDavid du Colombier for(um = um->next; um; um = um->next) { 525*8ccd4a63SDavid du Colombier f = newmount(m, um->to, flg, um->spec); 526*8ccd4a63SDavid du Colombier *h = f; 527*8ccd4a63SDavid du Colombier h = &f->next; 528*8ccd4a63SDavid du Colombier } 529*8ccd4a63SDavid du Colombier } 530*8ccd4a63SDavid du Colombier 531*8ccd4a63SDavid du Colombier if(m->mount && order == MREPL) { 532*8ccd4a63SDavid du Colombier mountfree(m->mount); 533*8ccd4a63SDavid du Colombier m->mount = 0; 534*8ccd4a63SDavid du Colombier } 535*8ccd4a63SDavid du Colombier 536*8ccd4a63SDavid du Colombier if(flag & MCREATE) 537*8ccd4a63SDavid du Colombier nm->mflag |= MCREATE; 538*8ccd4a63SDavid du Colombier 539*8ccd4a63SDavid du Colombier if(m->mount && order == MAFTER) { 540*8ccd4a63SDavid du Colombier for(f = m->mount; f->next; f = f->next) 541*8ccd4a63SDavid du Colombier ; 542*8ccd4a63SDavid du Colombier f->next = nm; 543*8ccd4a63SDavid du Colombier } 544*8ccd4a63SDavid du Colombier else { 545*8ccd4a63SDavid du Colombier for(f = nm; f->next; f = f->next) 546*8ccd4a63SDavid du Colombier ; 547*8ccd4a63SDavid du Colombier f->next = m->mount; 548*8ccd4a63SDavid du Colombier m->mount = nm; 549*8ccd4a63SDavid du Colombier } 550*8ccd4a63SDavid du Colombier 551*8ccd4a63SDavid du Colombier wunlock(&m->lock); 552*8ccd4a63SDavid du Colombier poperror(); 553*8ccd4a63SDavid du Colombier return nm->mountid; 554*8ccd4a63SDavid du Colombier } 555*8ccd4a63SDavid du Colombier 556*8ccd4a63SDavid du Colombier void 557*8ccd4a63SDavid du Colombier cunmount(Chan *mnt, Chan *mounted) 558*8ccd4a63SDavid du Colombier { 559*8ccd4a63SDavid du Colombier Pgrp *pg; 560*8ccd4a63SDavid du Colombier Mhead *m, **l; 561*8ccd4a63SDavid du Colombier Mount *f, **p; 562*8ccd4a63SDavid du Colombier 563*8ccd4a63SDavid du Colombier if(mnt->umh) /* should not happen */ 564*8ccd4a63SDavid du Colombier print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh); 565*8ccd4a63SDavid du Colombier 566*8ccd4a63SDavid du Colombier /* 567*8ccd4a63SDavid du Colombier * It _can_ happen that mounted->umh is non-nil, 568*8ccd4a63SDavid du Colombier * because mounted is the result of namec(Aopen) 569*8ccd4a63SDavid du Colombier * (see sysfile.c:/^sysunmount). 570*8ccd4a63SDavid du Colombier * If we open a union directory, it will have a umh. 571*8ccd4a63SDavid du Colombier * Although surprising, this is okay, since the 572*8ccd4a63SDavid du Colombier * cclose will take care of freeing the umh. 573*8ccd4a63SDavid du Colombier */ 574*8ccd4a63SDavid du Colombier 575*8ccd4a63SDavid du Colombier pg = up->pgrp; 576*8ccd4a63SDavid du Colombier wlock(&pg->ns); 577*8ccd4a63SDavid du Colombier 578*8ccd4a63SDavid du Colombier l = &MOUNTH(pg, mnt->qid); 579*8ccd4a63SDavid du Colombier for(m = *l; m; m = m->hash) { 580*8ccd4a63SDavid du Colombier if(eqchan(m->from, mnt, 1)) 581*8ccd4a63SDavid du Colombier break; 582*8ccd4a63SDavid du Colombier l = &m->hash; 583*8ccd4a63SDavid du Colombier } 584*8ccd4a63SDavid du Colombier 585*8ccd4a63SDavid du Colombier if(m == 0) { 586*8ccd4a63SDavid du Colombier wunlock(&pg->ns); 587*8ccd4a63SDavid du Colombier error(Eunmount); 588*8ccd4a63SDavid du Colombier } 589*8ccd4a63SDavid du Colombier 590*8ccd4a63SDavid du Colombier wlock(&m->lock); 591*8ccd4a63SDavid du Colombier if(mounted == 0) { 592*8ccd4a63SDavid du Colombier *l = m->hash; 593*8ccd4a63SDavid du Colombier wunlock(&pg->ns); 594*8ccd4a63SDavid du Colombier mountfree(m->mount); 595*8ccd4a63SDavid du Colombier m->mount = nil; 596*8ccd4a63SDavid du Colombier cclose(m->from); 597*8ccd4a63SDavid du Colombier wunlock(&m->lock); 598*8ccd4a63SDavid du Colombier putmhead(m); 599*8ccd4a63SDavid du Colombier return; 600*8ccd4a63SDavid du Colombier } 601*8ccd4a63SDavid du Colombier 602*8ccd4a63SDavid du Colombier p = &m->mount; 603*8ccd4a63SDavid du Colombier for(f = *p; f; f = f->next) { 604*8ccd4a63SDavid du Colombier /* BUG: Needs to be 2 pass */ 605*8ccd4a63SDavid du Colombier if(eqchan(f->to, mounted, 1) || 606*8ccd4a63SDavid du Colombier (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) { 607*8ccd4a63SDavid du Colombier *p = f->next; 608*8ccd4a63SDavid du Colombier f->next = 0; 609*8ccd4a63SDavid du Colombier mountfree(f); 610*8ccd4a63SDavid du Colombier if(m->mount == nil) { 611*8ccd4a63SDavid du Colombier *l = m->hash; 612*8ccd4a63SDavid du Colombier cclose(m->from); 613*8ccd4a63SDavid du Colombier wunlock(&m->lock); 614*8ccd4a63SDavid du Colombier wunlock(&pg->ns); 615*8ccd4a63SDavid du Colombier putmhead(m); 616*8ccd4a63SDavid du Colombier return; 617*8ccd4a63SDavid du Colombier } 618*8ccd4a63SDavid du Colombier wunlock(&m->lock); 619*8ccd4a63SDavid du Colombier wunlock(&pg->ns); 620*8ccd4a63SDavid du Colombier return; 621*8ccd4a63SDavid du Colombier } 622*8ccd4a63SDavid du Colombier p = &f->next; 623*8ccd4a63SDavid du Colombier } 624*8ccd4a63SDavid du Colombier wunlock(&m->lock); 625*8ccd4a63SDavid du Colombier wunlock(&pg->ns); 626*8ccd4a63SDavid du Colombier error(Eunion); 627*8ccd4a63SDavid du Colombier } 628*8ccd4a63SDavid du Colombier 629*8ccd4a63SDavid du Colombier Chan* 630*8ccd4a63SDavid du Colombier cclone(Chan *c) 631*8ccd4a63SDavid du Colombier { 632*8ccd4a63SDavid du Colombier Chan *nc; 633*8ccd4a63SDavid du Colombier Walkqid *wq; 634*8ccd4a63SDavid du Colombier 635*8ccd4a63SDavid du Colombier wq = devtab[c->type]->walk(c, nil, nil, 0); 636*8ccd4a63SDavid du Colombier if(wq == nil) 637*8ccd4a63SDavid du Colombier error("clone failed"); 638*8ccd4a63SDavid du Colombier nc = wq->clone; 639*8ccd4a63SDavid du Colombier free(wq); 640*8ccd4a63SDavid du Colombier nc->name = c->name; 641*8ccd4a63SDavid du Colombier if(c->name) 642*8ccd4a63SDavid du Colombier incref(&c->name->ref); 643*8ccd4a63SDavid du Colombier return nc; 644*8ccd4a63SDavid du Colombier } 645*8ccd4a63SDavid du Colombier 646*8ccd4a63SDavid du Colombier int 647*8ccd4a63SDavid du Colombier findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid) 648*8ccd4a63SDavid du Colombier { 649*8ccd4a63SDavid du Colombier Pgrp *pg; 650*8ccd4a63SDavid du Colombier Mhead *m; 651*8ccd4a63SDavid du Colombier 652*8ccd4a63SDavid du Colombier pg = up->pgrp; 653*8ccd4a63SDavid du Colombier rlock(&pg->ns); 654*8ccd4a63SDavid du Colombier for(m = MOUNTH(pg, qid); m; m = m->hash){ 655*8ccd4a63SDavid du Colombier rlock(&m->lock); 656*8ccd4a63SDavid du Colombier if(m->from == nil){ 657*8ccd4a63SDavid du Colombier print("m %p m->from 0\n", m); 658*8ccd4a63SDavid du Colombier runlock(&m->lock); 659*8ccd4a63SDavid du Colombier continue; 660*8ccd4a63SDavid du Colombier } 661*8ccd4a63SDavid du Colombier if(eqchantdqid(m->from, type, dev, qid, 1)) { 662*8ccd4a63SDavid du Colombier runlock(&pg->ns); 663*8ccd4a63SDavid du Colombier if(mp != nil){ 664*8ccd4a63SDavid du Colombier incref(&m->ref); 665*8ccd4a63SDavid du Colombier if(*mp != nil) 666*8ccd4a63SDavid du Colombier putmhead(*mp); 667*8ccd4a63SDavid du Colombier *mp = m; 668*8ccd4a63SDavid du Colombier } 669*8ccd4a63SDavid du Colombier if(*cp != nil) 670*8ccd4a63SDavid du Colombier cclose(*cp); 671*8ccd4a63SDavid du Colombier incref(&m->mount->to->ref); 672*8ccd4a63SDavid du Colombier *cp = m->mount->to; 673*8ccd4a63SDavid du Colombier runlock(&m->lock); 674*8ccd4a63SDavid du Colombier return 1; 675*8ccd4a63SDavid du Colombier } 676*8ccd4a63SDavid du Colombier runlock(&m->lock); 677*8ccd4a63SDavid du Colombier } 678*8ccd4a63SDavid du Colombier 679*8ccd4a63SDavid du Colombier runlock(&pg->ns); 680*8ccd4a63SDavid du Colombier return 0; 681*8ccd4a63SDavid du Colombier } 682*8ccd4a63SDavid du Colombier 683*8ccd4a63SDavid du Colombier int 684*8ccd4a63SDavid du Colombier domount(Chan **cp, Mhead **mp) 685*8ccd4a63SDavid du Colombier { 686*8ccd4a63SDavid du Colombier return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid); 687*8ccd4a63SDavid du Colombier } 688*8ccd4a63SDavid du Colombier 689*8ccd4a63SDavid du Colombier Chan* 690*8ccd4a63SDavid du Colombier undomount(Chan *c, Cname *name) 691*8ccd4a63SDavid du Colombier { 692*8ccd4a63SDavid du Colombier Chan *nc; 693*8ccd4a63SDavid du Colombier Pgrp *pg; 694*8ccd4a63SDavid du Colombier Mount *t; 695*8ccd4a63SDavid du Colombier Mhead **h, **he, *f; 696*8ccd4a63SDavid du Colombier 697*8ccd4a63SDavid du Colombier pg = up->pgrp; 698*8ccd4a63SDavid du Colombier rlock(&pg->ns); 699*8ccd4a63SDavid du Colombier if(waserror()) { 700*8ccd4a63SDavid du Colombier runlock(&pg->ns); 701*8ccd4a63SDavid du Colombier nexterror(); 702*8ccd4a63SDavid du Colombier } 703*8ccd4a63SDavid du Colombier 704*8ccd4a63SDavid du Colombier he = &pg->mnthash[MNTHASH]; 705*8ccd4a63SDavid du Colombier for(h = pg->mnthash; h < he; h++) { 706*8ccd4a63SDavid du Colombier for(f = *h; f; f = f->hash) { 707*8ccd4a63SDavid du Colombier if(strcmp(f->from->name->s, name->s) != 0) 708*8ccd4a63SDavid du Colombier continue; 709*8ccd4a63SDavid du Colombier for(t = f->mount; t; t = t->next) { 710*8ccd4a63SDavid du Colombier if(eqchan(c, t->to, 1)) { 711*8ccd4a63SDavid du Colombier /* 712*8ccd4a63SDavid du Colombier * We want to come out on the left hand side of the mount 713*8ccd4a63SDavid du Colombier * point using the element of the union that we entered on. 714*8ccd4a63SDavid du Colombier * To do this, find the element that has a from name of 715*8ccd4a63SDavid du Colombier * c->name->s. 716*8ccd4a63SDavid du Colombier */ 717*8ccd4a63SDavid du Colombier if(strcmp(t->head->from->name->s, name->s) != 0) 718*8ccd4a63SDavid du Colombier continue; 719*8ccd4a63SDavid du Colombier nc = t->head->from; 720*8ccd4a63SDavid du Colombier incref(&nc->ref); 721*8ccd4a63SDavid du Colombier cclose(c); 722*8ccd4a63SDavid du Colombier c = nc; 723*8ccd4a63SDavid du Colombier break; 724*8ccd4a63SDavid du Colombier } 725*8ccd4a63SDavid du Colombier } 726*8ccd4a63SDavid du Colombier } 727*8ccd4a63SDavid du Colombier } 728*8ccd4a63SDavid du Colombier poperror(); 729*8ccd4a63SDavid du Colombier runlock(&pg->ns); 730*8ccd4a63SDavid du Colombier return c; 731*8ccd4a63SDavid du Colombier } 732*8ccd4a63SDavid du Colombier 733*8ccd4a63SDavid du Colombier /* 734*8ccd4a63SDavid du Colombier * Either walks all the way or not at all. No partial results in *cp. 735*8ccd4a63SDavid du Colombier * *nerror is the number of names to display in an error message. 736*8ccd4a63SDavid du Colombier */ 737*8ccd4a63SDavid du Colombier static char Edoesnotexist[] = "does not exist"; 738*8ccd4a63SDavid du Colombier int 739*8ccd4a63SDavid du Colombier walk(Chan **cp, char **names, int nnames, int nomount, int *nerror) 740*8ccd4a63SDavid du Colombier { 741*8ccd4a63SDavid du Colombier int dev, dotdot, i, n, nhave, ntry, type; 742*8ccd4a63SDavid du Colombier Chan *c, *nc; 743*8ccd4a63SDavid du Colombier Cname *cname; 744*8ccd4a63SDavid du Colombier Mount *f; 745*8ccd4a63SDavid du Colombier Mhead *mh, *nmh; 746*8ccd4a63SDavid du Colombier Walkqid *wq; 747*8ccd4a63SDavid du Colombier 748*8ccd4a63SDavid du Colombier c = *cp; 749*8ccd4a63SDavid du Colombier incref(&c->ref); 750*8ccd4a63SDavid du Colombier cname = c->name; 751*8ccd4a63SDavid du Colombier incref(&cname->ref); 752*8ccd4a63SDavid du Colombier mh = nil; 753*8ccd4a63SDavid du Colombier 754*8ccd4a63SDavid du Colombier /* 755*8ccd4a63SDavid du Colombier * While we haven't gotten all the way down the path: 756*8ccd4a63SDavid du Colombier * 1. step through a mount point, if any 757*8ccd4a63SDavid du Colombier * 2. send a walk request for initial dotdot or initial prefix without dotdot 758*8ccd4a63SDavid du Colombier * 3. move to the first mountpoint along the way. 759*8ccd4a63SDavid du Colombier * 4. repeat. 760*8ccd4a63SDavid du Colombier * 761*8ccd4a63SDavid du Colombier * An invariant is that each time through the loop, c is on the undomount 762*8ccd4a63SDavid du Colombier * side of the mount point, and c's name is cname. 763*8ccd4a63SDavid du Colombier */ 764*8ccd4a63SDavid du Colombier for(nhave=0; nhave<nnames; nhave+=n){ 765*8ccd4a63SDavid du Colombier if((c->qid.type&QTDIR)==0){ 766*8ccd4a63SDavid du Colombier if(nerror) 767*8ccd4a63SDavid du Colombier *nerror = nhave; 768*8ccd4a63SDavid du Colombier cnameclose(cname); 769*8ccd4a63SDavid du Colombier cclose(c); 770*8ccd4a63SDavid du Colombier strcpy(up->errstr, Enotdir); 771*8ccd4a63SDavid du Colombier if(mh != nil) 772*8ccd4a63SDavid du Colombier {print("walk 1\n"); 773*8ccd4a63SDavid du Colombier putmhead(mh); 774*8ccd4a63SDavid du Colombier } 775*8ccd4a63SDavid du Colombier return -1; 776*8ccd4a63SDavid du Colombier } 777*8ccd4a63SDavid du Colombier ntry = nnames - nhave; 778*8ccd4a63SDavid du Colombier if(ntry > MAXWELEM) 779*8ccd4a63SDavid du Colombier ntry = MAXWELEM; 780*8ccd4a63SDavid du Colombier dotdot = 0; 781*8ccd4a63SDavid du Colombier for(i=0; i<ntry; i++){ 782*8ccd4a63SDavid du Colombier if(isdotdot(names[nhave+i])){ 783*8ccd4a63SDavid du Colombier if(i==0) { 784*8ccd4a63SDavid du Colombier dotdot = 1; 785*8ccd4a63SDavid du Colombier ntry = 1; 786*8ccd4a63SDavid du Colombier } else 787*8ccd4a63SDavid du Colombier ntry = i; 788*8ccd4a63SDavid du Colombier break; 789*8ccd4a63SDavid du Colombier } 790*8ccd4a63SDavid du Colombier } 791*8ccd4a63SDavid du Colombier 792*8ccd4a63SDavid du Colombier if(!dotdot && !nomount) 793*8ccd4a63SDavid du Colombier domount(&c, &mh); 794*8ccd4a63SDavid du Colombier 795*8ccd4a63SDavid du Colombier type = c->type; 796*8ccd4a63SDavid du Colombier dev = c->dev; 797*8ccd4a63SDavid du Colombier 798*8ccd4a63SDavid du Colombier if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){ 799*8ccd4a63SDavid du Colombier /* try a union mount, if any */ 800*8ccd4a63SDavid du Colombier if(mh && !nomount){ 801*8ccd4a63SDavid du Colombier /* 802*8ccd4a63SDavid du Colombier * mh->mount == c, so start at mh->mount->next 803*8ccd4a63SDavid du Colombier */ 804*8ccd4a63SDavid du Colombier rlock(&mh->lock); 805*8ccd4a63SDavid du Colombier for(f = mh->mount->next; f; f = f->next) 806*8ccd4a63SDavid du Colombier if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil) 807*8ccd4a63SDavid du Colombier break; 808*8ccd4a63SDavid du Colombier runlock(&mh->lock); 809*8ccd4a63SDavid du Colombier if(f != nil){ 810*8ccd4a63SDavid du Colombier type = f->to->type; 811*8ccd4a63SDavid du Colombier dev = f->to->dev; 812*8ccd4a63SDavid du Colombier } 813*8ccd4a63SDavid du Colombier } 814*8ccd4a63SDavid du Colombier if(wq == nil){ 815*8ccd4a63SDavid du Colombier cclose(c); 816*8ccd4a63SDavid du Colombier cnameclose(cname); 817*8ccd4a63SDavid du Colombier if(nerror) 818*8ccd4a63SDavid du Colombier *nerror = nhave+1; 819*8ccd4a63SDavid du Colombier if(mh != nil) 820*8ccd4a63SDavid du Colombier putmhead(mh); 821*8ccd4a63SDavid du Colombier return -1; 822*8ccd4a63SDavid du Colombier } 823*8ccd4a63SDavid du Colombier } 824*8ccd4a63SDavid du Colombier 825*8ccd4a63SDavid du Colombier nmh = nil; 826*8ccd4a63SDavid du Colombier if(dotdot) { 827*8ccd4a63SDavid du Colombier assert(wq->nqid == 1); 828*8ccd4a63SDavid du Colombier assert(wq->clone != nil); 829*8ccd4a63SDavid du Colombier 830*8ccd4a63SDavid du Colombier cname = addelem(cname, ".."); 831*8ccd4a63SDavid du Colombier nc = undomount(wq->clone, cname); 832*8ccd4a63SDavid du Colombier n = 1; 833*8ccd4a63SDavid du Colombier } else { 834*8ccd4a63SDavid du Colombier nc = nil; 835*8ccd4a63SDavid du Colombier if(!nomount) 836*8ccd4a63SDavid du Colombier for(i=0; i<wq->nqid && i<ntry-1; i++) 837*8ccd4a63SDavid du Colombier if(findmount(&nc, &nmh, type, dev, wq->qid[i])) 838*8ccd4a63SDavid du Colombier break; 839*8ccd4a63SDavid du Colombier if(nc == nil){ /* no mount points along path */ 840*8ccd4a63SDavid du Colombier if(wq->clone == nil){ 841*8ccd4a63SDavid du Colombier cclose(c); 842*8ccd4a63SDavid du Colombier cnameclose(cname); 843*8ccd4a63SDavid du Colombier if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){ 844*8ccd4a63SDavid du Colombier if(nerror) 845*8ccd4a63SDavid du Colombier *nerror = nhave+wq->nqid+1; 846*8ccd4a63SDavid du Colombier strcpy(up->errstr, Edoesnotexist); 847*8ccd4a63SDavid du Colombier }else{ 848*8ccd4a63SDavid du Colombier if(nerror) 849*8ccd4a63SDavid du Colombier *nerror = nhave+wq->nqid; 850*8ccd4a63SDavid du Colombier strcpy(up->errstr, Enotdir); 851*8ccd4a63SDavid du Colombier } 852*8ccd4a63SDavid du Colombier free(wq); 853*8ccd4a63SDavid du Colombier if(mh != nil) 854*8ccd4a63SDavid du Colombier putmhead(mh); 855*8ccd4a63SDavid du Colombier return -1; 856*8ccd4a63SDavid du Colombier } 857*8ccd4a63SDavid du Colombier n = wq->nqid; 858*8ccd4a63SDavid du Colombier nc = wq->clone; 859*8ccd4a63SDavid du Colombier }else{ /* stopped early, at a mount point */ 860*8ccd4a63SDavid du Colombier if(wq->clone != nil){ 861*8ccd4a63SDavid du Colombier cclose(wq->clone); 862*8ccd4a63SDavid du Colombier wq->clone = nil; 863*8ccd4a63SDavid du Colombier } 864*8ccd4a63SDavid du Colombier n = i+1; 865*8ccd4a63SDavid du Colombier } 866*8ccd4a63SDavid du Colombier for(i=0; i<n; i++) 867*8ccd4a63SDavid du Colombier cname = addelem(cname, names[nhave+i]); 868*8ccd4a63SDavid du Colombier } 869*8ccd4a63SDavid du Colombier cclose(c); 870*8ccd4a63SDavid du Colombier c = nc; 871*8ccd4a63SDavid du Colombier putmhead(mh); 872*8ccd4a63SDavid du Colombier mh = nmh; 873*8ccd4a63SDavid du Colombier free(wq); 874*8ccd4a63SDavid du Colombier } 875*8ccd4a63SDavid du Colombier 876*8ccd4a63SDavid du Colombier putmhead(mh); 877*8ccd4a63SDavid du Colombier 878*8ccd4a63SDavid du Colombier c = cunique(c); 879*8ccd4a63SDavid du Colombier 880*8ccd4a63SDavid du Colombier if(c->umh != nil){ //BUG 881*8ccd4a63SDavid du Colombier print("walk umh\n"); 882*8ccd4a63SDavid du Colombier putmhead(c->umh); 883*8ccd4a63SDavid du Colombier c->umh = nil; 884*8ccd4a63SDavid du Colombier } 885*8ccd4a63SDavid du Colombier 886*8ccd4a63SDavid du Colombier cnameclose(c->name); 887*8ccd4a63SDavid du Colombier c->name = cname; 888*8ccd4a63SDavid du Colombier 889*8ccd4a63SDavid du Colombier cclose(*cp); 890*8ccd4a63SDavid du Colombier *cp = c; 891*8ccd4a63SDavid du Colombier if(nerror) 892*8ccd4a63SDavid du Colombier *nerror = 0; 893*8ccd4a63SDavid du Colombier return 0; 894*8ccd4a63SDavid du Colombier } 895*8ccd4a63SDavid du Colombier 896*8ccd4a63SDavid du Colombier /* 897*8ccd4a63SDavid du Colombier * c is a mounted non-creatable directory. find a creatable one. 898*8ccd4a63SDavid du Colombier */ 899*8ccd4a63SDavid du Colombier Chan* 900*8ccd4a63SDavid du Colombier createdir(Chan *c, Mhead *m) 901*8ccd4a63SDavid du Colombier { 902*8ccd4a63SDavid du Colombier Chan *nc; 903*8ccd4a63SDavid du Colombier Mount *f; 904*8ccd4a63SDavid du Colombier 905*8ccd4a63SDavid du Colombier rlock(&m->lock); 906*8ccd4a63SDavid du Colombier if(waserror()) { 907*8ccd4a63SDavid du Colombier runlock(&m->lock); 908*8ccd4a63SDavid du Colombier nexterror(); 909*8ccd4a63SDavid du Colombier } 910*8ccd4a63SDavid du Colombier for(f = m->mount; f; f = f->next) { 911*8ccd4a63SDavid du Colombier if(f->mflag&MCREATE) { 912*8ccd4a63SDavid du Colombier nc = cclone(f->to); 913*8ccd4a63SDavid du Colombier runlock(&m->lock); 914*8ccd4a63SDavid du Colombier poperror(); 915*8ccd4a63SDavid du Colombier cclose(c); 916*8ccd4a63SDavid du Colombier return nc; 917*8ccd4a63SDavid du Colombier } 918*8ccd4a63SDavid du Colombier } 919*8ccd4a63SDavid du Colombier error(Enocreate); 920*8ccd4a63SDavid du Colombier return 0; 921*8ccd4a63SDavid du Colombier } 922*8ccd4a63SDavid du Colombier 923*8ccd4a63SDavid du Colombier void 924*8ccd4a63SDavid du Colombier saveregisters(void) 925*8ccd4a63SDavid du Colombier { 926*8ccd4a63SDavid du Colombier } 927*8ccd4a63SDavid du Colombier 928*8ccd4a63SDavid du Colombier /* 929*8ccd4a63SDavid du Colombier * In place, rewrite name to compress multiple /, eliminate ., and process .. 930*8ccd4a63SDavid du Colombier */ 931*8ccd4a63SDavid du Colombier void 932*8ccd4a63SDavid du Colombier cleancname(Cname *n) 933*8ccd4a63SDavid du Colombier { 934*8ccd4a63SDavid du Colombier char *p; 935*8ccd4a63SDavid du Colombier 936*8ccd4a63SDavid du Colombier if(n->s[0] == '#'){ 937*8ccd4a63SDavid du Colombier p = strchr(n->s, '/'); 938*8ccd4a63SDavid du Colombier if(p == nil) 939*8ccd4a63SDavid du Colombier return; 940*8ccd4a63SDavid du Colombier cleanname(p); 941*8ccd4a63SDavid du Colombier 942*8ccd4a63SDavid du Colombier /* 943*8ccd4a63SDavid du Colombier * The correct name is #i rather than #i/, 944*8ccd4a63SDavid du Colombier * but the correct name of #/ is #/. 945*8ccd4a63SDavid du Colombier */ 946*8ccd4a63SDavid du Colombier if(strcmp(p, "/")==0 && n->s[1] != '/') 947*8ccd4a63SDavid du Colombier *p = '\0'; 948*8ccd4a63SDavid du Colombier }else 949*8ccd4a63SDavid du Colombier cleanname(n->s); 950*8ccd4a63SDavid du Colombier n->len = strlen(n->s); 951*8ccd4a63SDavid du Colombier } 952*8ccd4a63SDavid du Colombier 953*8ccd4a63SDavid du Colombier static void 954*8ccd4a63SDavid du Colombier growparse(Elemlist *e) 955*8ccd4a63SDavid du Colombier { 956*8ccd4a63SDavid du Colombier char **new; 957*8ccd4a63SDavid du Colombier int *inew; 958*8ccd4a63SDavid du Colombier enum { Delta = 8 }; 959*8ccd4a63SDavid du Colombier 960*8ccd4a63SDavid du Colombier if(e->nelems % Delta == 0){ 961*8ccd4a63SDavid du Colombier new = smalloc((e->nelems+Delta) * sizeof(char*)); 962*8ccd4a63SDavid du Colombier memmove(new, e->elems, e->nelems*sizeof(char*)); 963*8ccd4a63SDavid du Colombier free(e->elems); 964*8ccd4a63SDavid du Colombier e->elems = new; 965*8ccd4a63SDavid du Colombier inew = smalloc((e->nelems+Delta+1) * sizeof(int)); 966*8ccd4a63SDavid du Colombier memmove(inew, e->off, e->nelems*sizeof(int)); 967*8ccd4a63SDavid du Colombier free(e->off); 968*8ccd4a63SDavid du Colombier e->off = inew; 969*8ccd4a63SDavid du Colombier } 970*8ccd4a63SDavid du Colombier } 971*8ccd4a63SDavid du Colombier 972*8ccd4a63SDavid du Colombier /* 973*8ccd4a63SDavid du Colombier * The name is known to be valid. 974*8ccd4a63SDavid du Colombier * Copy the name so slashes can be overwritten. 975*8ccd4a63SDavid du Colombier * An empty string will set nelem=0. 976*8ccd4a63SDavid du Colombier * A path ending in / or /. or /.//./ etc. will have 977*8ccd4a63SDavid du Colombier * e.mustbedir = 1, so that we correctly 978*8ccd4a63SDavid du Colombier * reject, e.g., "/adm/users/." when /adm/users is a file 979*8ccd4a63SDavid du Colombier * rather than a directory. 980*8ccd4a63SDavid du Colombier */ 981*8ccd4a63SDavid du Colombier static void 982*8ccd4a63SDavid du Colombier parsename(char *name, Elemlist *e) 983*8ccd4a63SDavid du Colombier { 984*8ccd4a63SDavid du Colombier char *slash; 985*8ccd4a63SDavid du Colombier 986*8ccd4a63SDavid du Colombier kstrdup(&e->name, name); 987*8ccd4a63SDavid du Colombier name = e->name; 988*8ccd4a63SDavid du Colombier e->nelems = 0; 989*8ccd4a63SDavid du Colombier e->elems = nil; 990*8ccd4a63SDavid du Colombier e->off = smalloc(sizeof(int)); 991*8ccd4a63SDavid du Colombier e->off[0] = skipslash(name) - name; 992*8ccd4a63SDavid du Colombier for(;;){ 993*8ccd4a63SDavid du Colombier name = skipslash(name); 994*8ccd4a63SDavid du Colombier if(*name=='\0'){ 995*8ccd4a63SDavid du Colombier e->mustbedir = 1; 996*8ccd4a63SDavid du Colombier break; 997*8ccd4a63SDavid du Colombier } 998*8ccd4a63SDavid du Colombier growparse(e); 999*8ccd4a63SDavid du Colombier e->elems[e->nelems++] = name; 1000*8ccd4a63SDavid du Colombier slash = utfrune(name, '/'); 1001*8ccd4a63SDavid du Colombier if(slash == nil){ 1002*8ccd4a63SDavid du Colombier e->off[e->nelems] = name+strlen(name) - e->name; 1003*8ccd4a63SDavid du Colombier e->mustbedir = 0; 1004*8ccd4a63SDavid du Colombier break; 1005*8ccd4a63SDavid du Colombier } 1006*8ccd4a63SDavid du Colombier e->off[e->nelems] = slash - e->name; 1007*8ccd4a63SDavid du Colombier *slash++ = '\0'; 1008*8ccd4a63SDavid du Colombier name = slash; 1009*8ccd4a63SDavid du Colombier } 1010*8ccd4a63SDavid du Colombier } 1011*8ccd4a63SDavid du Colombier 1012*8ccd4a63SDavid du Colombier void* 1013*8ccd4a63SDavid du Colombier memrchr(void *va, int c, long n) 1014*8ccd4a63SDavid du Colombier { 1015*8ccd4a63SDavid du Colombier uchar *a, *e; 1016*8ccd4a63SDavid du Colombier 1017*8ccd4a63SDavid du Colombier a = va; 1018*8ccd4a63SDavid du Colombier for(e=a+n-1; e>a; e--) 1019*8ccd4a63SDavid du Colombier if(*e == c) 1020*8ccd4a63SDavid du Colombier return e; 1021*8ccd4a63SDavid du Colombier return nil; 1022*8ccd4a63SDavid du Colombier } 1023*8ccd4a63SDavid du Colombier 1024*8ccd4a63SDavid du Colombier /* 1025*8ccd4a63SDavid du Colombier * Turn a name into a channel. 1026*8ccd4a63SDavid du Colombier * &name[0] is known to be a valid address. It may be a kernel address. 1027*8ccd4a63SDavid du Colombier * 1028*8ccd4a63SDavid du Colombier * Opening with amode Aopen, Acreate, or Aremove guarantees 1029*8ccd4a63SDavid du Colombier * that the result will be the only reference to that particular fid. 1030*8ccd4a63SDavid du Colombier * This is necessary since we might pass the result to 1031*8ccd4a63SDavid du Colombier * devtab[]->remove(). 1032*8ccd4a63SDavid du Colombier * 1033*8ccd4a63SDavid du Colombier * Opening Atodir, Amount, or Aaccess does not guarantee this. 1034*8ccd4a63SDavid du Colombier * 1035*8ccd4a63SDavid du Colombier * Opening Aaccess can, under certain conditions, return a 1036*8ccd4a63SDavid du Colombier * correct Chan* but with an incorrect Cname attached. 1037*8ccd4a63SDavid du Colombier * Since the functions that open Aaccess (sysstat, syswstat, sys_stat) 1038*8ccd4a63SDavid du Colombier * do not use the Cname*, this avoids an unnecessary clone. 1039*8ccd4a63SDavid du Colombier */ 1040*8ccd4a63SDavid du Colombier Chan* 1041*8ccd4a63SDavid du Colombier namec(char *aname, int amode, int omode, ulong perm) 1042*8ccd4a63SDavid du Colombier { 1043*8ccd4a63SDavid du Colombier int n, prefix, len, t, nomount, npath; 1044*8ccd4a63SDavid du Colombier Chan *c, *cnew; 1045*8ccd4a63SDavid du Colombier Cname *cname; 1046*8ccd4a63SDavid du Colombier Elemlist e; 1047*8ccd4a63SDavid du Colombier Rune r; 1048*8ccd4a63SDavid du Colombier Mhead *m; 1049*8ccd4a63SDavid du Colombier char *createerr, tmperrbuf[ERRMAX]; 1050*8ccd4a63SDavid du Colombier char *name; 1051*8ccd4a63SDavid du Colombier 1052*8ccd4a63SDavid du Colombier name = aname; 1053*8ccd4a63SDavid du Colombier if(name[0] == '\0') 1054*8ccd4a63SDavid du Colombier error("empty file name"); 1055*8ccd4a63SDavid du Colombier validname(name, 1); 1056*8ccd4a63SDavid du Colombier 1057*8ccd4a63SDavid du Colombier /* 1058*8ccd4a63SDavid du Colombier * Find the starting off point (the current slash, the root of 1059*8ccd4a63SDavid du Colombier * a device tree, or the current dot) as well as the name to 1060*8ccd4a63SDavid du Colombier * evaluate starting there. 1061*8ccd4a63SDavid du Colombier */ 1062*8ccd4a63SDavid du Colombier nomount = 0; 1063*8ccd4a63SDavid du Colombier switch(name[0]){ 1064*8ccd4a63SDavid du Colombier case '/': 1065*8ccd4a63SDavid du Colombier c = up->slash; 1066*8ccd4a63SDavid du Colombier incref(&c->ref); 1067*8ccd4a63SDavid du Colombier break; 1068*8ccd4a63SDavid du Colombier 1069*8ccd4a63SDavid du Colombier case '#': 1070*8ccd4a63SDavid du Colombier nomount = 1; 1071*8ccd4a63SDavid du Colombier up->genbuf[0] = '\0'; 1072*8ccd4a63SDavid du Colombier n = 0; 1073*8ccd4a63SDavid du Colombier while(*name!='\0' && (*name != '/' || n < 2)){ 1074*8ccd4a63SDavid du Colombier if(n >= sizeof(up->genbuf)-1) 1075*8ccd4a63SDavid du Colombier error(Efilename); 1076*8ccd4a63SDavid du Colombier up->genbuf[n++] = *name++; 1077*8ccd4a63SDavid du Colombier } 1078*8ccd4a63SDavid du Colombier up->genbuf[n] = '\0'; 1079*8ccd4a63SDavid du Colombier /* 1080*8ccd4a63SDavid du Colombier * noattach is sandboxing. 1081*8ccd4a63SDavid du Colombier * 1082*8ccd4a63SDavid du Colombier * the OK exceptions are: 1083*8ccd4a63SDavid du Colombier * | it only gives access to pipes you create 1084*8ccd4a63SDavid du Colombier * d this process's file descriptors 1085*8ccd4a63SDavid du Colombier * e this process's environment 1086*8ccd4a63SDavid du Colombier * the iffy exceptions are: 1087*8ccd4a63SDavid du Colombier * c time and pid, but also cons and consctl 1088*8ccd4a63SDavid du Colombier * p control of your own processes (and unfortunately 1089*8ccd4a63SDavid du Colombier * any others left unprotected) 1090*8ccd4a63SDavid du Colombier */ 1091*8ccd4a63SDavid du Colombier n = chartorune(&r, up->genbuf+1)+1; 1092*8ccd4a63SDavid du Colombier /* actually / is caught by parsing earlier */ 1093*8ccd4a63SDavid du Colombier if(utfrune("M", r)) 1094*8ccd4a63SDavid du Colombier error(Enoattach); 1095*8ccd4a63SDavid du Colombier if(up->pgrp->noattach && utfrune("|decp", r)==nil) 1096*8ccd4a63SDavid du Colombier error(Enoattach); 1097*8ccd4a63SDavid du Colombier t = devno(r, 1); 1098*8ccd4a63SDavid du Colombier if(t == -1) 1099*8ccd4a63SDavid du Colombier error(Ebadsharp); 1100*8ccd4a63SDavid du Colombier c = devtab[t]->attach(up->genbuf+n); 1101*8ccd4a63SDavid du Colombier break; 1102*8ccd4a63SDavid du Colombier 1103*8ccd4a63SDavid du Colombier default: 1104*8ccd4a63SDavid du Colombier c = up->dot; 1105*8ccd4a63SDavid du Colombier incref(&c->ref); 1106*8ccd4a63SDavid du Colombier break; 1107*8ccd4a63SDavid du Colombier } 1108*8ccd4a63SDavid du Colombier prefix = name - aname; 1109*8ccd4a63SDavid du Colombier 1110*8ccd4a63SDavid du Colombier e.name = nil; 1111*8ccd4a63SDavid du Colombier e.elems = nil; 1112*8ccd4a63SDavid du Colombier e.off = nil; 1113*8ccd4a63SDavid du Colombier e.nelems = 0; 1114*8ccd4a63SDavid du Colombier if(waserror()){ 1115*8ccd4a63SDavid du Colombier cclose(c); 1116*8ccd4a63SDavid du Colombier free(e.name); 1117*8ccd4a63SDavid du Colombier free(e.elems); 1118*8ccd4a63SDavid du Colombier free(e.off); 1119*8ccd4a63SDavid du Colombier //dumpmount(); 1120*8ccd4a63SDavid du Colombier nexterror(); 1121*8ccd4a63SDavid du Colombier } 1122*8ccd4a63SDavid du Colombier 1123*8ccd4a63SDavid du Colombier /* 1124*8ccd4a63SDavid du Colombier * Build a list of elements in the path. 1125*8ccd4a63SDavid du Colombier */ 1126*8ccd4a63SDavid du Colombier parsename(name, &e); 1127*8ccd4a63SDavid du Colombier 1128*8ccd4a63SDavid du Colombier /* 1129*8ccd4a63SDavid du Colombier * On create, .... 1130*8ccd4a63SDavid du Colombier */ 1131*8ccd4a63SDavid du Colombier if(amode == Acreate){ 1132*8ccd4a63SDavid du Colombier /* perm must have DMDIR if last element is / or /. */ 1133*8ccd4a63SDavid du Colombier if(e.mustbedir && !(perm&DMDIR)){ 1134*8ccd4a63SDavid du Colombier npath = e.nelems; 1135*8ccd4a63SDavid du Colombier strcpy(tmperrbuf, "create without DMDIR"); 1136*8ccd4a63SDavid du Colombier goto NameError; 1137*8ccd4a63SDavid du Colombier } 1138*8ccd4a63SDavid du Colombier 1139*8ccd4a63SDavid du Colombier /* don't try to walk the last path element just yet. */ 1140*8ccd4a63SDavid du Colombier if(e.nelems == 0) 1141*8ccd4a63SDavid du Colombier error(Eexist); 1142*8ccd4a63SDavid du Colombier e.nelems--; 1143*8ccd4a63SDavid du Colombier } 1144*8ccd4a63SDavid du Colombier 1145*8ccd4a63SDavid du Colombier if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){ 1146*8ccd4a63SDavid du Colombier if(npath < 0 || npath > e.nelems){ 1147*8ccd4a63SDavid du Colombier print("namec %s walk error npath=%d\n", aname, npath); 1148*8ccd4a63SDavid du Colombier nexterror(); 1149*8ccd4a63SDavid du Colombier } 1150*8ccd4a63SDavid du Colombier strcpy(tmperrbuf, up->errstr); 1151*8ccd4a63SDavid du Colombier NameError: 1152*8ccd4a63SDavid du Colombier len = prefix+e.off[npath]; 1153*8ccd4a63SDavid du Colombier if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname) 1154*8ccd4a63SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname); 1155*8ccd4a63SDavid du Colombier else 1156*8ccd4a63SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name); 1157*8ccd4a63SDavid du Colombier snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf); 1158*8ccd4a63SDavid du Colombier nexterror(); 1159*8ccd4a63SDavid du Colombier } 1160*8ccd4a63SDavid du Colombier 1161*8ccd4a63SDavid du Colombier if(e.mustbedir && !(c->qid.type&QTDIR)){ 1162*8ccd4a63SDavid du Colombier npath = e.nelems; 1163*8ccd4a63SDavid du Colombier strcpy(tmperrbuf, "not a directory"); 1164*8ccd4a63SDavid du Colombier goto NameError; 1165*8ccd4a63SDavid du Colombier } 1166*8ccd4a63SDavid du Colombier 1167*8ccd4a63SDavid du Colombier if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){ 1168*8ccd4a63SDavid du Colombier npath = e.nelems; 1169*8ccd4a63SDavid du Colombier error("cannot exec directory"); 1170*8ccd4a63SDavid du Colombier } 1171*8ccd4a63SDavid du Colombier 1172*8ccd4a63SDavid du Colombier switch(amode){ 1173*8ccd4a63SDavid du Colombier case Aaccess: 1174*8ccd4a63SDavid du Colombier if(!nomount) 1175*8ccd4a63SDavid du Colombier domount(&c, nil); 1176*8ccd4a63SDavid du Colombier break; 1177*8ccd4a63SDavid du Colombier 1178*8ccd4a63SDavid du Colombier case Abind: 1179*8ccd4a63SDavid du Colombier m = nil; 1180*8ccd4a63SDavid du Colombier if(!nomount) 1181*8ccd4a63SDavid du Colombier domount(&c, &m); 1182*8ccd4a63SDavid du Colombier if(c->umh != nil) 1183*8ccd4a63SDavid du Colombier putmhead(c->umh); 1184*8ccd4a63SDavid du Colombier c->umh = m; 1185*8ccd4a63SDavid du Colombier break; 1186*8ccd4a63SDavid du Colombier 1187*8ccd4a63SDavid du Colombier case Aremove: 1188*8ccd4a63SDavid du Colombier case Aopen: 1189*8ccd4a63SDavid du Colombier Open: 1190*8ccd4a63SDavid du Colombier /* save the name; domount might change c */ 1191*8ccd4a63SDavid du Colombier cname = c->name; 1192*8ccd4a63SDavid du Colombier incref(&cname->ref); 1193*8ccd4a63SDavid du Colombier m = nil; 1194*8ccd4a63SDavid du Colombier if(!nomount) 1195*8ccd4a63SDavid du Colombier domount(&c, &m); 1196*8ccd4a63SDavid du Colombier 1197*8ccd4a63SDavid du Colombier /* our own copy to open or remove */ 1198*8ccd4a63SDavid du Colombier c = cunique(c); 1199*8ccd4a63SDavid du Colombier 1200*8ccd4a63SDavid du Colombier /* now it's our copy anyway, we can put the name back */ 1201*8ccd4a63SDavid du Colombier cnameclose(c->name); 1202*8ccd4a63SDavid du Colombier c->name = cname; 1203*8ccd4a63SDavid du Colombier 1204*8ccd4a63SDavid du Colombier switch(amode){ 1205*8ccd4a63SDavid du Colombier case Aremove: 1206*8ccd4a63SDavid du Colombier putmhead(m); 1207*8ccd4a63SDavid du Colombier break; 1208*8ccd4a63SDavid du Colombier 1209*8ccd4a63SDavid du Colombier case Aopen: 1210*8ccd4a63SDavid du Colombier case Acreate: 1211*8ccd4a63SDavid du Colombier if(c->umh != nil){ 1212*8ccd4a63SDavid du Colombier print("cunique umh Open\n"); 1213*8ccd4a63SDavid du Colombier putmhead(c->umh); 1214*8ccd4a63SDavid du Colombier c->umh = nil; 1215*8ccd4a63SDavid du Colombier } 1216*8ccd4a63SDavid du Colombier 1217*8ccd4a63SDavid du Colombier /* only save the mount head if it's a multiple element union */ 1218*8ccd4a63SDavid du Colombier if(m && m->mount && m->mount->next) 1219*8ccd4a63SDavid du Colombier c->umh = m; 1220*8ccd4a63SDavid du Colombier else 1221*8ccd4a63SDavid du Colombier putmhead(m); 1222*8ccd4a63SDavid du Colombier 1223*8ccd4a63SDavid du Colombier /* save registers else error() in open has wrong value of c saved */ 1224*8ccd4a63SDavid du Colombier saveregisters(); 1225*8ccd4a63SDavid du Colombier 1226*8ccd4a63SDavid du Colombier if(omode == OEXEC) 1227*8ccd4a63SDavid du Colombier c->flag &= ~CCACHE; 1228*8ccd4a63SDavid du Colombier 1229*8ccd4a63SDavid du Colombier c = devtab[c->type]->open(c, omode&~OCEXEC); 1230*8ccd4a63SDavid du Colombier 1231*8ccd4a63SDavid du Colombier if(omode & OCEXEC) 1232*8ccd4a63SDavid du Colombier c->flag |= CCEXEC; 1233*8ccd4a63SDavid du Colombier if(omode & ORCLOSE) 1234*8ccd4a63SDavid du Colombier c->flag |= CRCLOSE; 1235*8ccd4a63SDavid du Colombier break; 1236*8ccd4a63SDavid du Colombier } 1237*8ccd4a63SDavid du Colombier break; 1238*8ccd4a63SDavid du Colombier 1239*8ccd4a63SDavid du Colombier case Atodir: 1240*8ccd4a63SDavid du Colombier /* 1241*8ccd4a63SDavid du Colombier * Directories (e.g. for cd) are left before the mount point, 1242*8ccd4a63SDavid du Colombier * so one may mount on / or . and see the effect. 1243*8ccd4a63SDavid du Colombier */ 1244*8ccd4a63SDavid du Colombier if(!(c->qid.type & QTDIR)) 1245*8ccd4a63SDavid du Colombier error(Enotdir); 1246*8ccd4a63SDavid du Colombier break; 1247*8ccd4a63SDavid du Colombier 1248*8ccd4a63SDavid du Colombier case Amount: 1249*8ccd4a63SDavid du Colombier /* 1250*8ccd4a63SDavid du Colombier * When mounting on an already mounted upon directory, 1251*8ccd4a63SDavid du Colombier * one wants subsequent mounts to be attached to the 1252*8ccd4a63SDavid du Colombier * original directory, not the replacement. Don't domount. 1253*8ccd4a63SDavid du Colombier */ 1254*8ccd4a63SDavid du Colombier break; 1255*8ccd4a63SDavid du Colombier 1256*8ccd4a63SDavid du Colombier case Acreate: 1257*8ccd4a63SDavid du Colombier /* 1258*8ccd4a63SDavid du Colombier * We've already walked all but the last element. 1259*8ccd4a63SDavid du Colombier * If the last exists, try to open it OTRUNC. 1260*8ccd4a63SDavid du Colombier * If omode&OEXCL is set, just give up. 1261*8ccd4a63SDavid du Colombier */ 1262*8ccd4a63SDavid du Colombier e.nelems++; 1263*8ccd4a63SDavid du Colombier if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){ 1264*8ccd4a63SDavid du Colombier if(omode&OEXCL) 1265*8ccd4a63SDavid du Colombier error(Eexist); 1266*8ccd4a63SDavid du Colombier omode |= OTRUNC; 1267*8ccd4a63SDavid du Colombier goto Open; 1268*8ccd4a63SDavid du Colombier } 1269*8ccd4a63SDavid du Colombier 1270*8ccd4a63SDavid du Colombier /* 1271*8ccd4a63SDavid du Colombier * The semantics of the create(2) system call are that if the 1272*8ccd4a63SDavid du Colombier * file exists and can be written, it is to be opened with truncation. 1273*8ccd4a63SDavid du Colombier * On the other hand, the create(5) message fails if the file exists. 1274*8ccd4a63SDavid du Colombier * If we get two create(2) calls happening simultaneously, 1275*8ccd4a63SDavid du Colombier * they might both get here and send create(5) messages, but only 1276*8ccd4a63SDavid du Colombier * one of the messages will succeed. To provide the expected create(2) 1277*8ccd4a63SDavid du Colombier * semantics, the call with the failed message needs to try the above 1278*8ccd4a63SDavid du Colombier * walk again, opening for truncation. This correctly solves the 1279*8ccd4a63SDavid du Colombier * create/create race, in the sense that any observable outcome can 1280*8ccd4a63SDavid du Colombier * be explained as one happening before the other. 1281*8ccd4a63SDavid du Colombier * The create/create race is quite common. For example, it happens 1282*8ccd4a63SDavid du Colombier * when two rc subshells simultaneously update the same 1283*8ccd4a63SDavid du Colombier * environment variable. 1284*8ccd4a63SDavid du Colombier * 1285*8ccd4a63SDavid du Colombier * The implementation still admits a create/create/remove race: 1286*8ccd4a63SDavid du Colombier * (A) walk to file, fails 1287*8ccd4a63SDavid du Colombier * (B) walk to file, fails 1288*8ccd4a63SDavid du Colombier * (A) create file, succeeds, returns 1289*8ccd4a63SDavid du Colombier * (B) create file, fails 1290*8ccd4a63SDavid du Colombier * (A) remove file, succeeds, returns 1291*8ccd4a63SDavid du Colombier * (B) walk to file, return failure. 1292*8ccd4a63SDavid du Colombier * 1293*8ccd4a63SDavid du Colombier * This is hardly as common as the create/create race, and is really 1294*8ccd4a63SDavid du Colombier * not too much worse than what might happen if (B) got a hold of a 1295*8ccd4a63SDavid du Colombier * file descriptor and then the file was removed -- either way (B) can't do 1296*8ccd4a63SDavid du Colombier * anything with the result of the create call. So we don't care about this race. 1297*8ccd4a63SDavid du Colombier * 1298*8ccd4a63SDavid du Colombier * Applications that care about more fine-grained decision of the races 1299*8ccd4a63SDavid du Colombier * can use the OEXCL flag to get at the underlying create(5) semantics; 1300*8ccd4a63SDavid du Colombier * by default we provide the common case. 1301*8ccd4a63SDavid du Colombier * 1302*8ccd4a63SDavid du Colombier * We need to stay behind the mount point in case we 1303*8ccd4a63SDavid du Colombier * need to do the first walk again (should the create fail). 1304*8ccd4a63SDavid du Colombier * 1305*8ccd4a63SDavid du Colombier * We also need to cross the mount point and find the directory 1306*8ccd4a63SDavid du Colombier * in the union in which we should be creating. 1307*8ccd4a63SDavid du Colombier * 1308*8ccd4a63SDavid du Colombier * The channel staying behind is c, the one moving forward is cnew. 1309*8ccd4a63SDavid du Colombier */ 1310*8ccd4a63SDavid du Colombier m = nil; 1311*8ccd4a63SDavid du Colombier cnew = nil; /* is this assignment necessary? */ 1312*8ccd4a63SDavid du Colombier if(!waserror()){ /* try create */ 1313*8ccd4a63SDavid du Colombier if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid)) 1314*8ccd4a63SDavid du Colombier cnew = createdir(cnew, m); 1315*8ccd4a63SDavid du Colombier else{ 1316*8ccd4a63SDavid du Colombier cnew = c; 1317*8ccd4a63SDavid du Colombier incref(&cnew->ref); 1318*8ccd4a63SDavid du Colombier } 1319*8ccd4a63SDavid du Colombier 1320*8ccd4a63SDavid du Colombier /* 1321*8ccd4a63SDavid du Colombier * We need our own copy of the Chan because we're 1322*8ccd4a63SDavid du Colombier * about to send a create, which will move it. Once we have 1323*8ccd4a63SDavid du Colombier * our own copy, we can fix the name, which might be wrong 1324*8ccd4a63SDavid du Colombier * if findmount gave us a new Chan. 1325*8ccd4a63SDavid du Colombier */ 1326*8ccd4a63SDavid du Colombier cnew = cunique(cnew); 1327*8ccd4a63SDavid du Colombier cnameclose(cnew->name); 1328*8ccd4a63SDavid du Colombier cnew->name = c->name; 1329*8ccd4a63SDavid du Colombier incref(&cnew->name->ref); 1330*8ccd4a63SDavid du Colombier 1331*8ccd4a63SDavid du Colombier devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm); 1332*8ccd4a63SDavid du Colombier poperror(); 1333*8ccd4a63SDavid du Colombier if(omode & OCEXEC) 1334*8ccd4a63SDavid du Colombier cnew->flag |= CCEXEC; 1335*8ccd4a63SDavid du Colombier if(omode & ORCLOSE) 1336*8ccd4a63SDavid du Colombier cnew->flag |= CRCLOSE; 1337*8ccd4a63SDavid du Colombier if(m) 1338*8ccd4a63SDavid du Colombier putmhead(m); 1339*8ccd4a63SDavid du Colombier cclose(c); 1340*8ccd4a63SDavid du Colombier c = cnew; 1341*8ccd4a63SDavid du Colombier c->name = addelem(c->name, e.elems[e.nelems-1]); 1342*8ccd4a63SDavid du Colombier break; 1343*8ccd4a63SDavid du Colombier }else{ /* create failed */ 1344*8ccd4a63SDavid du Colombier cclose(cnew); 1345*8ccd4a63SDavid du Colombier if(m) 1346*8ccd4a63SDavid du Colombier putmhead(m); 1347*8ccd4a63SDavid du Colombier if(omode & OEXCL) 1348*8ccd4a63SDavid du Colombier nexterror(); 1349*8ccd4a63SDavid du Colombier /* save error */ 1350*8ccd4a63SDavid du Colombier createerr = up->errstr; 1351*8ccd4a63SDavid du Colombier up->errstr = tmperrbuf; 1352*8ccd4a63SDavid du Colombier /* note: we depend that walk does not error */ 1353*8ccd4a63SDavid du Colombier if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){ 1354*8ccd4a63SDavid du Colombier up->errstr = createerr; 1355*8ccd4a63SDavid du Colombier error(createerr); /* report true error */ 1356*8ccd4a63SDavid du Colombier } 1357*8ccd4a63SDavid du Colombier up->errstr = createerr; 1358*8ccd4a63SDavid du Colombier omode |= OTRUNC; 1359*8ccd4a63SDavid du Colombier goto Open; 1360*8ccd4a63SDavid du Colombier } 1361*8ccd4a63SDavid du Colombier panic("namec: not reached"); 1362*8ccd4a63SDavid du Colombier 1363*8ccd4a63SDavid du Colombier default: 1364*8ccd4a63SDavid du Colombier panic("unknown namec access %d\n", amode); 1365*8ccd4a63SDavid du Colombier } 1366*8ccd4a63SDavid du Colombier 1367*8ccd4a63SDavid du Colombier poperror(); 1368*8ccd4a63SDavid du Colombier 1369*8ccd4a63SDavid du Colombier /* place final element in genbuf for e.g. exec */ 1370*8ccd4a63SDavid du Colombier if(e.nelems > 0) 1371*8ccd4a63SDavid du Colombier kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf); 1372*8ccd4a63SDavid du Colombier else 1373*8ccd4a63SDavid du Colombier kstrcpy(up->genbuf, ".", sizeof up->genbuf); 1374*8ccd4a63SDavid du Colombier free(e.name); 1375*8ccd4a63SDavid du Colombier free(e.elems); 1376*8ccd4a63SDavid du Colombier free(e.off); 1377*8ccd4a63SDavid du Colombier 1378*8ccd4a63SDavid du Colombier return c; 1379*8ccd4a63SDavid du Colombier } 1380*8ccd4a63SDavid du Colombier 1381*8ccd4a63SDavid du Colombier /* 1382*8ccd4a63SDavid du Colombier * name is valid. skip leading / and ./ as much as possible 1383*8ccd4a63SDavid du Colombier */ 1384*8ccd4a63SDavid du Colombier char* 1385*8ccd4a63SDavid du Colombier skipslash(char *name) 1386*8ccd4a63SDavid du Colombier { 1387*8ccd4a63SDavid du Colombier while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/'))) 1388*8ccd4a63SDavid du Colombier name++; 1389*8ccd4a63SDavid du Colombier return name; 1390*8ccd4a63SDavid du Colombier } 1391*8ccd4a63SDavid du Colombier 1392*8ccd4a63SDavid du Colombier char isfrog[256]={ 1393*8ccd4a63SDavid du Colombier /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */ 1394*8ccd4a63SDavid du Colombier /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */ 1395*8ccd4a63SDavid du Colombier /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */ 1396*8ccd4a63SDavid du Colombier /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */ 1397*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ 1398*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */ 1399*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ 1400*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ 1401*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ 1402*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */ 1403*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 1404*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ 1405*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ 1406*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */ 1407*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ 1408*8ccd4a63SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */ 1409*8ccd4a63SDavid du Colombier }; 1410*8ccd4a63SDavid du Colombier 1411*8ccd4a63SDavid du Colombier /* 1412*8ccd4a63SDavid du Colombier * Check that the name 1413*8ccd4a63SDavid du Colombier * a) is in valid memory. 1414*8ccd4a63SDavid du Colombier * b) is shorter than 2^16 bytes, so it can fit in a 9P string field. 1415*8ccd4a63SDavid du Colombier * c) contains no frogs. 1416*8ccd4a63SDavid du Colombier * The first byte is known to be addressible by the requester, so the 1417*8ccd4a63SDavid du Colombier * routine works for kernel and user memory both. 1418*8ccd4a63SDavid du Colombier * The parameter slashok flags whether a slash character is an error 1419*8ccd4a63SDavid du Colombier * or a valid character. 1420*8ccd4a63SDavid du Colombier */ 1421*8ccd4a63SDavid du Colombier void 1422*8ccd4a63SDavid du Colombier validname(char *aname, int slashok) 1423*8ccd4a63SDavid du Colombier { 1424*8ccd4a63SDavid du Colombier char *ename, *name; 1425*8ccd4a63SDavid du Colombier int c; 1426*8ccd4a63SDavid du Colombier Rune r; 1427*8ccd4a63SDavid du Colombier 1428*8ccd4a63SDavid du Colombier name = aname; 1429*8ccd4a63SDavid du Colombier /* 1430*8ccd4a63SDavid du Colombier if(((ulong)name & KZERO) != KZERO) { 1431*8ccd4a63SDavid du Colombier p = name; 1432*8ccd4a63SDavid du Colombier t = BY2PG-((ulong)p&(BY2PG-1)); 1433*8ccd4a63SDavid du Colombier while((ename=vmemchr(p, 0, t)) == nil) { 1434*8ccd4a63SDavid du Colombier p += t; 1435*8ccd4a63SDavid du Colombier t = BY2PG; 1436*8ccd4a63SDavid du Colombier } 1437*8ccd4a63SDavid du Colombier }else 1438*8ccd4a63SDavid du Colombier */ 1439*8ccd4a63SDavid du Colombier ename = memchr(name, 0, (1<<16)); 1440*8ccd4a63SDavid du Colombier 1441*8ccd4a63SDavid du Colombier if(ename==nil || ename-name>=(1<<16)) 1442*8ccd4a63SDavid du Colombier error("name too long"); 1443*8ccd4a63SDavid du Colombier 1444*8ccd4a63SDavid du Colombier while(*name){ 1445*8ccd4a63SDavid du Colombier /* all characters above '~' are ok */ 1446*8ccd4a63SDavid du Colombier c = *(uchar*)name; 1447*8ccd4a63SDavid du Colombier if(c >= Runeself) 1448*8ccd4a63SDavid du Colombier name += chartorune(&r, name); 1449*8ccd4a63SDavid du Colombier else{ 1450*8ccd4a63SDavid du Colombier if(isfrog[c]) 1451*8ccd4a63SDavid du Colombier if(!slashok || c!='/'){ 1452*8ccd4a63SDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname); 1453*8ccd4a63SDavid du Colombier error(up->genbuf); 1454*8ccd4a63SDavid du Colombier } 1455*8ccd4a63SDavid du Colombier name++; 1456*8ccd4a63SDavid du Colombier } 1457*8ccd4a63SDavid du Colombier } 1458*8ccd4a63SDavid du Colombier } 1459*8ccd4a63SDavid du Colombier 1460*8ccd4a63SDavid du Colombier void 1461*8ccd4a63SDavid du Colombier isdir(Chan *c) 1462*8ccd4a63SDavid du Colombier { 1463*8ccd4a63SDavid du Colombier if(c->qid.type & QTDIR) 1464*8ccd4a63SDavid du Colombier return; 1465*8ccd4a63SDavid du Colombier error(Enotdir); 1466*8ccd4a63SDavid du Colombier } 1467*8ccd4a63SDavid du Colombier 1468*8ccd4a63SDavid du Colombier /* 1469*8ccd4a63SDavid du Colombier * This is necessary because there are many 1470*8ccd4a63SDavid du Colombier * pointers to the top of a given mount list: 1471*8ccd4a63SDavid du Colombier * 1472*8ccd4a63SDavid du Colombier * - the mhead in the namespace hash table 1473*8ccd4a63SDavid du Colombier * - the mhead in chans returned from findmount: 1474*8ccd4a63SDavid du Colombier * used in namec and then by unionread. 1475*8ccd4a63SDavid du Colombier * - the mhead in chans returned from createdir: 1476*8ccd4a63SDavid du Colombier * used in the open/create race protect, which is gone. 1477*8ccd4a63SDavid du Colombier * 1478*8ccd4a63SDavid du Colombier * The RWlock in the Mhead protects the mount list it contains. 1479*8ccd4a63SDavid du Colombier * The mount list is deleted when we cunmount. 1480*8ccd4a63SDavid du Colombier * The RWlock ensures that nothing is using the mount list at that time. 1481*8ccd4a63SDavid du Colombier * 1482*8ccd4a63SDavid du Colombier * It is okay to replace c->mh with whatever you want as 1483*8ccd4a63SDavid du Colombier * long as you are sure you have a unique reference to it. 1484*8ccd4a63SDavid du Colombier * 1485*8ccd4a63SDavid du Colombier * This comment might belong somewhere else. 1486*8ccd4a63SDavid du Colombier */ 1487*8ccd4a63SDavid du Colombier void 1488*8ccd4a63SDavid du Colombier putmhead(Mhead *m) 1489*8ccd4a63SDavid du Colombier { 1490*8ccd4a63SDavid du Colombier if(m && decref(&m->ref) == 0){ 1491*8ccd4a63SDavid du Colombier m->mount = (Mount*)0xCafeBeef; 1492*8ccd4a63SDavid du Colombier free(m); 1493*8ccd4a63SDavid du Colombier } 1494*8ccd4a63SDavid du Colombier } 1495