vol: Use FDH_SIZE more consistently
[openafs.git] / src / volser / vol-dump.c
index 912f0b4..0fdf0e3 100644 (file)
 # pragma GCC diagnostic warning "-Wformat"
 #endif
 
+#include <roken.h>
+
 #include <ctype.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef AFS_NT40_ENV
-#include <fcntl.h>
-#include <time.h>
-#include <io.h>
-#else
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#endif
-#include <afs/cmd.h>
 
+#include <afs/cmd.h>
 #include <rx/xdr.h>
+#include <rx/rx_queue.h>
 #include <afs/afsint.h>
 #include <afs/nfs.h>
 #include <afs/errors.h>
 #include <afs/dir.h>
 #include <afs/com_err.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#ifdef _AIX
-#include <time.h>
-#endif
-
-#include <dirent.h>
-
 #include "volser.h"
 #include "volint.h"
 #include "dump.h"
 
-#define putint32(p, v)  *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
-#define putshort(p, v) *p++ = v>>8, *p++ = v
-
-#ifdef O_LARGEFILE
-#define afs_stat       stat64
-#define afs_fstat      fstat64
-#define afs_open       open64
-#else /* !O_LARGEFILE */
-#define afs_stat       stat
-#define afs_fstat      fstat
-#define afs_open       open
-#endif /* !O_LARGEFILE */
+#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
 
 int VolumeChanged;             /* needed by physio - leave alone */
 int verbose = 0;
+static int enable_padding; /* Pad errors with NUL bytes */
 
 /* Forward Declarations */
-void HandleVolume(struct DiskPartition64 *partP, char *name, char *filename, int fromtime);
-Volume *AttachVolume(struct DiskPartition64 *dp, char *volname,
-                    struct VolumeHeader *header);
+static void HandleVolume(struct DiskPartition64 *partP, char *name,
+                        char *filename, int fromtime);
+static Volume *AttachVolume(struct DiskPartition64 *dp, char *volname,
+                           struct VolumeHeader *header);
 static void DoMyVolDump(Volume * vp, struct DiskPartition64 *dp,
                        char *dumpfile, int fromtime);
 
@@ -106,7 +70,7 @@ static void DoMyVolDump(Volume * vp, struct DiskPartition64 *dp,
 char name[VMAXPATHLEN];
 
 
-int
+static int
 ReadHdr1(IHandle_t * ih, char *to, int size, u_int magic, u_int version)
 {
     int code;
@@ -119,7 +83,7 @@ ReadHdr1(IHandle_t * ih, char *to, int size, u_int magic, u_int version)
 }
 
 
-Volume *
+static Volume *
 AttachVolume(struct DiskPartition64 * dp, char *volname,
             struct VolumeHeader * header)
 {
@@ -141,7 +105,7 @@ AttachVolume(struct DiskPartition64 * dp, char *volname,
     vp->shuttingDown = 0;
     vp->goingOffline = 0;
     vp->nUsers = 1;
-    vp->header = (struct volHeader *)calloc(1, sizeof(*vp->header));
+    vp->header = calloc(1, sizeof(*vp->header));
     ec = ReadHdr1(V_diskDataHandle(vp), (char *)&V_disk(vp),
                  sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
     if (!ec) {
@@ -182,15 +146,6 @@ handleit(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
 
 
-#ifndef AFS_NT40_ENV
-#if 0
-    if (geteuid() != 0) {
-       fprintf(stderr, "voldump must be run as root; sorry\n");
-       exit(1);
-    }
-#endif
-#endif
-
     if ((ti = as->parms[0].items))
        partName = ti->data;
     if ((ti = as->parms[1].items))
@@ -207,6 +162,9 @@ handleit(struct cmd_syndesc *as, void *arock)
                return code;
        }
     }
+    if (as->parms[5].items != NULL) { /* -pad-errors */
+       enable_padding = 1;
+    }
 
     DInit(10);
 
@@ -243,12 +201,12 @@ handleit(struct cmd_syndesc *as, void *arock)
        exit(1);
     }
 
-    (void)afs_snprintf(name1, sizeof name1, VFORMAT, (unsigned long)volumeId);
+    snprintf(name1, sizeof name1, VFORMAT, (unsigned long)volumeId);
     HandleVolume(partP, name1, fileName, fromtime);
     return 0;
 }
 
-void
+static void
 HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtime)
 {
     struct VolumeHeader header;
@@ -260,8 +218,8 @@ HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtim
 
     afs_int32 n;
 
-    (void)afs_snprintf(headerName, sizeof headerName, "%s" OS_DIRSEP "%s",
-                      VPartitionPath(dp), name);
+    snprintf(headerName, sizeof headerName, "%s" OS_DIRSEP "%s",
+            VPartitionPath(dp), name);
     if ((fd = afs_open(headerName, O_RDONLY)) == -1
        || afs_fstat(fd, &status) == -1) {
        fprintf(stderr, "Cannot read volume header %s\n", name);
@@ -291,6 +249,8 @@ HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtim
     }
 
     DoMyVolDump(vp, dp, filename, fromtime);
+
+    free(vp);
 }
 
 
@@ -307,7 +267,7 @@ main(int argc, char **argv)
                        "trying to continue anyway\n");
     }
 
