diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/vnc/chan.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/vnc/chan.c')
-rwxr-xr-x | sys/src/cmd/vnc/chan.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/sys/src/cmd/vnc/chan.c b/sys/src/cmd/vnc/chan.c new file mode 100755 index 000000000..14bcdf390 --- /dev/null +++ b/sys/src/cmd/vnc/chan.c @@ -0,0 +1,203 @@ +#include <u.h> +#include <libc.h> +#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); +} |