volser: update log formatting in dump and restore
[openafs.git] / src / volser / dumpstuff.c
index 67bbbaf..8c01aa0 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>
-#include <string.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
-#include <sys/stat.h>
-#ifdef AFS_PTHREAD_ENV
-#include <assert.h>
-#else /* AFS_PTHREAD_ENV */
-#include <afs/assert.h>
-#endif /* AFS_PTHREAD_ENV */
-#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>
@@ -44,12 +26,16 @@ RCSID
 #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"
 
 #ifndef AFS_NT40_ENV
 #ifdef O_LARGEFILE
@@ -64,62 +50,87 @@ RCSID
 /*@printflike@*/ extern void Log(const char *format, ...);
 
 extern int DoLogging;
-
-/* 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;
-};
+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,
+static int DumpVnodeIndex(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,
+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, int incremental,
+                     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(register struct iod *iodp, register Volume * vp,
+static int SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
                              afs_int32 fromtime,
-                             register struct volintSize *size);
-static int SizeDumpPartial(register struct iod *iodp, register Volume * vp,
+                             struct volintSize *size);
+static int SizeDumpPartial(struct iod *iodp, Volume * vp,
                           afs_int32 fromtime, int dumpAllDirs,
-                          register struct volintSize *size);
-static int SizeDumpVnodeIndex(register struct iod *iodp, Volume * vp,
+                          struct volintSize *size);
+static int SizeDumpVnodeIndex(struct iod *iodp, Volume * vp,
                              VnodeClass class, afs_int32 fromtime,
                              int forcedump,
-                             register struct volintSize *size);
-static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
-                        int volid, int vnodeNumber, int dumpEverything,
-                        register struct volintSize *size);
+                             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
-iod_Init(register struct iod *iodp, register struct rx_call *call)
+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;
@@ -145,8 +156,8 @@ 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)
@@ -154,7 +165,7 @@ iod_Write(struct iod *iodp, char *buf, int nbytes)
     int code, i;
     int one_success = 0;
 
-    assert((iodp->call && iodp->ncalls == 1 && !iodp->calls)
+    opr_Assert((iodp->call && iodp->ncalls == 1 && !iodp->calls)
           || (!iodp->call && iodp->ncalls >= 1 && iodp->calls));
 
     if (iodp->call) {
@@ -188,7 +199,7 @@ iod_ungetc(struct iod *iodp, int achar)
 }
 
 static int
-iod_getc(register struct iod *iodp)
+iod_getc(struct iod *iodp)
 {
     unsigned char t;
 
@@ -196,15 +207,15 @@ iod_getc(register struct iod *iodp)
        iodp->haveOldChar = 0;
        return iodp->oldChar;
     }
-    if (iod_Read(iodp, &t, 1) == 1)
+    if (iod_Read(iodp, (char *) &t, 1) == 1)
        return t;
     return EOF;
 }
 
 static int
-ReadShort(register struct iod *iodp, register unsigned short *sp)
+ReadShort(struct iod *iodp, unsigned short *sp)
 {
-    register b1, b0;
+    int b1, b0;
     b1 = iod_getc(iodp);
     if (b1 == EOF)
        return 0;
@@ -216,9 +227,9 @@ ReadShort(register struct iod *iodp, register unsigned short *sp)
 }
 
 static int
-ReadInt32(register struct iod *iodp, afs_uint32 * lp)
+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;
@@ -236,10 +247,9 @@ ReadInt32(register struct iod *iodp, afs_uint32 * lp)
 }
 
 static void
-ReadString(register struct iod *iodp, register char *to, register int maxa)
+ReadString(struct iod *iodp, char *to, int maxa)
 {
-    register int c;
-    int first = 1;
+    int c;
 
     *to = '\0';
     if (maxa == 0)
@@ -256,20 +266,126 @@ ReadString(register struct iod *iodp, register char *to, register int maxa)
 }
 
 static void
-ReadByteString(register struct iod *iodp, register byte * to,
-              register int size)
+ReadByteString(struct iod *iodp, byte * to,
+              int size)
 {
     while (size--)
        *to++ = iod_getc(iodp);
 }
 
+/*
+ * 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 char skipbuf[256];
+
+static afs_int32
+SkipData(struct iod *iodp, afs_size_t length)
+{
+    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 char *secname[3] = {"ReadDumpHeader", "ReadVolumeHeader", "ReadVnodes"};
+
 static int
-ReadVolumeHeader(register struct iod *iodp, VolumeDiskData * vol)
+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))
@@ -385,9 +501,15 @@ ReadVolumeHeader(register struct iod *iodp, VolumeDiskData * vol)
                return VOLSERREAD_DUMPERROR;
            break;
        case 'V':
-           if (!ReadInt32(iodp, (afs_uint32 *) & vol->volUpdateCounter))
+           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);
@@ -395,7 +517,7 @@ ReadVolumeHeader(register struct iod *iodp, VolumeDiskData * vol)
 }
 
 static int
-DumpTag(register struct iod *iodp, register int tag)
+DumpTag(struct iod *iodp, int tag)
 {
     char p;
 
@@ -405,50 +527,50 @@ DumpTag(register struct iod *iodp, register int tag)
 }
 
 static int
-DumpByte(register struct iod *iodp, char tag, byte value)
+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);
 }
 
-#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)
+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);
+    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)
+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);
+    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)
+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;
@@ -456,7 +578,7 @@ DumpArrayInt32(register struct iod *iodp, char tag,
        p = (unsigned char *)tbuffer;
        v = *array++;           /*this was register */
 
