vol: Use FDH_SIZE more consistently
[openafs.git] / src / volser / dumpstuff.c
index 85da7bc..8c044d6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID("$Header$");
+#include <roken.h>
 
-#include <sys/types.h>
 #include <ctype.h>
-#include <stdio.h>
-#include <errno.h>
-#ifdef AFS_NT40_ENV
-#include <fcntl.h>
-#else
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/uio.h>
-#include <netinet/in.h>
-#include <unistd.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-#include <sys/stat.h>
-#include <afs/assert.h>
-#include <rx/xdr.h>
+
+#include <afs/opr.h>
 #include <rx/rx.h>
+#include <rx/rx_queue.h>
 #include <afs/afsint.h>
 #include <afs/nfs.h>
 #include <afs/errors.h>
@@ -45,70 +26,128 @@ RCSID("$Header$");
 #include <afs/vnode.h>
 #include <afs/volume.h>
 #include <afs/partition.h>
-#include "dump.h"
+#include <afs/daemon_com.h>
 #include <afs/fssync.h>
 #include <afs/acl.h>
+#include <afs/com_err.h>
+#include <afs/vol_prototypes.h>
+
+#include "dump.h"
 #include "volser.h"
 #include "volint.h"
+#include "dumpstuff.h"
 
-extern int DoLogging;
+#ifndef AFS_NT40_ENV
+#ifdef O_LARGEFILE
+#define afs_stat       stat64
+#define afs_fstat      fstat64
+#else /* !O_LARGEFILE */
+#define afs_stat       stat
+#define afs_fstat      fstat
+#endif /* !O_LARGEFILE */
+#endif /* !AFS_NT40_ENV */
 
-/* This iod stuff is a silly little package to emulate the old qi_in stuff, which
-   emulated the stdio stuff.  There is a big assumption here, that the
-   rx_Read will never be called directly, by a routine like readFile, when
-   there is an old character that was pushed back with iod_ungetc.  This
-   is really bletchy, and is here for compatibility only.  Eventually,
-   we should define a volume format that doesn't require
-   the pushing back of characters (i.e. characters should not double both
-   as an end marker and a begin marker) */
-struct iod {
-    struct rx_call *call;      /* call to which to write, might be an array */
-    int device;                        /* dump device ID for volume */
-    int parentId;              /* dump parent ID for volume */
-    struct DiskPartition *dumpPartition; /* Dump partition. */
-    struct rx_call **calls;      /* array of pointers to calls */
-    int ncalls;                 /* how many calls/codes in array */
-    int *codes;                 /* one return code for each call */
-    char haveOldChar;          /* state for pushing back a character */
-    char oldChar;
-};
+/*@printflike@*/ extern void Log(const char *format, ...);
+
+extern int DoLogging;
+extern int DoPreserveVolumeStats;
 
 
 /* Forward Declarations */
-static int DumpDumpHeader(register struct iod *iodp, register Volume *vp,
+static int DumpDumpHeader(struct iod *iodp, Volume * vp,
                          afs_int32 fromtime);
-static int DumpPartial(register struct iod *iodp, register Volume *vp,
+static int DumpPartial(struct iod *iodp, Volume * vp,
                       afs_int32 fromtime, int dumpAllDirs);
-static int DumpVnodeIndex(register struct iod *iodp, Volume *vp,
-                         VnodeClass class, afs_int32 fromtime, int forcedump);
-static int DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
-                    int volid, int vnodeNumber, int dumpEverything);
-static int ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp);
-static int ReadVnodes(register struct iod *iodp, Volume *vp,
-                     int incremental, afs_int32 *Lbuf, afs_int32 s1,
-                     afs_int32 *Sbuf, afs_int32 s2, afs_int32 delo);
-static afs_offs_t volser_WriteFile(int vn, struct iod *iodp,
-                                  FdHandle_t *handleP,
-                                  int tag, Error *status);
-
-
-static void iod_Init(register struct iod *iodp, register struct rx_call *call)
+static int DumpVnodeIndex(struct iod *iodp, Volume * vp,
+                         VnodeClass class, afs_int32 fromtime,
+                         int forcedump);
+static int DumpVnode(struct iod *iodp, struct VnodeDiskObject *v,
+                    VolumeId volid, int vnodeNumber, int dumpEverything);
+static int ReadDumpHeader(struct iod *iodp, struct DumpHeader *hp);
+static int ReadVnodes(struct iod *iodp, Volume * vp, afs_foff_t * Lbuf,
+                      afs_int32 s1, afs_foff_t * Sbuf, afs_int32 s2,
+                      afs_int32 delo);
+static afs_fsize_t volser_WriteFile(int vn, struct iod *iodp,
+                                   FdHandle_t * handleP, int tag,
+                                   Error * status);
+
+static int SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
+                             afs_int32 fromtime,
+                             struct volintSize *size);
+static int SizeDumpPartial(struct iod *iodp, Volume * vp,
+                          afs_int32 fromtime, int dumpAllDirs,
+                          struct volintSize *size);
+static int SizeDumpVnodeIndex(struct iod *iodp, Volume * vp,
+                             VnodeClass class, afs_int32 fromtime,
+                             int forcedump,
+                             struct volintSize *size);
+static int SizeDumpVnode(struct iod *iodp, struct VnodeDiskObject *v,
+                        VolumeId volid, int vnodeNumber, int dumpEverything,
+                        struct volintSize *size);
+
+#define MAX_SECTIONS    3
+
+/* The TLV range must start above D_MAX */
+#define MIN_TLV_TAG     21
+#define MAX_TLV_TAG     0x60
+#define MAX_STANDARD_TAG 0x7a
+static afs_uint32 oldtags[MAX_SECTIONS][16];
+int oldtagsInited = 0;
+
+static void
+RegisterTag(afs_int32 section, unsigned char tag)
+{
+    afs_uint32 off = tag >> 5;
+    afs_uint32 mask = 1 << (tag & 0x1f);
+    oldtags[section][off] |= mask;
+}
+
+static void
+initNonStandardTags(void)
+{
+    RegisterTag(0, 'n');                /* volume name */
+    RegisterTag(0, 't');                /* fromtime, V_backupDate */
+    RegisterTag(1, 'A');                /* V_accessDate */
+    RegisterTag(1, 'C');                /* V_creationDate */
+    RegisterTag(1, 'D');                /* V_dayUseDate */
+    RegisterTag(1, 'E');                /* V_expirationDate */
+    RegisterTag(1, 'M');                /* nullstring (motd) */
+    RegisterTag(1, 'U');                /* V_updateDate */
+    RegisterTag(1, 'W');                /* V_weekUse */
+    RegisterTag(1, 'Z');                /* V_dayUse */
+    RegisterTag(1, 'O');                /* V_offlineMessage */
+    RegisterTag(1, 'b');                /* V_blessed */
+    RegisterTag(1, 'n');                /* V_name */
+    RegisterTag(1, 's');                /* V_inService */
+    RegisterTag(1, 't');                /* V_type */
+    RegisterTag(2, 'A');                /* VVnodeDiskACL */
+    RegisterTag(2, 'b');                /* modeBits */
+    RegisterTag(2, 'f');                /* small file */
+    RegisterTag(2, 'h');                /* large file */
+    RegisterTag(2, 'l');                /* linkcount */
+    RegisterTag(2, 't');                /* type */
+    oldtagsInited = 1;
+}
+
+static void
+iod_Init(struct iod *iodp, struct rx_call *call)
 {
     iodp->call = call;
     iodp->haveOldChar = 0;
     iodp->ncalls = 1;
-    iodp->calls = (struct rx_call **) 0;
+    iodp->calls = (struct rx_call **)0;
 }
 
-static void iod_InitMulti(struct iod *iodp, struct rx_call **calls, int ncalls,
-                  int *codes)
+static void
+iod_InitMulti(struct iod *iodp, struct rx_call **calls, int ncalls,
+             int *codes)
 {
 
-  iodp->calls = calls;
-  iodp->haveOldChar = 0;
-  iodp->ncalls = ncalls;
-  iodp->codes = codes;
-  iodp->call = (struct rx_call *) 0;
+    iodp->calls = calls;
+    iodp->haveOldChar = 0;
+    iodp->ncalls = ncalls;
+    iodp->codes = codes;
+    iodp->call = (struct rx_call *)0;
 }
 
 /* N.B. iod_Read doesn't check for oldchar (see previous comment) */