-    ts = cmd_CreateSyntax(NULL, handleit, NULL,
+    ts = cmd_CreateSyntax(NULL, handleit, NULL, 0,
                          "Dump a volume to a 'vos dump' format file without using volserver");
     cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name");
     cmd_AddParm(ts, "-volumeid", CMD_LIST, CMD_OPTIONAL, "Volume id");
@@ -315,6 +275,8 @@ main(int argc, char **argv)
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
                "Trace dump progress (very verbose)");
     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
+    cmd_AddParm(ts, "-pad-errors", CMD_FLAG, CMD_OPTIONAL,
+               "pad i/o errors with NUL bytes");
     code = cmd_Dispatch(argc, argv);
     return code;
 }
@@ -330,8 +292,8 @@ DumpDouble(int dumpfd, char tag, afs_uint32 value1,
     char tbuffer[9];
     byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    putint32(p, value1);
-    putint32(p, value2);
+    afs_putint32(p, value1);
+    afs_putint32(p, value2);
 
     res = write(dumpfd, tbuffer, 9);
     return ((res == 9) ? 0 : VOLSERDUMPERROR);
@@ -343,7 +305,7 @@ DumpInt32(int dumpfd, char tag, afs_uint32 value)
     char tbuffer[5];
     byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    putint32(p, value);
+    afs_putint32(p, value);
     return ((write(dumpfd, tbuffer, 5) == 5) ? 0 : VOLSERDUMPERROR);
 }
 
