📄 chan.c
字号:
#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h"int chandebug=0; /* toggled by sysr1 */#define DBG if(chandebug)iprintenum{ PATHSLOP = 20, PATHMSLOP = 20,};struct{ Lock lk; int fid; Chan *free; Chan *list;}chanalloc;typedef struct Elemlist Elemlist;struct Elemlist{ char *aname; /* original name */ char *name; /* copy of name, so '/' can be overwritten */ int nelems; char **elems; int *off; int mustbedir; int nerror; int prefix;};#define SEP(c) ((c) == 0 || (c) == '/')/*static*/ 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->path->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->path->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev); } } poperror(); runlock(&pg->ns);}char*chanpath(Chan *c){ if(c == nil) return "<nil chan>"; if(c->path == nil) return "<nil path>"; if(c->path->s == nil) return "<nil path.s>"; return c->path->s;}intisdotdot(char *p){ return p[0]=='.' && p[1]=='.' && p[2]=='\0';}longincref(Ref *r){ long x; lock(&r->lk); x = ++r->ref; unlock(&r->lk); return x;}longdecref(Ref *r){ long x; lock(&r->lk); x = --r->ref; unlock(&r->lk); if(x < 0) panic("decref pc=0x%lux", 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->devoffset = 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->path = 0; c->ismtpt = 0; return c;}Ref npath;Path*newpath(char *s){ int i; Path *p; p = smalloc(sizeof(Path)); i = strlen(s); p->len = i; p->alen = i+PATHSLOP; p->s = smalloc(p->alen); memmove(p->s, s, i+1); p->ref.ref = 1; incref(&npath); /* * Cannot use newpath for arbitrary names because the mtpt * array will not be populated correctly. The names #/ and / are * allowed, but other names with / in them draw warnings. */ if(strchr(s, '/') && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0) print("newpath: %s from %lux\n", s, getcallerpc(&s)); p->mlen = 1; p->malen = PATHMSLOP; p->mtpt = smalloc(p->malen*sizeof p->mtpt[0]); return p;}static Path*copypath(Path *p){ int i; Path *pp; pp = smalloc(sizeof(Path)); pp->ref.ref = 1; incref(&npath); DBG("copypath %s %p => %p\n", p->s, p, pp); pp->len = p->len; pp->alen = p->alen; pp->s = smalloc(p->alen); memmove(pp->s, p->s, p->len+1); pp->mlen = p->mlen; pp->malen = p->malen; pp->mtpt = smalloc(p->malen*sizeof pp->mtpt[0]); for(i=0; i<pp->mlen; i++){ pp->mtpt[i] = p->mtpt[i]; if(pp->mtpt[i]) incref(&pp->mtpt[i]->ref); } return pp;}voidpathclose(Path *p){ int i; if(p == nil) return;//XXX DBG("pathclose %p %s ref=%ld =>", p, p->s, p->ref.ref); for(i=0; i<p->mlen; i++) DBG(" %p", p->mtpt[i]); DBG("\n"); if(decref(&p->ref)) return; decref(&npath); free(p->s); for(i=0; i<p->mlen; i++) if(p->mtpt[i]) cclose(p->mtpt[i]); free(p->mtpt); free(p);}/* * In place, rewrite name to compress multiple /, eliminate ., and process .. * (Really only called to remove a trailing .. that has been added. * Otherwise would need to update n->mtpt as well.) */static voidfixdotdotname(Path *p){ char *r; if(p->s[0] == '#'){ r = strchr(p->s, '/'); if(r == nil) return; cleanname(r); /* * The correct name is #i rather than #i/, * but the correct name of #/ is #/. */ if(strcmp(r, "/")==0 && p->s[1] != '/') *r = '\0'; }else cleanname(p->s); p->len = strlen(p->s);}static Path*uniquepath(Path *p){ Path *new; if(p->ref.ref > 1){ /* copy on write */ new = copypath(p); pathclose(p); p = new; } return p;}/*static*/ Path*addelem(Path *p, char *s, Chan *from){ char *t; int a, i; Chan *c, **tt; if(s[0]=='.' && s[1]=='\0') return p; p = uniquepath(p); i = strlen(s); if(p->len+1+i+1 > p->alen){ a = p->len+1+i+1 + PATHSLOP; t = smalloc(a); memmove(t, p->s, p->len+1); free(p->s); p->s = t; p->alen = a; } /* don't insert extra slash if one is present */ if(p->len>0 && p->s[p->len-1]!='/' && s[0]!='/') p->s[p->len++] = '/'; memmove(p->s+p->len, s, i+1); p->len += i; if(isdotdot(s)){ fixdotdotname(p); DBG("addelem %s .. => rm %p\n", p->s, p->mtpt[p->mlen-1]); if(p->mlen>1 && (c = p->mtpt[--p->mlen])){ p->mtpt[p->mlen] = nil; cclose(c); } }else{ if(p->mlen >= p->malen){ p->malen = p->mlen+1+PATHMSLOP; tt = smalloc(p->malen*sizeof tt[0]); memmove(tt, p->mtpt, p->mlen*sizeof tt[0]); free(p->mtpt); p->mtpt = tt; } DBG("addelem %s %s => add %p\n", p->s, s, from); p->mtpt[p->mlen++] = from; if(from) incref(&from->ref); } return p;}voidchanfree(Chan *c){ c->flag = CFREE; if(c->dirrock != nil){ free(c->dirrock); c->dirrock = 0; c->nrock = 0; c->mrock = 0; } 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; } pathclose(c->path); c->path = nil; lock(&chanalloc.lk); c->next = chanalloc.free; chanalloc.free = c; unlock(&chanalloc.lk);}voidcclose(Chan *c){ if(c->flag&CFREE) panic("cclose %lux", getcallerpc(&c)); DBG("cclose %p name=%s ref=%ld\n", c, c->path->s, c->ref.ref); if(decref(&c->ref)) return; if(!waserror()){ devtab[c->type]->close(c); poperror(); } chanfree(c);}/* * Queue a chan to be closed by one of the clunk procs. */struct { Chan *head; Chan *tail; int nqueued; int nclosed; Lock l; QLock q; Rendez r;} clunkq;void closeproc(void*);voidccloseq(Chan *c){ if(c->flag&CFREE) panic("cclose %lux", getcallerpc(&c)); DBG("ccloseq %p name=%s ref=%ld\n", c, c->path->s, c->ref.ref); if(decref(&c->ref)) return; lock(&clunkq.l); clunkq.nqueued++; c->next = nil; if(clunkq.head) clunkq.tail->next = c; else clunkq.head = c; clunkq.tail = c; unlock(&clunkq.l); if(!wakeup(&clunkq.r)) kproc("closeproc", closeproc, nil); }static intclunkwork(void *v){ return clunkq.head != nil;}voidcloseproc(void *v){ Chan *c; for(;;){ qlock(&clunkq.q); if(clunkq.head == nil){ if(!waserror()){ tsleep(&clunkq.r, clunkwork, nil, 5000); poperror(); } if(clunkq.head == nil){ qunlock(&clunkq.q); pexit("no work", 1); } } lock(&clunkq.l); c = clunkq.head; clunkq.head = c->next; clunkq.nclosed++; unlock(&clunkq.l); qunlock(&clunkq.q); 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 skipvers){ if(a->qid.path != b->qid.path) return 0; if(!skipvers && a->qid.vers!=b->qid.vers) return 0; if(a->type != b->type) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -