9ns: Extend struct dir and the stat M bufs
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 23 Feb 2018 22:34:05 +0000 (17:34 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Apr 2018 19:23:01 +0000 (15:23 -0400)
These extensions are IAW 9p2000.u.  Additionally, I extend the dir even
further to have full timespecs.  Between these timespecs and the extension
string, we might be able to do everything that statx() does.

This commit changes the kernel's side of things.  The stat bufs it produces
with convD2M() can be interpretted by older 9p readers, since the initial
part of the message is the same.  We can read old or new stat buffers with
convM2D().  For instance, userspace creates wstat messages (e.g. mkdir())
in the old format still.

I replaced the guts of convM2kdirent() and convM2kstat() with convM2D(),
which greatly simplifies that area.  Those functions are for converting
from Ms to glibc-style dirents and stat structures that Akaros used before
we had Plan 9.

I also cleaned up the STATFIXLEN mess.  I found that tricky to debug and a
little unclear.  Given there are two formats now, things would get even
worse; I wasn't about to change the magic '4's to '5's.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/ns.h
kern/src/net/devip.c
kern/src/ns/convD2M.c
kern/src/ns/convM2D.c
kern/src/ns/convM2S.c
kern/src/ns/convM2kdirent.c
kern/src/ns/dev.c
kern/src/ns/sysfile.c
kern/src/syscall.c

index 54ed587..a0e185d 100644 (file)
@@ -136,17 +136,25 @@ struct qid {
 struct dir {
        /* system-modified data */
        uint16_t type;                          /* server type */
 struct dir {
        /* system-modified data */
        uint16_t type;                          /* server type */
-       unsigned int dev;                       /* server subtype */
+       uint32_t dev;                   /* server subtype */
        /* file data */
        struct qid qid;                         /* unique id from server */
        /* file data */
        struct qid qid;                         /* unique id from server */
-       int mode;                                       /* permissions */
-       uint32_t atime;                         /* last read time */
-       uint32_t mtime;                         /* last write time */
-       int64_t length;                         /* file length: see <u.h> */
+       uint32_t mode;                          /* permissions */
+       /* 9p stat has u32 atime (seconds) here */
+       /* 9p stat has u32 mtime (seconds) here */
+       uint64_t length;                        /* file length: see <u.h> */
        char *name;                                     /* last element of path */
        char *uid;                                      /* owner name */
        char *gid;                                      /* group name */
        char *muid;                                     /* last modifier name */
        char *name;                                     /* last element of path */
        char *uid;                                      /* owner name */
        char *gid;                                      /* group name */
        char *muid;                                     /* last modifier name */
+       char *ext;                                      /* extensions for special files (symlinks) */
+       uint32_t n_uid;                         /* numeric owner uid */
+       uint32_t n_gid;                         /* numeric group id */
+       uint32_t n_muid;                        /* numeric last modifier id */
+       struct timespec atime;          /* last access time */
+       struct timespec btime;          /* file creation time */
+       struct timespec ctime;          /* last attribute change time */
+       struct timespec mtime;          /* last data modification time */
 };
 
 struct waitmsg {
 };
 
 struct waitmsg {
@@ -231,9 +239,49 @@ typedef
 #define        BIT64SZ         8
 #define        QIDSZ   (BIT8SZ+BIT32SZ+BIT64SZ)
 
 #define        BIT64SZ         8
 #define        QIDSZ   (BIT8SZ+BIT32SZ+BIT64SZ)
 
-/* STATFIXLEN includes leading 16-bit count */
-/* The count, however, excludes itself; total size is BIT16SZ+count */
-#define STATFIXLEN     (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ)   /* amount of fixed length data in a stat buffer */
+/* The 9p STATFIXLENs include the leading 16-bit count.  The count, however,
+ * excludes itself; total size is BIT16SZ + count.  This is the amount of fixed
+ * length data in a stat buffer.  This does not include the strings, but it
+ * includes the string counts (u16s)
+ *
+ * STAT_FIX_LEN_9P is the original 9p stat message: type to length, including
+ * u32 atime and u32 mtime.  This is the bare minimum for a stat that we
+ * receive.  We check in e.g. convM2D for any extra fields.
+ *
+ * STAT_FIX_LEN_AK is the stat message used by Akaros, which includes Eric VH's
+ * extensions and full timespecs.  It is analogous to struct dir, including the
+ * u32s for the legacy atime/mtime.  We always send stats of this size, e.g. in
+ * convD2M.
+ *
+ * Note that the extended stat message has fixed data after the strings, but to
+ * get to this data, you have to jump through the string and their counts
+ * (u16s).  The counts are part of the fixed length, but not the strings.  Also
+ * note that the _AK version has an extra string. */
+#define STAT_NR_STRINGS_9P 4
+#define STAT_NR_STRINGS_AK 5
+#define STAT_FIX_LEN_9P (BIT16SZ +                      /* size */             \
+                         BIT16SZ +                      /* type */             \
+                         BIT32SZ +                      /* dev */              \
+                         QIDSZ +                        /* qid */              \
+                         BIT32SZ +                      /* mode */             \
+                         BIT32SZ +                      /* atime u32 */        \
+                         BIT32SZ +                      /* mtime u32 */        \
+                         BIT64SZ +                      /* length */           \
+                         STAT_NR_STRINGS_9P * BIT16SZ + /* string counts */    \
+                                                0)
+#define __STAT_FIX_LEN_AK_NONSTRING (                                          \
+                         BIT32SZ +                      /* n_uid */            \
+                         BIT32SZ +                      /* n_gid */            \
+                         BIT32SZ +                      /* n_muid */           \
+                         2 * BIT64SZ +                  /* atime */            \
+                         2 * BIT64SZ +                  /* btime */            \
+                         2 * BIT64SZ +                  /* ctime */            \
+                         2 * BIT64SZ +                  /* mtime */            \
+                                                0)
+#define STAT_FIX_LEN_AK (STAT_FIX_LEN_9P +                                     \
+                         (STAT_NR_STRINGS_AK - STAT_NR_STRINGS_9P) * BIT16SZ + \
+                         __STAT_FIX_LEN_AK_NONSTRING +                         \
+                                                0)
 
 #define        NOTAG           (uint16_t)~0U   /* Dummy tag */
 #define        NOFID           (uint32_t)~0U   /* Dummy fid */
 
 #define        NOTAG           (uint16_t)~0U   /* Dummy tag */
 #define        NOFID           (uint32_t)~0U   /* Dummy fid */
index d8c1e81..6053e8a 100644 (file)
@@ -262,7 +262,7 @@ static int ip1gen(struct chan *c, int i, struct dir *dp)
        }
        devdir(c, q, p, len, network, prot, dp);
        if (i == Qndb && f->ndbmtime > kerndate)
        }
        devdir(c, q, p, len, network, prot, dp);
        if (i == Qndb && f->ndbmtime > kerndate)
-               dp->mtime = f->ndbmtime;
+               dp->mtime.tv_sec = f->ndbmtime;
        return 1;
 }
 
        return 1;
 }
 
index b38ed69..3c2e8e9 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Modified for the Akaros operating system:
  * Copyright (c) 2013-2014 The Regents of the University of California
  *
  * Modified for the Akaros operating system:
  * Copyright (c) 2013-2014 The Regents of the University of California
- * Copyright (c) 2013-2015 Google Inc.
+ * Copyright (c) 2013-2018 Google Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
 
 unsigned int sizeD2M(struct dir *d)
 {
 
 unsigned int sizeD2M(struct dir *d)
 {
-       char *sv[4];
+       char *sv[STAT_NR_STRINGS_AK];
        int i, ns;
 
        sv[0] = d->name;
        sv[1] = d->uid;
        sv[2] = d->gid;
        sv[3] = d->muid;
        int i, ns;
 
        sv[0] = d->name;
        sv[1] = d->uid;
        sv[2] = d->gid;
        sv[3] = d->muid;
+       sv[4] = d->ext;
 
        ns = 0;
 
        ns = 0;
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < STAT_NR_STRINGS_AK; i++)
                if (sv[i])
                        ns += strlen(sv[i]);
 
                if (sv[i])
                        ns += strlen(sv[i]);
 
-       return STATFIXLEN + ns;
+       return STAT_FIX_LEN_AK + ns;
 }
 
 }
 
+/* This converts dirs into the Akaros format (P92000.u + timespecs).  So far, we
+ * haven't needed to convert to a smaller format, such as you'd get if nbuf was
+ * too small. */
 unsigned int convD2M(struct dir *d, uint8_t * buf, unsigned int nbuf)
 {
        uint8_t *p, *ebuf;
 unsigned int convD2M(struct dir *d, uint8_t * buf, unsigned int nbuf)
 {
        uint8_t *p, *ebuf;
-       char *sv[4];
-       int i, ns, nsv[4], ss;
+       char *sv[STAT_NR_STRINGS_AK];
+       int i, ns, nsv[STAT_NR_STRINGS_AK], ss;
 
        if (nbuf < BIT16SZ)
                return 0;
 
        if (nbuf < BIT16SZ)
                return 0;
@@ -74,9 +78,10 @@ unsigned int convD2M(struct dir *d, uint8_t * buf, unsigned int nbuf)
        sv[1] = d->uid;
        sv[2] = d->gid;
        sv[3] = d->muid;
        sv[1] = d->uid;
        sv[2] = d->gid;
        sv[3] = d->muid;
+       sv[4] = d->ext;
 
        ns = 0;
 
        ns = 0;
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < STAT_NR_STRINGS_AK; i++) {
                if (sv[i])
                        nsv[i] = strlen(sv[i]);
                else
                if (sv[i])
                        nsv[i] = strlen(sv[i]);
                else
@@ -84,45 +89,46 @@ unsigned int convD2M(struct dir *d, uint8_t * buf, unsigned int nbuf)
                ns += nsv[i];
        }
 
                ns += nsv[i];
        }
 
