📄 chan.c
字号:
#include "u.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "error.h"int chandebug=0; /* toggled by sysr1 */QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */int domount(Chan**, Mhead**);voiddumpmount(void) /* DEBUGGING */{ Pgrp *pg; Mount *t; Mhead **h, **he, *f; if(up == nil){ print("no process for dumpmount\n"); return; } pg = up->pgrp; if(pg == nil){ print("no pgrp for dumpmount\n"); return; } 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) { print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f, f->from->name->s, f->from->qid.path, f->from->qid.vers, devtab[f->from->type]->dc, f->from->dev); for(t = f->mount; t; t = t->next) 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); } } poperror(); runlock(&pg->ns);}char*c2name(Chan *c) /* DEBUGGING */{ if(c == nil) return "<nil chan>"; if(c->name == nil) return "<nil name>"; if(c->name->s == nil) return "<nil name.s>"; return c->name->s;}enum{ CNAMESLOP = 20};struct{ Lock lk; int fid; Chan *free; Chan *list;}chanalloc;typedef struct Elemlist Elemlist;struct Elemlist{ char *name; /* copy of name, so '/' can be overwritten */ int nelems; char **elems; int *off; int mustbedir;};#define SEP(c) ((c) == 0 || (c) == '/')void cleancname(Cname*);intisdotdot(char *p){ return p[0]=='.' && p[1]=='.' && p[2]=='\0';}intincref(Ref *r){ int x; lock(&r->lk); x = ++r->ref; unlock(&r->lk); return x;}intdecref(Ref *r){ int x; lock(&r->lk); x = --r->ref; unlock(&r->lk); if(x < 0) panic("decref, pc=0x%p", getcallerpc(&r)); return x;}/* * Rather than strncpy, which zeros the rest of the buffer, kstrcpy * truncates if necessary, always zero terminates, does not zero fill, * and puts ... at the end of the string if it's too long. Usually used to * save a string in up->genbuf; */voidkstrcpy(char *s, char *t, int ns){ int nt; nt = strlen(t); if(nt+1 <= ns){ memmove(s, t, nt+1); return; } /* too long */ if(ns < 4){ /* but very short! */ strncpy(s, t, ns); return; } /* truncate with ... at character boundary (very rare case) */ memmove(s, t, ns-4); ns -= 4; s[ns] = '\0'; /* look for first byte of UTF-8 sequence by skipping continuation bytes */ while(ns>0 && (s[--ns]&0xC0)==0x80) ; strcpy(s+ns, "...");}intemptystr(char *s){ if(s == nil) return 1; if(s[0] == '\0') return 1; return 0;}/* * Atomically replace *p with copy of s */voidkstrdup(char **p, char *s){ int n; char *t, *prev; n = strlen(s)+1; /* if it's a user, we can wait for memory; if not, something's very wrong */ if(up){ t = smalloc(n); setmalloctag(t, getcallerpc(&p)); }else{ t = malloc(n); if(t == nil) panic("kstrdup: no memory"); } memmove(t, s, n); prev = *p; *p = t; free(prev);}voidchandevreset(void){ int i; for(i=0; devtab[i] != nil; i++) devtab[i]->reset();}voidchandevinit(void){ int i; for(i=0; devtab[i] != nil; i++) devtab[i]->init();}voidchandevshutdown(void){ int i; /* shutdown in reverse order */ for(i=0; devtab[i] != nil; i++) ; for(i--; i >= 0; i--) devtab[i]->shutdown();}Chan*newchan(void){ Chan *c; lock(&chanalloc.lk); c = chanalloc.free; if(c != 0) chanalloc.free = c->next; unlock(&chanalloc.lk); if(c == nil) { c = smalloc(sizeof(Chan)); lock(&chanalloc.lk); c->fid = ++chanalloc.fid; c->link = chanalloc.list; chanalloc.list = c; unlock(&chanalloc.lk); } /* if you get an error before associating with a dev, close calls rootclose, a nop */ c->type = 0; c->flag = 0; c->ref.ref = 1; c->dev = 0; c->offset = 0; c->iounit = 0; c->umh = 0; c->uri = 0; c->dri = 0; c->aux = 0; c->mchan = 0; c->mcp = 0; c->mux = 0; memset(&c->mqid, 0, sizeof(c->mqid)); c->name = 0; return c;}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.ref = 1; incref(&ncname); return n;}voidcnameclose(Cname *n){ if(n == nil) return; if(decref(&n->ref)) return; decref(&ncname); free(n->s); free(n);}Cname*addelem(Cname *n, char *s){ int i, a; char *t; Cname *new; if(s[0]=='.' && s[1]=='\0') return n; if(n->ref.ref > 1){ /* copy on write */ new = newcname(n->s); cnameclose(n); n = new; } i = strlen(s); if(n->len+1+i+1 > n->alen){ 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; } if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */ n->s[n->len++] = '/'; memmove(n->s+n->len, s, i+1); n->len += i; if(isdotdot(s)) cleancname(n); return n;}voidchanfree(Chan *c){ c->flag = CFREE; if(c->umh != nil){ putmhead(c->umh); c->umh = nil; } if(c->umc != nil){ cclose(c->umc); c->umc = nil; } if(c->mux != nil){ muxclose(c->mux); c->mux = nil; } if(c->mchan != nil){ cclose(c->mchan); c->mchan = nil; } cnameclose(c->name); lock(&chanalloc.lk); c->next = chanalloc.free; chanalloc.free = c; unlock(&chanalloc.lk);}voidcclose(Chan *c){ if(c->flag&CFREE) panic("cclose %p", getcallerpc(&c)); if(decref(&c->ref)) return; if(!waserror()){ devtab[c->type]->close(c); poperror(); } chanfree(c);}/* * Make sure we have the only copy of c. (Copy on write.) */Chan*cunique(Chan *c){ Chan *nc; if(c->ref.ref != 1) { nc = cclone(c); cclose(c); c = nc; } return c;}inteqqid(Qid a, Qid b){ return a.path==b.path && a.vers==b.vers;}inteqchan(Chan *a, Chan *b, int pathonly){ if(a->qid.path != b->qid.path) return 0; if(!pathonly && a->qid.vers!=b->qid.vers) return 0; if(a->type != b->type) return 0; if(a->dev != b->dev) return 0; return 1;}inteqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly){ if(a->qid.path != qid.path) return 0; if(!pathonly && a->qid.vers!=qid.vers) return 0; if(a->type != type) return 0; if(a->dev != dev) return 0; return 1;}Mhead*newmhead(Chan *from){ Mhead *mh; mh = smalloc(sizeof(Mhead)); mh->ref.ref = 1; mh->from = from; incref(&from->ref);/* n = from->name->len; if(n >= sizeof(mh->fromname)) n = sizeof(mh->fromname)-1; memmove(mh->fromname, from->name->s, n); mh->fromname[n] = 0;*/ return mh;}intcmount(Chan **newp, Chan *old, int flag, char *spec){ Pgrp *pg; int order, flg; Mhead *m, **l, *mh; Mount *nm, *f, *um, **h; Chan *new; if(QTDIR & (old->qid.type^(*newp)->qid.type)) error(Emount);if(old->umh)print("cmount old extra umh\n"); order = flag&MORDER; if((old->qid.type&QTDIR)==0 && order != MREPL) error(Emount); new = *newp; mh = new->umh; /* * Not allowed to bind when the old directory * is itself a union. (Maybe it should be allowed, but I don't see * what the semantics would be.) * * We need to check mh->mount->next to tell unions apart from * simple mount points, so that things like * mount -c fd /root * bind -c /root / * work. The check of mount->mflag catches things like * mount fd /root * bind -c /root / * * This is far more complicated than it should be, but I don't * see an easier way at the moment. -rsc */ if((flag&MCREATE) && mh && mh->mount && (mh->mount->next || !(mh->mount->mflag&MCREATE))) error(Emount); pg = up->pgrp; wlock(&pg->ns); l = &MOUNTH(pg, old->qid); for(m = *l; m; m = m->hash) { if(eqchan(m->from, old, 1)) break; l = &m->hash; } if(m == nil) { /* * nothing mounted here yet. create a mount * head and add to the hash table. */ m = newmhead(old); *l = m; /* * if this is a union mount, add the old * node to the mount chain. */ if(order != MREPL) m->mount = newmount(m, old, 0, 0); } wlock(&m->lock); if(waserror()){ wunlock(&m->lock); nexterror(); } wunlock(&pg->ns); nm = newmount(m, new, flag, spec); if(mh != nil && mh->mount != nil) { /* * copy a union when binding it onto a directory */ flg = order; if(order == MREPL) flg = MAFTER; h = &nm->next; um = mh->mount; for(um = um->next; um; um = um->next) { f = newmount(m, um->to, flg, um->spec); *h = f; h = &f->next; } } if(m->mount && order == MREPL) { mountfree(m->mount); m->mount = 0; } if(flag & MCREATE) nm->mflag |= MCREATE; if(m->mount && order == MAFTER) { for(f = m->mount; f->next; f = f->next) ; f->next = nm; } else { for(f = nm; f->next; f = f->next) ; f->next = m->mount; m->mount = nm; } wunlock(&m->lock); poperror(); return nm->mountid;}voidcunmount(Chan *mnt, Chan *mounted){ Pgrp *pg; Mhead *m, **l; Mount *f, **p; if(mnt->umh) /* should not happen */ print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh); /* * It _can_ happen that mounted->umh is non-nil, * because mounted is the result of namec(Aopen) * (see sysfile.c:/^sysunmount). * If we open a union directory, it will have a umh. * Although surprising, this is okay, since the * cclose will take care of freeing the umh. */ pg = up->pgrp; wlock(&pg->ns); l = &MOUNTH(pg, mnt->qid); for(m = *l; m; m = m->hash) { if(eqchan(m->from, mnt, 1)) break; l = &m->hash; } if(m == 0) { wunlock(&pg->ns); error(Eunmount); } wlock(&m->lock); if(mounted == 0) { *l = m->hash; wunlock(&pg->ns); mountfree(m->mount); m->mount = nil; cclose(m->from); wunlock(&m->lock); putmhead(m); return; } p = &m->mount; for(f = *p; f; f = f->next) { /* BUG: Needs to be 2 pass */ if(eqchan(f->to, mounted, 1) || (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) { *p = f->next; f->next = 0; mountfree(f); if(m->mount == nil) { *l = m->hash; cclose(m->from); wunlock(&m->lock); wunlock(&pg->ns); putmhead(m); return; } wunlock(&m->lock); wunlock(&pg->ns); return; } p = &f->next; } wunlock(&m->lock); wunlock(&pg->ns); error(Eunion);}Chan*cclone(Chan *c){ Chan *nc; Walkqid *wq; wq = devtab[c->type]->walk(c, nil, nil, 0); if(wq == nil) error("clone failed"); nc = wq->clone; free(wq); nc->name = c->name; if(c->name) incref(&c->name->ref); return nc;}intfindmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid){ Pgrp *pg; Mhead *m; pg = up->pgrp; rlock(&pg->ns); for(m = MOUNTH(pg, qid); m; m = m->hash){ rlock(&m->lock);if(m->from == nil){ print("m %p m->from 0\n", m); runlock(&m->lock); continue;} if(eqchantdqid(m->from, type, dev, qid, 1)) { runlock(&pg->ns); if(mp != nil){ incref(&m->ref); if(*mp != nil) putmhead(*mp); *mp = m; } if(*cp != nil) cclose(*cp); incref(&m->mount->to->ref); *cp = m->mount->to; runlock(&m->lock); return 1; } runlock(&m->lock); } runlock(&pg->ns); return 0;}intdomount(Chan **cp, Mhead **mp){ return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid);}Chan*undomount(Chan *c, Cname *name){ Chan *nc; Pgrp *pg; Mount *t; Mhead **h, **he, *f; 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) { if(strcmp(f->from->name->s, name->s) != 0) continue; for(t = f->mount; t; t = t->next) { if(eqchan(c, t->to, 1)) { /* * 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, name->s) != 0) continue; nc = t->head->from; incref(&nc->ref); cclose(c); c = nc; break; } } } } poperror(); runlock(&pg->ns); return c;}/* * Either walks all the way or not at all. No partial results in *cp. * *nerror is the number of names to display in an error message. */static char Edoesnotexist[] = "does not exist";intwalk(Chan **cp, char **names, int nnames, int nomount, int *nerror){ int dev, dotdot, i, n, nhave, ntry, type; Chan *c, *nc; Cname *cname; Mount *f; Mhead *mh, *nmh; Walkqid *wq; c = *cp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -