From f6a9d9269a4f07eb7b2161884dde52a65f58c9f6 Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Mon, 11 Mar 2013 07:07:46 +0100
Subject: [PATCH 12/48] vma: add verify command

Users wants to verify the archive after backup.

Examples:

 # vma verify -v test.vma

 # lzop -d -c test.vma.lzo |vma verify -

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
---
 vma-reader.c | 121 ++++++++++++++++++++++++++++++++++++++++++++---------------
 vma.c        |  55 +++++++++++++++++++++++++++
 vma.h        |   1 +
 3 files changed, 147 insertions(+), 30 deletions(-)

diff --git a/vma-reader.c b/vma-reader.c
index 51dd8fe..2aafb26 100644
--- a/vma-reader.c
+++ b/vma-reader.c
@@ -45,6 +45,8 @@ struct VmaReader {
     time_t start_time;
     int64_t cluster_count;
     int64_t clusters_read;
+    int64_t zero_cluster_data;
+    int64_t partial_zero_cluster_data;
     int clusters_read_per;
 };
 
@@ -425,6 +427,27 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id)
     return NULL;
 }
 
+static void allocate_rstate(VmaReader *vmar,  guint8 dev_id,
+                            BlockDriverState *bs, bool write_zeroes)
+{
+    assert(vmar);
+    assert(dev_id);
+
+    vmar->rstate[dev_id].bs = bs;
+    vmar->rstate[dev_id].write_zeroes = write_zeroes;
+
+    int64_t size = vmar->devinfo[dev_id].size;
+
+    int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) +
+        (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1;
+    bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG;
+
+    vmar->rstate[dev_id].bitmap_size = bitmap_size;
+    vmar->rstate[dev_id].bitmap = g_new0(unsigned long, bitmap_size);
+
+    vmar->cluster_count += size/VMA_CLUSTER_SIZE;
+}
+
 int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
                            bool write_zeroes, Error **errp)
 {
@@ -447,17 +470,7 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
         return -1;
     }
 
-    vmar->rstate[dev_id].bs = bs;
-    vmar->rstate[dev_id].write_zeroes = write_zeroes;
-
-    int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) +
-        (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1;
-    bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG;
-
-    vmar->rstate[dev_id].bitmap_size = bitmap_size;
-    vmar->rstate[dev_id].bitmap = g_new0(unsigned long, bitmap_size);
-
-    vmar->cluster_count += size/VMA_CLUSTER_SIZE;
+    allocate_rstate(vmar, dev_id, bs, write_zeroes);
 
     return 0;
 }
@@ -524,9 +537,10 @@ static int restore_write_data(VmaReader *vmar, guint8 dev_id,
     }
     return 0;
 }
+
 static int restore_extent(VmaReader *vmar, unsigned char *buf,
                           int extent_size, int vmstate_fd,
-                          bool verbose, Error **errp)
+                          bool verbose, bool verify, Error **errp)
 {
     assert(vmar);
     assert(buf);
@@ -551,7 +565,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
 
         if (dev_id != vmar->vmstate_stream) {
             bs = rstate->bs;
-            if (!bs) {
+            if (!verify && !bs) {
                 error_setg(errp, "got wrong dev id %d", dev_id);
                 return -1;
             }
@@ -607,10 +621,13 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
                 return -1;
             }
 
-            int nb_sectors = end_sector - sector_num;
-            if (restore_write_data(vmar, dev_id, bs, vmstate_fd, buf + start,
-                                   sector_num, nb_sectors, errp) < 0) {
-                return -1;
+            if (!verify) {
+                int nb_sectors = end_sector - sector_num;
+                if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
+                                       buf + start, sector_num, nb_sectors,
+                                       errp) < 0) {
+                    return -1;
+                }
             }
 
             start += VMA_CLUSTER_SIZE;
@@ -640,26 +657,37 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
                         return -1;
                     }
 
-                    int nb_sectors = end_sector - sector_num;
-                    if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
-                                           buf + start, sector_num,
-                                           nb_sectors, errp) < 0) {
-                        return -1;
+                    if (!verify) {
+                        int nb_sectors = end_sector - sector_num;
+                        if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
+                                               buf + start, sector_num,
+                                               nb_sectors, errp) < 0) {
+                            return -1;
+                        }
                     }
 
                     start += VMA_BLOCK_SIZE;
 
                 } else {
 
-                    if (rstate->write_zeroes && (end_sector > sector_num)) {
+
+                    if (end_sector > sector_num) {
                         /* Todo: use bdrv_co_write_zeroes (but that need to
                          * be run inside coroutine?)
                          */
                         int nb_sectors = end_sector - sector_num;
-                        if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
-                                              zero_vma_block, sector_num,
-                                               nb_sectors, errp) < 0) {
-                            return -1;
+                        int zero_size = BDRV_SECTOR_SIZE*nb_sectors;
+                        vmar->zero_cluster_data += zero_size;
+                        if (mask != 0) {
+                            vmar->partial_zero_cluster_data += zero_size;
+                        }
+
+                        if (rstate->write_zeroes && !verify) {
+                            if (restore_write_data(vmar, dev_id, bs, vmstate_fd,
+                                                   zero_vma_block, sector_num,
+                                                   nb_sectors, errp) < 0) {
+                                return -1;
+                            }
                         }
                     }
                 }