@@ -117,344 +156,601 @@ static void iod_InitMulti(struct iod *iodp, struct rx_call **calls, int ncalls,
 /* For the single dump case, it's ok to just return the "bytes written"
  * that rx_Write returns, since all the callers of iod_Write abort when
  * the returned value is less than they expect.  For the multi dump case,
- * I don't think we want half the replicas to go bad just because one 
- * connection timed out, but if they all time out, then we should give up. 
+ * I don't think we want half the replicas to go bad just because one
+ * connection timed out, but if they all time out, then we should give up.
  */
-static int iod_Write(struct iod *iodp, char *buf, int nbytes)
+static int
+iod_Write(struct iod *iodp, char *buf, int nbytes)
 {
-  int code, i;
-  int one_success = 0;
-
-  assert ((iodp->call && iodp->ncalls == 1 && !iodp->calls) ||
-         (!iodp->call && iodp->ncalls >= 1 && iodp->calls));
-
-  if (iodp->call) {
-    code = rx_Write(iodp->call, buf, nbytes); 
-    return code;     
-  }
-
-  for (i=0; i < iodp->ncalls; i++) {
-    if (iodp->calls[i] && !iodp->codes[i]) {
-      code = rx_Write(iodp->calls[i], buf, nbytes);
-      if (code != nbytes) { /* everything gets merged into a single error */
-       iodp->codes[i] = VOLSERDUMPERROR;  /* but that's exactly what the */
-      }                                   /* standard dump does, anyways */
-      else {
-       one_success = TRUE;
-      }
+    int code, i;
+    int one_success = 0;
+
+    opr_Assert((iodp->call && iodp->ncalls == 1 && !iodp->calls)
+          || (!iodp->call && iodp->ncalls >= 1 && iodp->calls));
+
+    if (iodp->call) {
+       code = rx_Write(iodp->call, buf, nbytes);
+       return code;
     }
-  } /* for all calls */
 
-if (one_success)
-  return nbytes;
-else return 0;
+    for (i = 0; i < iodp->ncalls; i++) {
+       if (iodp->calls[i] && !iodp->codes[i]) {
+           code = rx_Write(iodp->calls[i], buf, nbytes);
+           if (code != nbytes) {       /* everything gets merged into a single error */
+               iodp->codes[i] = VOLSERDUMPERROR;       /* but that's exactly what the */
+           } /* standard dump does, anyways */
+           else {
+               one_success = TRUE;
+           }
+       }
+    }                          /* for all calls */
+
+    if (one_success)
+       return nbytes;
+    else
+       return 0;
 }
 
-static void iod_ungetc(struct iod *iodp, int achar)
+static void
+iod_ungetc(struct iod *iodp, int achar)
 {
     iodp->oldChar = achar;
     iodp->haveOldChar = 1;
 }
 
-static int iod_getc(register struct iod *iodp)
+static int
+iod_getc(struct iod *iodp)
 {
     unsigned char t;
-   
+
     if (iodp->haveOldChar) {
        iodp->haveOldChar = 0;
        return iodp->oldChar;
     }
-    if (iod_Read(iodp, &t, 1) == 1) return t;
+    if (iod_Read(iodp, (char *) &t, 1) == 1)
+       return t;
     return EOF;
 }
 
-static int ReadShort(register struct iod *iodp, register unsigned short *sp)
+static int
+ReadShort(struct iod *iodp, unsigned short *sp)
 {
-    register b1,b0;
+    int b1, b0;
     b1 = iod_getc(iodp);
+    if (b1 == EOF)
+       return 0;
     b0 = iod_getc(iodp);
-    *sp = (b1<<8) | b0;
-    return b0 != EOF;
+    if (b0 == EOF)
+       return 0;
+    *sp = (b1 << 8) | b0;
+    return 1;
 }
 
-static int ReadInt32(register struct iod *iodp, afs_uint32 *lp)
+static int
+ReadInt32(struct iod *iodp, afs_uint32 * lp)
 {
-    afs_uint32 register b3,b2,b1,b0;
+    afs_uint32 b3, b2, b1, b0;
     b3 = iod_getc(iodp);
+    if (b3 == EOF)
+       return 0;
     b2 = iod_getc(iodp);
+    if (b2 == EOF)
+       return 0;
     b1 = iod_getc(iodp);
+    if (b1 == EOF)
+       return 0;
     b0 = iod_getc(iodp);
-    *lp = (((((b3<<8)|b2)<<8)|b1)<<8)|b0;
-    return b0 != EOF;
+    if (b0 == EOF)
+       return 0;
+    *lp = (((((b3 << 8) | b2) << 8) | b1) << 8) | b0;
+    return 1;
 }
 
-static void ReadString(register struct iod *iodp, register char *to,
-                     register int maxa)
+static void
+ReadString(struct iod *iodp, char *to, int maxa)
 {
-    register int c;
+    int c;
+
+    *to = '\0';
+    if (maxa == 0)
+       return;
+
     while (maxa--) {
-       if ((*to++ = iod_getc(iodp)) == 0)
+       if ((*to++ = c = iod_getc(iodp)) == 0 || c == EOF)
            break;
     }
     if (to[-1]) {
        while ((c = iod_getc(iodp)) && c != EOF);
-       to[-1] = 0;
+       to[-1] = '\0';
+    }
+}
+
+static int
+ReadByteString(struct iod *iodp, byte * to, int size)
+{
+    int nbytes = 0;
+    int c;
+
+    while (size-- > 0 && (c = iod_getc(iodp)) != EOF) {
+       *to++ = c;
+       nbytes++;
+    }
+    return nbytes;
+}
+
+/*
+ * returns 1 on success and 0 otherwise
+ */
+static afs_int32
+ReadStandardTagLen(struct iod *iodp, unsigned char tag, afs_int32 section,
+                        afs_size_t *length)
+{
+    afs_int32 code, i;
+    afs_uint32 off = tag >> 5;
+    afs_uint32 mask = 1 << (tag & 0x1f);
+    int len;
+    unsigned char buf[8], *p;
+
+    if (!oldtagsInited)
+        initNonStandardTags();
+
+    if (tag < MIN_TLV_TAG
+      || tag > MAX_STANDARD_TAG
+      || section >= MAX_SECTIONS
+      || (oldtags[section][ off] & mask)) {
+        Log("Trying to use ReadStandardTag with tag 0x%02x for section %d, aborting\n", tag, section);
+        return 0;
+    }
+    if (tag <= MAX_TLV_TAG) {
+        len = iod_getc(iodp);
+       if (len == EOF)
+           return VOLSERDUMPERROR;
+       else if (len < 128)
+            *length = len;
+        else {
+            len &= 0x7f;
+            if ((code = iod_Read(iodp, (char *)buf, len)) != len)
+                return VOLSERDUMPERROR;
+            *length = 0;
+            p = (unsigned char *)&buf;
+            for (i=0; i<len; i++) {
+                *length = ((*length) << 8) | *p++;
+            }
+        }
+    } else {
+        if (tag < MAX_STANDARD_TAG)
+            *length = 4;
     }
+    return 1;
 }
 
-static void ReadByteString(register struct iod *iodp, register byte *to,
-                  register int size)
+static char skipbuf[256];
+
+static afs_int32
+SkipData(struct iod *iodp, afs_size_t length)
 {
-    while (size--)
-       *to++ = iod_getc(iodp);
+    while (length > 256) {
+        if (iod_Read(iodp, (char *)&skipbuf, 256) != 256)
+            return 0;
+        length -= 256;
+    }
+    if (iod_Read(iodp, (char *)&skipbuf, length) != length)
+        return 0;
+    return 1;
 }
 
-static int ReadVolumeHeader(register struct iod *iodp, VolumeDiskData *vol)
+static char *secname[3] = {"ReadDumpHeader", "ReadVolumeHeader", "ReadVnodes"};
+
+static int
+HandleUnknownTag(struct iod *iodp, int tag, afs_int32 section,
+               afs_int32 critical)
 {
-    register tag;
+    afs_size_t taglen = 0;
     afs_uint32 trash;
+
+    if (critical) {
+        Log("%s: unknown critical tag x%02x, aborting\n",
+                secname[section], tag);
+        return 0;
+    }
+    Log("%s: unknown tag x%02x found, skipping\n", secname[section], tag);
+    if (tag >= 0x06 && tag <= 0x60) {
+        if (!ReadStandardTagLen(iodp, tag, 1, &taglen)) {
+            Log("%s: error reading length field for tag x%02x, aborting\n",
+                secname[section], tag);
+            return 0;
+        }
+        if (!SkipData(iodp, taglen)) {
+            Log("%s: error skipping %llu bytes for tag x%02x, aborting\n",
+                secname[section], taglen, tag);
+            return 0;
+        }
+        return 1;
+    }
+    if (tag >= 0x61 && tag <= 0x7a) {
+        if (!ReadInt32(iodp, &trash)) {
+            Log("%s: error skipping int32 for tag x%02x, aborting\n",
+                secname[section], tag);
+            return 0;
+        }
+        return 1;
+    }
+    if (tag >= 0x7b && tag < 0x80)      /* dataless tag */
+        return 1;
+    Log("%s: unknown invalid tag x%02x, aborting\n", secname[section], tag);
+    return 0;
+}
+
+static int
+ReadVolumeHeader(struct iod *iodp, VolumeDiskData * vol)
+{
+    int tag;
+    afs_uint32 trash;
+    afs_int32 critical = 0;
     memset(vol, 0, sizeof(*vol));
     while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
+        if (critical)
+            critical--;
        switch (tag) {
-           case 'i':
-               if(!ReadInt32(iodp, &vol->id)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'v':
-               if(!ReadInt32(iodp, &trash)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'n':
-                ReadString(iodp, vol->name, sizeof(vol->name));
-               /*this means the name of the retsored volume could be possibly different. In conjunction with SAFSVolSignalRestore */
-               break;
-           case 's':
-               vol->inService = iod_getc(iodp );
-               break;
-           case 'b':
-               vol->blessed = iod_getc(iodp );
-               break;
-           case 'u':
-               if(!ReadInt32(iodp, &vol->uniquifier)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 't':
-               vol->type = iod_getc(iodp );
-               break;
-           case 'p':
-               if(!ReadInt32(iodp, &vol->parentId)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'c':
-               if(!ReadInt32(iodp, &vol->cloneId)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'q':
-               if(!ReadInt32(iodp, (afs_uint32 *)&vol->maxquota)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'm':
-               if(!ReadInt32(iodp, (afs_uint32 *)&vol->minquota)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'd':
-               if(!ReadInt32(iodp, (afs_uint32 *)&vol->diskused)) return VOLSERREAD_DUMPERROR; /* Bogus:  should calculate this */
-               break;
-           case 'f':
-               if(!ReadInt32(iodp, (afs_uint32 *)&vol->filecount)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'a':
-               if(!ReadInt32(iodp, &vol->accountNumber)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'o':
-               if(!ReadInt32(iodp, &vol->owner)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'C':
-               if(!ReadInt32(iodp, &vol->creationDate)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'A':
-               if(!ReadInt32(iodp, &vol->accessDate)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'U':
-               if(!ReadInt32(iodp, &vol->updateDate)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'E':
-               if(!ReadInt32(iodp, &vol->expirationDate)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'B':
-               if(!ReadInt32(iodp, &vol->backupDate)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'O':
-               ReadString(iodp, vol->offlineMessage, sizeof(vol->offlineMessage));
-               break;
-           case 'M':
-               /*
-                * Detailed volume statistics are never stored in dumps,
-                * so we just restore either the null string if this volume
-                * had already been set to store statistics, or the old motd
-                * contents otherwise.  It doesn't matter, since this field
-                * will soon get initialized anyway.
-                */
-               ReadString(iodp, (char *)(vol->stat_reads), VMSGSIZE);
-               break;
-           case 'W': {
+       case 'i':
+           if (!ReadInt32(iodp, &vol->id))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'v':
+           if (!ReadInt32(iodp, &trash))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'n':
+           ReadString(iodp, vol->name, sizeof(vol->name));
+           /*this means the name of the retsored volume could be possibly different. In conjunction with SAFSVolSignalRestore */
+           break;
+       case 's':
+           vol->inService = iod_getc(iodp);
+           break;
+       case 'b':
+           vol->blessed = iod_getc(iodp);
+           break;
+       case 'u':
+           if (!ReadInt32(iodp, &vol->uniquifier))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 't':
+           vol->type = iod_getc(iodp);
+           break;
+       case 'p':
+           if (!ReadInt32(iodp, &vol->parentId))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'c':
+           if (!ReadInt32(iodp, &vol->cloneId))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'q':
+           if (!ReadInt32(iodp, (afs_uint32 *) & vol->maxquota))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'm':
+           if (!ReadInt32(iodp, (afs_uint32 *) & vol->minquota))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'd':
+           if (!ReadInt32(iodp, (afs_uint32 *) & vol->diskused))
+               return VOLSERREAD_DUMPERROR;    /* Bogus:  should calculate this */
+           break;
+       case 'f':
+           if (!ReadInt32(iodp, (afs_uint32 *) & vol->filecount))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'a':
+           if (!ReadInt32(iodp, &vol->accountNumber))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'o':
+           if (!ReadInt32(iodp, &vol->owner))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'C':
+           if (!ReadInt32(iodp, &vol->creationDate))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'A':
+           if (!ReadInt32(iodp, &vol->accessDate))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'U':
+           if (!ReadInt32(iodp, &vol->updateDate))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'E':
+           if (!ReadInt32(iodp, &vol->expirationDate))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'B':
+           if (!ReadInt32(iodp, &vol->backupDate))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'O':
+           ReadString(iodp, vol->offlineMessage,
+                      sizeof(vol->offlineMessage));
+           break;
+       case 'M':
+           /*
+            * Detailed volume statistics are never stored in dumps,
+            * so we just restore either the null string if this volume
+            * had already been set to store statistics, or the old motd
+            * contents otherwise.  It doesn't matter, since this field
+            * will soon get initialized anyway.
+            */
+           ReadString(iodp, (char *)(vol->stat_reads), VMSGSIZE);
+           break;
+       case 'W':{
                unsigned short length;
                int i;
-               afs_uint32 data;
-               if(!ReadShort(iodp, &length)) return VOLSERREAD_DUMPERROR;
-               for (i = 0; i<length; i++) {
-                   if(!ReadInt32(iodp, &data)) return VOLSERREAD_DUMPERROR;
-                   if (i < sizeof(vol->weekUse)/sizeof(vol->weekUse[0]))
+               afs_uint32 data;
+               if (!ReadShort(iodp, &length))
+                   return VOLSERREAD_DUMPERROR;
+               for (i = 0; i < length; i++) {
+                   if (!ReadInt32(iodp, &data))
+                       return VOLSERREAD_DUMPERROR;
+                   if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
                        vol->weekUse[i] = data;
                }
                break;
            }
-           case 'D':
-               if(!ReadInt32(iodp, &vol->dayUseDate)) return VOLSERREAD_DUMPERROR;
-               break;
-           case 'Z':
-               if(!ReadInt32(iodp, (afs_uint32 *)&vol->dayUse)) return VOLSERREAD_DUMPERROR;
-               break;
+       case 'D':
+           if (!ReadInt32(iodp, &vol->dayUseDate))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'Z':
+           if (!ReadInt32(iodp, (afs_uint32 *) & vol->dayUse))
+               return VOLSERREAD_DUMPERROR;
+           break;
+       case 'V':
+           if (!ReadInt32(iodp, (afs_uint32 *) &trash/*volUpdateCounter*/))
+               return VOLSERREAD_DUMPERROR;
+           break;
+        case 0x7e:
+            critical = 2;
+            break;
+        default:
+            if (!HandleUnknownTag(iodp, tag, 1, critical))
+                return VOLSERREAD_DUMPERROR;
        }
     }
     iod_ungetc(iodp, tag);
     return 0;
 }
 
-static int DumpTag(register struct iod *iodp, register int tag)
+static int
+DumpTag(struct iod *iodp, int tag)
 {
     char p;
-    
+
     p = tag;
-    return((iod_Write(iodp, &p, 1) == 1)? 0 : VOLSERDUMPERROR);
-    
+    return ((iod_Write(iodp, &p, 1) == 1) ? 0 : VOLSERDUMPERROR);
+
 }
 
-static int DumpByte(register struct iod *iodp, char tag, byte value)
+static int
+DumpByte(struct iod *iodp, char tag, byte value)
 {
     char tbuffer[2];
-    register byte *p = (unsigned char *) tbuffer;
+    byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
     *p = value;
-    return((iod_Write(iodp, tbuffer, 2) == 2)? 0: VOLSERDUMPERROR);
+    return ((iod_Write(iodp, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
 }
 
-#define putint32(p, v)  *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
-#define putshort(p, v) *p++ = v>>8, *p++ = v
+#define afs_putint32(p, v)  *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
+#define afs_putshort(p, v) *p++ = v>>8, *p++ = v
 
-static int DumpDouble(register struct iod *iodp, char tag,
-                     register afs_uint32 value1, register afs_uint32 value2)
+static int
+DumpDouble(struct iod *iodp, char tag, afs_uint32 value1,
+          afs_uint32 value2)
 {
     char tbuffer[9];
-    register byte *p = (unsigned char *) tbuffer;
+    byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    putint32(p, value1);
-    putint32(p, value2);
-    return((iod_Write(iodp, tbuffer, 9) == 9)? 0: VOLSERDUMPERROR);
+    afs_putint32(p, value1);
+    afs_putint32(p, value2);
+    return ((iod_Write(iodp, tbuffer, 9) == 9) ? 0 : VOLSERDUMPERROR);
 }
 
-static int DumpInt32(register struct iod *iodp, char tag,
-                    register afs_uint32 value)
+static int
+DumpInt32(struct iod *iodp, char tag, afs_uint32 value)
 {
     char tbuffer[5];
-    register byte *p = (unsigned char *) tbuffer;
+    byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    putint32(p, value);
-    return((iod_Write(iodp, tbuffer, 5) == 5)? 0: VOLSERDUMPERROR);
+    afs_putint32(p, value);
+    return ((iod_Write(iodp, tbuffer, 5) == 5) ? 0 : VOLSERDUMPERROR);
 }
 
-static int DumpArrayInt32(register struct iod *iodp, char tag,
-                         register afs_uint32 *array, register int nelem)
+static int
+DumpArrayInt32(struct iod *iodp, char tag,
+              afs_uint32 * array, int nelem)
 {
     char tbuffer[4];
-    register afs_uint32 v ;
+    afs_uint32 v;
     int code = 0;
-    register byte *p = (unsigned char *) tbuffer;
+    byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    putshort(p, nelem);
+    afs_putshort(p, nelem);
     code = iod_Write(iodp, tbuffer, 3);
-    if (code != 3) return VOLSERDUMPERROR;
+    if (code != 3)
+       return VOLSERDUMPERROR;
     while (nelem--) {
-       p = (unsigned char *) tbuffer;
-       v = *array++;/*this was register */
-       
-       putint32(p, v);
+       p = (unsigned char *)tbuffer;
+       v = *array++;           /*this was register */
+
+       afs_putint32(p, v);
        code = iod_Write(iodp, tbuffer, 4);
-       if(code != 4) return VOLSERDUMPERROR;
+       if (code != 4)
+           return VOLSERDUMPERROR;
     }
     return 0;
 }
 
-static int DumpShort(register struct iod *iodp, char tag, unsigned int value)
+static int
+DumpShort(struct iod *iodp, char tag, unsigned int value)
 {
     char tbuffer[3];
-    register byte *p = (unsigned char *) tbuffer;
+    byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    *p++ = value>>8;
+    *p++ = value >> 8;
     *p = value;
-    return((iod_Write(iodp, tbuffer, 3) == 3)? 0: VOLSERDUMPERROR);
+    return ((iod_Write(iodp, tbuffer, 3) == 3) ? 0 : VOLSERDUMPERROR);
 }
 
-static int DumpBool(register struct iod *iodp, char tag, unsigned int value)
+static int
+DumpBool(struct iod *iodp, char tag, unsigned int value)
 {
     char tbuffer[2];
-    register byte *p = (unsigned char *) tbuffer;
+    byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
     *p = value;
-    return((iod_Write(iodp, tbuffer, 2) == 2)? 0: VOLSERDUMPERROR);
+    return ((iod_Write(iodp, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
 }
 
-static int DumpString(register struct iod *iodp, char tag, register char *s)
+static int
+DumpString(struct iod *iodp, char tag, char *s)
 {
-    register n;
+    int n;
     int code = 0;
     code = iod_Write(iodp, &tag, 1);
-    if(code != 1) return VOLSERDUMPERROR;
-    n = strlen(s)+1;
+    if (code != 1)
+       return VOLSERDUMPERROR;
+    n = strlen(s) + 1;
     code = iod_Write(iodp, s, n);
-    if(code != n) return VOLSERDUMPERROR;
+    if (code != n)
+       return VOLSERDUMPERROR;
     return 0;
 }
 
-static int DumpByteString(register struct iod *iodp, char tag,
-                         register byte *bs, register int nbytes)
+static int
+DumpByteString(struct iod *iodp, char tag, byte * bs,
+              int nbytes)
 {
     int code = 0;
 
     code = iod_Write(iodp, &tag, 1);
-    if(code != 1) return VOLSERDUMPERROR;
+    if (code != 1)
+       return VOLSERDUMPERROR;
     code = iod_Write(iodp, (char *)bs, nbytes);
-    if(code != nbytes) return VOLSERDUMPERROR;
+    if (code != nbytes)
+       return VOLSERDUMPERROR;
     return 0;
 }
-    
-static int DumpFile(struct iod *iodp, int vnode, FdHandle_t *handleP)
+
+static afs_int32
+DumpStandardTag(struct iod *iodp, char tag, afs_uint32 section)
 {
-    int   code = 0, lcode = 0, error = 0;
-    afs_int32 pad = 0, offset;
-    afs_size_t   n, nbytes, howMany, howBig;
-    byte  *p;
-#ifdef AFS_LARGEFILE_ENV
-    struct stat64 status;
+    afs_int32 code;
+    afs_uint32 off = tag >> 5;
+    afs_uint32 mask = 1 << (tag & 0x1f);
+
+    if (!oldtagsInited)
+        initNonStandardTags();
+
+    if (tag < MIN_TLV_TAG
+      || tag > MAX_STANDARD_TAG
+      || section >= MAX_SECTIONS
+      || (oldtags[section][ off] & mask)) {
+        Log("Trying to use DumpStandardTag with tag 0x%02x for section %d, aborting\n", tag, section);
+        return VOLSERDUMPERROR;
+    }
+    code = iod_Write(iodp, &tag, 1);
+    if (code != 1)
+       return VOLSERDUMPERROR;
+    return 0;
+}
+
+AFS_UNUSED
+static afs_int32
+DumpStandardTagLen(struct iod *iodp, char tag, afs_uint32 section,
+                        afs_size_t length)
+{
+    char buf[10];
+    char *p;
+    afs_int32 code, len;
+
+    if (tag < MIN_TLV_TAG || tag > MAX_TLV_TAG) {
+        Log("Trying to use DumpStandardTagLen with tag 0x%02x for section %d, aborting\n", tag, section);
+        return VOLSERDUMPERROR;
+    }
+    code = DumpStandardTag(iodp, tag, section);
+    if (code)
+        return code;
+    p = &buf[9];
+    if (length < 128) { /* byte after tag contains length */
+        *p-- = length;
+        len = 1;
+    } else {            /* byte after tag contains length of length field | 0x80 */
+        for (len=0; length; length=length >> 8) {
+            *p-- = length;
+            len++;
+        }
+        *p-- = len + 128;
+        len += 1;
+    }
+    p++;
+    code = iod_Write(iodp, p, len);
+    if (code != len)
+        return VOLSERDUMPERROR;
+    return 0;
+}
+
+static int
+DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
+{
+    int code = 0, error = 0;
+    afs_sfsize_t nbytes, howBig;
+    ssize_t n = 0;
+    size_t howMany;
+    afs_foff_t howFar = 0;
+    byte *p;
+    afs_uint32 hi, lo;
+    afs_ino_str_t stmp;
+#ifndef AFS_NT40_ENV
+    struct afs_stat status;
 #else
-    struct stat status;
+    LARGE_INTEGER fileSize;
 #endif
-    afs_size_t size;
 #ifdef AFS_AIX_ENV
 #include <sys/statfs.h>
+#if defined(AFS_AIX52_ENV)
+    struct statfs64 tstatfs;
+#else /* !AFS_AIX52_ENV */
     struct statfs tstatfs;
+#endif /* !AFS_AIX52_ENV */
+    int statfs_code;
 #endif
 
 #ifdef AFS_NT40_ENV
-    howBig = _filelength(handleP->fd_fd);
+    if (!GetFileSizeEx(handleP->fd_fd, &fileSize)) {
+        Log("DumpFile: GetFileSizeEx returned error code %d on descriptor %d\n", GetLastError(), handleP->fd_fd);
+           return VOLSERDUMPERROR;
+    }
+    howBig = fileSize.QuadPart;
     howMany = 4096;
 
 #else
-#ifdef AFS_LARGEFILE_ENV
-    fstat64(handleP->fd_fd, &status);
-#else /* !AFS_LARGEFILE_ENV */
-    fstat(handleP->fd_fd, &status);
-#endif /* !AFS_LARGEFILE_ENV */
+    afs_fstat(handleP->fd_fd, &status);
     howBig = status.st_size;
 
 #ifdef AFS_AIX_ENV
-    /* Unfortunately in AIX valuable fields such as st_blksize are 
+    /* Unfortunately in AIX valuable fields such as st_blksize are
      * gone from the stat structure.
      */
-    fstatfs(handleP->fd_fd, &tstatfs);
+#if defined(AFS_AIX52_ENV)
+    statfs_code = fstatfs64(handleP->fd_fd, &tstatfs);
+#else /* !AFS_AIX52_ENV */
+    statfs_code = fstatfs(handleP->fd_fd, &tstatfs);
+#endif /* !AFS_AIX52_ENV */
+    if (statfs_code != 0) {
+        Log("DumpFile: fstatfs returned error code %d on descriptor %d\n", errno, handleP->fd_fd);
+       return VOLSERDUMPERROR;
+    }
     howMany = tstatfs.f_bsize;
 #else
     howMany = status.st_blksize;
@@ -462,241 +758,248 @@ static int DumpFile(struct iod *iodp, int vnode, FdHandle_t *handleP)
 #endif /* AFS_NT40_ENV */
 
 
-    size = FDH_SIZE(handleP);
-#ifdef AFS_LARGEFILE_ENV
-    {
-       afs_uint32      hi,lo;
-       SplitInt64(size, hi, lo);
-       if (hi == 0L) {
-           code = DumpInt32(iodp, 'f', lo);
-       } else {
-           code = DumpDouble(iodp, 'h', hi, lo);
-       }
+    SplitInt64(howBig, hi, lo);
+    if (hi == 0L) {
+       code = DumpInt32(iodp, 'f', lo);
+    } else {
+       code = DumpDouble(iodp, 'h', hi, lo);
     }
-#else /* !AFS_LARGEFILE_ENV */
-    code = DumpInt32(iodp, 'f', size);
-#endif /* !AFS_LARGEFILE_ENV */
     if (code) {
-       return VOLSERDUMPERROR;
+       return VOLSERDUMPERROR;
     }
 
-    p = (unsigned char *) malloc(howMany);
+    p = malloc(howMany);
     if (!p) {
-       Log("1 Volser: DumpFile: no memory");
-       return VOLSERDUMPERROR;
+       Log("1 Volser: DumpFile: not enough memory to allocate %u bytes\n", (unsigned)howMany);
+       return VOLSERDUMPERROR;
     }
 
-    for (nbytes = size; (nbytes && !error); nbytes -= howMany) {
-       if (nbytes < howMany) 
-          howMany = nbytes;
-
-       /* Read the data - unless we know we can't */
-       n = (lcode ? 0 : FDH_READ(handleP, p, howMany));        
-
-       /* If read any good data and we null padded previously, log the
-        * amount that we had null padded.
-        */
-       if ((n > 0) && pad) {
-          Log("1 Volser: DumpFile: Null padding file %d bytes at offset %u\n",
-              pad, offset);
-          pad = 0;
+    for (nbytes = howBig; (nbytes && !error); ) {
+       if (nbytes < howMany)
+           howMany = nbytes;
+
+       /* Read the data */
+       n = FDH_PREAD(handleP, p, howMany, howFar);
+       if (n < 0) {
+           Log("1 Volser: DumpFile: Error reading inode %s for vnode %d: %s\n",
+               PrintInode(stmp, handleP->fd_ih->ih_ino), vnode,
+               afs_error_message(errno));
+           error = VOLSERDUMPERROR;
+
+       } else if (n == 0) {
+           Log("1 Volser: DumpFile: Premature EOF reading inode %s for vnode %d\n",
+               PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
+           error = VOLSERDUMPERROR;
        }
-
-       /* If didn't read enough data, null padd the rest of the buffer. This
-        * can happen if, for instance, the media has some bad spots. We don't
-        * want to quit the dump, so we start null padding.
-        */
-       if (n < howMany) {
-          /* Record the read error */
-          if (n < 0) {
-             n = 0;
-             Log("1 Volser: DumpFile: Error %d reading inode %s for vnode %d\n", 
-                 errno, PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
-          }
-          else if (!pad) {
-             Log("1 Volser: DumpFile: Error reading inode %s for vnode %d\n",
-                 PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
-          }
-          
-          /* Pad the rest of the buffer with zeros. Remember offset we started 
-           * padding. Keep total tally of padding.
-           */
-          memset(p+n, 0, howMany-n);
-          if (!pad)
-             offset = (howBig - nbytes) + n;
-          pad += (howMany-n);
-          
-          /* Now seek over the data we could not get. An error here means we
-           * can't do the next read.
-           */
-          lcode = FDH_SEEK(handleP, ((size - nbytes) + howMany), SEEK_SET);
-          if (lcode != ((size - nbytes) + howMany)) {
-             if (lcode < 0) {
-                Log("1 Volser: DumpFile: Error %d seeking in inode %s for vnode %d\n",
-                    errno, PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
-             }
-             else {
-                Log("1 Volser: DumpFile: Error seeking in inode %s for vnode %d\n",
-                    PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
-                lcode = -1;
-             }
-          }
-          else {
-            lcode = 0;
-          }
+       if (error != 0) {
+           break;
        }
 
+       howFar += n;
+       nbytes -= n;
+
        /* Now write the data out */
-       if (iod_Write(iodp, (char *)p, howMany) != howMany) 
-          error = VOLSERDUMPERROR;
+       if (iod_Write(iodp, (char *)p, n) != n)
+           error = VOLSERDUMPERROR;
+#ifndef AFS_PTHREAD_ENV
        IOMGR_Poll();
-    }
-
-    if (pad) {                     /* Any padding we hadn't reported yet */
-       Log("1 Volser: DumpFile: Null padding file: %d bytes at offset %u\n",
-          pad, offset);
+#endif
     }
 
     free(p);
     return error;
 }
 
-static int DumpVolumeHeader(register struct iod *iodp, register Volume *vp)
+static int
+DumpVolumeHeader(struct iod *iodp, Volume * vp)
 {
     int code = 0;
-    static char nullString[1] = "";  /*The ``contents'' of motd*/
-
-    if (!code) code = DumpTag(iodp, D_VOLUMEHEADER);
-    if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));}
-    if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version);
-    if (!code) code = DumpString(iodp, 'n',V_name(vp));
-    if (!code) code = DumpBool(iodp, 's',V_inService(vp));
-    if (!code) code = DumpBool(iodp, 'b',V_blessed(vp));
-    if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp));
-    if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp));
-    if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));}
-    if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp));
-    if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp));
-    if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp));
-    if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp));
-    if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp));
-    if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp));
-    if (!code) code = DumpInt32(iodp, 'o', V_owner(vp));
-    if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp)); /* Rw volume creation date */
-    if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp));
-    if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp));
-    if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp));
-    if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));           /* Rw volume backup clone date */
-    if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp));
+    static char nullString[1] = "";    /*The ``contents'' of motd */
+
+    if (!code)
+       code = DumpTag(iodp, D_VOLUMEHEADER);
+    if (!code) {
+       code = DumpInt32(iodp, 'i', V_id(vp));
+    }
+    if (!code)
+       code = DumpInt32(iodp, 'v', V_stamp(vp).version);
+    if (!code)
+       code = DumpString(iodp, 'n', V_name(vp));
+    if (!code)
+       code = DumpBool(iodp, 's', V_inService(vp));
+    if (!code)
+       code = DumpBool(iodp, 'b', V_blessed(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'u', V_uniquifier(vp));
+    if (!code)
+       code = DumpByte(iodp, 't', (byte) V_type(vp));
+    if (!code) {
+       code = DumpInt32(iodp, 'p', V_parentId(vp));
+    }
+    if (!code)
+       code = DumpInt32(iodp, 'c', V_cloneId(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'q', V_maxquota(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'm', V_minquota(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'd', V_diskused(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'f', V_filecount(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'a', V_accountNumber(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'o', V_owner(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'C', V_creationDate(vp));        /* Rw volume creation date */
+    if (!code)
+       code = DumpInt32(iodp, 'A', V_accessDate(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'U', V_updateDate(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'E', V_expirationDate(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'B', V_backupDate(vp));  /* Rw volume backup clone date */
+    if (!code)
+       code = DumpString(iodp, 'O', V_offlineMessage(vp));
     /*
      * We do NOT dump the detailed volume statistics residing in the old
      * motd field, since we cannot tell from the info in a dump whether
      * statistics data has been put there.  Instead, we dump a null string,
      * just as if that was what the motd contained.
      */
-    if (!code) code = DumpString(iodp, 'M', nullString);
-    if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0]));
-    if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp));
-    if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp));
+    if (!code)
+       code = DumpString(iodp, 'M', nullString);
+    if (!code)
+       code =
+           DumpArrayInt32(iodp, 'W', (afs_uint32 *) V_weekUse(vp),
+                          sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]));
+    if (!code)
+       code = DumpInt32(iodp, 'D', V_dayUseDate(vp));
+    if (!code)
+       code = DumpInt32(iodp, 'Z', V_dayUse(vp));
     return code;
 }
 
-static int DumpEnd(register struct iod *iodp)
+static int
+DumpEnd(struct iod *iodp)
 {
-    return(DumpInt32(iodp, D_DUMPEND, DUMPENDMAGIC));
+    return (DumpInt32(iodp, D_DUMPEND, DUMPENDMAGIC));
 }
 
 /* Guts of the dump code */
 
 /* Dump a whole volume */
-int DumpVolume(register struct rx_call *call, register Volume *vp,
-                     afs_int32 fromtime, int dumpAllDirs)
+int
+DumpVolume(struct rx_call *call, Volume * vp,
+          afs_int32 fromtime, int dumpAllDirs)
 {
     struct iod iod;
     int code = 0;
-    register struct iod *iodp = &iod;
+    struct iod *iodp = &iod;
     iod_Init(iodp, call);
-    
-    if (!code) code = DumpDumpHeader(iodp, vp, fromtime);
-    
-    if (!code) code = DumpPartial(iodp, vp, fromtime, dumpAllDirs);
-    
+
+    if (!code)
+       code = DumpDumpHeader(iodp, vp, fromtime);
+
+    if (!code)
+       code = DumpPartial(iodp, vp, fromtime, dumpAllDirs);
+
 /* hack follows.  Errors should be handled quite differently in this version of dump than they used to be.*/
     if (rx_Error(iodp->call)) {
-       Log("1 Volser: DumpVolume: Rx call failed during dump, error %d\n", rx_Error(iodp->call));
+       Log("1 Volser: DumpVolume: Rx call failed during dump, error %d\n",
+           rx_Error(iodp->call));
        return VOLSERDUMPERROR;
     }
-    if (!code) code = DumpEnd(iodp);
-    
+    if (!code)
+       code = DumpEnd(iodp);
+
     return code;
 }
 
 /* Dump a volume to multiple places*/
-int DumpVolMulti(struct rx_call **calls, int ncalls, Volume *vp,
-                afs_int32 fromtime, int dumpAllDirs, int *codes)
+int
+DumpVolMulti(struct rx_call **calls, int ncalls, Volume * vp,
+            afs_int32 fromtime, int dumpAllDirs, int *codes)
 {
     struct iod iod;
     int code = 0;
     iod_InitMulti(&iod, calls, ncalls, codes);
-    
-    if (!code) code = DumpDumpHeader(&iod, vp, fromtime);
-    if (!code) code = DumpPartial(&iod, vp, fromtime, dumpAllDirs);
-    if (!code) code = DumpEnd(&iod);
+
+    if (!code)
+       code = DumpDumpHeader(&iod, vp, fromtime);
+    if (!code)
+       code = DumpPartial(&iod, vp, fromtime, dumpAllDirs);
+    if (!code)
+       code = DumpEnd(&iod);
     return code;
 }
 
 /* A partial dump (no dump header) */
-static int DumpPartial(register struct iod *iodp, register Volume *vp,
-                      afs_int32 fromtime, int dumpAllDirs)
+static int
+DumpPartial(struct iod *iodp, Volume * vp,
+           afs_int32 fromtime, int dumpAllDirs)
 {
     int code = 0;
-    if (!code) code = DumpVolumeHeader(iodp, vp);
-    if (!code) code = DumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs);
-    if (!code) code = DumpVnodeIndex(iodp, vp, vSmall, fromtime, 0);
+    if (!code)
+       code = DumpVolumeHeader(iodp, vp);
+    if (!code)
+       code = DumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs);
+    if (!code)
+       code = DumpVnodeIndex(iodp, vp, vSmall, fromtime, 0);
     return code;
 }
 
-static int DumpVnodeIndex(register struct iod *iodp, Volume *vp,
-                         VnodeClass class, afs_int32 fromtime, int forcedump)
+static int
+DumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
+              afs_int32 fromtime, int forcedump)
 {
-    register int code = 0;
-    register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
+    int code = 0;
+    struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
     char buf[SIZEOF_LARGEDISKVNODE];
-    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
+    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
     StreamHandle_t *file;
     FdHandle_t *fdP;
-    int size;
+    afs_sfsize_t size, nVnodes;
     int flag;
-    register int vnodeIndex, nVnodes;
+    int vnodeIndex;
 
     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
-    assert(fdP != NULL);
+    opr_Assert(fdP != NULL);
     file = FDH_FDOPEN(fdP, "r+");
-    assert(file != NULL);
-    size = OS_SIZE(fdP->fd_fd);
-    assert(size != -1);
+    opr_Assert(file != NULL);
+    size = FDH_SIZE(fdP);
+    opr_Assert(size != -1);
     nVnodes = (size / vcp->diskSize) - 1;
     if (nVnodes > 0) {
-       assert((nVnodes+1)*vcp->diskSize == size);
-       assert(STREAM_SEEK(file, vcp->diskSize, 0) == 0);
-    }
-    else nVnodes = 0;
-    for (vnodeIndex = 0; nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
-      nVnodes--, vnodeIndex++) {
+       opr_Assert((nVnodes + 1) * vcp->diskSize == size);
+       opr_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
+    } else
+       nVnodes = 0;
+    for (vnodeIndex = 0;
+        nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
+        nVnodes--, vnodeIndex++) {
        flag = forcedump || (vnode->serverModifyTime >= fromtime);
        /* Note:  the >= test is very important since some old volumes may not have
-          a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
-          does dump the file! */
-       if (!code) code = DumpVnode(iodp, vnode, V_id(vp), bitNumberToVnodeNumber(vnodeIndex, class), flag);
-       if (!flag) IOMGR_Poll(); /* if we dont' xfr data, but scan instead, could lose conn */
+        * a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
+        * does dump the file! */
+       if (!code)
+           code =
+               DumpVnode(iodp, vnode, V_id(vp),
+                         bitNumberToVnodeNumber(vnodeIndex, class), flag);
+#ifndef AFS_PTHREAD_ENV
+       if (!flag)
+           IOMGR_Poll();       /* if we dont' xfr data, but scan instead, could lose conn */
+#endif
     }
     STREAM_CLOSE(file);
     FDH_CLOSE(fdP);
     return code;
 }
 
-static int DumpDumpHeader(register struct iod *iodp, register Volume *vp,
-                         afs_int32 fromtime)
+static int
+DumpDumpHeader(struct iod *iodp, Volume * vp,
+              afs_int32 fromtime)
 {
     int code = 0;
     int UseLatestReadOnlyClone = 1;
@@ -704,50 +1007,106 @@ static int DumpDumpHeader(register struct iod *iodp, register Volume *vp,
     iodp->device = vp->device;
     iodp->parentId = V_parentId(vp);
     iodp->dumpPartition = vp->partition;
-    if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
-    if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp));
-    if (!code) code = DumpString(iodp, 'n',V_name(vp));
+    if (!code)
+       code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
+    if (!code)
+       code =
+           DumpInt32(iodp, 'v',
+                     UseLatestReadOnlyClone ? V_id(vp) : V_parentId(vp));
+    if (!code)
+       code = DumpString(iodp, 'n', V_name(vp));
     dumpTimes[0] = fromtime;
-    dumpTimes[1] = V_backupDate(vp);   /* Until the time the clone was made */
-    if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2);
+    switch (V_type(vp)) {
+    case readwriteVolume:
+       dumpTimes[1] = V_updateDate(vp);        /* until last update */
+       break;
+    case readonlyVolume:
+       dumpTimes[1] = V_creationDate(vp);      /* until clone was updated */
+       break;
+    case backupVolume:
+       /* until backup was made */
+       dumpTimes[1] = V_backupDate(vp) != 0 ? V_backupDate(vp) :
+                                              V_creationDate(vp);
+       break;
+    default:
+       code = EINVAL;
+    }
+    if (!code)
+       code = DumpArrayInt32(iodp, 't', (afs_uint32 *) dumpTimes, 2);
     return code;
 }
 
