volser: Catch EOFs when reading dumps
[openafs.git] / src / volser / dumpstuff.c
index 16f5e79..ee4a794 100644 (file)
@@ -14,9 +14,9 @@
 
 #include <ctype.h>
 
-#include <afs/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>
@@ -50,6 +50,7 @@
 /*@printflike@*/ extern void Log(const char *format, ...);
 
 extern int DoLogging;
+extern int DoPreserveVolumeStats;
 
 
 /* Forward Declarations */
@@ -162,7 +163,7 @@ iod_Write(struct iod *iodp, char *buf, int nbytes)
     int code, i;
     int one_success = 0;
 
-    osi_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) {
@@ -280,7 +281,8 @@ ReadStandardTagLen(struct iod *iodp, unsigned char tag, afs_int32 section,
     afs_int32 code, i;
     afs_uint32 off = tag >> 5;
     afs_uint32 mask = 1 << (tag & 0x1f);
-    unsigned char len, buf[8], *p;
+    int len;
+    unsigned char buf[8], *p;
 
     if (!oldtagsInited)
         initNonStandardTags();
@@ -294,7 +296,9 @@ ReadStandardTagLen(struct iod *iodp, unsigned char tag, afs_int32 section,
     }
     if (tag <= MAX_TLV_TAG) {
         len = iod_getc(iodp);
-        if (len < 128)
+       if (len == EOF)
+           return VOLSERDUMPERROR;
+       else if (len < 128)
             *length = len;
         else {
             len &= 0x7f;
@@ -704,6 +708,8 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
     afs_ino_str_t stmp;
 #ifndef AFS_NT40_ENV
     struct afs_stat status;
+#else
+    LARGE_INTEGER fileSize;
 #endif
 #ifdef AFS_AIX_ENV
 #include <sys/statfs.h>
@@ -716,7 +722,11 @@ DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
 #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
@@ -974,15 +984,15 @@ DumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
     int vnodeIndex;
 
     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
-    osi_Assert(fdP != NULL);
+    opr_Assert(fdP != NULL);
     file = FDH_FDOPEN(fdP, "r+");
-    osi_Assert(file != NULL);
+    opr_Assert(file != NULL);
     size = OS_SIZE(fdP->fd_fd);
-    osi_Assert(size != -1);
+    opr_Assert(size != -1);
     nVnodes = (size / vcp->diskSize) - 1;
     if (nVnodes > 0) {
-       osi_Assert((nVnodes + 1) * vcp->diskSize == size);
-       osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
+       opr_Assert((nVnodes + 1) * vcp->diskSize == size);
+       opr_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
     } else
        nVnodes = 0;
     for (vnodeIndex = 0;
@@ -1073,6 +1083,7 @@ DumpVnode(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) {
@@ -1080,6 +1091,17 @@ DumpVnode(struct iod *iodp, struct VnodeDiskObject *v, int volid,
            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 %lu vnode %lu has inconsistent length "
+               "(index %lu disk %lu); aborting dump\n",
+               (unsigned long)volid, (unsigned long)vnodeNumber,
+               (unsigned long)indexlen, (unsigned long)disklen);
+           return VOLSERREAD_DUMPERROR;
+       }
        code = DumpFile(iodp, vnodeNumber, fdP);
        FDH_CLOSE(fdP);
        IH_RELEASE(ihP);
@@ -1142,22 +1164,17 @@ ProcessIndex(Volume * vp, VnodeClass class, afs_foff_t ** Bufp, int *sizep,
        OS_SYNC(afile->str_fd);
     } else {
        size = OS_SIZE(fdP->fd_fd);
-       osi_Assert(size != -1);
+       opr_Assert(size != -1);
        nVnodes =
            (size <=
             vcp->diskSize ? 0 : size - vcp->diskSize) >> vcp->logSize;
        if (nVnodes > 0) {
-           if (DoLogging) {
-               Log("RestoreVolume ProcessIndex: Set up %d inodes for volume %d\n",
-                   nVnodes, V_id(vp));
-           }
-           Buf = malloc(nVnodes * sizeof(afs_foff_t));
+           Buf = calloc(nVnodes,  sizeof(afs_foff_t));
            if (Buf == NULL) {
                STREAM_CLOSE(afile);
                FDH_CLOSE(fdP);
                return -1;
            }
-           memset(Buf, 0, nVnodes * sizeof(afs_foff_t));
            STREAM_ASEEK(afile, offset = vcp->diskSize);
            while (1) {
                code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
@@ -1170,9 +1187,6 @@ ProcessIndex(Volume * vp, VnodeClass class, afs_foff_t ** Bufp, int *sizep,
                }
                offset += vcp->diskSize;
            }
-           if (DoLogging) {
-               Log("RestoreVolume ProcessIndex: found %d inodes\n", cnt);
-           }
            *Bufp = Buf;
            *sizep = nVnodes;
        }
@@ -1197,11 +1211,16 @@ RestoreVolume(struct rx_call *call, Volume * avp, int incremental,
     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;
@@ -1228,6 +1247,8 @@ RestoreVolume(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)) {
@@ -1268,7 +1289,16 @@ RestoreVolume(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);
@@ -1280,9 +1310,9 @@ RestoreVolume(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;
 }
 
@@ -1316,9 +1346,6 @@ ReadVnodes(struct iod *iodp, Volume * vp, int incremental,
        if (!ReadInt32(iodp, &vnode->uniquifier))
            return VOLSERREAD_DUMPERROR;
 
-       if (DoLogging) {
-           Log("ReadVnodes: setup %d/%d\n", vnodeNumber, vnode->uniquifier);
-       }
        while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
            haveStuff = 1;
             if (critical)
@@ -1517,7 +1544,7 @@ volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
        }
        FillInt64(filesize, filesize_high, filesize_low);
     }
-    p = (unsigned char *)malloc(size);
+    p = malloc(size);
     if (p == NULL) {
        *status = 2;
        return (0);
@@ -1847,15 +1874,15 @@ SizeDumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
     int vnodeIndex;
 
     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
-    osi_Assert(fdP != NULL);
+    opr_Assert(fdP != NULL);
     file = FDH_FDOPEN(fdP, "r+");
-    osi_Assert(file != NULL);
+    opr_Assert(file != NULL);
     size = OS_SIZE(fdP->fd_fd);
-    osi_Assert(size != -1);
+    opr_Assert(size != -1);
     nVnodes = (size / vcp->diskSize) - 1;
     if (nVnodes > 0) {
-       osi_Assert((nVnodes + 1) * vcp->diskSize == size);
-       osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
+       opr_Assert((nVnodes + 1) * vcp->diskSize == size);
+       opr_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
     } else
        nVnodes = 0;
     for (vnodeIndex = 0;