| plan 9 kernel history: overview | file list | diff list |
1991/0912/port/chan.c (diff list | history)
| 1991/0912/sys/src/9/port/chan.c:1,718 – 1991/1011/sys/src/9/port/chan.c:1,680 (short | long | prev | next) | ||
| 1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "errno.h" struct{ Lock; Chan *free; }chanalloc; 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 | } | |
| 1991/0722 | #include "ureg.h" | |
| 1990/0227 | int decref(Ref *r) { | |
| 1990/1104 | int x; | |
| 1991/0722 | int i; Segment *s; | |
| 1990/1104 | ||
| 1990/0227 | lock(r); | |
| 1990/1104 | x = --r->ref; | |
| 1990/0227 | unlock(r); | |
| 1991/0723 | if(x < 0) | |
| 1991/0705 | panic("decref"); | |
| 1991/0723 | ||
| 1990/1104 | return x; | |
| 1990/0227 | } void chaninit(void) { int i; Chan *c; chanalloc.free = ialloc(conf.nchan*sizeof(Chan), 0); c = chanalloc.free; for(i=0; i<conf.nchan-1; i++,c++){ c->fid = i; c->next = c+1; } c->next = 0; } void chandevreset(void) { int i; for(i=0; i<strlen(devchar); i++) (*devtab[i].reset)(); } void chandevinit(void) { int i; for(i=0; i<strlen(devchar); i++) (*devtab[i].init)(); } Chan* newchan(void) { Chan *c; | |
| 1990/0707 |
| |
| 1990/0227 |
| |
| 1991/1011 | for(;;) { lock(&chanalloc); if(c = chanalloc.free) { chanalloc.free = c->next; /* if closed before changed, this calls rooterror, a nop */ c->type = 0; c->flag = 0; c->ref = 1; unlock(&chanalloc); c->dev = 0; c->offset = 0; c->mnt = 0; c->stream = 0; c->aux = 0; c->mntindex = 0; c->mchan = 0; c->mqid = (Qid){0, 0}; return c; } | |
| 1990/0227 | unlock(&chanalloc); | |
| 1990/11211 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1991/0421 |
| |
| 1991/0427 |
| |
| 1990/0303 |
| |
| 1990/11211 |
| |
| 1990/0227 |
| |
| 1991/1011 | resrcwait("no chans\n"); | |
| 1990/0227 | } | |
| 1990/0907 | if(c->flag & CFREE) panic("close"); | |
| 1991/1011 | ||
| 1990/0227 | if(decref(c) == 0){ | |
| 1991/0414 | if(!waserror()) { (*devtab[c->type].close)(c); poperror(); | |
| 1990/0227 | } | |
| 1991/0414 | c->flag = CFREE; lock(&chanalloc); c->next = chanalloc.free; chanalloc.free = c; unlock(&chanalloc); | |
| 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; } | |
| 1990/0603 |
| |
| 1990/0227 |
| |
| 1990/0321 |
| |
| 1991/1011 | Mount *nm, *f; Mhead *m, **l; int order; | |
| 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 |
| |
| 1990/0321 |
| |
| 1990/0227 | pg = u->p->pgrp; | |
| 1990/0321 |
| |
| 1990/0227 |
| |
| 1991/1011 | wlock(&pg->ns); if(waserror()) { wunlock(&pg->ns); | |
| 1990/0227 | nexterror(); } | |
| 1990/1122 |
| |
| 1990/0321 |
| |
| 1990/0227 |
| |
| 1990/0321 |
| |
| 1991/1011 | l = &MOUNTH(pg, old); for(m = *l; m; m = m->hash) { if(eqchan(m->from, old, 1)) break; l = &m->hash; | |
| 1990/0227 | } | |
| 1990/11211 |
| |
| 1990/0227 |
| |
| 1990/0321 |
| |
| 1991/1011 | if(m == 0) { m = newmnthead(); m->from = old; incref(old); m->hash = *l; *l = m; if(order != MREPL) m->mount = newmount(m, old); | |
| 1990/0227 | } | |
| 1991/1011 | if(m->mount && order == MREPL) { mountfree(m->mount); m->mount = 0; } nm = newmount(m, new); | |
| 1990/0227 | if(flag & MCREATE) new->flag |= CCREATE; | |
| 1990/11211 |
| |
| 1990/0227 |
| |
| 1991/1011 | if(m->mount && order == MAFTER) { for(f = m->mount; f->next; f = f->next) ; f->next = nm; } else { nm->next = m->mount; m->mount = nm; } | |
| 1990/0227 |
| |
| 1990/0603 |
| |
| 1990/0227 |
| |
| 1990/0603 |
| |
| 1990/0227 |
| |
| 1991/1011 | wunlock(&pg->ns); poperror(); return nm->mountid; } | |
| 1990/0227 |
| |
| 1990/11211 |
| |
| 1990/0227 |
| |
| 1991/1011 | void unmount(Chan *mnt, Chan *mounted) { Pgrp *pg; Mhead *m, **l; Mount *f, **p; pg = u->p->pgrp; 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 | } | |
| 1990/0321 |
| |
| 1990/0227 |
| |
| 1991/1011 | if(m == 0) { wunlock(&pg->ns); errors("not mounted"); | |
| 1990/0321 | } | |
| 1990/0227 |
| |
| 1991/1011 | if(mounted == 0) { *l = m->hash; wunlock(&pg->ns); mountfree(m->mount); close(m->from); mntheadfree(m); return; } p = &m->mount; for(f = *p; f; f = f->next) { if(eqchan(f->to, mounted, 1)) { *p = f->next; f->next = 0; mountfree(f); if(m->mount == 0) { *l = m->hash; wunlock(&pg->ns); close(m->from); mntheadfree(m); return; } wunlock(&pg->ns); return; } p = &f->next; } wunlock(&pg->ns); errors("not in union"); | |
| 1990/0227 | } Chan* clone(Chan *c, Chan *nc) { return (*devtab[c->type].clone)(c, nc); } | |
| 1991/0427 | Chan* domount(Chan *c) | |
| 1990/0227 | { | |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0227 | Pgrp *pg; | |
| 1991/0427 |
| |
| 1991/1011 | Chan *nc; Mhead *m; | |
| 1990/0227 | pg = u->p->pgrp; | |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0321 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1991/1011 | rlock(&pg->ns); if(waserror()) { runlock(&pg->ns); | |
| 1991/0427 | nexterror(); } | |
| 1991/1011 | c->mnt = 0; for(m = MOUNTH(pg, c); m; m = m->hash) if(eqchan(m->from, c, 1)) { nc = clone(m->mount->to, 0); nc->mnt = m->mount; nc->mountid = m->mount->mountid; close(c); c = nc; break; } | |
| 1991/0427 | poperror(); | |
| 1991/1011 | runlock(&pg->ns); return c; | |
| 1990/0227 | } | |
| 1991/0427 | Chan* | |
| 1991/1011 | undomount(Chan *c) | |
| 1990/0227 | { | |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/1011 | Pgrp *pg; Mhead **h, **he, *f; Mount *t; | |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1990/0914 |
| |
| 1991/0427 |
| |
| 1991/0423 |
| |
| 1991/0427 |
| |
| 1991/1011 | pg = u->p->pgrp; rlock(&pg->ns); if(waserror()) { runlock(&pg->ns); nexterror(); | |
| 1991/0427 | } | |
| 1991/0423 |
| |
| 1991/0427 |
| |
| 1991/1011 | 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) if(eqchan(c, t->to, 1)) { close(c); c = clone(t->head->from, 0); break; } | |
| 1991/0427 | } | |
| 1990/0914 | } | |
| 1991/1011 | poperror(); runlock(&pg->ns); return c; } | |
| 1990/0914 | ||
| 1991/0427 |
| |
| 1991/1011 | Chan* walk(Chan *ac, char *name, int domnt) { Pgrp *pg; Chan *c = 0; Mount *f; int dotdot; | |
| 1990/0227 | ||
| 1991/1011 | if(*name == '\0') return ac; | |
| 1990/0914 | ||
| 1991/0427 |
| |
| 1991/1011 | dotdot = 0; if(name[0] == '.') if(name[1] == '.') if(name[2] == '\0') { ac = undomount(ac); dotdot = 1; } | |
| 1991/0427 | ||
| 1990/0227 |
| |
| 1991/1011 | if((*devtab[ac->type].walk)(ac, name) != 0) { if(dotdot) ac = undomount(ac); if(domnt) ac = domount(ac); return ac; } if(ac->mnt == 0) return 0; pg = u->p->pgrp; rlock(&pg->ns); if(waserror()) { runlock(&pg->ns); if(c) close(c); nexterror(); } for(f = ac->mnt; f; f = f->next) { c = clone(f->to, 0); if((*devtab[c->type].walk)(c, name) != 0) break; | |
| 1990/0227 | close(c); | |
| 1991/1011 | c = 0; } poperror(); runlock(&pg->ns); if(c) { if(dotdot) c = undomount(c); c->mnt = 0; if(domnt) { if(waserror()) { close(c); nexterror(); } c = domount(c); poperror(); } close(ac); } return c; | |
| 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/0427 |
| |
| 1991/1011 | Pgrp *pg; Chan *nc; Mount *f; | |
| 1990/0227 |
| |
| 1991/1011 | pg = u->p->pgrp; rlock(&pg->ns); if(waserror()) { runlock(&pg->ns); | |
| 1990/0227 | nexterror(); } | |
| 1991/0427 |
| |
| 1990/0321 |
| |
| 1990/11211 |
| |
| 1991/1011 | for(f = c->mnt; f; f = f->next) { if(f->to->flag&CCREATE) { nc = clone(f->to, 0); nc->mnt = f; runlock(&pg->ns); close(c); return nc; } | |
| 1990/0227 | } | |
| 1990/11211 |
| |
| 1990/0227 |
| |
| 1991/0912 |
| |
| 1991/0427 |
| |
| 1990/0227 |
| |
| 1991/0427 |
| |
| 1991/1011 | error(Enocreate); | |
| 1990/0227 | } | |
| 1990/0914 | void saveregisters(void) { } | |
| 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) { | |
| 1991/0427 | Chan *c, *nc, *cc; | |
| 1990/0227 | int t; | |
| 1990/0820 | int mntok, isdot; | |
| 1990/0821 | char *p; | |
| 1991/1011 | char *elem, *nn; | |
| 1990/0227 | if(name[0] == 0) | |
| 1990/11211 | error(Enonexist); | |
| 1990/0821 | /* * Make sure all of name is o.k. first byte is validated * externally so if it's a kernel address we know it's o.k. */ if(!((ulong)name & KZERO)){ p = name; t = BY2PG-((ulong)p&(BY2PG-1)); while(vmemchr(p, 0, t) == 0){ p += t; t = BY2PG; } } elem = u->elem; | |
| 1990/0227 | mntok = 1; | |
| 1990/0820 | isdot = 0; | |
| 1990/0227 | if(name[0] == '/'){ | |
| 1991/0427 | c = clone(u->slash, 0); | |
| 1990/0227 | /* * Skip leading slashes. */ name = skipslash(name); }else if(name[0] == '#'){ mntok = 0; | |
| 1990/1009 | if(name[1]=='M') | |
| 1990/11211 | error(Enonexist); | |
| 1990/0227 | t = devno(name[1], 1); if(t == -1) | |
| 1990/11211 | error(Ebadsharp); | |
| 1990/0227 | name += 2; if(*name == '/'){ name = skipslash(name); elem[0]=0; }else name = nextelem(name, elem); | |
| 1991/0427 | c = (*devtab[t].attach)(elem); | |
| 1990/0820 | }else{ | |
| 1991/0427 | c = clone(u->dot, 0); | |
| 1990/0820 | name = skipslash(name); /* eat leading ./ */ if(*name == 0) isdot = 1; } | |
| 1990/0227 | if(waserror()){ | |
| 1991/0427 | close(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 | /* * How to treat the last element of the name depends on the operation. * Therefore do all but the last element by the easy algorithm. */ while(*name){ | |
| 1991/0427 | if((nc=walk(c, elem, mntok)) == 0) | |
| 1990/11211 | error(Enonexist); | |
| 1991/0427 | c = nc; | |
| 1990/0227 | name = nextelem(name, elem); } | |
| 1990/0820 | ||
| 1990/0227 | /* * Last element; act according to type of access. */ switch(amode){ case Aaccess: | |
| 1990/0820 | if(isdot) | |
| 1991/0427 | c = domount(c); | |
| 1990/0820 | else{ | |
| 1991/0427 | if((nc=walk(c, elem, mntok)) == 0) | |
| 1990/11211 | error(Enonexist); | |
| 1991/0427 | c = nc; | |
| 1990/0820 | } | |
| 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. */ | |
| 1991/0427 | if((nc=walk(c, elem, 0)) == 0) | |
| 1990/11211 | error(Enonexist); | |
| 1991/0427 | c = nc; if(!(c->qid.path & CHDIR)) | |
| 1990/11211 | error(Enotdir); | |
| 1990/0227 | break; case Aopen: | |
| 1990/0820 | if(isdot) | |
| 1991/0427 | c = domount(c); | |
| 1990/0820 | else{ | |
| 1991/0427 | if((nc=walk(c, elem, mntok)) == 0) | |
| 1990/11211 | error(Enonexist); | |
| 1991/0427 | c = nc; | |
| 1990/0820 | } | |
| 1990/0227 | Open: | |
| 1991/0427 |
| |
| 1991/1011 | /* else error() in open has wrong value of c saved */ saveregisters(); | |
| 1991/0427 | c = (*devtab[c->type].open)(c, omode); | |
| 1990/08141 | if(omode & OCEXEC) | |
| 1991/0427 | c->flag |= CCEXEC; | |
| 1990/0227 | break; case Amount: /* * When mounting on an already mounted upon directory, one wants * the second mount to be attached to the original directory, not * the replacement. */ | |
| 1991/0427 | if((nc=walk(c, elem, 0)) == 0) | |
| 1990/11211 | error(Enonexist); | |
| 1991/0427 | c = nc; | |
| 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. */ cc = clone(c, 0); if(waserror()){ close(cc); nexterror(); } | |
| 1991/0727 | nameok(elem); | |
| 1991/0427 | if((nc=walk(cc, elem, 1)) != 0){ poperror(); close(c); c = nc; | |
| 1990/0227 | omode |= OTRUNC; goto Open; } | |
| 1991/0427 | close(cc); poperror(); /* * the file didn't exist, try the create */ | |
| 1991/1011 | if(c->mnt && !(c->flag&CCREATE)) | |
| 1991/0427 | c = createdir(c); (*devtab[c->type].create)(c, elem, omode, perm); | |
| 1990/08141 | if(omode & OCEXEC) | |
| 1991/0427 | c->flag |= CCEXEC; | |
| 1990/0227 | break; default: panic("unknown namec access %d\n", amode); } 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; } char isfrog[]={ /*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, [' '] 1, ['/'] 1, [0x7f] 1, }; | |
| 1991/0727 | void nameok(char *elem) { while(*elem) { if((*elem&0x80) || isfrog[*elem]) error(Ebadchar); elem++; } } | |
| 1990/0227 | /* * name[0] should not be a slash. * Advance name to next element in path, copying current element into elem. * Return pointer to next element, skipping slashes. */ char* nextelem(char *name, char *elem) { int i, user, c; char *end, *e; if(*name == '/') | |
| 1990/11211 | error(Efilename); | |
| 1990/0821 | end = memchr(name, 0, NAMELEN); | |
| 1990/0227 | if(end == 0){ | |
| 1990/0821 | end = memchr(name, '/', NAMELEN); | |
| 1990/0227 | if(end == 0) | |
| 1990/11211 | error(Efilename); | |
| 1990/0227 | }else{ e = memchr(name, '/', end-name); if(e) end = e; } while(name < end){ c = *name++; if((c&0x80) || isfrog[c]) | |
| 1990/11211 | error(Ebadchar); | |
| 1990/0227 | *elem++ = c; } *elem = 0; return skipslash(name); } void isdir(Chan *c) { | |
| 1990/11211 | if(c->qid.path & CHDIR) | |
| 1990/0227 | return; | |
| 1990/11211 | error(Enotdir); | |
| 1990/0227 | } | |