-       ss = STATFIXLEN + ns;
+       ss = STAT_FIX_LEN_AK + ns;
 
        /* set size befor erroring, so user can know how much is needed */
 
        /* set size befor erroring, so user can know how much is needed */
-       /* note that length excludes count field itself */
+       /* note that length excludes the count field itself */
        PBIT16(p, ss - BIT16SZ);
        p += BIT16SZ;
 
        if (ss > nbuf)
                return BIT16SZ;
 
        PBIT16(p, ss - BIT16SZ);
        p += BIT16SZ;
 
        if (ss > nbuf)
                return BIT16SZ;
 
-       PBIT16(p, d->type);
-       p += BIT16SZ;
-       PBIT32(p, d->dev);
-       p += BIT32SZ;
-       PBIT8(p, d->qid.type);
-       p += BIT8SZ;
-       PBIT32(p, d->qid.vers);
-       p += BIT32SZ;
-       PBIT64(p, d->qid.path);
-       p += BIT64SZ;
-       PBIT32(p, d->mode);
-       p += BIT32SZ;
-       PBIT32(p, d->atime);
-       p += BIT32SZ;
-       PBIT32(p, d->mtime);
-       p += BIT32SZ;
-       PBIT64(p, d->length);
-       p += BIT64SZ;
-
-       for (i = 0; i < 4; i++) {
+       PBIT16(p, d->type);             p += BIT16SZ;
+       PBIT32(p, d->dev);              p += BIT32SZ;
+       PBIT8(p, d->qid.type);          p += BIT8SZ;
+       PBIT32(p, d->qid.vers);         p += BIT32SZ;
+       PBIT64(p, d->qid.path);         p += BIT64SZ;
+       PBIT32(p, d->mode);             p += BIT32SZ;
+       PBIT32(p, d->atime.tv_sec);     p += BIT32SZ;
+       PBIT32(p, d->mtime.tv_sec);     p += BIT32SZ;
+       PBIT64(p, d->length);           p += BIT64SZ;
+
+       for (i = 0; i < STAT_NR_STRINGS_AK; i++) {
                ns = nsv[i];
                if (p + ns + BIT16SZ > ebuf)
                        return 0;
                ns = nsv[i];
                if (p + ns + BIT16SZ > ebuf)
                        return 0;
-               PBIT16(p, ns);
-               p += BIT16SZ;
+               PBIT16(p, ns); p += BIT16SZ;
                if (ns)
                        memmove(p, sv[i], ns);
                p += ns;
        }
                if (ns)
                        memmove(p, sv[i], ns);
                p += ns;
        }
+       PBIT32(p, d->n_uid);            p += BIT32SZ;
+       PBIT32(p, d->n_gid);            p += BIT32SZ;
+       PBIT32(p, d->n_muid);           p += BIT32SZ;
+       PBIT64(p, d->atime.tv_sec);     p += BIT64SZ;
+       PBIT64(p, d->atime.tv_nsec);    p += BIT64SZ;
+       PBIT64(p, d->btime.tv_sec);     p += BIT64SZ;
+       PBIT64(p, d->btime.tv_nsec);    p += BIT64SZ;
+       PBIT64(p, d->ctime.tv_sec);     p += BIT64SZ;
+       PBIT64(p, d->ctime.tv_nsec);    p += BIT64SZ;
+       PBIT64(p, d->mtime.tv_sec);     p += BIT64SZ;
+       PBIT64(p, d->mtime.tv_nsec);    p += BIT64SZ;
 
        if (ss != p - buf)
                return 0;
 
        if (ss != p - buf)
                return 0;
index a0ba36c..bb7b7bf 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Modified for the Akaros operating system:
  * Copyright (c) 2013-2014 The Regents of the University of California
  *
  * Modified for the Akaros operating system:
  * Copyright (c) 2013-2014 The Regents of the University of California
- * Copyright (c) 2013-2015 Google Inc.
+ * Copyright (c) 2013-2018 Google Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -40,6 +40,8 @@
 #include <smp.h>
 #include <net/ip.h>
 
 #include <smp.h>
 #include <net/ip.h>
 
