summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vnc/chan.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/vnc/chan.c203
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);
+}