9ns: Extend struct dir and the stat M bufs
[akaros.git] / kern / src / ns / convM2D.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-2018 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 /* It looks like the intent of this code is to check any stat that we, the
44  * kernel or our userspace, send out. */
45 int statcheck(uint8_t * buf, unsigned int nbuf)
46 {
47         uint8_t *ebuf;
48         int i;
49
50         ebuf = buf + nbuf;
51
52         if (nbuf < STAT_FIX_LEN_9P || nbuf != BIT16SZ + GBIT16(buf)) {
53                 printk("nbuf %d, STAT_FIX_LEN_9P %d ", nbuf, STAT_FIX_LEN_9P);
54                 printk("BIT16SZ %d, GBIT16(buf) %d ",
55                         BIT16SZ, GBIT16(buf));
56                 printk("This is bad!\n");
57                 return -1;
58         }
59
60         buf += STAT_FIX_LEN_9P - STAT_NR_STRINGS_9P * BIT16SZ;
61
62         /* Check the legacy strings that all stats have. */
63         for (i = 0; i < STAT_NR_STRINGS_9P; i++) {
64                 if (buf + BIT16SZ > ebuf)
65                         return -1;
66                 buf += BIT16SZ + GBIT16(buf);
67         }
68         /* Legacy 9p stats are OK
69          * TODO: consider removing this.  We get them from userspace, e.g. mkdir. */
70         if (buf == ebuf)
71                 return 0;
72
73         for (i = STAT_NR_STRINGS_9P; i < STAT_NR_STRINGS_AK; i++) {
74                 if (buf + BIT16SZ > ebuf)
75                         return -1;
76                 buf += BIT16SZ + GBIT16(buf);
77         }
78
79         if (buf + __STAT_FIX_LEN_AK_NONSTRING > ebuf)
80                 return -1;
81         buf += __STAT_FIX_LEN_AK_NONSTRING;
82         if (buf != ebuf)
83                 return -1;
84         return 0;
85 }
86
87 static char nullstring[] = "";
88
89 unsigned int
90 convM2D(uint8_t * buf, unsigned int nbuf, struct dir *d, char *strs)
91 {
92         uint8_t *p, *ebuf;
93         char *sv[STAT_NR_STRINGS_AK] = {nullstring};
94         int i, ns;
95         bool good_stat = false;
96         size_t msg_sz = 0;
97
98         if (nbuf < STAT_FIX_LEN_9P)
99                 return 0;
100
101         /* This M might not have all the fields we expect.  We'll ensure the strings
102          * have the right values later.  We still need to initialize all of the
103          * non-string extended fields. */
104         init_empty_dir(d);
105
106         p = buf;
107         /* They might have given us more than one M, so we need to use the size
108          * field to determine the real end of this M. */
109         msg_sz = GBIT16(p) + BIT16SZ;
110         ebuf = buf + MIN(nbuf, msg_sz);
111
112         p += BIT16SZ;   /* jump over size */
113         d->type = GBIT16(p);            p += BIT16SZ;
114         d->dev = GBIT32(p);             p += BIT32SZ;
115         d->qid.type = GBIT8(p);         p += BIT8SZ;
116         d->qid.vers = GBIT32(p);        p += BIT32SZ;
117         d->qid.path = GBIT64(p);        p += BIT64SZ;
118         d->mode = GBIT32(p);            p += BIT32SZ;
119         /* Get a first attempt at atime/mtime.  Revisit this in 2038. */
120         d->atime.tv_sec = GBIT32(p);    p += BIT32SZ;
121         d->mtime.tv_sec = GBIT32(p);    p += BIT32SZ;
122         d->length = GBIT64(p);          p += BIT64SZ;
123
124         /* They might have asked for -1, meaning "don't touch".  Need to convert
125          * that to our 64 bit times. */
126         if ((int32_t)d->atime.tv_sec == -1)
127                 d->atime.tv_sec = ~0;
128         if ((int32_t)d->mtime.tv_sec == -1)
129                 d->mtime.tv_sec = ~0;
130
131         /* Anything beyond the legacy 9p strings might not be supported.  Though if
132          * you have more, you probably have at least EVH's 9p2000.u extensions.
133          * Once we get all of the legacy strings, we have a good stat. */
134         for (i = 0; i < STAT_NR_STRINGS_AK; i++) {
135                 if (i == STAT_NR_STRINGS_9P)
136                         good_stat = true;
137                 if (p + BIT16SZ > ebuf)
138                         goto out;
139                 ns = GBIT16(p); p += BIT16SZ;
140                 if (p + ns > ebuf)
141                         goto out;
142                 if (strs) {
143                         sv[i] = strs;
144                         memmove(strs, p, ns);
145                         strs += ns;
146                         *strs++ = '\0';
147                 }
148                 p += ns;
149         }
150
151         /* Check for 9p2000.u */
152         if (p + 3 * BIT32SZ > ebuf)
153                 goto out;
154         d->n_uid = GBIT32(p);           p += BIT32SZ;
155         d->n_gid = GBIT32(p);           p += BIT32SZ;
156         d->n_muid = GBIT32(p);          p += BIT32SZ;
157
158         /* Check for extended timespecs */
159         if (p + 4 * (2 * BIT64SZ) > ebuf)
160                 goto out;
161         d->atime.tv_sec = GBIT64(p);    p += BIT64SZ;
162         d->atime.tv_nsec = GBIT64(p);   p += BIT64SZ;
163         d->btime.tv_sec = GBIT64(p);    p += BIT64SZ;
164         d->btime.tv_nsec = GBIT64(p);   p += BIT64SZ;
165         d->ctime.tv_sec = GBIT64(p);    p += BIT64SZ;
166         d->ctime.tv_nsec = GBIT64(p);   p += BIT64SZ;
167         d->mtime.tv_sec = GBIT64(p);    p += BIT64SZ;
168         d->mtime.tv_nsec = GBIT64(p);   p += BIT64SZ;
169
170         /* Fall-through */
171 out:
172         if (!good_stat)
173                 return 0;
174         d->name = sv[0];
175         d->uid = sv[1];
176         d->gid = sv[2];
177         d->muid = sv[3];
178         d->ext = sv[4];
179         return p - buf;
180 }