+/* It looks like the intent of this code is to check any stat that we, the
+ * kernel or our userspace, send out. */
 int statcheck(uint8_t * buf, unsigned int nbuf)
 {
        uint8_t *ebuf;
 int statcheck(uint8_t * buf, unsigned int nbuf)
 {
        uint8_t *ebuf;
@@ -47,26 +49,38 @@ int statcheck(uint8_t * buf, unsigned int nbuf)
 
        ebuf = buf + nbuf;
 
 
        ebuf = buf + nbuf;
 
-       if (nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)){
-               printk("nbuf %d, STATFIXLEN %d ", nbuf, STATFIXLEN);
+       if (nbuf < STAT_FIX_LEN_9P || nbuf != BIT16SZ + GBIT16(buf)) {
+               printk("nbuf %d, STAT_FIX_LEN_9P %d ", nbuf, STAT_FIX_LEN_9P);
                printk("BIT16SZ %d, GBIT16(buf) %d ",
                        BIT16SZ, GBIT16(buf));
                printk("This is bad!\n");
                return -1;
        }
 
                printk("BIT16SZ %d, GBIT16(buf) %d ",
                        BIT16SZ, GBIT16(buf));
                printk("This is bad!\n");
                return -1;
        }
 
-       buf += STATFIXLEN - 4 * BIT16SZ;
+       buf += STAT_FIX_LEN_9P - STAT_NR_STRINGS_9P * BIT16SZ;
 
 
-       for (i = 0; i < 4; i++) {
+       /* Check the legacy strings that all stats have. */
+       for (i = 0; i < STAT_NR_STRINGS_9P; i++) {
                if (buf + BIT16SZ > ebuf)
                        return -1;
                buf += BIT16SZ + GBIT16(buf);
        }
                if (buf + BIT16SZ > ebuf)
                        return -1;
                buf += BIT16SZ + GBIT16(buf);
        }
+       /* Legacy 9p stats are OK
+        * TODO: consider removing this.  We get them from userspace, e.g. mkdir. */
+       if (buf == ebuf)
+               return 0;
 
 
-       if (buf != ebuf){
-               return -1;
+       for (i = STAT_NR_STRINGS_9P; i < STAT_NR_STRINGS_AK; i++) {
+               if (buf + BIT16SZ > ebuf)
+                       return -1;
+               buf += BIT16SZ + GBIT16(buf);
        }
 
        }
 
+       if (buf + __STAT_FIX_LEN_AK_NONSTRING > ebuf)
+               return -1;
+       buf += __STAT_FIX_LEN_AK_NONSTRING;
+       if (buf != ebuf)
+               return -1;
        return 0;
 }
 
        return 0;
 }
 
