]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/chan.c
vnc/devdraw: fix topnwindows() panic when images are not windows (thanks aiju)
[plan9front.git] / sys / src / cmd / vnc / chan.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        "compat.h"
4 #include        "error.h"
5
6 Chan*
7 newchan(void)
8 {
9         Chan *c;
10
11         c = smalloc(sizeof(Chan));
12
13         /* if you get an error before associating with a dev,
14            close calls rootclose, a nop */
15         c->type = 0;
16         c->flag = 0;
17         c->ref = 1;
18         c->dev = 0;
19         c->offset = 0;
20         c->iounit = 0;
21         c->aux = 0;
22         c->name = 0;
23         return c;
24 }
25
26 void
27 chanfree(Chan *c)
28 {
29         c->flag = CFREE;
30
31         cnameclose(c->name);
32         free(c);
33 }
34
35 void
36 cclose(Chan *c)
37 {
38         if(c->flag&CFREE)
39                 panic("cclose %#p", getcallerpc(&c));
40         if(decref(c))
41                 return;
42
43         if(!waserror()){
44                 devtab[c->type]->close(c);
45                 poperror();
46         }
47
48         chanfree(c);
49 }
50
51 Chan*
52 cclone(Chan *c)
53 {
54         Chan *nc;
55         Walkqid *wq;
56
57         wq = devtab[c->type]->walk(c, nil, nil, 0);
58         if(wq == nil)
59                 error("clone failed");
60         nc = wq->clone;
61         free(wq);
62         nc->name = c->name;
63         if(c->name)
64                 incref(c->name);
65         return nc;
66 }
67
68 enum
69 {
70         CNAMESLOP       = 20
71 };
72
73 static Ref ncname;
74
75 void cleancname(Cname*);
76
77 int
78 isdotdot(char *p)
79 {
80         return p[0]=='.' && p[1]=='.' && p[2]=='\0';
81 }
82
83 int
84 incref(Ref *r)
85 {
86         int x;
87
88         lock(r);
89         x = ++r->ref;
90         unlock(r);
91         return x;
92 }
93
94 int
95 decref(Ref *r)
96 {
97         int x;
98
99         lock(r);
100         x = --r->ref;
101         unlock(r);
102         if(x < 0)
103                 panic("decref");
104
105         return x;
106 }
107
108 Cname*
109 newcname(char *s)
110 {
111         Cname *n;
112         int i;
113
114         n = smalloc(sizeof(Cname));
115         i = strlen(s);
116         n->len = i;
117         n->alen = i+CNAMESLOP;
118         n->s = smalloc(n->alen);
119         memmove(n->s, s, i+1);
120         n->ref = 1;
121         incref(&ncname);
122         return n;
123 }
124
125 void
126 cnameclose(Cname *n)
127 {
128         if(n == nil)
129                 return;
130         if(decref(n))
131                 return;
132         decref(&ncname);
133         free(n->s);
134         free(n);
135 }
136
137 Cname*
138 addelem(Cname *n, char *s)
139 {
140         int i, a;
141         char *t;
142         Cname *new;
143
144         if(s[0]=='.' && s[1]=='\0')
145                 return n;
146
147         if(n->ref > 1){
148                 /* copy on write */
149                 new = newcname(n->s);
150                 cnameclose(n);
151                 n = new;
152         }
153
154         i = strlen(s);
155         if(n->len+1+i+1 > n->alen){
156                 a = n->len+1+i+1 + CNAMESLOP;
157                 t = smalloc(a);
158                 memmove(t, n->s, n->len+1);
159                 free(n->s);
160                 n->s = t;
161                 n->alen = a;
162         }
163         if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/')        /* don't insert extra slash if one is present */
164                 n->s[n->len++] = '/';
165         memmove(n->s+n->len, s, i+1);
166         n->len += i;
167         if(isdotdot(s))
168                 cleancname(n);
169         return n;
170 }
171
172 /*
173  * In place, rewrite name to compress multiple /, eliminate ., and process ..
174  */
175 void
176 cleancname(Cname *n)
177 {
178         char *p;
179
180         if(n->s[0] == '#'){
181                 p = strchr(n->s, '/');
182                 if(p == nil)
183                         return;
184                 cleanname(p);
185
186                 /*
187                  * The correct name is #i rather than #i/,
188                  * but the correct name of #/ is #/.
189                  */
190                 if(strcmp(p, "/")==0 && n->s[1] != '/')
191                         *p = '\0';
192         }else
193                 cleanname(n->s);
194         n->len = strlen(n->s);
195 }
196
197 void
198 isdir(Chan *c)
199 {
200         if(c->qid.type & QTDIR)
201                 return;
202         error(Enotdir);
203 }