-static int DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
-                    int volid, int vnodeNumber, int dumpEverything)
+static int
+DumpVnode(struct iod *iodp, struct VnodeDiskObject *v, VolumeId volid,
+         int vnodeNumber, int dumpEverything)
 {
     int code = 0;
     IHandle_t *ihP;
     FdHandle_t *fdP;
+    afs_ino_str_t stmp;
 
     if (!v || v->type == vNull)
        return code;
-    if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier);
+    if (!code)
+       code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier);
     if (!dumpEverything)
-        return code;
-    if (!code) code = DumpByte(iodp, 't',(byte)v->type);
-    if (!code) code = DumpShort(iodp, 'l', v->linkCount); /* May not need this */
-    if (!code) code = DumpInt32(iodp, 'v', v->dataVersion);
-    if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime);
-    if (!code) code = DumpInt32(iodp, 'a', v->author);
-    if (!code) code = DumpInt32(iodp, 'o', v->owner);
-    if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);      /* default group is 0 */
-    if (!code) code = DumpShort(iodp, 'b', v->modeBits);
-    if (!code) code = DumpInt32(iodp, 'p', v->parent);
-    if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime);
+       return code;
+    if (!code)
+       code = DumpByte(iodp, 't', (byte) v->type);
+    if (!code)
+       code = DumpShort(iodp, 'l', v->linkCount);      /* May not need this */
+    if (!code)
+       code = DumpInt32(iodp, 'v', v->dataVersion);
+    if (!code)
+       code = DumpInt32(iodp, 'm', v->unixModifyTime);
+    if (!code)
+       code = DumpInt32(iodp, 'a', v->author);
+    if (!code)
+       code = DumpInt32(iodp, 'o', v->owner);
+    if (!code && v->group)
+       code = DumpInt32(iodp, 'g', v->group);  /* default group is 0 */
+    if (!code)
+       code = DumpShort(iodp, 'b', v->modeBits);
+    if (!code)
+       code = DumpInt32(iodp, 'p', v->parent);
+    if (!code)
+       code = DumpInt32(iodp, 's', v->serverModifyTime);
     if (v->type == vDirectory) {
-       acl_HtonACL(VVnodeDiskACL(v));
-       if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v));
+       code = acl_HtonACL(VVnodeDiskACL(v));
+       if (code) {
+           Log("DumpVnode: Skipping invalid acl vnode %u (volume %"AFS_VOLID_FMT")\n",
+                vnodeNumber, afs_printable_VolumeId_lu(volid));
+       }
+       if (!code)
+           code =
+               DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v),
+                              VAclDiskSize(v));
     }
     if (VNDISK_GET_INO(v)) {
+       afs_sfsize_t indexlen, disklen;
        IH_INIT(ihP, iodp->device, iodp->parentId, VNDISK_GET_INO(v));
        fdP = IH_OPEN(ihP);
        if (fdP == NULL) {
-           Log("1 Volser: DumpVnode: dump: Unable to open inode %d for vnode %d (volume %d); not dumped, error %d\n",
-               VNDISK_GET_INO(v), vnodeNumber, volid, errno);
+           Log("1 Volser: DumpVnode: dump: Unable to open inode %s "
+               "for vnode %u (volume %" AFS_VOLID_FMT "); "
+               "not dumped, error %d\n",
+               PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber,
+               afs_printable_VolumeId_lu(volid), errno);
            IH_RELEASE(ihP);
            return VOLSERREAD_DUMPERROR;
        }
+       VNDISK_GET_LEN(indexlen, v);
+       disklen = FDH_SIZE(fdP);
+       if (indexlen != disklen) {
+           FDH_REALLYCLOSE(fdP);
+           IH_RELEASE(ihP);
+           Log("DumpVnode: volume %"AFS_VOLID_FMT" "
+               "vnode %lu has inconsistent length "
+               "(index %lu disk %lu); aborting dump\n",
+               afs_printable_VolumeId_lu(volid), (unsigned long)vnodeNumber,
+               (unsigned long)indexlen, (unsigned long)disklen);
+           return VOLSERREAD_DUMPERROR;
+       }
        code = DumpFile(iodp, vnodeNumber, fdP);
        FDH_CLOSE(fdP);
        IH_RELEASE(ihP);
@@ -756,83 +1115,83 @@ static int DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
 }
 
 
-int ProcessIndex(Volume *vp, VnodeClass class, afs_int32 **Bufp, int *sizep,
-                int del)
+int
+ProcessIndex(Volume * vp, VnodeClass class, afs_foff_t ** Bufp, int *sizep,
+            int del)
 {
-    int i, nVnodes, offset, code, index=0;
-    afs_int32 *Buf;
-    int cnt=0; 
-    int size;
+    int i, nVnodes, code;
+    afs_foff_t offset;
+    afs_foff_t *Buf;
+    int cnt = 0;
+    afs_sfsize_t size;
     StreamHandle_t *afile;
     FdHandle_t *fdP;
     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
     char buf[SIZEOF_LARGEDISKVNODE], zero[SIZEOF_LARGEDISKVNODE];
-    register struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
-    
+    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
+    afs_ino_str_t stmp;
+
     memset(zero, 0, sizeof(zero));     /* zero out our proto-vnode */
     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
     if (fdP == NULL)
        return -1;
     afile = FDH_FDOPEN(fdP, "r+");
     if (del) {
-       int cnt1=0;
+       int cnt1 = 0;
        Buf = *Bufp;
-       for (i = 0; i<*sizep; i++) {
+       for (i = 0; i < *sizep; i++) {
            if (Buf[i]) {
                cnt++;
-               STREAM_SEEK(afile, Buf[i], 0);    
+               STREAM_ASEEK(afile, Buf[i]);
                code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
                if (code == 1) {
                    if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
                        cnt1++;
                        if (DoLogging) {
-#ifdef AFS_LARGEFILE_ENV
-                          afs_offs_t fileLen;
-                          VNDISK_GET_LEN(fileLen, vnode);
-                          Log("RestoreVolume %d Cleanup: Removing old vnode=%d inode=%d size=(0X%x,0X%x)\n", 
-                              V_id(vp), bitNumberToVnodeNumber(i,class),
-                              VNDISK_GET_INO(vnode),
-                              (unsigned) (fileLen >> 32),
-                              (unsigned) (fileLen & 0xffffffff));
-#else /* !AFS_LARGEFILE_ENV */
-                          Log("RestoreVolume %d Cleanup: Removing old vnode=%d inode=%d size=%d\n", 
-                              V_id(vp), bitNumberToVnodeNumber(i,class),
-                              VNDISK_GET_INO(vnode), vnode->length);
-#endif /* !AFS_LARGEFILE_ENV */
+                           Log("RestoreVolume %"AFS_VOLID_FMT" "
+                               "Cleanup: Removing old vnode=%u inode=%s "
+                               "size=unknown\n",
+                               afs_printable_VolumeId_lu(V_id(vp)),
+                               bitNumberToVnodeNumber(i, class),
+                               PrintInode(stmp, VNDISK_GET_INO(vnode)));
                        }
                        IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(vnode),
-                            V_parentId(vp));
+                              V_parentId(vp));
                        DOPOLL;
                    }
-                   STREAM_SEEK(afile, Buf[i], 0);
-                   (void ) STREAM_WRITE(zero, vcp->diskSize, 1, afile);        /* Zero it out */
+                   STREAM_ASEEK(afile, Buf[i]);
+                   (void)STREAM_WRITE(zero, vcp->diskSize, 1, afile);  /* Zero it out */
                }
                Buf[i] = 0;
            }
        }
        if (DoLogging) {
-          Log("RestoreVolume Cleanup: Removed %d inodes for volume %d\n",
-              cnt1, V_id(vp));
+           Log("RestoreVolume Cleanup: Removed %d inodes for volume %d\n",
+               cnt1, V_id(vp));
        }