@@ -76,42 +90,55 @@ unsigned int
 convM2D(uint8_t * buf, unsigned int nbuf, struct dir *d, char *strs)
 {
        uint8_t *p, *ebuf;
 convM2D(uint8_t * buf, unsigned int nbuf, struct dir *d, char *strs)
 {
        uint8_t *p, *ebuf;
-       char *sv[4];
+       char *sv[STAT_NR_STRINGS_AK] = {nullstring};
        int i, ns;
        int i, ns;
+       bool good_stat = false;
+       size_t msg_sz = 0;
 
 
-       if (nbuf < STATFIXLEN)
+       if (nbuf < STAT_FIX_LEN_9P)
                return 0;
 
                return 0;
 
-       p = buf;
-       ebuf = buf + nbuf;
+       /* This M might not have all the fields we expect.  We'll ensure the strings
+        * have the right values later.  We still need to initialize all of the
+        * non-string extended fields. */
+       init_empty_dir(d);
 
 
-       p += BIT16SZ;   /* ignore size */
-       d->type = GBIT16(p);
-       p += BIT16SZ;
-       d->dev = GBIT32(p);
-       p += BIT32SZ;
-       d->qid.type = GBIT8(p);
-       p += BIT8SZ;
-       d->qid.vers = GBIT32(p);
-       p += BIT32SZ;
-       d->qid.path = GBIT64(p);
-       p += BIT64SZ;
-       d->mode = GBIT32(p);
-       p += BIT32SZ;
-       d->atime = GBIT32(p);
-       p += BIT32SZ;
-       d->mtime = GBIT32(p);
-       p += BIT32SZ;
-       d->length = GBIT64(p);
-       p += BIT64SZ;
-
-       for (i = 0; i < 4; i++) {
+       p = buf;
+       /* They might have given us more than one M, so we need to use the size
+        * field to determine the real end of this M. */
+       msg_sz = GBIT16(p) + BIT16SZ;
+       ebuf = buf + MIN(nbuf, msg_sz);
+
+       p += BIT16SZ;   /* jump over size */
+       d->type = GBIT16(p);            p += BIT16SZ;
+       d->dev = GBIT32(p);             p += BIT32SZ;
+       d->qid.type = GBIT8(p);         p += BIT8SZ;
+       d->qid.vers = GBIT32(p);        p += BIT32SZ;
+       d->qid.path = GBIT64(p);        p += BIT64SZ;
+       d->mode = GBIT32(p);            p += BIT32SZ;
+       /* Get a first attempt at atime/mtime.  Revisit this in 2038. */
+       d->atime.tv_sec = GBIT32(p);    p += BIT32SZ;
+       d->mtime.tv_sec = GBIT32(p);    p += BIT32SZ;
+       d->length = GBIT64(p);          p += BIT64SZ;
+
+       /* They might have asked for -1, meaning "don't touch".  Need to convert
+        * that to our 64 bit times. */
+       if ((int32_t)d->atime.tv_sec == -1)
+               d->atime.tv_sec = ~0;
+       if ((int32_t)d->mtime.tv_sec == -1)
+               d->mtime.tv_sec = ~0;
+
+       /* Anything beyond the legacy 9p strings might not be supported.  Though if
+        * you have more, you probably have at least EVH's 9p2000.u extensions.
+        * Once we get all of the legacy strings, we have a good stat. */
+       for (i = 0; i < STAT_NR_STRINGS_AK; i++) {
+               if (i == STAT_NR_STRINGS_9P)
+                       good_stat = true;
                if (p + BIT16SZ > ebuf)
                if (p + BIT16SZ > ebuf)
-                       return 0;
-               ns = GBIT16(p);
-               p += BIT16SZ;
+                       goto out;
+               ns = GBIT16(p); p += BIT16SZ;
                if (p + ns > ebuf)
                if (p + ns > ebuf)
-                       return 0;
+                       goto out;
                if (strs) {
                        sv[i] = strs;
                        memmove(strs, p, ns);
                if (strs) {
                        sv[i] = strs;
                        memmove(strs, p, ns);
@@ -121,17 +148,33 @@ convM2D(uint8_t * buf, unsigned int nbuf, struct dir *d, char *strs)
                p += ns;
        }
 
                p += ns;
        }
 
-       if (strs) {
-               d->name = sv[0];
-               d->uid = sv[1];
-               d->gid = sv[2];
-               d->muid = sv[3];
-       } else {
-               d->name = nullstring;
-               d->uid = nullstring;
-               d->gid = nullstring;
-               d->muid = nullstring;
-       }
-
+       /* Check for 9p2000.u */
+       if (p + 3 * BIT32SZ > ebuf)
+               goto out;
+       d->n_uid = GBIT32(p);           p += BIT32SZ;
+       d->n_gid = GBIT32(p);           p += BIT32SZ;
+       d->n_muid = GBIT32(p);          p += BIT32SZ;
+
+       /* Check for extended timespecs */
+       if (p + 4 * (2 * BIT64SZ) > ebuf)
+               goto out;
+       d->atime.tv_sec = GBIT64(p);    p += BIT64SZ;
+       d->atime.tv_nsec = GBIT64(p);   p += BIT64SZ;
+       d->btime.tv_sec = GBIT64(p);    p += BIT64SZ;
+       d->btime.tv_nsec = GBIT64(p);   p += BIT64SZ;
+       d->ctime.tv_sec = GBIT64(p);    p += BIT64SZ;
+       d->ctime.tv_nsec = GBIT64(p);   p += BIT64SZ;
+       d->mtime.tv_sec = GBIT64(p);    p += BIT64SZ;
+       d->mtime.tv_nsec = GBIT64(p);   p += BIT64SZ;
+
+       /* Fall-through */
+out:
+       if (!good_stat)
+               return 0;
+       d->name = sv[0];
+       d->uid = sv[1];
+       d->gid = sv[2];
+       d->muid = sv[3];
+       d->ext = sv[4];
        return p - buf;
 }
        return p - buf;
 }
index 9b527bf..a3a5936 100644 (file)
@@ -73,6 +73,8 @@ uint8_t *gqid(uint8_t * p, uint8_t * ep, struct qid *q)
        return p;
 }
 
        return p;
 }
 
