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