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