#include "u.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "error.h" enum{ PATHSLOP = 20, PATHMSLOP = 20,}; static struct Chanalloc{ 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;}; 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';} 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 < ns){ memmove(s, t, nt); s[nt] = '\0'; return; } /* too long, truncate */ nt = ns-1; memmove(s, t, nt); s[nt] = '\0'; /* append ... if there is space */ ns -= 4; if(ns < 0) return; /* 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); /* if it's a user, we can wait for memory; if not, something's very wrong */ if(up != nil) t = smalloc(n+1); else{ t = malloc(n+1); if(t == nil) panic("kstrdup: no memory"); } setmalloctag(t, getcallerpc(&p)); memmove(t, s, n); t[n] = '\0'; 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 != nil){ chanalloc.free = c->next; c->next = nil; } else { unlock(&chanalloc.lk); c = smalloc(sizeof(Chan)); lock(&chanalloc.lk); c->link = chanalloc.list; chanalloc.list = c; } if(c->fid == 0) c->fid = ++chanalloc.fid; 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 = nil; c->umc = nil; c->uri = 0; c->dri = 0; c->dirrock = nil; c->nrock = 0; c->mrock = 0; c->ismtpt = 0; c->mux = nil; c->aux = nil; c->mchan = nil; memset(&c->mqid, 0, sizeof(c->mqid)); c->path = nil; return c;} 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; /* * 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, '/') != nil && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0) print("newpath: %s from %#p\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; 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] != nil) incref(&pp->mtpt[i]->ref); } return pp;} voidpathclose(Path *p){ int i; if(p == nil || decref(&p->ref)) return; for(i=0; i<p->mlen; i++) if(p->mtpt[i] != nil) cclose(p->mtpt[i]); free(p->mtpt); free(p->s); 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); a = p->len+1+i+1; if(a > p->alen){ a += 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); if(p->mlen > 1 && (c = p->mtpt[--p->mlen]) != nil){ 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; } p->mtpt[p->mlen++] = from; if(from != nil) incref(&from->ref); } return p;} voidchanfree(Chan *c){ c->flag = CFREE; if(c->dirrock != nil){ free(c->dirrock); c->dirrock = nil; 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 == nil || c->ref.ref < 1 || 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; } if(c->umh != nil){ //BUG print("cunique umh != nil from %#p\n", getcallerpc(&c)); putmhead(c->umh); c->umh = nil; } 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; if(a->dev != b->dev) return 0; return 1;} inteqchantdqid(Chan *a, int type, int dev, Qid qid, int skipvers){ if(a->qid.path != qid.path) return 0; if(!skipvers && 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); return mh;} /* * This is necessary because there are manyLines 1–500 of 1634. Load more
#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" enum { PATHSLOP = 20, PATHMSLOP = 20, }; static struct Chanalloc { 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; }; 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; } int isdotdot(char *p) { return p[0]=='.' && p[1]=='.' && p[2]=='\0'; } int incref(Ref *r) { int x; lock(&r->lk); x = ++r->ref; unlock(&r->lk); return x; } int decref(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; */ void kstrcpy(char *s, char *t, int ns) { int nt; nt = strlen(t); if(nt < ns){ memmove(s, t, nt); s[nt] = '\0'; return; } /* too long, truncate */ nt = ns-1; memmove(s, t, nt); s[nt] = '\0'; /* append ... if there is space */ ns -= 4; if(ns < 0) return; /* look for first byte of UTF-8 sequence by skipping continuation bytes */ while(ns>0 && (s[--ns]&0xC0)==0x80) ; strcpy(s+ns, "..."); } int emptystr(char *s) { if(s == nil) return 1; if(s[0] == '\0') return 1; return 0; } /* * Atomically replace *p with copy of s */ void kstrdup(char **p, char *s) { int n; char *t, *prev; n = strlen(s); /* if it's a user, we can wait for memory; if not, something's very wrong */ if(up != nil) t = smalloc(n+1); else{ t = malloc(n+1); if(t == nil) panic("kstrdup: no memory"); } setmalloctag(t, getcallerpc(&p)); memmove(t, s, n); t[n] = '\0'; prev = *p; *p = t; free(prev); } void chandevreset(void) { int i; for(i=0; devtab[i] != nil; i++) devtab[i]->reset(); } void chandevinit(void) { int i; for(i=0; devtab[i] != nil; i++) devtab[i]->init(); } void chandevshutdown(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 != nil){ chanalloc.free = c->next; c->next = nil; } else { unlock(&chanalloc.lk); c = smalloc(sizeof(Chan)); lock(&chanalloc.lk); c->link = chanalloc.list; chanalloc.list = c; } if(c->fid == 0) c->fid = ++chanalloc.fid; 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 = nil; c->umc = nil; c->uri = 0; c->dri = 0; c->dirrock = nil; c->nrock = 0; c->mrock = 0; c->ismtpt = 0; c->mux = nil; c->aux = nil; c->mchan = nil; memset(&c->mqid, 0, sizeof(c->mqid)); c->path = nil; return c; } 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; /* * 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, '/') != nil && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0) print("newpath: %s from %#p\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; 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] != nil) incref(&pp->mtpt[i]->ref); } return pp; } void pathclose(Path *p) { int i; if(p == nil || decref(&p->ref)) return; for(i=0; i<p->mlen; i++) if(p->mtpt[i] != nil) cclose(p->mtpt[i]); free(p->mtpt); free(p->s); 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 void fixdotdotname(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); a = p->len+1+i+1; if(a > p->alen){ a += 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); if(p->mlen > 1 && (c = p->mtpt[--p->mlen]) != nil){ 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; } p->mtpt[p->mlen++] = from; if(from != nil) incref(&from->ref); } return p; } void chanfree(Chan *c) { c->flag = CFREE; if(c->dirrock != nil){ free(c->dirrock); c->dirrock = nil; 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); } void cclose(Chan *c) { if(c == nil || c->ref.ref < 1 || 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; } if(c->umh != nil){ //BUG print("cunique umh != nil from %#p\n", getcallerpc(&c)); putmhead(c->umh); c->umh = nil; } return c; } int eqqid(Qid a, Qid b) { return a.path==b.path && a.vers==b.vers; } int eqchan(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; if(a->dev != b->dev) return 0; return 1; } int eqchantdqid(Chan *a, int type, int dev, Qid qid, int skipvers) { if(a->qid.path != qid.path) return 0; if(!skipvers && 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); return mh; } /* * This is necessary because there are many