+/* This initializes a dir to "don't touch" values.  These fields are ignored on
+ * a wstat. */
 void init_empty_dir(struct dir *d)
 {
        d->type = ~0;
 void init_empty_dir(struct dir *d)
 {
        d->type = ~0;
@@ -81,13 +83,25 @@ void init_empty_dir(struct dir *d)
        d->qid.vers = ~0;
        d->qid.type = ~0;
        d->mode = ~0;
        d->qid.vers = ~0;
        d->qid.type = ~0;
        d->mode = ~0;
-       d->atime = ~0;
-       d->mtime = ~0;
        d->length = ~0;
        d->name = "";
        d->uid = "";
        d->gid = "";
        d->muid = "";
        d->length = ~0;
        d->name = "";
        d->uid = "";
        d->gid = "";
        d->muid = "";
+       d->ext = "";
+       d->n_uid = ~0;
+       d->n_gid = ~0;
+       d->n_muid = ~0;
+       d->atime.tv_sec = ~0;
+       d->btime.tv_sec = ~0;
+       d->ctime.tv_sec = ~0;
+       d->mtime.tv_sec = ~0;
+       /* We don't look at tv_nsec to determine whether or not the field is "don't
+        * touch".  This way, all nsecs are normal. */
+       d->atime.tv_nsec = 0;
+       d->btime.tv_nsec = 0;
+       d->ctime.tv_nsec = 0;
+       d->mtime.tv_nsec = 0;
 }
 
 /*
 }
 
 /*
index 083b874..c581601 100644 (file)
@@ -1,3 +1,8 @@
+/* Copyright (c) 2013-2018 Google Inc
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * Ron Minnich <rminnich@google.com>
+ *
+ * See LICENSE for details.  */
 
 #include <vfs.h>
 #include <kfs.h>
 
 #include <vfs.h>
 #include <kfs.h>
 #include <net/ip.h>
 
 /* Special akaros edition. */
 #include <net/ip.h>
 
 /* Special akaros edition. */
-/* akaros does not (yet) pass as much info as plan 9 does,
- * and it still has stuff I'm not happy about like an inode number.
- */
-#if 0
-struct kdirent {
-       __ino64_t d_ino;                        /* inod
-                                                                  e number */
-       __off64_t d_off;                        /* offs
-                                                                  et to the next dirent */
-       unsigned short d_reclen;        /* length of th
-                                                                  is record */
-       unsigned char d_type;
-       char d_name[MAX_FILENAME_SZ + 1];       /* filename */
-} __attribute__ ((aligned(8)));
-
-#endif
-
 unsigned int convM2kdirent(uint8_t * buf, unsigned int nbuf, struct kdirent *kd,
                                                   char *strs)
 {
 unsigned int convM2kdirent(uint8_t * buf, unsigned int nbuf, struct kdirent *kd,
                                                   char *strs)
 {
-       uint8_t *p, *ebuf;
-       char *sv[4];
-       int i, ns;
-       uint32_t junk;
-       printd("%s >>>>>>>>>nbuf %d STATFIXLEN %d\n", __func__, nbuf, STATFIXLEN);
-       if (nbuf < STATFIXLEN)
-               return 0;
-
-       p = buf;
-       ebuf = buf + nbuf;
-
-       p += BIT16SZ;   /* ignore size */
-       kd->d_type = GBIT16(p);
-       p += BIT16SZ;
-       junk = GBIT32(p);
-       p += BIT32SZ;
-       junk = GBIT8(p);
-       p += BIT8SZ;
-       junk = GBIT32(p);
-       p += BIT32SZ;
-       kd->d_ino = GBIT64(p);
-       p += BIT64SZ;
-       junk /* mode */  = GBIT32(p);
-       p += BIT32SZ;
-       junk /*d->atime */  = GBIT32(p);
-       p += BIT32SZ;
-       junk /*d->mtime */  = GBIT32(p);
-       p += BIT32SZ;
-       junk /*d->length */  = GBIT64(p);
-       p += BIT64SZ;
-
-       /* for now, uids in akaros are ints. Does not
-        * matter; kdirents are limited in what they tell you.
-        * get the name, ignore the rest. Maybe we can
-        * fix this later.
-        */
-       for (i = 0; i < 4; i++) {
-               if (p + BIT16SZ > ebuf)
-                       return 0;
-               ns = GBIT16(p);
-               p += BIT16SZ;
-               if (p + ns > ebuf)
-                       return 0;
-               if (strs) {
-                       sv[i] = strs;
-                       memmove(strs, p, ns);
-                       strs += ns;
-                       *strs++ = '\0';
-               }
-               if (i == 0) {
-                       kd->d_reclen = ns;
-                       printd("memmove %p %p %d\n", kd->d_name, p, ns);
-                       memmove(kd->d_name, p, ns);
-                       kd->d_name[ns] = 0;
-               }
-               p += ns;
-       }
+       struct dir *dir;
+       size_t conv_sz, name_sz;
 
 
-       printd("%s returns %d %s\n", __func__, p - buf, kd->d_name);
-       return p - buf;
+       if (nbuf < STAT_FIX_LEN_9P)
+               return 0;
+       dir = kmalloc(sizeof(struct dir) + nbuf, MEM_WAIT);
+       conv_sz = convM2D(buf, nbuf, dir, (char*)&dir[1]);
+
+       kd->d_ino = dir->qid.path;
+       kd->d_off = 0;          /* ignored for 9ns readdir */
+       kd->d_type = 0;         /* TODO: might need this; never used this in the VFS */
+       name_sz = dir->name ? strlen(dir->name) : 0;
+       kd->d_reclen = name_sz;
+       /* Our caller should have made sure kd was big enough... */
+       memcpy(kd->d_name, dir->name, name_sz);
+       kd->d_name[name_sz] = 0;
+
+       kfree(dir);
+       return conv_sz;
 }
 
 static int mode_9ns_to_posix(int mode_9ns)
 }
 
 static int mode_9ns_to_posix(int mode_9ns)
@@ -116,41 +63,28 @@ static int mode_9ns_to_posix(int mode_9ns)
 
 unsigned int convM2kstat(uint8_t * buf, unsigned int nbuf, struct kstat *ks)
 {
 
 unsigned int convM2kstat(uint8_t * buf, unsigned int nbuf, struct kstat *ks)
 {
-       uint8_t *p, *ebuf;
-       char *sv[4];
-       int i, ns;
-       uint32_t junk;
+       struct dir *dir;
+       size_t conv_sz, name_sz;
 
 
-       if (nbuf < STATFIXLEN)
+       if (nbuf < STAT_FIX_LEN_9P)
                return 0;
                return 0;
-
-       p = buf;
-       ebuf = buf + nbuf;
-
-       p += BIT16SZ;   /* ignore size */
-       junk /*kd->d_type */  = GBIT16(p);
-       p += BIT16SZ;
-       ks->st_rdev = ks->st_dev = GBIT32(p);
-       p += BIT32SZ;
-       junk /*qid.type */  = GBIT8(p);
-       p += BIT8SZ;
-       junk /*qid.vers */  = GBIT32(p);
-       p += BIT32SZ;
-       ks->st_ino = GBIT64(p);
-       p += BIT64SZ;
-       ks->st_mode = mode_9ns_to_posix(GBIT32(p));
-       p += BIT32SZ;
-       ks->st_atim.tv_sec = GBIT32(p);
-       p += BIT32SZ;
-       ks->st_mtim.tv_sec = GBIT32(p);
-       p += BIT32SZ;
-       ks->st_size = GBIT64(p);
-       p += BIT64SZ;
-       ks->st_blksize = 512;
-       ks->st_blocks = ROUNDUP(ks->st_size, ks->st_blksize) / ks->st_blksize;
-
-       ks->st_nlink = 2;       // links make no sense any more.
-       ks->st_uid = ks->st_gid = 0;
-
-       return p - buf;
+       dir = kmalloc(sizeof(struct dir) + nbuf, MEM_WAIT);
+       conv_sz = convM2D(buf, nbuf, dir, (char*)&dir[1]);
+
+       ks->st_dev = dir->type;
+       ks->st_ino = dir->qid.path;
+       ks->st_mode = mode_9ns_to_posix(dir->mode);
+       ks->st_nlink = dir->mode & DMDIR ? 2 : 1;
+       ks->st_uid = dir->n_uid;
+       ks->st_gid = dir->n_gid;
+       ks->st_rdev = dir->dev;
+       ks->st_size = dir->length;
+       ks->st_blksize = 1;
+       ks->st_blocks = dir->length;
+       ks->st_atim = dir->atime;
+       ks->st_mtim = dir->mtime;
+       ks->st_ctim = dir->ctime;
+
+       kfree(dir);
+       return conv_sz;
 }
 }
index a849bc3..5d94e55 100644 (file)
@@ -68,6 +68,8 @@ void
 devdir(struct chan *c, struct qid qid, char *n,
           int64_t length, char *user, long perm, struct dir *db)
 {
 devdir(struct chan *c, struct qid qid, char *n,
           int64_t length, char *user, long perm, struct dir *db)
 {
+       struct timespec now = nsec2timespec(epoch_nsec());
+
        db->name = n;
        if (c->flag & CMSG)
                qid.type |= QTMOUNT;
        db->name = n;
        if (c->flag & CMSG)
                qid.type |= QTMOUNT;
@@ -76,12 +78,22 @@ devdir(struct chan *c, struct qid qid, char *n,
        db->dev = c->dev;
        db->mode = perm;
        db->mode |= qid.type << 24;
        db->dev = c->dev;
        db->mode = perm;
        db->mode |= qid.type << 24;
-       db->atime = seconds();
-       db->mtime = kerndate;
        db->length = length;
        db->uid = user;
        db->gid = eve.name;
        db->muid = user;
        db->length = length;
        db->uid = user;
        db->gid = eve.name;
        db->muid = user;
+       db->ext = NULL;
+       /* TODO: once we figure out what to do for uid/gid, then we can try to tie
+        * that to the n_uid.  Or just ignore it, and only use that as a
+        * pass-through for 9p2000.u. */
+       db->n_uid = 0;
+       db->n_gid = 0;
+       db->n_muid = 0;
+       /* TODO: what does devdir really want? */
+       db->atime = now;
+       db->btime = now;
+       db->ctime = now;
+       db->mtime = now;
 }
 
 /*
 }
 
 /*
index a66b438..2011281 100644 (file)
 #include <smp.h>
 #include <net/ip.h>
 
 #include <smp.h>
 #include <net/ip.h>
 
+/* TODO: these sizes are hokey.  DIRSIZE is used in chandirstat, and it looks
+ * like it's the size of a common-case stat. */
 enum {
 enum {
-       DIRSIZE = STATFIXLEN + 32 * 4,
+       DIRSIZE = STAT_FIX_LEN_AK + 32 * STAT_NR_STRINGS_AK,
        DIRREADLIM = 2048,      /* should handle the largest reasonable directory entry */
        DIRREADSIZE=8192,       /* Just read a lot. Memory is cheap, lots of bandwidth,
                                 * and RPCs are very expensive. At the same time,
        DIRREADLIM = 2048,      /* should handle the largest reasonable directory entry */
        DIRREADSIZE=8192,       /* Just read a lot. Memory is cheap, lots of bandwidth,
                                 * and RPCs are very expensive. At the same time,
@@ -858,7 +860,7 @@ void validstat(uint8_t * s, int n, int slashok)
        if (statcheck(s, n) < 0)
                error(EINVAL, ERROR_FIXME);
        /* verify that name entry is acceptable */
        if (statcheck(s, n) < 0)
                error(EINVAL, ERROR_FIXME);
        /* verify that name entry is acceptable */
-       s += STATFIXLEN - 4 * BIT16SZ;  /* location of first string */
+       s += STAT_FIX_LEN_9P - STAT_NR_STRINGS_9P * BIT16SZ;
        /*
         * s now points at count for first string.
         * if it's too long, let the server decide; this is
        /*
         * s now points at count for first string.
         * if it's too long, let the server decide; this is
@@ -1205,6 +1207,7 @@ static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
        nn = 0;
        for (i = 0; i < ts; i += m) {
                m = BIT16SZ + GBIT16((uint8_t *) & buf[i]);
        nn = 0;
        for (i = 0; i < ts; i += m) {
                m = BIT16SZ + GBIT16((uint8_t *) & buf[i]);
+               /* Note 's' is ignored by convM2kdirent */
                if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
                        kfree(*d);
                        *d = NULL;
                if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
                        kfree(*d);
                        *d = NULL;
index b6eb3d4..c7c1f87 100644 (file)
@@ -2409,15 +2409,10 @@ static int vfs_wstat(struct file *file, uint8_t *stat_m, size_t stat_sz,
                if (retval < 0)
                        goto out;
        }
                if (retval < 0)
                        goto out;
        }
-       if (flags & WSTAT_ATIME) {
-               /* wstat only gives us seconds */
-               file->f_dentry->d_inode->i_atime.tv_sec = dir->atime;
-               file->f_dentry->d_inode->i_atime.tv_nsec = 0;
-       }
-       if (flags & WSTAT_MTIME) {
-               file->f_dentry->d_inode->i_mtime.tv_sec = dir->mtime;
-               file->f_dentry->d_inode->i_mtime.tv_nsec = 0;
-       }
+       if (flags & WSTAT_ATIME)
+               file->f_dentry->d_inode->i_atime = dir->atime;
+       if (flags & WSTAT_MTIME)
+               file->f_dentry->d_inode->i_mtime = dir->mtime;
 
 out:
        kfree(dir);
 
 out:
        kfree(dir);
@@ -2536,7 +2531,7 @@ intreg_t sys_rename(struct proc *p, char *old_path, size_t old_path_l,
 
        struct dir dir;
        size_t mlen;
 
        struct dir dir;
        size_t mlen;
-       uint8_t mbuf[STATFIXLEN + MAX_PATH_LEN + 1];
+       uint8_t mbuf[STAT_FIX_LEN_AK + MAX_PATH_LEN + 1];
 
        init_empty_dir(&dir);
        dir.name = to_path;
 
        init_empty_dir(&dir);
        dir.name = to_path;