-       STREAM_FLUSH(afile);            /* ensure 0s are on the disk */
+       STREAM_FLUSH(afile);    /* ensure 0s are on the disk */
        OS_SYNC(afile->str_fd);
     } else {
-       size = OS_SIZE(fdP->fd_fd);
-       assert(size != -1);
-       nVnodes = (size <= vcp->diskSize ? 0 :
-                  size-vcp->diskSize) >> vcp->logSize;
+       size = FDH_SIZE(fdP);
+       opr_Assert(size != -1);
+       nVnodes =
+           (size <=
+            vcp->diskSize ? 0 : size - vcp->diskSize) >> vcp->logSize;
        if (nVnodes > 0) {
-           Buf = (afs_int32 *) malloc(nVnodes * sizeof(afs_int32));
-           if (Buf == NULL) return 1;
-           memset((char *)Buf, 0, nVnodes * sizeof(afs_int32));
-           STREAM_SEEK(afile, offset = vcp->diskSize, 0);
+           Buf = calloc(nVnodes,  sizeof(afs_foff_t));
+           if (Buf == NULL) {
+               STREAM_CLOSE(afile);
+               FDH_CLOSE(fdP);
+               return -1;
+           }
+           STREAM_ASEEK(afile, offset = vcp->diskSize);
            while (1) {
                code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
                if (code != 1) {
                    break;
                }
                if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
-                   Buf[(offset >> vcp->logSize)-1] = offset;
+                   Buf[(offset >> vcp->logSize) - 1] = offset;
                    cnt++;
                }
                offset += vcp->diskSize;
@@ -847,66 +1206,85 @@ int ProcessIndex(Volume *vp, VnodeClass class, afs_int32 **Bufp, int *sizep,
 }
 
 
-int RestoreVolume(register struct rx_call *call, Volume *avp,
-                 int incremental, struct restoreCookie *cookie)
+int
+RestoreVolume(struct rx_call *call, Volume * avp, struct restoreCookie *cookie)
 {
     VolumeDiskData vol;
     struct DumpHeader header;
     afs_uint32 endMagic;
     Error error = 0, vupdate;
-    register Volume *vp;
+    Volume *vp;
     struct iod iod;
-    register struct iod *iodp = &iod;
-    afs_int32 *b1=0, *b2=0;
-    int s1=0, s2=0, delo=0, tdelo;
+    struct iod *iodp = &iod;
+    afs_foff_t *b1 = NULL, *b2 = NULL;
+    int s1 = 0, s2 = 0, delo = 0, tdelo;
     int tag;
+    VolumeDiskData saved_header;
+    afs_uint32 uptime, crtime;
 
     iod_Init(iodp, call);
-    
+
     vp = avp;
-    if (!ReadDumpHeader(iodp, &header)){
+
+    if (DoPreserveVolumeStats) {
+       CopyVolumeStats(&V_disk(vp), &saved_header);
+    }
+
+    if (!ReadDumpHeader(iodp, &header)) {
        Log("1 Volser: RestoreVolume: Error reading header file for dump; aborted\n");
        return VOLSERREAD_DUMPERROR;
     }
-    if (iod_getc(iodp) != D_VOLUMEHEADER){
+    if (iod_getc(iodp) != D_VOLUMEHEADER) {
        Log("1 Volser: RestoreVolume: Volume header missing from dump; not restored\n");
        return VOLSERREAD_DUMPERROR;
     }
-    if(ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) return VOLSERREAD_DUMPERROR;
-
-    delo = ProcessIndex(vp, vLarge, &b1, &s1, 0);
-    if (!delo) delo = ProcessIndex(vp, vSmall, &b2, &s2, 0);
-    if (delo) {
-       if (b1) free((char *)b1);
-       if (b2) free((char *)b2);
-       b1 = b2 = 0;
+    if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) {
+       Log("1 Volser: RestoreVolume: Error reading volume header (id: %u); aborted\n",
+           V_id(vp));
+       return VOLSERREAD_DUMPERROR;
+    }
+
+    if (!delo)
+       delo = ProcessIndex(vp, vLarge, &b1, &s1, 0);
+    if (!delo)
+       delo = ProcessIndex(vp, vSmall, &b2, &s2, 0);
+    if (delo < 0) {
+       Log("1 Volser: RestoreVolume: ProcessIndex failed; not restored\n");
+       error = VOLSERREAD_DUMPERROR;
+       goto out;
     }
 
-    strncpy(vol.name,cookie->name,VOLSER_OLDMAXVOLNAME);
+    strncpy(vol.name, cookie->name, VOLSER_OLDMAXVOLNAME);
     vol.type = cookie->type;
     vol.cloneId = cookie->clone;
     vol.parentId = cookie->parent;
-    
+
+    V_needsSalvaged(vp) = 0;
 
     tdelo = delo;
     while (1) {
-       if (ReadVnodes(iodp, vp, 0, b1, s1, b2, s2, tdelo)) {
-         error =  VOLSERREAD_DUMPERROR;
-         goto clean;
-       }
-       tag = iod_getc(iodp);
-       if (tag != D_VOLUMEHEADER)
-         break;
-       if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) {
-         error = VOLSERREAD_DUMPERROR;
-         goto out;
-       }
-       tdelo = -1;
+       if (ReadVnodes(iodp, vp, b1, s1, b2, s2, tdelo)) {
+           Log("1 Volser: RestoreVolume: Error reading vnodes (id: %u); aborted\n",
+               V_id(vp));
+           error = VOLSERREAD_DUMPERROR;
+           goto clean;
+       }
+       tag = iod_getc(iodp);
+       if (tag != D_VOLUMEHEADER)
+           break;
+
+       if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) {
+           Log("1 Volser: RestoreVolume: Error reading volume header (id: %u); aborted\n",
+               V_id(vp));
+           error = VOLSERREAD_DUMPERROR;
+           goto out;
+       }
     }
-    if (tag != D_DUMPEND || !ReadInt32(iodp, &endMagic) || endMagic != DUMPENDMAGIC){
-       Log("1 Volser: RestoreVolume: End of dump not found; restore aborted\n");
-       error =  VOLSERREAD_DUMPERROR;
-       goto clean;
+    if (tag != D_DUMPEND || !ReadInt32(iodp, &endMagic)
+       || endMagic != DUMPENDMAGIC) {
+       Log("1 Volser: RestoreVolume: End of dump not found; restore aborted\n");
+       error = VOLSERREAD_DUMPERROR;
+       goto clean;
     }
 
 
@@ -917,12 +1295,28 @@ int RestoreVolume(register struct rx_call *call, Volume *avp,
     }
 
     if (!delo) {
-       ProcessIndex(vp, vLarge, &b1, &s1, 1);
-       ProcessIndex(vp, vSmall, &b2, &s2, 1);
+       delo = ProcessIndex(vp, vLarge, &b1, &s1, 1);
+       if (!delo)
+           delo = ProcessIndex(vp, vSmall, &b2, &s2, 1);
+       if (delo < 0) {
+           error = VOLSERREAD_DUMPERROR;
+           goto clean;
+       }
     }
 
- clean:
-    ClearVolumeStats(&vol);
+  clean:
+    if (DoPreserveVolumeStats) {
+       CopyVolumeStats(&saved_header, &vol);
+    } else {
+       ClearVolumeStats(&vol);
+    }
+    if (V_needsSalvaged(vp)) {
+       /* needsSalvaged may have been set while we tried to write volume data.
+        * prevent it from getting overwritten. */
+       vol.needsSalvaged = V_needsSalvaged(vp);
+    }
+    crtime = V_creationDate(vp);
+    uptime = V_updateDate(vp);
     CopyVolumeHeader(&vol, &V_disk(vp));
     V_destroyMe(vp) = 0;
     VUpdateVolume(&vupdate, vp);
@@ -930,166 +1324,221 @@ int RestoreVolume(register struct rx_call *call, Volume *avp,
        Log("1 Volser: RestoreVolume: Unable to rewrite volume header; restore aborted\n");
        error = VOLSERREAD_DUMPERROR;
        goto out;
+    } else {
+       /*
+        * If the volume was not a new empty volume and the restored dump was
+        * older than the volume in question, this is probably a mistake, and
+        * may mean the resulting volume is corrupted. Log the following message
+        * to give a clue as to why this volume suddenly looks strange or corrupt.
+        */
+       if ((crtime != uptime) && (uptime > V_updateDate(vp))) {
+           Log("1 Volser: RestoreVolume: volume %s (%u) appears to have been partially or "
+               "completely restored to an earlier version (updateDate went from %u to %u). "
+               "This is allowed, but may indicate a mistake in whatever tool is restoring "
+               "this volume. If this volume appears corrupted, this is probably why.\n",
+               V_name(vp), V_id(vp), uptime, V_updateDate(vp));
+       }
     }
- out:
+  out:
     /* Free the malloced space above */
-    if (b1) free((char *)b1);
-    if (b2) free((char *)b2);
+    if (b1)
+       free(b1);
+    if (b2)
+       free(b2);
     return error;
 }
 
-static int ReadVnodes(register struct iod *iodp, Volume *vp,
-                     int incremental, afs_int32 *Lbuf, afs_int32 s1,
-                     afs_int32 *Sbuf, afs_int32 s2, afs_int32 delo)
+static int
+ReadVnodes(struct iod *iodp, Volume * vp, afs_foff_t * Lbuf, afs_int32 s1,
+           afs_foff_t * Sbuf, afs_int32 s2, afs_int32 delo)
 {
     afs_int32 vnodeNumber;
     char buf[SIZEOF_LARGEDISKVNODE];
-    register tag;
-    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
+    int tag;
+    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
     struct VnodeDiskObject oldvnode;
     int idx;
     VnodeClass class;
     struct VnodeClassInfo *vcp;
     IHandle_t *tmpH;
     FdHandle_t *fdP;
-    Inode      nearInode;
+    Inode nearInode AFS_UNUSED;
+    afs_int32 critical = 0;
+    int nbytes;
 
     tag = iod_getc(iodp);
     V_pref(vp, nearInode);
     while (tag == D_VNODE) {
-        int haveStuff = 0;
-       memset(buf, 0, sizeof (buf));
-       if (!ReadInt32(iodp, (afs_uint32 *)&vnodeNumber))
+       int haveStuff = 0;
+       int saw_f = 0;
+       memset(buf, 0, sizeof(buf));
+       if (!ReadInt32(iodp, (afs_uint32 *) & vnodeNumber))
            break;
 
-       ReadInt32(iodp, &vnode->uniquifier);
+       if (!ReadInt32(iodp, &vnode->uniquifier))
+           return VOLSERREAD_DUMPERROR;
+
        while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
            haveStuff = 1;
+            if (critical)
+                critical--;
            switch (tag) {
-               case 't':
-                   vnode->type = (VnodeType) iod_getc(iodp);
-                   break;
-               case 'l':
-                   {
-                       unsigned short tlc;
-                       ReadShort(iodp, &tlc);
-                       vnode->linkCount = (signed int)tlc;
-                   }
-                   break;
-               case 'v':
-                   ReadInt32(iodp, &vnode->dataVersion);
-                   break;
-               case 'm':
-                   ReadInt32(iodp, &vnode->unixModifyTime);
-                   break;
-               case 's':
-                   ReadInt32(iodp, &vnode->serverModifyTime);
-                   break;
-               case 'a':
-                   ReadInt32(iodp, &vnode->author);
-                   break;
-               case 'o':
-                   ReadInt32(iodp, &vnode->owner);
-                   break;
-               case 'g':
-                   ReadInt32(iodp, (afs_uint32 *)&vnode->group);
-                   break;
-               case 'b': {
+           case 't':
+               vnode->type = (VnodeType) iod_getc(iodp);
+               break;
+           case 'l':
+               {
+                   unsigned short tlc;
+                   if (!ReadShort(iodp, &tlc))
+                       return VOLSERREAD_DUMPERROR;
+                   vnode->linkCount = (signed int)tlc;
+               }
+               break;
+           case 'v':
+               if (!ReadInt32(iodp, &vnode->dataVersion))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 'm':
+               if (!ReadInt32(iodp, &vnode->unixModifyTime))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 's':
+               if (!ReadInt32(iodp, &vnode->serverModifyTime))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 'a':
+               if (!ReadInt32(iodp, &vnode->author))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 'o':
+               if (!ReadInt32(iodp, &vnode->owner))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 'g':
+               if (!ReadInt32(iodp, (afs_uint32 *) & vnode->group))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 'b':{
                    unsigned short modeBits;
-                   ReadShort(iodp, &modeBits);
+                   if (!ReadShort(iodp, &modeBits))
+                       return VOLSERREAD_DUMPERROR;
                    vnode->modeBits = (unsigned int)modeBits;
                    break;
                }
-               case 'p':
-                   ReadInt32(iodp, &vnode->parent);
-                   break;
-               case 'A':
-                   ReadByteString(iodp, (byte *)VVnodeDiskACL(vnode),
-                                  VAclDiskSize(vnode));
-                   acl_NtohACL(VVnodeDiskACL(vnode));
-                   break;
-#ifdef AFS_LARGEFILE_ENV
-               case 'h':
-#endif
-               case 'f': {
+           case 'p':
+               if (!ReadInt32(iodp, &vnode->parent))
+                   return VOLSERREAD_DUMPERROR;
+               break;
+           case 'A':
+               nbytes = ReadByteString(iodp, (byte *) VVnodeDiskACL(vnode),
+                              VAclDiskSize(vnode));
+               if (nbytes != VAclDiskSize(vnode)) {
+                   Log("ReadVnodes: could not read acl for vnode %lu in dump.\n",
+                        (unsigned long)vnodeNumber);
+                   return VOLSERREAD_DUMPERROR;
+               }
+               if (acl_NtohACL(VVnodeDiskACL(vnode)) != 0) {
+                   Log("ReadVnodes: invalid acl for vnode %lu in dump.\n",
+                        (unsigned long)vnodeNumber);
+                   return VOLSERREAD_DUMPERROR;
+               }
+               break;
+           case 'h':
+           case 'f':{
                    Inode ino;
                    Error error;
-                   afs_offs_t fileLen;
-
-                   ino = IH_CREATE(V_linkHandle(vp),
-                                   V_device(vp),
-                                   VPartitionPath(V_partition(vp)),
-                                   nearInode, V_parentId(vp), vnodeNumber,
-                                   vnode->uniquifier,
-                                   vnode->dataVersion);
-                   if (!VALID_INO(ino)) {
-                       perror("unable to allocate inode");
-                       Log("1 Volser: ReadVnodes: Restore aborted\n");
+                   afs_fsize_t vnodeLength;
+
+                   if (saw_f) {
+                       Log("Volser: ReadVnodes: warning: ignoring duplicate "
+                           "file entries for vnode %lu in dump\n",
+                           (unsigned long)vnodeNumber);
+                       volser_WriteFile(vnodeNumber, iodp, NULL, tag, &error);
+                       break;
+                   }
+                   saw_f = 1;
+
+                   tmpH =
+                       IH_CREATE_INIT(V_linkHandle(vp), V_device(vp),
+                                 VPartitionPath(V_partition(vp)), nearInode,
+                                 V_parentId(vp), vnodeNumber,
+                                 vnode->uniquifier, vnode->dataVersion);
+                   if (!tmpH) {
+                       Log("1 Volser: ReadVnodes: IH_CREATE: %s - restore aborted\n",
+                            afs_error_message(errno));
+                       V_needsSalvaged(vp) = 1;
                        return VOLSERREAD_DUMPERROR;
                    }
+                   ino = tmpH->ih_ino;
                    nearInode = ino;
                    VNDISK_SET_INO(vnode, ino);
-                   IH_INIT(tmpH, vp->device, V_parentId(vp), ino);
                    fdP = IH_OPEN(tmpH);
                    if (fdP == NULL) {
+                       Log("1 Volser: ReadVnodes: IH_OPEN: %s - restore aborted\n",
+                            afs_error_message(errno));
                        IH_RELEASE(tmpH);
+                       V_needsSalvaged(vp) = 1;
                        return VOLSERREAD_DUMPERROR;
                    }
-                   
-                   fileLen = volser_WriteFile(vnodeNumber, iodp, fdP,
-                                                    tag, &error);
-                   VNDISK_SET_LEN(vnode, fileLen);
+                   vnodeLength =
+                       volser_WriteFile(vnodeNumber, iodp, fdP, tag, &error);
+                   VNDISK_SET_LEN(vnode, vnodeLength);
                    FDH_REALLYCLOSE(fdP);
                    IH_RELEASE(tmpH);
                    if (error) {
-                        Log("1 Volser: ReadVnodes: IDEC inode %d\n", ino);
+                       Log("1 Volser: ReadVnodes: IDEC inode %llu\n",
+                           (afs_uintmax_t) ino);
                        IH_DEC(V_linkHandle(vp), ino, V_parentId(vp));
+                       V_needsSalvaged(vp) = 1;
                        return VOLSERREAD_DUMPERROR;
                    }
                    break;
                }
+            case 0x7e:
+                critical = 2;
+                break;
+            default:
+                if (!HandleUnknownTag(iodp, tag, 2, critical))
+                    return VOLSERREAD_DUMPERROR;
            }
        }
 
        class = vnodeIdToClass(vnodeNumber);
-       vcp   = &VnodeClassInfo[class];
+       vcp = &VnodeClassInfo[class];
 
        /* Mark this vnode as in this dump - so we don't delete it later */
        if (!delo) {
-          idx = (vnodeIndexOffset(vcp,vnodeNumber) >> vcp->logSize) - 1;
-          if (class == vLarge) {
-             if (Lbuf && (idx < s1)) Lbuf[idx] = 0;
-          } else {
-             if (Sbuf && (idx < s2)) Sbuf[idx] = 0;
-          }
+           idx = (vnodeIndexOffset(vcp, vnodeNumber) >> vcp->logSize) - 1;
+           if (class == vLarge) {
+               if (Lbuf && (idx < s1))
+                   Lbuf[idx] = 0;
+           } else {
+               if (Sbuf && (idx < s2))
+                   Sbuf[idx] = 0;
+           }
        }
 
        if (haveStuff) {
            FdHandle_t *fdP = IH_OPEN(vp->vnodeIndex[class].handle);
            if (fdP == NULL) {
-               Log("1 Volser: ReadVnodes: Error opening vnode index; restore aborted\n");
+               Log("1 Volser: ReadVnodes: Error opening vnode index: %s; restore aborted\n",
+                   afs_error_message(errno));
+               V_needsSalvaged(vp) = 1;
                return VOLSERREAD_DUMPERROR;
            }
-           if (FDH_SEEK(fdP, vnodeIndexOffset(vcp, vnodeNumber), SEEK_SET) < 0) {
-               Log("1 Volser: ReadVnodes: Error seeking into vnode index; restore aborted\n");
-               FDH_REALLYCLOSE(fdP);
-               return VOLSERREAD_DUMPERROR;
-           }
-           if (FDH_READ(fdP, &oldvnode, sizeof(oldvnode)) == sizeof(oldvnode)) {
+           if (FDH_PREAD(fdP, &oldvnode, sizeof(oldvnode), vnodeIndexOffset(vcp, vnodeNumber)) ==
+               sizeof(oldvnode)) {
                if (oldvnode.type != vNull && VNDISK_GET_INO(&oldvnode)) {
                    IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(&oldvnode),
-                        V_parentId(vp));
+                          V_parentId(vp));
                }
            }
            vnode->vnodeMagic = vcp->magic;
-           if (FDH_SEEK(fdP, vnodeIndexOffset(vcp, vnodeNumber), SEEK_SET) < 0) {
-               Log("1 Volser: ReadVnodes: Error seeking into vnode index; restore aborted\n");
-               FDH_REALLYCLOSE(fdP);
-               return VOLSERREAD_DUMPERROR;
-           }
-           if (FDH_WRITE(fdP, vnode, vcp->diskSize) != vcp->diskSize) {
-               Log("1 Volser: ReadVnodes: Error writing vnode index; restore aborted\n");
+           if (FDH_PWRITE(fdP, vnode, vcp->diskSize, vnodeIndexOffset(vcp, vnodeNumber)) != vcp->diskSize) {
+               Log("1 Volser: ReadVnodes: Error writing vnode index: %s; restore aborted\n",
+                   afs_error_message(errno));
                FDH_REALLYCLOSE(fdP);
+               V_needsSalvaged(vp) = 1;
                return VOLSERREAD_DUMPERROR;
            }
            FDH_CLOSE(fdP);
@@ -1097,7 +1546,6 @@ static int ReadVnodes(register struct iod *iodp, Volume *vp,
     }
     iod_ungetc(iodp, tag);
 
-
     return 0;
 }
 
@@ -1105,105 +1553,107 @@ static int ReadVnodes(register struct iod *iodp, Volume *vp,
 /* called with disk file only.  Note that we don't have to worry about rx_Read
  * needing to read an ungetc'd character, since the ReadInt32 will have read
  * it instead.
+ *
+ * if handleP == NULL, don't write the file anywhere; just read and discard
+ * the file contents
  */
-static afs_offs_t volser_WriteFile(int vn, struct iod *iodp, FdHandle_t *handleP,
-                             int tag, Error *status)
+static afs_fsize_t
+volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
+                Error * status)
 {
     afs_int32 code;
-    afs_offs_t filesize;
-    afs_offs_t written=0;
-    register afs_uint32 size = 8192;
-    register afs_offs_t nbytes;
+    ssize_t nBytes;
+    afs_fsize_t filesize;
+    afs_fsize_t written = 0;
+    size_t size = 8192;
+    afs_fsize_t nbytes;
     unsigned char *p;
 
 
     *status = 0;
-#ifdef AFS_64BIT_ENV
     {
        afs_uint32 filesize_high = 0L, filesize_low = 0L;
-#ifdef AFS_LARGEFILE_ENV
        if (tag == 'h') {
-           if (!ReadInt32(iodp, &filesize_high) ) {
+           if (!ReadInt32(iodp, &filesize_high)) {
                *status = 1;
-               return(0);
+               return 0;
            }
        }
-#endif
        if (!ReadInt32(iodp, &filesize_low)) {
            *status = 1;
-           return(0);
+           return 0;
        }
        FillInt64(filesize, filesize_high, filesize_low);
     }
-#else /* !AFS_64BIT_ENV */
-    if (!ReadInt32(iodp, &filesize)) {
-        *status = 1;
-       return(0);
-    }
-#endif /* !AFS_64BIT_ENV */
-    p = (unsigned char *) malloc(size);
+    p = malloc(size);
     if (p == NULL) {
-        *status = 2;
-        return(0);
+       *status = 2;
+       return (0);
     }
     for (nbytes = filesize; nbytes; nbytes -= size) {
        if (nbytes < size)
            size = nbytes;
-       
-       if ((code = iod_Read(iodp, p, size)) != size) {
-#ifdef AFS_64BIT_ENV
-           Log("1 Volser: WriteFile: Error reading dump file %d size=(0X%x,0X%x) nbytes=%d (%d of %d); restore aborted\n", vn,
-               (unsigned) (filesize >> 32),
-               (unsigned) (filesize & 0xffffffff),
-               nbytes, code, size);
-#else /* !AFS_LARGEFILE_ENV */
-           Log("1 Volser: WriteFile: Error reading dump file %d size=%d nbytes=%d (%d of %d); restore aborted\n", vn, filesize, nbytes, code, size);
-#endif /* !AFS_LARGEFILE_ENV */
+
+       if ((code = iod_Read(iodp, (char *) p, size)) != size) {
+           Log("1 Volser: WriteFile: Error reading dump file %d size=%llu nbytes=%u (%d of %u): %s; restore aborted\n", vn, (afs_uintmax_t) filesize, nbytes, code, (unsigned)size, afs_error_message(errno));
            *status = 3;
            break;
        }
-       code = FDH_WRITE(handleP, p, size);
-       if (code > 0) written += code;
-       if (code != size) {
-           Log("1 Volser: WriteFile: Error creating file in volume; restore aborted\n");
-           *status = 4;
-           break;
+       if (handleP) {
+           nBytes = FDH_PWRITE(handleP, p, size, written);
+           if (nBytes > 0)
+               written += nBytes;
+           if (nBytes != size) {
+               Log("1 Volser: WriteFile: Error writing (%u) bytes to vnode %d; %s; restore aborted\n", (int)(nBytes & 0xffffffff), vn, afs_error_message(errno));
+               *status = 4;
+               break;
+           }
        }
     }
     free(p);
-    return(written);
+    return (written);
 }
 
-static int ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
+static int
+ReadDumpHeader(struct iod *iodp, struct DumpHeader *hp)
 {
-    register tag;
+    int tag;
     afs_uint32 beginMagic;
+    afs_int32 critical = 0;
     if (iod_getc(iodp) != D_DUMPHEADER || !ReadInt32(iodp, &beginMagic)
-       || !ReadInt32(iodp, (afs_uint32 *)&hp->version)
-       || beginMagic != DUMPBEGINMAGIC
-       ) return 0;
+       || !ReadInt32(iodp, (afs_uint32 *) & hp->version)
+       || beginMagic != DUMPBEGINMAGIC)
+       return 0;
     hp->volumeId = 0;
     hp->nDumpTimes = 0;
     while ((tag = iod_getc(iodp)) > D_MAX) {
-        unsigned short arrayLength;
-       register int i;
-       switch(tag) {
-           case 'v':
-               if (!ReadInt32(iodp, &hp->volumeId))
-                   return 0;
-               break;
-           case 'n':
-               ReadString(iodp, hp->volumeName, sizeof(hp->volumeName));
-               break;
-           case 't':
-               if (!ReadShort(iodp, &arrayLength))
+       unsigned short arrayLength;
+       int i;
+       if (critical)
+           critical--;
+       switch (tag) {
+       case 'v':
+           if (!ReadInt32(iodp, &hp->volumeId))
+               return 0;
+           break;
+       case 'n':
+           ReadString(iodp, hp->volumeName, sizeof(hp->volumeName));
+           break;
+       case 't':
+           if (!ReadShort(iodp, &arrayLength))
+               return 0;
+           hp->nDumpTimes = (arrayLength >> 1);
+           for (i = 0; i < hp->nDumpTimes; i++)
+               if (!ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].from)
+                   || !ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].to))
                    return 0;
-               hp->nDumpTimes = (arrayLength >> 1);
-               for (i = 0; i<hp->nDumpTimes; i++)
-                   if (!ReadInt32(iodp, (afs_uint32 *)&hp->dumpTimes[i].from)
-                       || !ReadInt32(iodp, (afs_uint32 *)&hp->dumpTimes[i].to))
-                       return 0;
-               break;
+           break;
+        case 0x7e:
+            critical = 2;
+            break;
+        default:
+            if (!HandleUnknownTag(iodp, tag, 0, critical))
+                return VOLSERREAD_DUMPERROR;
        }
     }
     if (!hp->volumeId || !hp->nDumpTimes) {
@@ -1212,3 +1662,288 @@ static int ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
     iod_ungetc(iodp, tag);
     return 1;
 }
+
+
+/* ----- Below are the calls that calculate dump size ----- */
+
+static int
+SizeDumpVolumeHeader(struct iod *iodp, Volume * vp,
+                    struct volintSize *v_size)
+{
+    int code = 0;
+    static char nullString[1] = "";    /*The ``contents'' of motd */
+    afs_uint64 addvar;
+
+/*     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER); */
+    FillInt64(addvar,0, 1);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));} */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
+    FillInt64(addvar,0, (2 + strlen(V_name(vp))));
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpBool(iodp, 's',V_inService(vp)); */
+    FillInt64(addvar,0, 2);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp)); */
+    FillInt64(addvar,0, 2);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp)); */
+    FillInt64(addvar,0, 2);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));} */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));      /\* Rw volume creation date *\/ */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));                /\* Rw volume backup clone date *\/ */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp)); */
+    FillInt64(addvar,0, (2 + strlen(V_offlineMessage(vp))));
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     /\* */
+/*      * We do NOT dump the detailed volume statistics residing in the old */
+/*      * motd field, since we cannot tell from the info in a dump whether */
+/*      * statistics data has been put there.  Instead, we dump a null string, */
+/*      * just as if that was what the motd contained. */
+/*      *\/ */
+/*     if (!code) code = DumpString(iodp, 'M', nullString); */
+    FillInt64(addvar,0, (2 + strlen(nullString)));
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])); */
+    FillInt64(addvar,0, (3 + 4 * (sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]))));
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    return code;
+}
+
+static int
+SizeDumpEnd(struct iod *iodp, struct volintSize *v_size)
+{
+    int code = 0;
+    afs_uint64 addvar;
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    return code;
+}
+
+int
+SizeDumpVolume(struct rx_call *call, Volume * vp,
+              afs_int32 fromtime, int dumpAllDirs,
+              struct volintSize *v_size)
+{
+    int code = 0;
+    struct iod *iodp = (struct iod *)0;
+/*    iod_Init(iodp, call); */
+
+    if (!code)
+       code = SizeDumpDumpHeader(iodp, vp, fromtime, v_size);
+    if (!code)
+       code = SizeDumpPartial(iodp, vp, fromtime, dumpAllDirs, v_size);
+    if (!code)
+       code = SizeDumpEnd(iodp, v_size);
+
+    return code;
+}
+
+static int
+SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
+                  afs_int32 fromtime, struct volintSize *v_size)
+{
+    int code = 0;
+/*    int UseLatestReadOnlyClone = 1; */
+/*    afs_int32 dumpTimes[2]; */
+    afs_uint64 addvar;
+/*    iodp->device = vp->device; */
+/*    iodp->parentId = V_parentId(vp); */
+/*    iodp->dumpPartition = vp->partition; */
+
+    ZeroInt64(v_size->dump_size);      /* initialize the size */
+/*     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION); */
+    FillInt64(addvar,0, 9);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp)); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
+    FillInt64(addvar,0, (2 + strlen(V_name(vp))));
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     dumpTimes[0] = fromtime; */
+/*     dumpTimes[1] = V_backupDate(vp);        /\* Until the time the clone was made *\/ */
+/*     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2); */
+    FillInt64(addvar,0, (3 + 4 * 2));
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    return code;
+}
+
+static int
+SizeDumpVnode(struct iod *iodp, struct VnodeDiskObject *v, VolumeId volid,
+             int vnodeNumber, int dumpEverything,
+             struct volintSize *v_size)
+{
+    int code = 0;
+    afs_uint64 addvar;
+
+    if (!v || v->type == vNull)
+       return code;
+/*     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier); */
+    FillInt64(addvar,0, 9);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    if (!dumpEverything)
+       return code;
+/*     if (!code)  code = DumpByte(iodp, 't',(byte)v->type); */
+    FillInt64(addvar,0, 2);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /\* May not need this *\/ */
+    FillInt64(addvar,0, 3);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'a', v->author); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'o', v->owner); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);   /\* default group is 0 *\/ */
+    if (v->group) {
+       FillInt64(addvar,0, 5);
+       AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    }
+/*     if (!code) code = DumpShort(iodp, 'b', v->modeBits); */
+    FillInt64(addvar,0, 3);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 'p', v->parent); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+/*     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime); */
+    FillInt64(addvar,0, 5);
+    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    if (v->type == vDirectory) {
+/*     acl_HtonACL(VVnodeDiskACL(v)); */
+/*     if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v)); */
+       FillInt64(addvar,0, (1 + VAclDiskSize(v)));
+       AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    }
+
+    if (VNDISK_GET_INO(v)) {
+       VNDISK_GET_LEN(addvar, v);
+       if (v->vn_length_hi)
+           addvar += 9;
+       else
+           addvar += 5;
+       AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
+    }
+    return code;
+}
+
+/* A partial dump (no dump header) */
+static int
+SizeDumpPartial(struct iod *iodp, Volume * vp,
+               afs_int32 fromtime, int dumpAllDirs,
+               struct volintSize *v_size)
+{
+    int code = 0;
+    if (!code)
+       code = SizeDumpVolumeHeader(iodp, vp, v_size);
+    if (!code)
+       code =
+           SizeDumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs,
+                              v_size);
+    if (!code)
+       code = SizeDumpVnodeIndex(iodp, vp, vSmall, fromtime, 0, v_size);
+    return code;
+}
+
+static int
+SizeDumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
+                  afs_int32 fromtime, int forcedump,
+                  struct volintSize *v_size)
+{
+    int code = 0;
+    struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
+    char buf[SIZEOF_LARGEDISKVNODE];
+    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
+    StreamHandle_t *file;
+    FdHandle_t *fdP;
+    afs_sfsize_t size, nVnodes;
+    int flag;
+    int vnodeIndex;
+
+    fdP = IH_OPEN(vp->vnodeIndex[class].handle);
+    opr_Assert(fdP != NULL);
+    file = FDH_FDOPEN(fdP, "r+");
+    opr_Assert(file != NULL);
+    size = FDH_SIZE(fdP);
+    opr_Assert(size != -1);
+    nVnodes = (size / vcp->diskSize) - 1;
+    if (nVnodes > 0) {
+       opr_Assert((nVnodes + 1) * vcp->diskSize == size);
+       opr_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
+    } else
+       nVnodes = 0;
+    for (vnodeIndex = 0;
+        nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
+        nVnodes--, vnodeIndex++) {
+       flag = forcedump || (vnode->serverModifyTime >= fromtime);
+       /* Note:  the >= test is very important since some old volumes may not have
+        * a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
+        * does dump the file! */
+       if (!code)
+           code =
+               SizeDumpVnode(iodp, vnode, V_id(vp),
+                             bitNumberToVnodeNumber(vnodeIndex, class), flag,
+                             v_size);
+    }
+    STREAM_CLOSE(file);
+    FDH_CLOSE(fdP);
+    return code;
+}