convM2S.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
convM2S.c (5598B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <fcall.h> | |
4 | |
5 static | |
6 uchar* | |
7 gstring(uchar *p, uchar *ep, char **s) | |
8 { | |
9 uint n; | |
10 | |
11 if(p+BIT16SZ > ep) | |
12 return nil; | |
13 n = GBIT16(p); | |
14 p += BIT16SZ - 1; | |
15 if(p+n+1 > ep) | |
16 return nil; | |
17 /* move it down, on top of count, to make room for '\0' */ | |
18 memmove(p, p + 1, n); | |
19 p[n] = '\0'; | |
20 *s = (char*)p; | |
21 p += n+1; | |
22 return p; | |
23 } | |
24 | |
25 static | |
26 uchar* | |
27 gqid(uchar *p, uchar *ep, Qid *q) | |
28 { | |
29 if(p+QIDSZ > ep) | |
30 return nil; | |
31 q->type = GBIT8(p); | |
32 p += BIT8SZ; | |
33 q->vers = GBIT32(p); | |
34 p += BIT32SZ; | |
35 q->path = GBIT64(p); | |
36 p += BIT64SZ; | |
37 return p; | |
38 } | |
39 | |
40 /* | |
41 * no syntactic checks. | |
42 * three causes for error: | |
43 * 1. message size field is incorrect | |
44 * 2. input buffer too short for its own data (counts too long, etc.) | |
45 * 3. too many names or qids | |
46 * gqid() and gstring() return nil if they would reach beyond buffer. | |
47 * main switch statement checks range and also can fall through | |
48 * to test at end of routine. | |
49 */ | |
50 uint | |
51 convM2Su(uchar *ap, uint nap, Fcall *f, int dotu) | |
52 { | |
53 uchar *p, *ep; | |
54 uint i, size; | |
55 | |
56 p = ap; | |
57 ep = p + nap; | |
58 | |
59 if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) | |
60 return 0; | |
61 size = GBIT32(p); | |
62 p += BIT32SZ; | |
63 | |
64 if(size < BIT32SZ+BIT8SZ+BIT16SZ) | |
65 return 0; | |
66 | |
67 f->type = GBIT8(p); | |
68 p += BIT8SZ; | |
69 f->tag = GBIT16(p); | |
70 p += BIT16SZ; | |
71 | |
72 switch(f->type) | |
73 { | |
74 default: | |
75 return 0; | |
76 | |
77 case Tversion: | |
78 if(p+BIT32SZ > ep) | |
79 return 0; | |
80 f->msize = GBIT32(p); | |
81 p += BIT32SZ; | |
82 p = gstring(p, ep, &f->version); | |
83 break; | |
84 | |
85 case Tflush: | |
86 if(p+BIT16SZ > ep) | |
87 return 0; | |
88 f->oldtag = GBIT16(p); | |
89 p += BIT16SZ; | |
90 break; | |
91 | |
92 case Tauth: | |
93 if(p+BIT32SZ > ep) | |
94 return 0; | |
95 f->afid = GBIT32(p); | |
96 p += BIT32SZ; | |
97 p = gstring(p, ep, &f->uname); | |
98 if(p == nil) | |
99 break; | |
100 p = gstring(p, ep, &f->aname); | |
101 if(p == nil) | |
102 break; | |
103 f->uidnum = NOUID; | |
104 if(dotu){ | |
105 if(p+BIT32SZ > ep) | |
106 return 0; | |
107 f->uidnum = GBIT32(p); | |
108 p += BIT32SZ; | |
109 } | |
110 break; | |
111 | |
112 case Tattach: | |
113 if(p+BIT32SZ > ep) | |
114 return 0; | |
115 f->fid = GBIT32(p); | |
116 p += BIT32SZ; | |
117 if(p+BIT32SZ > ep) | |
118 return 0; | |
119 f->afid = GBIT32(p); | |
120 p += BIT32SZ; | |
121 p = gstring(p, ep, &f->uname); | |
122 if(p == nil) | |
123 break; | |
124 p = gstring(p, ep, &f->aname); | |
125 if(p == nil) | |
126 break; | |
127 f->uidnum = NOUID; | |
128 if(dotu){ | |
129 if(p+BIT32SZ > ep) | |
130 return 0; | |
131 f->uidnum = GBIT32(p); | |
132 p += BIT32SZ; | |
133 } | |
134 break; | |
135 | |
136 case Twalk: | |
137 if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) | |
138 return 0; | |
139 f->fid = GBIT32(p); | |
140 p += BIT32SZ; | |
141 f->newfid = GBIT32(p); | |
142 p += BIT32SZ; | |
143 f->nwname = GBIT16(p); | |
144 p += BIT16SZ; | |
145 if(f->nwname > MAXWELEM) | |
146 return 0; | |
147 for(i=0; i<f->nwname; i++){ | |
148 p = gstring(p, ep, &f->wname[i]); | |
149 if(p == nil) | |
150 break; | |
151 } | |
152 break; | |
153 | |
154 case Topen: | |
155 case Topenfd: | |
156 if(p+BIT32SZ+BIT8SZ > ep) | |
157 return 0; | |
158 f->fid = GBIT32(p); | |
159 p += BIT32SZ; | |
160 f->mode = GBIT8(p); | |
161 p += BIT8SZ; | |
162 break; | |
163 | |
164 case Tcreate: | |
165 if(p+BIT32SZ > ep) | |
166 return 0; | |
167 f->fid = GBIT32(p); | |
168 p += BIT32SZ; | |
169 p = gstring(p, ep, &f->name); | |
170 if(p == nil) | |
171 break; | |
172 if(p+BIT32SZ+BIT8SZ > ep) | |
173 return 0; | |
174 f->perm = GBIT32(p); | |
175 p += BIT32SZ; | |
176 f->mode = GBIT8(p); | |
177 p += BIT8SZ; | |
178 if(dotu) | |
179 p = gstring(p, ep, &f->extension); | |
180 break; | |
181 | |
182 case Tread: | |
183 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) | |
184 return 0; | |
185 f->fid = GBIT32(p); | |
186 p += BIT32SZ; | |
187 f->offset = GBIT64(p); | |
188 p += BIT64SZ; | |
189 f->count = GBIT32(p); | |
190 p += BIT32SZ; | |
191 break; | |
192 | |
193 case Twrite: | |
194 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) | |
195 return 0; | |
196 f->fid = GBIT32(p); | |
197 p += BIT32SZ; | |
198 f->offset = GBIT64(p); | |
199 p += BIT64SZ; | |
200 f->count = GBIT32(p); | |
201 p += BIT32SZ; | |
202 if(p+f->count > ep) | |
203 return 0; | |
204 f->data = (char*)p; | |
205 p += f->count; | |
206 break; | |
207 | |
208 case Tclunk: | |
209 case Tremove: | |
210 if(p+BIT32SZ > ep) | |
211 return 0; | |
212 f->fid = GBIT32(p); | |
213 p += BIT32SZ; | |
214 break; | |
215 | |
216 case Tstat: | |
217 if(p+BIT32SZ > ep) | |
218 return 0; | |
219 f->fid = GBIT32(p); | |
220 p += BIT32SZ; | |
221 break; | |
222 | |
223 case Twstat: | |
224 if(p+BIT32SZ+BIT16SZ > ep) | |
225 return 0; | |
226 f->fid = GBIT32(p); | |
227 p += BIT32SZ; | |
228 f->nstat = GBIT16(p); | |
229 p += BIT16SZ; | |
230 if(p+f->nstat > ep) | |
231 return 0; | |
232 f->stat = p; | |
233 p += f->nstat; | |
234 break; | |
235 | |
236 /* | |
237 */ | |
238 case Rversion: | |
239 if(p+BIT32SZ > ep) | |
240 return 0; | |
241 f->msize = GBIT32(p); | |
242 p += BIT32SZ; | |
243 p = gstring(p, ep, &f->version); | |
244 break; | |
245 | |
246 case Rerror: | |
247 p = gstring(p, ep, &f->ename); | |
248 f->errornum = 0; | |
249 if(dotu){ | |
250 if(p+BIT32SZ > ep) | |
251 return 0; | |
252 f->errornum = GBIT32(p); | |
253 p += BIT32SZ; | |
254 } | |
255 break; | |
256 | |
257 case Rflush: | |
258 break; | |
259 | |
260 case Rauth: | |
261 p = gqid(p, ep, &f->aqid); | |
262 if(p == nil) | |
263 break; | |
264 break; | |
265 | |
266 case Rattach: | |
267 p = gqid(p, ep, &f->qid); | |
268 if(p == nil) | |
269 break; | |
270 break; | |
271 | |
272 case Rwalk: | |
273 if(p+BIT16SZ > ep) | |
274 return 0; | |
275 f->nwqid = GBIT16(p); | |
276 p += BIT16SZ; | |
277 if(f->nwqid > MAXWELEM) | |
278 return 0; | |
279 for(i=0; i<f->nwqid; i++){ | |
280 p = gqid(p, ep, &f->wqid[i]); | |
281 if(p == nil) | |
282 break; | |
283 } | |
284 break; | |
285 | |
286 case Ropen: | |
287 case Ropenfd: | |
288 case Rcreate: | |
289 p = gqid(p, ep, &f->qid); | |
290 if(p == nil) | |
291 break; | |
292 if(p+BIT32SZ > ep) | |
293 return 0; | |
294 f->iounit = GBIT32(p); | |
295 p += BIT32SZ; | |
296 if(f->type == Ropenfd){ | |
297 if(p+BIT32SZ > ep) | |
298 return 0; | |
299 f->unixfd = GBIT32(p); | |
300 p += BIT32SZ; | |
301 } | |
302 break; | |
303 | |
304 case Rread: | |
305 if(p+BIT32SZ > ep) | |
306 return 0; | |
307 f->count = GBIT32(p); | |
308 p += BIT32SZ; | |
309 if(p+f->count > ep) | |
310 return 0; | |
311 f->data = (char*)p; | |
312 p += f->count; | |
313 break; | |
314 | |
315 case Rwrite: | |
316 if(p+BIT32SZ > ep) | |
317 return 0; | |
318 f->count = GBIT32(p); | |
319 p += BIT32SZ; | |
320 break; | |
321 | |
322 case Rclunk: | |
323 case Rremove: | |
324 break; | |
325 | |
326 case Rstat: | |
327 if(p+BIT16SZ > ep) | |
328 return 0; | |
329 f->nstat = GBIT16(p); | |
330 p += BIT16SZ; | |
331 if(p+f->nstat > ep) | |
332 return 0; | |
333 f->stat = p; | |
334 p += f->nstat; | |
335 break; | |
336 | |
337 case Rwstat: | |
338 break; | |
339 } | |
340 | |
341 if(p==nil || p>ep) | |
342 return 0; | |
343 if(ap+size == p) | |
344 return size; | |
345 return 0; | |
346 } | |
347 | |
348 uint | |
349 convM2S(uchar *ap, uint nap, Fcall *f) | |
350 { | |
351 return convM2Su(ap, nap, f, 0); | |
352 } |