xref: /plan9/sys/src/cmd/vnc/chan.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
1 #include	<u.h>
2 #include	<libc.h>
3 #include	"compat.h"
4 #include	"error.h"
5 
6 Chan*
newchan(void)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
chanfree(Chan * c)27 chanfree(Chan *c)
28 {
29 	c->flag = CFREE;
30 
31 	cnameclose(c->name);
32 	free(c);
33 }
34 
35 void
cclose(Chan * c)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*
cclone(Chan * c)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
isdotdot(char * p)78 isdotdot(char *p)
79 {
80 	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
81 }
82 
83 int
incref(Ref * r)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
decref(Ref * r)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*
newcname(char * s)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
cnameclose(Cname * n)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*
addelem(Cname * n,char * s)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
cleancname(Cname * n)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
isdir(Chan * c)198 isdir(Chan *c)
199 {
200 	if(c->qid.type & QTDIR)
201 		return;
202 	error(Enotdir);
203 }
204