## diffname gnot/chan.c 1990/03091 ## diff -e /dev/null /n/bootesdump/1990/03091/sys/src/9/68020/chan.c 0a #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) { lock(r); r->ref++; unlock(r); return r->ref; } int decref(Ref *r) { lock(r); r->ref--; unlock(r); return r->ref; } void chaninit(void) { int i; Chan *c; chanalloc.free = ialloc(conf.nchan*sizeof(Chan), 0); c = chanalloc.free; for(i=0; ifid = i; c->next = c+1; } c->next = 0; } void chandevreset(void) { int i; for(i=0; inext; c->flag = 0; c->ref = 1; unlock(&chanalloc); c->offset = 0; c->mnt = 0; c->stream = 0; c->mchan = 0; c->mqid = 0; return c; } unlock(&chanalloc); print("no chans\n"); if(u == 0) panic("newchan"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); goto loop; } void close(Chan *c) { if(decref(c) == 0){ if(!waserror()){ (*devtab[c->type].close)(c); poperror(); } lock(&chanalloc); c->next = chanalloc.free; chanalloc.free = c; unlock(&chanalloc); } } int eqchan(Chan *a, Chan *b, long qmask) { if((a->qid^b->qid) & qmask) return 0; if(a->type != b->type) return 0; if(a->dev != b->dev) return 0; return 1; } /* * omnt is locked. return with nmnt locked. */ Mount* mountsplit(Mount *omnt) { Mount *nmnt; print("mount copy on write\n"); nmnt = newmount(); lock(nmnt); nmnt->term = omnt->term; nmnt->mountid = omnt->mountid; nmnt->next = omnt->next; if(nmnt->next) incref(nmnt); nmnt->c = omnt->c; incref(nmnt->c); omnt->ref--; unlock(omnt); return nmnt; } int mount(Chan *new, Chan *old, int flag) { int i; Mtab *mt, *mz; Mount *mnt, *omnt, *nmnt, *pmnt; Pgrp *pg; int isnew; if(CHDIR & (old->qid^new->qid)) error(0, Emount); if((old->qid&CHDIR)==0 && (flag&MORDER)!=MREPL) error(0, Emount); mz = 0; isnew = 0; pg = u->p->pgrp; lock(pg); if(waserror()){ unlock(pg); nexterror(); } /* * Is old already in mount table? */ mt = pg->mtab; for(i=0; inmtab; i++,mt++){ if(mt->c==0 && mz==0) mz = mt; else if(eqchan(mt->c, old, CHDIR|QPATH)) goto Found; } isnew = 1; if(mz == 0){ if(i == conf.nmtab) error(0, Enomount); mz = &pg->mtab[i]; pg->nmtab++; } mz->mnt = 0; mz->c = old; mt = mz; Found: new->flag = CMOUNT; if(flag & MCREATE) new->flag |= CCREATE; mnt = newmount(); mnt->c = new; switch(flag & MORDER){ /* * These two always go at head of list */ case MBEFORE: if(mt->mnt == 0) error(0, Enotunion); /* fall through */ case MREPL: omnt = mt->mnt; if(omnt) incref(omnt); mnt->next = omnt; mt->mnt = mnt; mnt->term = 1; if((flag&MORDER) == MBEFORE) mnt->term = 0; break; /* * This one never goes at head of list */ case MAFTER: if(mt->mnt == 0) error(0, Enotunion); omnt = mt->mnt; pmnt = 0; while(!omnt->term){ lock(omnt); if(omnt->ref > 1){ omnt = mountsplit(omnt); if(pmnt) pmnt->next = omnt; else mt->mnt = omnt; } unlock(omnt); nmnt = omnt->next; if(nmnt == 0) panic("MAFTER term"); pmnt = omnt; omnt = nmnt; } mnt->next = omnt->next; omnt->next = mnt; mnt->term = 1; omnt->term = 0; break; } incref(new); if(isnew) incref(old); unlock(pg); poperror(); return mnt->mountid; } Chan* clone(Chan *c, Chan *nc) { return (*devtab[c->type].clone)(c, nc); } Chan* domount(Chan *c) { int i; ulong mntid; Mtab *mt; Mount *mnt; Pgrp *pg; Chan *nc, *mc; pg = u->p->pgrp; /* * Is c in in mount table? */ mt = pg->mtab; for(i=0; inmtab; i++,mt++) if(mt->c && eqchan(mt->c, c, CHDIR|QPATH)) goto Found; /* * No; c is unaffected */ return c; /* * Yes; move c through table */ Found: lock(pg); if(!eqchan(mt->c, c, CHDIR|QPATH)){ /* table changed underfoot */ print("domount: changed underfoot?\n"); unlock(pg); return c; } mnt = mt->mnt; mntid = mnt->mountid; mc = mnt->c; incref(mc); unlock(pg); if(waserror()){ close(mc); nexterror(); } nc = clone(mc, 0); close(mc); poperror(); close(c); nc->mnt = mnt; nc->mountid = mntid; return nc; } Chan* walk(Chan *ac, char *name, int domnt) { Mount *mnt; int first = 1; Chan *c = ac; Chan *nc, *mc; Pgrp *pg = u->p->pgrp; /* * name may be empty if the file name is "/", "#c" etc. */ Again: if(name[0] && (*devtab[c->type].walk)(c, name)==0){ if(!(c->flag&CMOUNT)) goto Notfound; mnt = c->mnt; if(mnt == 0) panic("walk"); lock(pg); if(mnt->term){ unlock(pg); goto Notfound; } if(c->mountid != mnt->mountid){ print("walk: changed underfoot?\n"); unlock(pg); goto Notfound; } mnt = mnt->next; mc = mnt->c; incref(mc); unlock(pg); if(waserror()){ close(mc); nexterror(); } if(mnt == 0) panic("walk 1"); nc = clone(mc, 0); close(mc); poperror(); if(!first) close(c); nc->mnt = mnt; c = nc; first = 0; goto Again; } if(name[0]) /* walk succeeded */ c->flag &= ~CMOUNT; if(!first) close(ac); if(domnt) return domount(c); return c; Notfound: if(!first) close(c); return 0; } /* * c is a mounted non-creatable directory. find a creatable one. */ Chan* createdir(Chan *c) { Mount *mnt; Pgrp *pg = u->p->pgrp; Chan *mc, *nc; lock(pg); if(waserror()){ unlock(pg); nexterror(); } mnt = c->mnt; if(c->mountid != mnt->mountid){ print("createdir: changed underfoot?\n"); error(0, Enocreate); } do{ if(mnt->term) error(0, Enocreate); mnt = mnt->next; }while(!(mnt->c->flag&CCREATE)); mc = mnt->c; incref(mc); unlock(pg); if(waserror()){ close(mc); nexterror(); } nc = clone(mc, 0); poperror(); close(c); close(mc); nc->mnt = mnt; return nc; } /* * 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) { Chan *c, *nc; int t; int mntok; char *elem = u->elem; if(name[0] == 0) error(0, Enonexist); mntok = 1; if(name[0] == '/'){ c = clone(u->slash, 0); /* * Skip leading slashes. */ name = skipslash(name); }else if(name[0] == '#'){ mntok = 0; if(!((ulong)name & KZERO)) validaddr((ulong)(name+1), 2, 0); if(name[1]=='|' || ('A'<=name[1] && name[1]<='Z')) error(0, Enonexist); t = devno(name[1], 1); if(t == -1) error(0, Ebadsharp); name += 2; if(*name == '/'){ name = skipslash(name); elem[0]=0; }else name = nextelem(name, elem); c = (*devtab[t].attach)(elem); }else c = clone(u->dot, 0); if(waserror()){ close(c); nexterror(); } name = nextelem(name, elem); if(mntok) if(!(amode==Amount && elem[0]==0)) /* don't domount on dot or slash */ c = domount(c); /* see case Atodir below */ /* * 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){ if((nc=walk(c, elem, mntok)) == 0) error(0, Enonexist); c = nc; name = nextelem(name, elem); } /* * Last element; act according to type of access. */ switch(amode){ case Aaccess: if((nc=walk(c, elem, mntok)) == 0) error(0, Enonexist); c = nc; break; case Atodir: /* * Directories (e.g. for cd) are left before the mount point, * so one may mount on / or . and see the effect. */ if((nc=walk(c, elem, 0)) == 0) error(0, Enonexist); c = nc; if(!(c->qid & CHDIR)) error(0, Enotdir); break; case Aopen: if((nc=walk(c, elem, mntok)) == 0) error(0, Enonexist); c = nc; Open: c = (*devtab[c->type].open)(c, omode); 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. */ if((nc=walk(c, elem, 0)) == 0) error(0, Enonexist); c = nc; break; case Acreate: if((nc=walk(c, elem, 1)) != 0){ c = nc; omode |= OTRUNC; goto Open; } if((c->flag&(CMOUNT|CCREATE)) == CMOUNT) c = createdir(c); (*devtab[c->type].create)(c, elem, omode, perm); break; default: panic("unknown namec access %d\n", amode); } poperror(); return c; } /* * name[0] is addressable. */ char* skipslash(char *name) { while(*name == '/'){ if(((ulong)name&KZERO)==0 && (((ulong)name+1)&(BY2PG-1))==0) validaddr((ulong)name+1, 1, 0); name++; } 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, }; /* * 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. * &name[0] is known to be a valid address. */ char* nextelem(char *name, char *elem) { int i, user, c; char *end, *e; if(*name == '/') error(0, Efilename); end = vmemchr(name, 0, NAMELEN); if(end == 0){ end = vmemchr(name, '/', NAMELEN); if(end == 0) error(0, Efilename); }else{ e = memchr(name, '/', end-name); if(e) end = e; } while(name < end){ c = *name++; if((c&0x80) || isfrog[c]) error(0, Ebadchar); *elem++ = c; } *elem = 0; return skipslash(name); } void isdir(Chan *c) { if(c->qid & CHDIR) return; error(0, Enotdir); } . ## diffname gnot/chan.c 1990/0321 ## diff -e /n/bootesdump/1990/03091/sys/src/9/68020/chan.c /n/bootesdump/1990/0321/sys/src/9/68020/chan.c 394c pprint("createdir: changed underfoot?\n"); . 355a nc->mountid = mnt->mountid; . 336c pprint("walk: changed underfoot?\n"); . 289c pprint("domount: changed underfoot?\n"); . 248a } if(islast) pg->nmtab++; . 247c if(mz){ mz->c = old; . 185d 182c islast++; . 177d 175a } . 174c else if(eqchan(mt->c, old, CHDIR|QPATH)){ mz = 0; . 163a if(mnt){ mnt->c = 0; /* caller will close new */ closemount(mnt); } . 160c islast = 0; mnt = 0; . 152c int islast; . ## diffname gnot/chan.c 1990/0603 ## diff -e /n/bootesdump/1990/0321/sys/src/9/68020/chan.c /n/bootesdump/1990/0603/sys/src/9/68020/chan.c 217a else mnt->term = 1; . 215d 210,213c mnt->next = mt->mnt; . 137c incref(nmnt->next); . ## diffname gnot/chan.c 1990/0604 ## diff -e /n/bootesdump/1990/0603/sys/src/9/68020/chan.c /n/bootesdump/1990/0604/sys/src/9/68020/chan.c 130d ## diffname gnot/chan.c 1990/0707 ## diff -e /n/bootesdump/1990/0604/sys/src/9/68020/chan.c /n/bootesdump/1990/0707/sys/src/9/68020/chan.c 74a c->type = 0; /* if closed before changed, this calls rooterror, a nop */ . ## diffname gnot/chan.c 1990/08101 ## diff -e /n/bootesdump/1990/0707/sys/src/9/68020/chan.c /n/bootesdump/1990/08101/sys/src/9/68020/chan.c 450c if(name[1]=='|' || name[1]=='M') . ## diffname gnot/chan.c 1990/08141 ## diff -e /n/bootesdump/1990/08101/sys/src/9/68020/chan.c /n/bootesdump/1990/08141/sys/src/9/68020/chan.c 535a if(omode & OCEXEC) c->flag |= CCEXEC; . 513a if(omode & OCEXEC) c->flag |= CCEXEC; . ## diffname gnot/chan.c 1990/0820 ## diff -e /n/bootesdump/1990/08141/sys/src/9/68020/chan.c /n/bootesdump/1990/0820/sys/src/9/68020/chan.c 558a } if(*name == '.'){ if(((ulong)name&KZERO)==0 && (((ulong)name+1)&(BY2PG-1))==0) validaddr((ulong)name+1, 1, 0); if(name[1]==0 || name[1]=='/'){ name++; goto Again; } . 554a Again: . 529a if(isdot) error(0, Eisdir); . 509,511c if(isdot) c = domount(c); else{ if((nc=walk(c, elem, mntok)) == 0) error(0, Enonexist); c = nc; } . 491,493c if(isdot) c = domount(c); else{ if((nc=walk(c, elem, mntok)) == 0) error(0, Enonexist); c = nc; } . 484a . 471,472c if(mntok && !isdot) if(!(amode==Amount && elem[0]==0)) /* don't domount on slash */ . 463a name = skipslash(name); /* eat leading ./ */ if(*name == 0) isdot = 1; } . 462c }else{ . 439a isdot = 0; . 434c int mntok, isdot; . 343c pprint("walk: changed underfoot? '%s'\n", name); . ## diffname gnot/chan.c 1990/0821 ## diff -e /n/bootesdump/1990/0820/sys/src/9/68020/chan.c /n/bootesdump/1990/0821/sys/src/9/68020/chan.c 615c end = memchr(name, '/', NAMELEN); . 613c end = memchr(name, 0, NAMELEN); . 603d 578,585d 576a if(*name=='.' && (name[1]==0 || name[1]=='/')){ name++; goto Again; . 573,575c while(*name == '/') . 449,450d 438a /* * 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; . 435c char *p; char *elem; . ## diffname gnot/chan.c 1990/0914 ## diff -e /n/bootesdump/1990/0821/sys/src/9/68020/chan.c /n/bootesdump/1990/0914/sys/src/9/68020/chan.c 541a saveregisters(); /* else error() in open has wrong value of c saved */ . 424a void saveregisters(void) { } . 375,376c . 371a if(domnt){ if(waserror()){ print("domount error\n"); if(!first) close(c); return 0; } c = domount(c); poperror(); } . 103a c->flag = CFREE; . 98a if(c->flag & CFREE) panic("close"); . ## diffname gnot/chan.c 1990/09141 ## diff -e /n/bootesdump/1990/0914/sys/src/9/68020/chan.c /n/bootesdump/1990/09141/sys/src/9/68020/chan.c 377d ## diffname gnot/chan.c 1990/1006 ## diff -e /n/bootesdump/1990/09141/sys/src/9/68020/chan.c /n/bootesdump/1990/1006/sys/src/9/68020/chan.c 482c if(name[1]=='M') . ## diffname gnot/chan.c 1990/1104 ## diff -e /n/bootesdump/1990/1006/sys/src/9/68020/chan.c /n/bootesdump/1990/1104/sys/src/9/68020/chan.c 29c return x; . 27c x = --r->ref; . 25a int x; . 20c return x; . 18c x = ++r->ref; . 16a int x; . ## diffname gnot/chan.c 1990/11062 ## diff -e /n/bootesdump/1990/1104/sys/src/9/68020/chan.c /n/bootesdump/1990/11062/sys/src/9/68020/chan.c 82a c->dev = 0; . ## diffname gnot/chan.c 1990/11211 ## diff -e /n/bootesdump/1990/11062/sys/src/9/68020/chan.c /n/bootesdump/1990/11211/sys/src/9/68020/chan.c 667c error(Enotdir); . 665c if(c->qid.path & CHDIR) . 655c error(Ebadchar); . 646c error(Efilename); . 641c error(Efilename); . 583c error(Eisdir); . 577c error(Enonexist); . 560c error(Enonexist); . 551,552c if(!(c->qid.path & CHDIR)) error(Enotdir); . 549c error(Enonexist); . 538c error(Enonexist); . 523c error(Enonexist); . 491c error(Ebadsharp); . 488c error(Enonexist); . 461c error(Enonexist); . 424c error(Enocreate); . 420c error(Enocreate); . 231c error(Enotunion); . 214c error(Enotunion); . 194c error(Enomount); . 162,165c if(CHDIR & (old->qid.path^new->qid.path)) error(Emount); if((old->qid.path&CHDIR)==0 && (flag&MORDER)!=MREPL) error(Emount); . 123a if(!pathonly && a->qid.vers!=b->qid.vers) return 0; . 122c return a.path==b.path && a.vers==b.vers; } int eqchan(Chan *a, Chan *b, int pathonly) { if(a->qid.path != b->qid.path) . 120c eqqid(Qid a, Qid b) . 88c c->mqid = (Qid){0, 0}; . ## diffname gnot/chan.c 1990/1122 ## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/chan.c /n/bootesdump/1990/1122/sys/src/9/68020/chan.c 311c if(!eqchan(mt->c, c, 1)){ /* table changed underfoot */ . 299c if(mt->c && eqchan(mt->c, c, 1)) . 195c else if(eqchan(mt->c, old, 1)){ . ## diffname gnot/chan.c 1990/1210 # deleted ## diff -e /n/bootesdump/1990/1122/sys/src/9/68020/chan.c /n/bootesdump/1990/1210/sys/src/9/68020/chan.c 1,676d