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