-       putint32(p, v);
+       afs_putint32(p, v);
        code = iod_Write(iodp, tbuffer, 4);
        if (code != 4)
            return VOLSERDUMPERROR;
@@ -465,10 +587,10 @@ DumpArrayInt32(register struct iod *iodp, char tag,
 }
 
 static int
-DumpShort(register struct iod *iodp, char tag, unsigned int value)
+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;
@@ -476,19 +598,19 @@ DumpShort(register struct iod *iodp, char tag, unsigned int value)
 }
 
 static int
-DumpBool(register struct iod *iodp, char tag, unsigned int value)
+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);
 }
 
 static int
-DumpString(register struct iod *iodp, char tag, register char *s)
+DumpString(struct iod *iodp, char tag, char *s)
 {
-    register n;
+    int n;
     int code = 0;
     code = iod_Write(iodp, &tag, 1);
     if (code != 1)
@@ -501,8 +623,8 @@ DumpString(register struct iod *iodp, char tag, register char *s)
 }
 
 static int
-DumpByteString(register struct iod *iodp, char tag, register byte * bs,
-              register int nbytes)
+DumpByteString(struct iod *iodp, char tag, byte * bs,
+              int nbytes)
 {
     int code = 0;
 
@@ -515,30 +637,98 @@ DumpByteString(register struct iod *iodp, char tag, register byte * bs,
     return 0;
 }
 
+static afs_int32
+DumpStandardTag(struct iod *iodp, char tag, afs_uint32 section)
+{
+    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_int32 pad = 0, offset;
-    afs_sfsize_t n, nbytes, howMany, howBig;
-    afs_foff_t lcode = 0;
+    afs_int32 pad = 0;
+    afs_foff_t offset = 0;
+    afs_sfsize_t nbytes, howBig;
+    ssize_t n;
+    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
+    LARGE_INTEGER fileSize;
 #endif
-    afs_sfsize_t size;
 #ifdef AFS_AIX_ENV
 #include <sys/statfs.h>
-#if defined(AFS_AIX52_ENV) && defined(AFS_LARGEFILE_ENV)
+#if defined(AFS_AIX52_ENV)
     struct statfs64 tstatfs;
-#else /* !AFS_AIX52_ENV || !AFS_LARGEFILE_ENV */
+#else /* !AFS_AIX52_ENV */
     struct statfs tstatfs;
-#endif /* !AFS_AIX52_ENV || !AFS_LARGEFILE_ENV */
+#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
@@ -546,61 +736,54 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
     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.
      */
-#if defined(AFS_AIX52_ENV) && defined(AFS_LARGEFILE_ENV)
+#if defined(AFS_AIX52_ENV)
     statfs_code = fstatfs64(handleP->fd_fd, &tstatfs);
-#else /* !AFS_AIX52_ENV || !AFS_LARGEFILE_ENV */
+#else /* !AFS_AIX52_ENV */
     statfs_code = fstatfs(handleP->fd_fd, &tstatfs);
-#endif /* !AFS_AIX52_ENV || !AFS_LARGEFILE_ENV */
+#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 = (afs_sfsize_t) tstatfs.f_bsize;
+    howMany = tstatfs.f_bsize;
 #else
     howMany = status.st_blksize;
 #endif /* AFS_AIX_ENV */
 #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;
     }
 
-    p = (unsigned char *)malloc((size_t)howMany);
+    p = malloc(howMany);
     if (!p) {
-       Log("1 Volser: DumpFile: not enough memory to allocate %u bytes\n", howMany);
+       Log("1 Volser: DumpFile: not enough memory to allocate %u bytes\n", (unsigned)howMany);
        return VOLSERDUMPERROR;
     }
 
-    for (nbytes = size; (nbytes && !error); nbytes -= howMany) {
+    for (nbytes = howBig; (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, (size_t)howMany));
+       /* Read the data */
+       n = FDH_PREAD(handleP, p, howMany, howFar);
+       howFar += n;
 
        /* 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);
+           Log("1 Volser: DumpFile: Null padding file %d bytes at offset %lld\n", pad, (long long)offset);
            pad = 0;
        }
 
@@ -612,12 +795,12 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
            /* 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);
+               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));
            } else if (!pad) {
-               Log("1 Volser: DumpFile: Error reading inode %s for vnode %d\n", PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
+               Log("1 Volser: DumpFile: Error reading inode %s for vnode %d\n", PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
            }
 
-           /* Pad the rest of the buffer with zeros. Remember offset we started 
+           /* Pad the rest of the buffer with zeros. Remember offset we started
             * padding. Keep total tally of padding.
             */
            memset(p + n, 0, howMany - n);
@@ -628,21 +811,11 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
            /* 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_t)((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;
-           }
+           howFar = (size_t)((howBig - nbytes) + howMany);
        }
 
        /* Now write the data out */
-       if (iod_Write(iodp, (char *)p, (size_t)howMany) != howMany)
+       if (iod_Write(iodp, (char *)p, howMany) != howMany)
            error = VOLSERDUMPERROR;
 #ifndef AFS_PTHREAD_ENV
        IOMGR_Poll();
@@ -650,8 +823,8 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
     }
 
     if (pad) {                 /* Any padding we hadn't reported yet */
-       Log("1 Volser: DumpFile: Null padding file: %d bytes at offset %u\n",
-           pad, offset);
+       Log("1 Volser: DumpFile: Null padding file: %d bytes at offset %lld\n",
+           pad, (long long)offset);
     }
 
     free(p);
@@ -659,7 +832,7 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
 }
 
 static int
