#include #include #include "compat.h" #include "error.h" Chan* newchan(void) { Chan *c; c = smalloc(sizeof(Chan)); /* 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; c->iounit = 0; c->aux = 0; c->name = 0; return c; } void chanfree(Chan *c) { c->flag = CFREE; cnameclose(c->name); free(c); } void cclose(Chan *c) { if(c->flag&CFREE) panic("cclose %#p", getcallerpc(&c)); if(decref(c)) return; if(!waserror()){ devtab[c->type]->close(c); poperror(); } chanfree(c); } 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); return nc; } enum { CNAMESLOP = 20 }; static Ref ncname; void cleancname(Cname*); int isdotdot(char *p) { return p[0]=='.' && p[1]=='.' && p[2]=='\0'; } int incref(Ref *r) { int x; lock(r); x = ++r->ref; unlock(r); return x; } int decref(Ref *r) { int x; lock(r); x = --r->ref; unlock(r); if(x < 0) panic("decref"); return x; } 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; } void cnameclose(Cname *n) { if(n == nil) 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(s[0]=='.' && s[1]=='\0') return n; if(n->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; } /* * In place, rewrite name to compress multiple /, eliminate ., and process .. */ void cleancname(Cname *n) { char *p; if(n->s[0] == '#'){ p = strchr(n->s, '/'); if(p == nil) return; cleanname(p); /* * 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); } void isdir(Chan *c) { if(c->qid.type & QTDIR) return; error(Enotdir); }