@@ -372,7 +334,7 @@ DumpArrayInt32(int dumpfd, char tag, afs_uint32 * array,
     int code = 0;
     byte *p = (unsigned char *)tbuffer;
     *p++ = tag;
-    putshort(p, nelem);
+    afs_putshort(p, nelem);
     code = write(dumpfd, tbuffer, 3);
     if (code != 3)
        return VOLSERDUMPERROR;
@@ -380,7 +342,7 @@ DumpArrayInt32(int dumpfd, char tag, afs_uint32 * array,
        p = (unsigned char *)tbuffer;
        v = *array++;           /*this was register */
 
-       putint32(p, v);
+       afs_putint32(p, v);
        code = write(dumpfd, tbuffer, 4);
        if (code != 4)
            return VOLSERDUMPERROR;
@@ -410,7 +372,21 @@ DumpDumpHeader(int dumpfd, Volume * vp, afs_int32 fromtime)
        code = DumpString(dumpfd, '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(dumpfd, 't', (afs_uint32 *) dumpTimes, 2);
 
@@ -557,11 +533,11 @@ DumpByteString(int dumpfd, char tag, byte * bs, int nbytes)
 static int
 DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v)
 {
-    int code = 0, failed_seek = 0, failed_write = 0;
+    int code = 0;
     afs_int32 pad = 0;
     afs_foff_t offset = 0;
     afs_sfsize_t nbytes, howBig;
-    ssize_t n;
+    ssize_t n = 0;
     size_t howMany;
     afs_foff_t howFar = 0;
     byte *p;
@@ -569,6 +545,8 @@ DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v
     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
@@ -580,7 +558,11 @@ DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v
        fprintf(stderr, "dumping file for vnode %d\n", vnode);
 
 #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
@@ -617,20 +599,18 @@ DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v
        return VOLSERDUMPERROR;
     }
 
-    p = (unsigned char *)malloc(howMany);
+    p = malloc(howMany);
     if (!p) {
        fprintf(stderr, "out of memory!\n");
        return VOLSERDUMPERROR;
     }
 
     /* loop through whole file, while we still have bytes left, and no errors, in chunks of howMany bytes */
-    for (nbytes = size; (nbytes && !failed_write); nbytes -= howMany) {
+    for (nbytes = size; (nbytes && !code); ) {
        if (nbytes < howMany)
            howMany = nbytes;
 
-       /* Read the data - unless we know we can't */
-       n = (failed_seek ? 0 : FDH_PREAD(handleP, p, howMany, howFar));
-       howFar += n;
+       n = FDH_PREAD(handleP, p, howMany, howFar);
 
        /* If read any good data and we null padded previously, log the
         * amount that we had null padded.
@@ -641,42 +621,48 @@ DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v
            pad = 0;
        }
 
-       /* 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) {
-
-               if (verbose) fprintf(stderr, "  read %u instead of %u bytes.\n", (unsigned)n, (unsigned)howMany);
-
-           /* Record the read error */
-           if (n < 0) {
-               n = 0;
-               fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
-                       errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
-                       vnode);
-           } else if (!pad) {
-               fprintf(stderr, "Error reading inode %s for vnode %d\n",
+       if (n < 0) {
+           fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
+                   errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
+                   vnode);
+           code = VOLSERDUMPERROR;
+       }
+       if (n == 0) {
+           if (pad == 0) {
+               fprintf(stderr, "Unexpected EOF reading inode %s for vnode %d\n",
                        PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
            }
+           code = VOLSERDUMPERROR;
+       }
 
-           /* Pad the rest of the buffer with zeros. Remember offset we started
-            * padding. Keep total tally of padding.
+       if (code != 0 && enable_padding) {
+           /*
+            * If our read failed, NUL-pad 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 NUL padding.
             */
-           memset(p + n, 0, howMany - n);
+           memset(p, 0, howMany);
+
+           /* Remember the offset where we started padding, and keep a total
+            * tally of how much padding we've done. */
            if (!pad)
-               offset = (howBig - nbytes) + n;
-           pad += (howMany - n);
+               offset = howFar;
+           pad += howMany;
 
-           /* Now seek over the data we could not get. An error here means we
-            * can't do the next read.
-            */
-           howFar = ((size - nbytes) + howMany);
+           /* Pretend we read 'howMany' bytes. */
+           n = howMany;
+           code = 0;
+       }
+       if (code != 0) {
+           break;
        }
 
+       howFar += n;
+       nbytes -= n;
+
        /* Now write the data out */
-       if (write(dumpfd, (char *)p, howMany) != howMany)
-           failed_write = VOLSERDUMPERROR;
+       if (write(dumpfd, (char *)p, n) != n)
+           code = VOLSERDUMPERROR;
     }
 
     if (pad) {                 /* Any padding we hadn't reported yet */
@@ -685,12 +671,12 @@ DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v
     }
 
     free(p);
-    return failed_write;
+    return code;
 }
 
 
 static int
-DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
+DumpVnode(int dumpfd, struct VnodeDiskObject *v, VolumeId volid, int vnodeNumber,
          int dumpEverything, struct Volume *vp)
 {
     int code = 0;
@@ -728,7 +714,11 @@ DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
     if (!code)
        code = DumpInt32(dumpfd, 's', v->serverModifyTime);
     if (v->type == vDirectory) {
-       acl_HtonACL(VVnodeDiskACL(v));
+       code = acl_HtonACL(VVnodeDiskACL(v));
+       if (code) {
+           fprintf(stderr, "Skipping invalid acl in vnode %u (volume %"AFS_VOLID_FMT")\n",
+                       vnodeNumber, afs_printable_VolumeId_lu(volid));
+       }
        if (!code)
            code =
                DumpByteString(dumpfd, 'A', (byte *) VVnodeDiskACL(v),
@@ -740,9 +730,10 @@ DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
        fdP = IH_OPEN(ihP);
        if (fdP == NULL) {
            fprintf(stderr,
-                   "Unable to open inode %s for vnode %u (volume %i); not dumped, error %d\n",
-                   PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber, volid,
-                   errno);
+                   "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);
        }
        else
        {
@@ -778,7 +769,7 @@ DumpVnodeIndex(int dumpfd, Volume * vp, VnodeClass class, afs_int32 fromtime,
 
     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
     file = FDH_FDOPEN(fdP, "r+");
-    size = OS_SIZE(fdP->fd_fd);
+    size = FDH_SIZE(fdP);
     nVnodes = (size / vcp->diskSize) - 1;
 
     if (nVnodes > 0) {