9ns: Extend struct dir and the stat M bufs
[akaros.git] / kern / src / ns / convM2S.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <net/ip.h>
42
43 static
44 uint8_t *gstring(uint8_t * p, uint8_t * ep, char **s)
45 {
46         unsigned int n;
47
48         if (p + BIT16SZ > ep)
49                 return NULL;
50         n = GBIT16(p);
51         p += BIT16SZ - 1;
52         if (p + n + 1 > ep)
53                 return NULL;
54         /* move it down, on top of count, to make room for '\0' */
55         memmove(p, p + 1, n);
56         p[n] = '\0';
57         *s = (char *)p;
58         p += n + 1;
59         return p;
60 }
61
62 static
63 uint8_t *gqid(uint8_t * p, uint8_t * ep, struct qid *q)
64 {
65         if (p + QIDSZ > ep)
66                 return NULL;
67         q->type = GBIT8(p);
68         p += BIT8SZ;
69         q->vers = GBIT32(p);
70         p += BIT32SZ;
71         q->path = GBIT64(p);
72         p += BIT64SZ;
73         return p;
74 }
75
76 /* This initializes a dir to "don't touch" values.  These fields are ignored on
77  * a wstat. */
78 void init_empty_dir(struct dir *d)
79 {
80         d->type = ~0;
81         d->dev = ~0;
82         d->qid.path = ~0;
83         d->qid.vers = ~0;
84         d->qid.type = ~0;
85         d->mode = ~0;
86         d->length = ~0;
87         d->name = "";
88         d->uid = "";
89         d->gid = "";
90         d->muid = "";
91         d->ext = "";
92         d->n_uid = ~0;
93         d->n_gid = ~0;
94         d->n_muid = ~0;
95         d->atime.tv_sec = ~0;
96         d->btime.tv_sec = ~0;
97         d->ctime.tv_sec = ~0;
98         d->mtime.tv_sec = ~0;
99         /* We don't look at tv_nsec to determine whether or not the field is "don't
100          * touch".  This way, all nsecs are normal. */
101         d->atime.tv_nsec = 0;
102         d->btime.tv_nsec = 0;
103         d->ctime.tv_nsec = 0;
104         d->mtime.tv_nsec = 0;
105 }
106
107 /*
108  * no syntactic checks.
109  * three causes for error:
110  *  1. message size field is incorrect
111  *  2. input buffer too short for its own data (counts too long, etc.)
112  *  3. too many names or qids
113  * gqid() and gstring() return NULL if they would reach beyond buffer.
114  * main switch statement checks range and also can fall through
115  * to test at end of routine.
116  */
117 unsigned int convM2S(uint8_t * ap, unsigned int nap, struct fcall *f)
118 {
119         uint8_t *p, *ep;
120         unsigned int i, size;
121
122         p = ap;
123         ep = p + nap;
124
125         if (p + BIT32SZ + BIT8SZ + BIT16SZ > ep)
126                 return 0;
127         size = GBIT32(p);
128         p += BIT32SZ;
129
130         if (size < BIT32SZ + BIT8SZ + BIT16SZ)
131                 return 0;
132
133         f->type = GBIT8(p);
134         p += BIT8SZ;
135         f->tag = GBIT16(p);
136         p += BIT16SZ;
137
138         switch (f->type) {
139                 default:
140                         return 0;
141
142                 case Tversion:
143                         if (p + BIT32SZ > ep)
144                                 return 0;
145                         f->msize = GBIT32(p);
146                         p += BIT32SZ;
147                         p = gstring(p, ep, &f->version);
148                         break;
149
150                 case Tflush:
151                         if (p + BIT16SZ > ep)
152                                 return 0;
153                         f->oldtag = GBIT16(p);
154                         p += BIT16SZ;
155                         break;
156
157                 case Tauth:
158                         if (p + BIT32SZ > ep)
159                                 return 0;
160                         f->afid = GBIT32(p);
161                         p += BIT32SZ;
162                         p = gstring(p, ep, &f->uname);
163                         if (p == NULL)
164                                 break;
165                         p = gstring(p, ep, &f->aname);
166                         if (p == NULL)
167                                 break;
168                         break;
169
170                 case Tattach:
171                         if (p + BIT32SZ > ep)
172                                 return 0;
173                         f->fid = GBIT32(p);
174                         p += BIT32SZ;
175                         if (p + BIT32SZ > ep)
176                                 return 0;
177                         f->afid = GBIT32(p);
178                         p += BIT32SZ;
179                         p = gstring(p, ep, &f->uname);
180                         if (p == NULL)
181                                 break;
182                         p = gstring(p, ep, &f->aname);
183                         if (p == NULL)
184                                 break;
185                         break;
186
187                 case Twalk:
188                         if (p + BIT32SZ + BIT32SZ + BIT16SZ > ep)
189                                 return 0;
190                         f->fid = GBIT32(p);
191                         p += BIT32SZ;
192                         f->newfid = GBIT32(p);
193                         p += BIT32SZ;
194                         f->nwname = GBIT16(p);
195                         p += BIT16SZ;
196                         if (f->nwname > MAXWELEM)
197                                 return 0;
198                         for (i = 0; i < f->nwname; i++) {
199                                 p = gstring(p, ep, &f->wname[i]);
200                                 if (p == NULL)
201                                         break;
202                         }
203                         break;
204
205                 case Topen:
206                         if (p + BIT32SZ + BIT8SZ > ep)
207                                 return 0;
208                         f->fid = GBIT32(p);
209                         p += BIT32SZ;
210                         f->mode = GBIT8(p);
211                         p += BIT8SZ;
212                         break;
213
214                 case Tcreate:
215                         if (p + BIT32SZ > ep)
216                                 return 0;
217                         f->fid = GBIT32(p);
218                         p += BIT32SZ;
219                         p = gstring(p, ep, &f->name);
220                         if (p == NULL)
221                                 break;
222                         if (p + BIT32SZ + BIT8SZ > ep)
223                                 return 0;
224                         f->perm = GBIT32(p);
225                         p += BIT32SZ;
226                         f->mode = GBIT8(p);
227                         p += BIT8SZ;
228                         break;
229
230                 case Tread:
231                         if (p + BIT32SZ + BIT64SZ + BIT32SZ > ep)
232                                 return 0;
233                         f->fid = GBIT32(p);
234                         p += BIT32SZ;
235                         f->offset = GBIT64(p);
236                         p += BIT64SZ;
237                         f->count = GBIT32(p);
238                         p += BIT32SZ;
239                         break;
240
241                 case Twrite:
242                         if (p + BIT32SZ + BIT64SZ + BIT32SZ > ep)
243                                 return 0;
244                         f->fid = GBIT32(p);
245                         p += BIT32SZ;
246                         f->offset = GBIT64(p);
247                         p += BIT64SZ;
248                         f->count = GBIT32(p);
249                         p += BIT32SZ;
250                         if (p + f->count > ep)
251                                 return 0;
252                         f->data = (char *)p;
253                         p += f->count;
254                         break;
255
256                 case Tclunk:
257                 case Tremove:
258                         if (p + BIT32SZ > ep)
259                                 return 0;
260                         f->fid = GBIT32(p);
261                         p += BIT32SZ;
262                         break;
263
264                 case Tstat:
265                         if (p + BIT32SZ > ep)
266                                 return 0;
267                         f->fid = GBIT32(p);
268                         p += BIT32SZ;
269                         break;
270
271                 case Twstat:
272                         if (p + BIT32SZ + BIT16SZ > ep)
273                                 return 0;
274                         f->fid = GBIT32(p);
275                         p += BIT32SZ;
276                         f->nstat = GBIT16(p);
277                         p += BIT16SZ;
278                         if (p + f->nstat > ep)
279                                 return 0;
280                         f->stat = p;
281                         p += f->nstat;
282                         break;
283
284 /*
285  */
286                 case Rversion:
287                         if (p + BIT32SZ > ep)
288                                 return 0;
289                         f->msize = GBIT32(p);
290                         p += BIT32SZ;
291                         p = gstring(p, ep, &f->version);
292                         break;
293
294                 case Rerror:
295                         p = gstring(p, ep, &f->ename);
296                         break;
297
298                 case Rflush:
299                         break;
300
301                 case Rauth:
302                         p = gqid(p, ep, &f->aqid);
303                         if (p == NULL)
304                                 break;
305                         break;
306
307                 case Rattach:
308                         p = gqid(p, ep, &f->qid);
309                         if (p == NULL)
310                                 break;
311                         break;
312
313                 case Rwalk:
314                         if (p + BIT16SZ > ep)
315                                 return 0;
316                         f->nwqid = GBIT16(p);
317                         p += BIT16SZ;
318                         if (f->nwqid > MAXWELEM)
319                                 return 0;
320                         for (i = 0; i < f->nwqid; i++) {
321                                 p = gqid(p, ep, &f->wqid[i]);
322                                 if (p == NULL)
323                                         break;
324                         }
325                         break;
326
327                 case Ropen:
328                 case Rcreate:
329                         p = gqid(p, ep, &f->qid);
330                         if (p == NULL)
331                                 break;
332                         if (p + BIT32SZ > ep)
333                                 return 0;
334                         f->iounit = GBIT32(p);
335                         p += BIT32SZ;
336                         break;
337
338                 case Rread:
339                         if (p + BIT32SZ > ep)
340                                 return 0;
341                         f->count = GBIT32(p);
342                         p += BIT32SZ;
343                         if (p + f->count > ep)
344                                 return 0;
345                         f->data = (char *)p;
346                         p += f->count;
347                         break;
348
349                 case Rwrite:
350                         if (p + BIT32SZ > ep)
351                                 return 0;
352                         f->count = GBIT32(p);
353                         p += BIT32SZ;
354                         break;
355
356                 case Rclunk:
357                 case Rremove:
358                         break;
359
360                 case Rstat:
361                         if (p + BIT16SZ > ep)
362                                 return 0;
363                         f->nstat = GBIT16(p);
364                         p += BIT16SZ;
365                         if (p + f->nstat > ep)
366                                 return 0;
367                         f->stat = p;
368                         p += f->nstat;
369                         break;
370
371                 case Rwstat:
372                         break;
373         }
374
375         if (p == NULL || p > ep)
376                 return 0;
377         if (ap + size == p)
378                 return size;
379         return 0;
380 }