@@ -677,8 +705,9 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
     return 0;
 }
 
-int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
-                       Error **errp)
+static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd,
+                                   bool verbose, bool verify,
+                                   Error **errp)
 {
     assert(vmar);
     assert(vmar->head_data);
@@ -745,7 +774,7 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
         }
 
         if (restore_extent(vmar, buf, extent_size, vmstate_fd, verbose,
-                           errp) < 0) {
+                           verify, errp) < 0) {
             return -1;
         }
 
@@ -792,6 +821,38 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
         }
     }
 
+    if (verbose) {
+        printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n",
+               vmar->clusters_read*VMA_CLUSTER_SIZE,
+               vmar->zero_cluster_data,
+               (double)(100.0*vmar->zero_cluster_data)/
+               (vmar->clusters_read*VMA_CLUSTER_SIZE));
+
+        int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data;
+        if (datasize) { // this does not make sense for empty files
+            printf("space reduction due to 4K zero blocks %.3g%%\n",
+                   (double)(100.0*vmar->partial_zero_cluster_data) / datasize);
+        }
+    }
     return ret;
 }
 
+int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
+                       Error **errp)
+{
+    return vma_reader_restore_full(vmar, vmstate_fd, verbose, false, errp);
+}
+
+int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp)
+{
+    guint8 dev_id;
+
+    for (dev_id = 1; dev_id < 255; dev_id++) {
+        if (vma_reader_get_device_info(vmar, dev_id)) {
+            allocate_rstate(vmar, dev_id, NULL, false);
+        }
+    }
+
+    return vma_reader_restore_full(vmar, -1, verbose, true, errp);
+}
+
diff --git a/vma.c b/vma.c
index 8732bfa..ab7b766 100644
--- a/vma.c
+++ b/vma.c
@@ -29,6 +29,7 @@ static void help(void)
         "vma list <filename>\n"
         "vma create <filename> [-c config] <archive> pathname ...\n"
         "vma extract <filename> [-r <fifo>] <targetdir>\n"
+        "vma verify <filename> [-v]\n"
         ;
 
     printf("%s", help_msg);
@@ -333,6 +334,58 @@ static int extract_content(int argc, char **argv)
     return ret;
 }
 
+static int verify_content(int argc, char **argv)
+{
+    int c, ret = 0;
+    int verbose = 0;
+    const char *filename;
+
+    for (;;) {
+        c = getopt(argc, argv, "hv");
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case '?':
+        case 'h':
+            help();
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        default:
+            help();
+        }
+    }
+
+    /* Get the filename */
+    if ((optind + 1) != argc) {
+        help();
+    }
+    filename = argv[optind++];
+
+    Error *errp = NULL;
+    VmaReader *vmar = vma_reader_create(filename, &errp);
+
+    if (!vmar) {
+        g_error("%s", error_get_pretty(errp));
+    }
+
+    if (verbose) {
+        print_content(vmar);
+    }
+
+    if (vma_reader_verify(vmar, verbose, &errp) < 0) {
+        g_error("verify failed - %s", error_get_pretty(errp));
+    }
+
+    vma_reader_destroy(vmar);
+
+    bdrv_close_all();
+
+    return ret;
+}
+
 typedef struct BackupJob {
     BlockDriverState *bs;
     int64_t len;
@@ -579,6 +632,8 @@ int main(int argc, char **argv)
         return create_archive(argc, argv);
     } else if (!strcmp(cmdname, "extract")) {
         return extract_content(argc, argv);
+    } else if (!strcmp(cmdname, "verify")) {
+        return verify_content(argc, argv);
     }
 
     help();
diff --git a/vma.h b/vma.h
index 6625eb9..9bb6ea4 100644
--- a/vma.h
+++ b/vma.h
@@ -142,5 +142,6 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id,
                            Error **errp);
 int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
                        Error **errp);
+int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp);
 
 #endif /* BACKUP_VMA_H */
-- 
2.1.4

