conv* functions
authorRonald G. Minnich <rminnich@google.com>
Fri, 17 Jan 2014 17:59:09 +0000 (09:59 -0800)
committerRonald G. Minnich <rminnich@google.com>
Fri, 17 Jan 2014 17:59:09 +0000 (09:59 -0800)
Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/src/ns/Kbuild
kern/src/ns/convD2M.c [new file with mode: 0644]
kern/src/ns/convM2D.c [new file with mode: 0644]
kern/src/ns/convM2S.c [new file with mode: 0644]
kern/src/ns/convS2M.c [new file with mode: 0644]

index 47f738f..79e5172 100644 (file)
@@ -1,5 +1,9 @@
 obj-y                                          += allocb.o
 obj-y                                          += chan.o
+obj-y                                          += convD2M.o
+obj-y                                          += convM2D.o
+obj-y                                          += convM2S.o
+obj-y                                          += convS2M.o
 obj-y                                          += error.o
 obj-y                                          += qio.o
 obj-y                                          += util.o
diff --git a/kern/src/ns/convD2M.c b/kern/src/ns/convD2M.c
new file mode 100644 (file)
index 0000000..508e3bb
--- /dev/null
@@ -0,0 +1,106 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+unsigned int
+sizeD2M(struct dir *d)
+{
+       char *sv[4];
+       int i, ns;
+
+       sv[0] = d->name;
+       sv[1] = d->uid;
+       sv[2] = d->gid;
+       sv[3] = d->muid;
+
+       ns = 0;
+       for(i = 0; i < 4; i++)
+               if(sv[i])
+                       ns += strlen(sv[i]);
+
+       return STATFIXLEN + ns;
+}
+
+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;
+
+       if(nbuf < BIT16SZ)
+               return 0;
+
+       p = buf;
+       ebuf = buf + nbuf;
+
+       sv[0] = d->name;
+       sv[1] = d->uid;
+       sv[2] = d->gid;
+       sv[3] = d->muid;
+
+       ns = 0;
+       for(i = 0; i < 4; i++){
+               if(sv[i])
+                       nsv[i] = strlen(sv[i]);
+               else
+                       nsv[i] = 0;
+               ns += nsv[i];
+       }
+
+       ss = STATFIXLEN + ns;
+
+       /* set size befor erroring, so user can know how much is needed */
+       /* note that length excludes count field itself */
+       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++){
+               ns = nsv[i];
+               if(p + ns + BIT16SZ > ebuf)
+                       return 0;
+               PBIT16(p, ns);
+               p += BIT16SZ;
+               if(ns)
+                       memmove(p, sv[i], ns);
+               p += ns;
+       }
+
+       if(ss != p - buf)
+               return 0;
+
+       return p - buf;
+}
diff --git a/kern/src/ns/convM2D.c b/kern/src/ns/convM2D.c
new file mode 100644 (file)
index 0000000..91ce85b
--- /dev/null
@@ -0,0 +1,105 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+int
+statcheck(uint8_t *buf, unsigned int nbuf)
+{
+       uint8_t *ebuf;
+       int i;
+
+       ebuf = buf + nbuf;
+
+       if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
+               return -1;
+
+       buf += STATFIXLEN - 4 * BIT16SZ;
+
+       for(i = 0; i < 4; i++){
+               if(buf + BIT16SZ > ebuf)
+                       return -1;
+               buf += BIT16SZ + GBIT16(buf);
+       }
+
+       if(buf != ebuf)
+               return -1;
+
+       return 0;
+}
+
+static char nullstring[] = "";
+
+unsigned int
+convM2D(uint8_t *buf, unsigned int nbuf, struct dir *d, char *strs)
+{
+       uint8_t *p, *ebuf;
+       char *sv[4];
+       int i, ns;
+
+       if(nbuf < STATFIXLEN)
+               return 0; 
+
+       p = buf;
+       ebuf = buf + nbuf;
+
+       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++){
+               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';
+               }
+               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;
+       }
+       
+       return p - buf;
+}
diff --git a/kern/src/ns/convM2S.c b/kern/src/ns/convM2S.c
new file mode 100644 (file)
index 0000000..88dce5c
--- /dev/null
@@ -0,0 +1,326 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+static
+uint8_t*
+gstring(uint8_t *p, uint8_t *ep, char **s)
+{
+       unsigned int n;
+
+       if(p+BIT16SZ > ep)
+               return NULL;
+       n = GBIT16(p);
+       p += BIT16SZ - 1;
+       if(p+n+1 > ep)
+               return NULL;
+       /* move it down, on top of count, to make room for '\0' */
+       memmove(p, p + 1, n);
+       p[n] = '\0';
+       *s = ( char *)p;
+       p += n+1;
+       return p;
+}
+
+static
+uint8_t*
+gqid(uint8_t *p, uint8_t *ep, struct qid *q)
+{
+       if(p+QIDSZ > ep)
+               return NULL;
+       q->type = GBIT8(p);
+       p += BIT8SZ;
+       q->vers = GBIT32(p);
+       p += BIT32SZ;
+       q->path = GBIT64(p);
+       p += BIT64SZ;
+       return p;
+}
+
+/*
+ * no syntactic checks.
+ * three causes for error:
+ *  1. message size field is incorrect
+ *  2. input buffer too short for its own data (counts too long, etc.)
+ *  3. too many names or qids
+ * gqid() and gstring() return NULL if they would reach beyond buffer.
+ * main switch statement checks range and also can fall through
+ * to test at end of routine.
+ */
+unsigned int
+convM2S(uint8_t *ap, unsigned int nap, struct fcall *f)
+{
+       uint8_t *p, *ep;
+       unsigned int i, size;
+
+       p = ap;
+       ep = p + nap;
+
+       if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
+               return 0;
+       size = GBIT32(p);
+       p += BIT32SZ;
+
+       if(size < BIT32SZ+BIT8SZ+BIT16SZ)
+               return 0;
+
+       f->type = GBIT8(p);
+       p += BIT8SZ;
+       f->tag = GBIT16(p);
+       p += BIT16SZ;
+
+       switch(f->type)
+       {
+       default:
+               return 0;
+
+       case Tversion:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->msize = GBIT32(p);
+               p += BIT32SZ;
+               p = gstring(p, ep, &f->version);
+               break;
+
+       case Tflush:
+               if(p+BIT16SZ > ep)
+                       return 0;
+               f->oldtag = GBIT16(p);
+               p += BIT16SZ;
+               break;
+
+       case Tauth:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->afid = GBIT32(p);
+               p += BIT32SZ;
+               p = gstring(p, ep, &f->uname);
+               if(p == NULL)
+                       break;
+               p = gstring(p, ep, &f->aname);
+               if(p == NULL)
+                       break;
+               break;
+
+       case Tattach:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->afid = GBIT32(p);
+               p += BIT32SZ;
+               p = gstring(p, ep, &f->uname);
+               if(p == NULL)
+                       break;
+               p = gstring(p, ep, &f->aname);
+               if(p == NULL)
+                       break;
+               break;
+
+       case Twalk:
+               if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               f->newfid = GBIT32(p);
+               p += BIT32SZ;
+               f->nwname = GBIT16(p);
+               p += BIT16SZ;
+               if(f->nwname > MAXWELEM)
+                       return 0;
+               for(i=0; i<f->nwname; i++){
+                       p = gstring(p, ep, &f->wname[i]);
+                       if(p == NULL)
+                               break;
+               }
+               break;
+
+       case Topen:
+               if(p+BIT32SZ+BIT8SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               f->mode = GBIT8(p);
+               p += BIT8SZ;
+               break;
+
+       case Tcreate:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               p = gstring(p, ep, &f->name);
+               if(p == NULL)
+                       break;
+               if(p+BIT32SZ+BIT8SZ > ep)
+                       return 0;
+               f->perm = GBIT32(p);
+               p += BIT32SZ;
+               f->mode = GBIT8(p);
+               p += BIT8SZ;
+               break;
+
+       case Tread:
+               if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               f->offset = GBIT64(p);
+               p += BIT64SZ;
+               f->count = GBIT32(p);
+               p += BIT32SZ;
+               break;
+
+       case Twrite:
+               if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               f->offset = GBIT64(p);
+               p += BIT64SZ;
+               f->count = GBIT32(p);
+               p += BIT32SZ;
+               if(p+f->count > ep)
+                       return 0;
+               f->data = ( char *)p;
+               p += f->count;
+               break;
+
+       case Tclunk:
+       case Tremove:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               break;
+
+       case Tstat:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               break;
+
+       case Twstat:
+               if(p+BIT32SZ+BIT16SZ > ep)
+                       return 0;
+               f->fid = GBIT32(p);
+               p += BIT32SZ;
+               f->nstat = GBIT16(p);
+               p += BIT16SZ;
+               if(p+f->nstat > ep)
+                       return 0;
+               f->stat = p;
+               p += f->nstat;
+               break;
+
+/*
+ */
+       case Rversion:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->msize = GBIT32(p);
+               p += BIT32SZ;
+               p = gstring(p, ep, &f->version);
+               break;
+
+       case Rerror:
+               p = gstring(p, ep, &f->ename);
+               break;
+
+       case Rflush:
+               break;
+
+       case Rauth:
+               p = gqid(p, ep, &f->aqid);
+               if(p == NULL)
+                       break;
+               break;
+
+       case Rattach:
+               p = gqid(p, ep, &f->qid);
+               if(p == NULL)
+                       break;
+               break;
+
+       case Rwalk:
+               if(p+BIT16SZ > ep)
+                       return 0;
+               f->nwqid = GBIT16(p);
+               p += BIT16SZ;
+               if(f->nwqid > MAXWELEM)
+                       return 0;
+               for(i=0; i<f->nwqid; i++){
+                       p = gqid(p, ep, &f->wqid[i]);
+                       if(p == NULL)
+                               break;
+               }
+               break;
+
+       case Ropen:
+       case Rcreate:
+               p = gqid(p, ep, &f->qid);
+               if(p == NULL)
+                       break;
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->iounit = GBIT32(p);
+               p += BIT32SZ;
+               break;
+
+       case Rread:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->count = GBIT32(p);
+               p += BIT32SZ;
+               if(p+f->count > ep)
+                       return 0;
+               f->data = ( char *)p;
+               p += f->count;
+               break;
+
+       case Rwrite:
+               if(p+BIT32SZ > ep)
+                       return 0;
+               f->count = GBIT32(p);
+               p += BIT32SZ;
+               break;
+
+       case Rclunk:
+       case Rremove:
+               break;
+
+       case Rstat:
+               if(p+BIT16SZ > ep)
+                       return 0;
+               f->nstat = GBIT16(p);
+               p += BIT16SZ;
+               if(p+f->nstat > ep)
+                       return 0;
+               f->stat = p;
+               p += f->nstat;
+               break;
+
+       case Rwstat:
+               break;
+       }
+
+       if(p==NULL || p>ep)
+               return 0;
+       if(ap+size == p)
+               return size;
+       return 0;
+}
diff --git a/kern/src/ns/convS2M.c b/kern/src/ns/convS2M.c
new file mode 100644 (file)
index 0000000..c7babdf
--- /dev/null
@@ -0,0 +1,397 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+static
+uint8_t*
+pstring(uint8_t *p, char *s)
+{
+       unsigned int n;
+
+       if(s == NULL){
+               PBIT16(p, 0);
+               p += BIT16SZ;
+               return p;
+       }
+
+       n = strlen(s);
+       PBIT16(p, n);
+       p += BIT16SZ;
+       memmove(p, s, n);
+       p += n;
+       return p;
+}
+
+static
+uint8_t*
+pqid(uint8_t *p, struct qid *q)
+{
+       PBIT8(p, q->type);
+       p += BIT8SZ;
+       PBIT32(p, q->vers);
+       p += BIT32SZ;
+       PBIT64(p, q->path);
+       p += BIT64SZ;
+       return p;
+}
+
+static
+unsigned int
+stringsz(char *s)
+{
+       if(s == NULL)
+               return BIT16SZ;
+
+       return BIT16SZ+strlen(s);
+}
+
+unsigned int
+sizeS2M(struct fcall *f)
+{
+       unsigned int n;
+       int i;
+
+       n = 0;
+       n += BIT32SZ;   /* size */
+       n += BIT8SZ;    /* type */
+       n += BIT16SZ;   /* tag */
+
+       switch(f->type)
+       {
+       default:
+               return 0;
+
+       case Tversion:
+               n += BIT32SZ;
+               n += stringsz(f->version);
+               break;
+
+       case Tflush:
+               n += BIT16SZ;
+               break;
+
+       case Tauth:
+               n += BIT32SZ;
+               n += stringsz(f->uname);
+               n += stringsz(f->aname);
+               break;
+
+       case Tattach:
+               n += BIT32SZ;
+               n += BIT32SZ;
+               n += stringsz(f->uname);
+               n += stringsz(f->aname);
+               break;
+
+       case Twalk:
+               n += BIT32SZ;
+               n += BIT32SZ;
+               n += BIT16SZ;
+               for(i=0; i<f->nwname; i++)
+                       n += stringsz(f->wname[i]);
+               break;
+
+       case Topen:
+               n += BIT32SZ;
+               n += BIT8SZ;
+               break;
+
+       case Tcreate:
+               n += BIT32SZ;
+               n += stringsz(f->name);
+               n += BIT32SZ;
+               n += BIT8SZ;
+               break;
+
+       case Tread:
+               n += BIT32SZ;
+               n += BIT64SZ;
+               n += BIT32SZ;
+               break;
+
+       case Twrite:
+               n += BIT32SZ;
+               n += BIT64SZ;
+               n += BIT32SZ;
+               n += f->count;
+               break;
+
+       case Tclunk:
+       case Tremove:
+               n += BIT32SZ;
+               break;
+
+       case Tstat:
+               n += BIT32SZ;
+               break;
+
+       case Twstat:
+               n += BIT32SZ;
+               n += BIT16SZ;
+               n += f->nstat;
+               break;
+/*
+ */
+
+       case Rversion:
+               n += BIT32SZ;
+               n += stringsz(f->version);
+               break;
+
+       case Rerror:
+               n += stringsz(f->ename);
+               break;
+
+       case Rflush:
+               break;
+
+       case Rauth:
+               n += QIDSZ;
+               break;
+
+       case Rattach:
+               n += QIDSZ;
+               break;
+
+       case Rwalk:
+               n += BIT16SZ;
+               n += f->nwqid*QIDSZ;
+               break;
+
+       case Ropen:
+       case Rcreate:
+               n += QIDSZ;
+               n += BIT32SZ;
+               break;
+
+       case Rread:
+               n += BIT32SZ;
+               n += f->count;
+               break;
+
+       case Rwrite:
+               n += BIT32SZ;
+               break;
+
+       case Rclunk:
+               break;
+
+       case Rremove:
+               break;
+
+       case Rstat:
+               n += BIT16SZ;
+               n += f->nstat;
+               break;
+
+       case Rwstat:
+               break;
+       }
+       return n;
+}
+
+unsigned int
+convS2M(struct fcall *f, uint8_t *ap, unsigned int nap)
+{
+       uint8_t *p;
+       unsigned int i, size;
+
+       size = sizeS2M(f);
+       if(size == 0)
+               return 0;
+       if(size > nap)
+               return 0;
+
+       p = ( uint8_t *)ap;
+
+       PBIT32(p, size);
+       p += BIT32SZ;
+       PBIT8(p, f->type);
+       p += BIT8SZ;
+       PBIT16(p, f->tag);
+       p += BIT16SZ;
+
+       switch(f->type)
+       {
+       default:
+               return 0;
+
+       case Tversion:
+               PBIT32(p, f->msize);
+               p += BIT32SZ;
+               p = pstring(p, f->version);
+               break;
+
+       case Tflush:
+               PBIT16(p, f->oldtag);
+               p += BIT16SZ;
+               break;
+
+       case Tauth:
+               PBIT32(p, f->afid);
+               p += BIT32SZ;
+               p  = pstring(p, f->uname);
+               p  = pstring(p, f->aname);
+               break;
+
+       case Tattach:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               PBIT32(p, f->afid);
+               p += BIT32SZ;
+               p  = pstring(p, f->uname);
+               p  = pstring(p, f->aname);
+               break;
+
+       case Twalk:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               PBIT32(p, f->newfid);
+               p += BIT32SZ;
+               PBIT16(p, f->nwname);
+               p += BIT16SZ;
+               if(f->nwname > MAXWELEM)
+                       return 0;
+               for(i=0; i<f->nwname; i++)
+                       p = pstring(p, f->wname[i]);
+               break;
+
+       case Topen:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               PBIT8(p, f->mode);
+               p += BIT8SZ;
+               break;
+
+       case Tcreate:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               p = pstring(p, f->name);
+               PBIT32(p, f->perm);
+               p += BIT32SZ;
+               PBIT8(p, f->mode);
+               p += BIT8SZ;
+               break;
+
+       case Tread:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               PBIT64(p, f->offset);
+               p += BIT64SZ;
+               PBIT32(p, f->count);
+               p += BIT32SZ;
+               break;
+
+       case Twrite:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               PBIT64(p, f->offset);
+               p += BIT64SZ;
+               PBIT32(p, f->count);
+               p += BIT32SZ;
+               memmove(p, f->data, f->count);
+               p += f->count;
+               break;
+
+       case Tclunk:
+       case Tremove:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               break;
+
+       case Tstat:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               break;
+
+       case Twstat:
+               PBIT32(p, f->fid);
+               p += BIT32SZ;
+               PBIT16(p, f->nstat);
+               p += BIT16SZ;
+               memmove(p, f->stat, f->nstat);
+               p += f->nstat;
+               break;
+/*
+ */
+
+       case Rversion:
+               PBIT32(p, f->msize);
+               p += BIT32SZ;
+               p = pstring(p, f->version);
+               break;
+
+       case Rerror:
+               p = pstring(p, f->ename);
+               break;
+
+       case Rflush:
+               break;
+
+       case Rauth:
+               p = pqid(p, &f->aqid);
+               break;
+
+       case Rattach:
+               p = pqid(p, &f->qid);
+               break;
+
+       case Rwalk:
+               PBIT16(p, f->nwqid);
+               p += BIT16SZ;
+               if(f->nwqid > MAXWELEM)
+                       return 0;
+               for(i=0; i<f->nwqid; i++)
+                       p = pqid(p, &f->wqid[i]);
+               break;
+
+       case Ropen:
+       case Rcreate:
+               p = pqid(p, &f->qid);
+               PBIT32(p, f->iounit);
+               p += BIT32SZ;
+               break;
+
+       case Rread:
+               PBIT32(p, f->count);
+               p += BIT32SZ;
+               memmove(p, f->data, f->count);
+               p += f->count;
+               break;
+
+       case Rwrite:
+               PBIT32(p, f->count);
+               p += BIT32SZ;
+               break;
+
+       case Rclunk:
+               break;
+
+       case Rremove:
+               break;
+
+       case Rstat:
+               PBIT16(p, f->nstat);
+               p += BIT16SZ;
+               memmove(p, f->stat, f->nstat);
+               p += f->nstat;
+               break;
+
+       case Rwstat:
+               break;
+       }
+       if(size != p-ap)
+               return 0;
+       return size;
+}