-DumpVolumeHeader(register struct iod *iodp, register Volume * vp)
+DumpVolumeHeader(struct iod *iodp, Volume * vp)
 {
     int code = 0;
     static char nullString[1] = "";    /*The ``contents'' of motd */
@@ -726,13 +899,11 @@ DumpVolumeHeader(register struct iod *iodp, register Volume * vp)
        code = DumpInt32(iodp, 'D', V_dayUseDate(vp));
     if (!code)
        code = DumpInt32(iodp, 'Z', V_dayUse(vp));
-    if (!code)
-       code = DumpInt32(iodp, 'V', V_volUpCounter(vp));
     return code;
 }
 
 static int
-DumpEnd(register struct iod *iodp)
+DumpEnd(struct iod *iodp)
 {
     return (DumpInt32(iodp, D_DUMPEND, DUMPENDMAGIC));
 }
@@ -741,12 +912,12 @@ DumpEnd(register struct iod *iodp)
 
 /* Dump a whole volume */
 int
-DumpVolume(register struct rx_call *call, register Volume * vp,
+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)
@@ -787,7 +958,7 @@ DumpVolMulti(struct rx_call **calls, int ncalls, Volume * vp,
 
 /* A partial dump (no dump header) */
 static int
-DumpPartial(register struct iod *iodp, register Volume * vp,
+DumpPartial(struct iod *iodp, Volume * vp,
            afs_int32 fromtime, int dumpAllDirs)
 {
     int code = 0;
@@ -801,29 +972,29 @@ DumpPartial(register struct iod *iodp, register Volume * vp,
 }
 
 static int
-DumpVnodeIndex(register struct iod *iodp, Volume * vp, VnodeClass class,
+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;
     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);
+    opr_Assert(file != NULL);
     size = OS_SIZE(fdP->fd_fd);
-    assert(size != -1);
+    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);
+       opr_Assert((nVnodes + 1) * vcp->diskSize == size);
+       opr_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
     } else
        nVnodes = 0;
     for (vnodeIndex = 0;
@@ -848,7 +1019,7 @@ DumpVnodeIndex(register struct iod *iodp, Volume * vp, VnodeClass class,
 }
 
 static int
-DumpDumpHeader(register struct iod *iodp, register Volume * vp,
+DumpDumpHeader(struct iod *iodp, Volume * vp,
               afs_int32 fromtime)
 {
     int code = 0;
@@ -866,19 +1037,34 @@ DumpDumpHeader(register struct iod *iodp, register Volume * 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 */
+    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,
+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;
@@ -914,13 +1100,30 @@ DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid,
                               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 %llu for vnode %u (volume %i); not dumped, error %d\n", (afs_uintmax_t) 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);
@@ -930,18 +1133,20 @@ DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid,
 
 
 int
-ProcessIndex(Volume * vp, VnodeClass class, afs_int32 ** Bufp, int *sizep,
+ProcessIndex(Volume * vp, VnodeClass class, afs_foff_t ** Bufp, int *sizep,
             int del)
 {
-    int i, nVnodes, offset, code, index = 0;
-    afs_int32 *Buf;
+    int i, nVnodes, code;
+    afs_foff_t offset;
+    afs_foff_t *Buf;
     int cnt = 0;
-    int size;
+    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);
@@ -954,21 +1159,24 @@ ProcessIndex(Volume * vp, VnodeClass class, afs_int32 ** Bufp, int *sizep,
        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) {
-                           Log("RestoreVolume %u Cleanup: Removing old vnode=%u inode=%llu size=unknown\n", 
-                     V_id(vp), bitNumberToVnodeNumber(i, class), 
-                     (afs_uintmax_t) VNDISK_GET_INO(vnode));
+                           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));
                        DOPOLL;
                    }
-                   STREAM_SEEK(afile, Buf[i], 0);
+                   STREAM_ASEEK(afile, Buf[i]);
                    (void)STREAM_WRITE(zero, vcp->diskSize, 1, afile);  /* Zero it out */
                }
                Buf[i] = 0;
@@ -982,19 +1190,18 @@ ProcessIndex(Volume * vp, VnodeClass class, afs_int32 ** Bufp, int *sizep,
        OS_SYNC(afile->str_fd);
     } else {
        size = OS_SIZE(fdP->fd_fd);
-       assert(size != -1);
+       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));
+           Buf = calloc(nVnodes,  sizeof(afs_foff_t));
            if (Buf == NULL) {
                STREAM_CLOSE(afile);
                FDH_CLOSE(fdP);
                return -1;
            }
-           memset((char *)Buf, 0, nVnodes * sizeof(afs_int32));
-           STREAM_SEEK(afile, offset = vcp->diskSize, 0);
+           STREAM_ASEEK(afile, offset = vcp->diskSize);
            while (1) {
                code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
                if (code != 1) {
@@ -1017,24 +1224,29 @@ ProcessIndex(Volume * vp, VnodeClass class, afs_int32 ** Bufp, int *sizep,
 
 
 int
-RestoreVolume(register struct rx_call *call, Volume * avp, int incremental,
+RestoreVolume(struct rx_call *call, Volume * avp, int incremental,
              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 = NULL, *b2 = NULL;
+    struct iod *iodp = &iod;
+    afs_foff_t *b1 = NULL, *b2 = NULL;
     int s1 = 0, s2 = 0, delo = 0, tdelo;
     int tag;
+    VolumeDiskData saved_header;
 
     iod_Init(iodp, call);
 
     vp = avp;
 
+    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;
@@ -1061,6 +1273,8 @@ RestoreVolume(register struct rx_call *call, Volume * avp, int incremental,
     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)) {
@@ -1101,7 +1315,16 @@ RestoreVolume(register struct rx_call *call, Volume * avp, int incremental,
     }
 
   clean:
-    ClearVolumeStats(&vol);
+    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);
+    }
     CopyVolumeHeader(&vol, &V_disk(vp));
     V_destroyMe(vp) = 0;
     VUpdateVolume(&vupdate, vp);
@@ -1113,20 +1336,20 @@ RestoreVolume(register struct rx_call *call, Volume * avp, int incremental,
   out:
     /* Free the malloced space above */
     if (b1)
-       free((char *)b1);
+       free(b1);
     if (b2)
-       free((char *)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,
+ReadVnodes(struct iod *iodp, Volume * vp, int incremental,
+          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;
+    int tag;
     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
     struct VnodeDiskObject oldvnode;
     int idx;
@@ -1134,20 +1357,25 @@ ReadVnodes(register struct iod *iodp, Volume * vp, int incremental,
     struct VnodeClassInfo *vcp;
     IHandle_t *tmpH;
     FdHandle_t *fdP;
-    Inode nearInode;
+    Inode nearInode AFS_UNUSED;
+    afs_int32 critical = 0;
 
     tag = iod_getc(iodp);
     V_pref(vp, nearInode);
     while (tag == D_VNODE) {
        int haveStuff = 0;
+       int saw_f = 0;
        memset(buf, 0, sizeof(buf));
        if (!ReadInt32(iodp, (afs_uint32 *) & vnodeNumber))
            break;
 
        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);
@@ -1200,30 +1428,41 @@ ReadVnodes(register struct iod *iodp, Volume * vp, int incremental,
                               VAclDiskSize(vnode));
                acl_NtohACL(VVnodeDiskACL(vnode));
                break;
-#ifdef AFS_LARGEFILE_ENV
            case 'h':
-#endif
            case 'f':{
                    Inode ino;
                    Error error;
                    afs_fsize_t vnodeLength;
 
-                   ino =
-                       IH_CREATE(V_linkHandle(vp), V_device(vp),
+                   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 (!VALID_INO(ino)) {
-                       perror("unable to allocate inode");
-                       Log("1 Volser: ReadVnodes: Restore aborted\n");
+                   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;
                    }
                    vnodeLength =
@@ -1235,10 +1474,17 @@ ReadVnodes(register struct iod *iodp, Volume * vp, int incremental,
                        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;
            }
        }
 
@@ -1260,16 +1506,12 @@ ReadVnodes(register struct iod *iodp, Volume * vp, int incremental,
        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)) ==
+           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),
@@ -1277,15 +1519,11 @@ ReadVnodes(register struct iod *iodp, Volume * vp, int incremental,
                }
            }
            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);
@@ -1300,45 +1538,39 @@ ReadVnodes(register struct iod *iodp, Volume * vp, int incremental,
 /* 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_fsize_t
 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
                 Error * status)
 {
     afs_int32 code;
-    afs_sfsize_t lcode;
+    ssize_t nBytes;
     afs_fsize_t filesize;
     afs_fsize_t written = 0;
-    register afs_uint32 size = 8192;
-    register afs_fsize_t nbytes;
+    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)) {
                *status = 1;
                return 0;
            }
        }
-#endif /* !AFS_LARGEFILE_ENV */
        if (!ReadInt32(iodp, &filesize_low)) {
            *status = 1;
            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);
@@ -1347,18 +1579,20 @@ volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
        if (nbytes < size)
            size = nbytes;
 
-       if ((code = iod_Read(iodp, p, size)) != size) {
-           Log("1 Volser: WriteFile: Error reading dump file %d size=%llu nbytes=%u (%d of %u); restore aborted\n", vn, (afs_uintmax_t) filesize, nbytes, code, size);
+       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;
        }
-       lcode = FDH_WRITE(handleP, p, size);
-       if (lcode > 0)
-           written += lcode;
-       if (lcode != size) {
-           Log("1 Volser: WriteFile: Error writing (%d,%u) bytes to vnode %d; restore aborted\n", (int)(lcode>>32), (int)(lcode & 0xffffffff), vn);
-           *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);
@@ -1366,10 +1600,11 @@ volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
 }
 
 static int
-ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
+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)
@@ -1378,7 +1613,9 @@ ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
     hp->nDumpTimes = 0;
     while ((tag = iod_getc(iodp)) > D_MAX) {
        unsigned short arrayLength;
-       register int i;
+       int i;
+       if (critical)
+           critical--;
        switch (tag) {
        case 'v':
            if (!ReadInt32(iodp, &hp->volumeId))
@@ -1396,6 +1633,12 @@ ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
                    || !ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].to))
                    return 0;
            break;
+        case 0x7e:
+            critical = 2;
+            break;
+        default:
+            if (!HandleUnknownTag(iodp, tag, 0, critical))
+                return VOLSERREAD_DUMPERROR;
        }
     }
     if (!hp->volumeId || !hp->nDumpTimes) {
@@ -1409,8 +1652,8 @@ ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
 /* ----- Below are the calls that calculate dump size ----- */
 
 static int
-SizeDumpVolumeHeader(register struct iod *iodp, register Volume * vp,
-                    register struct volintSize *v_size)
+SizeDumpVolumeHeader(struct iod *iodp, Volume * vp,
+                    struct volintSize *v_size)
 {
     int code = 0;
     static char nullString[1] = "";    /*The ``contents'' of motd */
@@ -1500,14 +1743,11 @@ SizeDumpVolumeHeader(register struct iod *iodp, register Volume * vp,
 /*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
     FillInt64(addvar,0, 5);
     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
-/*     if (!code) code = DumpInt32(iodp, 'V', V_volUpCounter(vp)); */
-    FillInt64(addvar,0, 5);
-    AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
     return code;
 }
 
 static int
-SizeDumpEnd(register struct iod *iodp, register struct volintSize *v_size)
+SizeDumpEnd(struct iod *iodp, struct volintSize *v_size)
 {
     int code = 0;
     afs_uint64 addvar;
@@ -1517,12 +1757,12 @@ SizeDumpEnd(register struct iod *iodp, register struct volintSize *v_size)
 }
 
 int
-SizeDumpVolume(register struct rx_call *call, register Volume * vp,
+SizeDumpVolume(struct rx_call *call, Volume * vp,
               afs_int32 fromtime, int dumpAllDirs,
-              register struct volintSize *v_size)
+              struct volintSize *v_size)
 {
     int code = 0;
-    register struct iod *iodp = (struct iod *)0;
+    struct iod *iodp = (struct iod *)0;
 /*    iod_Init(iodp, call); */
 
     if (!code)
@@ -1536,11 +1776,11 @@ SizeDumpVolume(register struct rx_call *call, register Volume * vp,
 }
 
 static int
-SizeDumpDumpHeader(register struct iod *iodp, register Volume * vp,
-                  afs_int32 fromtime, register struct volintSize *v_size)
+SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
+                  afs_int32 fromtime, struct volintSize *v_size)
 {
     int code = 0;
-    int UseLatestReadOnlyClone = 1;
+/*    int UseLatestReadOnlyClone = 1; */
 /*    afs_int32 dumpTimes[2]; */
     afs_uint64 addvar;
 /*    iodp->device = vp->device; */
@@ -1566,9 +1806,9 @@ SizeDumpDumpHeader(register struct iod *iodp, register Volume * vp,
 }
 
 static int
-SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid,
+SizeDumpVnode(struct iod *iodp, struct VnodeDiskObject *v, VolumeId volid,
              int vnodeNumber, int dumpEverything,
-             register struct volintSize *v_size)
+             struct volintSize *v_size)
 {
     int code = 0;
     afs_uint64 addvar;
@@ -1620,7 +1860,11 @@ SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid,
     }
 
     if (VNDISK_GET_INO(v)) {
-       FillInt64(addvar,0, (v->length + 5));
+       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;
@@ -1628,9 +1872,9 @@ SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid,
 
 /* A partial dump (no dump header) */
 static int
-SizeDumpPartial(register struct iod *iodp, register Volume * vp,
+SizeDumpPartial(struct iod *iodp, Volume * vp,
                afs_int32 fromtime, int dumpAllDirs,
-               register struct volintSize *v_size)
+               struct volintSize *v_size)
 {
     int code = 0;
     if (!code)
@@ -1645,30 +1889,30 @@ SizeDumpPartial(register struct iod *iodp, register Volume * vp,
 }
 
 static int
-SizeDumpVnodeIndex(register struct iod *iodp, Volume * vp, VnodeClass class,
+SizeDumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
                   afs_int32 fromtime, int forcedump,
-                  register struct volintSize *v_size)
+                  struct volintSize *v_size)
 {
-    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;
     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);
+    opr_Assert(file != NULL);
     size = OS_SIZE(fdP->fd_fd);
-    assert(size != -1);
+    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);
+       opr_Assert((nVnodes + 1) * vcp->diskSize == size);
+       opr_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
     } else
        nVnodes = 0;
     for (vnodeIndex = 0;