]> xenbits.xensource.com Git - people/dstodden/blktap.git/commitdiff
vhd-util dm-decrypt
authorJake Wires <Jake.Wires@citrix.com>
Thu, 1 Jul 2010 18:25:26 +0000 (11:25 -0700)
committerDaniel Stodden <daniel.stodden@citrix.com>
Tue, 30 Aug 2011 12:50:15 +0000 (13:50 +0100)
takes a vhd and a raw image as input, writes a new vhd to stdout containing
the metadata from the original vhd and the data from the raw image

include/vhd-util.h
vhd/lib/Makefile.am
vhd/lib/vhd-util-dm-decrypt.c [new file with mode: 0644]
vhd/vhd-util.c

index b91e75e93c5e7e5c39030304551272c12f0bfbb6..8c42194a39d0299fa0db6be637c70c0b13820ea5 100644 (file)
@@ -47,5 +47,6 @@ int vhd_util_revert(int argc, char **argv);
 int vhd_util_stream_coalesce(int argc, char **argv);
 int vhd_util_clone_metadata(int argc, char **argv);
 int vhd_util_dm_encrypt(int argc, char **argv);
+int vhd_util_dm_decrypt(int argc, char **argv);
 
 #endif
index fb639737ea88d6efab61a2dec5f7bdfaa279b560..f8b29bc3b0e8ede9dd70ed50fb6e132435fe8063 100644 (file)
@@ -31,6 +31,7 @@ libvhd_la_SOURCES += vhd-util-check.c
 libvhd_la_SOURCES += vhd-util-clone-metadata.c
 libvhd_la_SOURCES += vhd-util-stream-coalesce.c
 libvhd_la_SOURCES += vhd-util-dm-encrypt.c
+libvhd_la_SOURCES += vhd-util-dm-decrypt.c
 libvhd_la_SOURCES += relative-path.c
 libvhd_la_SOURCES += relative-path.h
 libvhd_la_SOURCES += atomicio.c
diff --git a/vhd/lib/vhd-util-dm-decrypt.c b/vhd/lib/vhd-util-dm-decrypt.c
new file mode 100644 (file)
index 0000000..c69ff5b
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2010, Citrix Systems, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "libvhd.h"
+
+struct vhd_decrypt_progress {
+       char                          display;
+       uint32_t                      total;
+       uint32_t                      cur;
+};
+
+struct vhd_decrypt_context {
+       int                           src_raw;
+       vhd_context_t                *src_vhd;
+       vhd_context_t                *dst_vhd;
+       struct vhd_decrypt_progress   progress;
+};
+
+#define ERR(_fmt, _args...) fprintf(stderr, "%d: " _fmt, __LINE__, ##_args)
+
+#define VERR(_v, _fmt, _args...)                                       \
+       do {                                                            \
+               char uuid[37];                                          \
+               uuid_unparse((_v)->footer.uuid, uuid);                  \
+               ERR("%s: " _fmt, uuid, ##_args);                        \
+       } while (0)                                                     \
+
+#define PROGRESS(_ctx)                                                 \
+       do {                                                            \
+               if ((_ctx)->progress.display &&                         \
+                   (_ctx)->progress.total) {                           \
+                       float cur = (float)(_ctx)->progress.cur;        \
+                       float total = (float)(_ctx)->progress.total;    \
+                       float pct = (cur / total) * 100.0;              \
+                       fprintf(stderr, "\r%6.2f%%", pct);              \
+                       fflush(stderr);                                 \
+               }                                                       \
+       } while (0)
+
+static int
+vhd_util_pread_data(int fd, char *buf, size_t size, off64_t off)
+{
+       int err;
+       ssize_t ret;
+
+       err = 0;
+
+       if (lseek64(fd, off, SEEK_SET) == (off64_t)-1) {
+               err = -errno;
+               goto out;
+       }
+
+       while (size) {
+               ret = read(fd, buf, size);
+               if (ret == -1) {
+                       if (errno == EAGAIN)
+                               continue;
+                       err = -errno;
+                       goto out;
+               }
+
+               buf  += ret;
+               size -= ret;
+       }
+
+out:
+       return err;
+}
+
+static int
+vhd_util_stream_copy_block(struct vhd_decrypt_context *ctx, uint32_t blk)
+{
+       off64_t off;
+       char *bm, *data;
+       int err, i, empty;
+       vhd_context_t *src, *dst;
+
+       bm    = NULL;
+       data  = NULL;
+       src   = ctx->src_vhd;
+       dst   = ctx->dst_vhd;
+       empty = 1;
+
+       if (src->bat.bat[blk] == DD_BLK_UNUSED) {
+               if (dst->bat.bat[blk] == DD_BLK_UNUSED)
+                       err = 0;
+               else {
+                       err = -EIO;
+                       ERR("skipping allocated block 0x%x\n", blk);
+               }
+               goto out;
+       }
+
+       PROGRESS(ctx);
+
+       err = posix_memalign((void **)&data,
+                            VHD_SECTOR_SIZE, src->header.block_size);
+       if (err) {
+               err  = -err;
+               data = NULL;
+               ERR("allocating block 0x%x\n", blk);
+               goto out;
+       }
+
+       memset(data, 0, src->header.block_size);
+       off = ((uint64_t)blk * src->header.block_size) >> VHD_SECTOR_SHIFT;
+
+       err = vhd_read_bitmap(src, blk, &bm);
+       if (err) {
+               ERR("error reading source bitmap for "
+                   "block 0x%x: %d\n", blk, err);
+               goto out;
+       }
+
+       i = 0;
+       while (i < src->spb) {
+               char *buf;
+               off64_t pos;
+               int cnt, copy;
+
+               cnt  = 1;
+               pos  = off + i;
+               buf  = data + vhd_sectors_to_bytes(i);
+               copy = vhd_bitmap_test(src, bm, i);
+
+               while (i + cnt < src->spb &&
+                      copy == vhd_bitmap_test(src, bm, i + cnt))
+                       cnt++;
+
+               if (copy) {
+                       empty = 0;
+                       err = vhd_util_pread_data(ctx->src_raw, buf,
+                                                 vhd_sectors_to_bytes(cnt),
+                                                 vhd_sectors_to_bytes(pos));
+                       if (err) {
+                               ERR("reading dev block 0x%x: %d\n", blk, err);
+                               goto out;
+                       }
+               }
+
+               i += cnt;
+       }
+
+       if (!empty) {
+               err = vhd_write_bitmap(dst, blk, bm);
+               if (err) {
+                       ERR("writing bitmap 0x%x: %d\n", blk, err);
+                       goto out;
+               }
+
+               err = vhd_write_block(dst, blk, data);
+               if (err) {
+                       ERR("writing data 0x%x: %d\n", blk, err);
+                       goto out;
+               }
+       }
+
+out:
+       free(bm);
+       free(data);
+       return err;
+}
+
+static int
+__vhd_util_dm_decrypt(struct vhd_decrypt_context *ctx)
+{
+       char *buf;
+       uint32_t i;
+       int err, spp;
+       vhd_bat_t bat;
+       off64_t off, eoh;
+       vhd_context_t *src;
+       vhd_context_t *dst;
+
+       buf = NULL;
+       src = ctx->src_vhd;
+       dst = ctx->dst_vhd;
+       spp = getpagesize() >> VHD_SECTOR_SHIFT;
+
+       /*
+        * We copy all the source metadata unmodified,
+        * with the exception of the BAT, which must be sorted
+        * by physical block address to enable serial output to a fifo.
+        */
+       err = vhd_end_of_headers(src, &eoh);
+       if (err) {
+               ERR("finding end of source headers: %d\n", err);
+               goto out;
+       }
+
+       err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, eoh);
+       if (err) {
+               err = -err;
+               buf = NULL;
+               ERR("allocating metadata\n");
+               goto out;
+       }
+
+       err = vhd_pread(src, buf, eoh, 0);
+       if (err) {
+               ERR("reading vhd headers: %d\n", err);
+               goto out;
+       }
+
+       bat.spb     = src->bat.spb;
+       bat.entries = src->bat.entries;
+       bat.bat     = (uint32_t *)(buf + src->header.table_offset);
+
+       /*
+        * sort output BAT
+        */
+       memset(dst->bat.bat, DD_BLK_UNUSED,
+              dst->bat.entries * sizeof(uint32_t));
+       for (i = 0; i < src->bat.entries; i++) {
+               if (src->bat.bat[i] != DD_BLK_UNUSED) {
+                       int gap;
+       
+                       gap = 0;
+                       err = vhd_end_of_data(dst, &off);
+                       if (err) {
+                               ERR("finding end of data: %d\n", err);
+                               goto out;
+                       }
+
+                       off >>= VHD_SECTOR_SHIFT;
+
+                       /* data region of block should be page aligned */
+                       if ((off + dst->bm_secs) % spp) {
+                               gap  = (spp - ((off + dst->bm_secs) % spp));
+                               off += gap;
+                       }
+
+                       dst->bat.bat[i] = off;
+                       bat.bat[i] = off;
+
+                       if (ctx->progress.display)
+                               ctx->progress.total++;
+               }
+       }
+
+       vhd_bat_out(&bat);
+
+       err = vhd_pwrite(dst, buf, eoh, 0);
+       if (err) {
+               ERR("copying vhd headers\n");
+               goto out;
+       }
+
+       for (i = 0; i < src->bat.entries; i++) {
+               err = vhd_util_stream_copy_block(ctx, i);
+               if (err)
+                       goto out;
+       }
+
+       err = vhd_end_of_data(dst, &off);
+       if (err) {
+               ERR("finding end of data: %d\n", err);
+               goto out;
+       }
+
+       err = vhd_write_footer_at(dst, &dst->footer, off);
+       if (err) {
+               ERR("writing primary footer: %d\n", err);
+               goto out;
+       }
+
+       PROGRESS(ctx);
+
+out:
+       free(buf);
+       return err;
+}
+
+static int
+vhd_util_dm_decrypt_open_output(struct vhd_decrypt_context *ctx,
+                               const char *vhd_out)
+{
+       int err;
+       FILE *file;
+
+       if (!strcmp(vhd_out, "-")) {
+               file = stdout;
+       } else {
+               if (!access(vhd_out, F_OK)) {
+                       err = -EEXIST;
+                       ERR("%s already exists\n", vhd_out);
+                       goto out;
+               }
+
+               file = fopen(vhd_out, "w");
+               if (!file) {
+                       err = -errno;
+                       ERR("error opening %s: %d\n", vhd_out, err);
+                       goto out;
+               }
+       }
+
+       ctx->dst_vhd = vhd_stream_initialize(file, ctx->src_vhd);
+       if (!ctx->dst_vhd)
+               goto out;
+
+out:
+       return err;
+}
+
+int
+vhd_util_dm_decrypt(int argc, char **argv)
+{
+       int c, err;
+       vhd_context_t src;
+       struct vhd_decrypt_context ctx;
+       const char *raw_in, *vhd_in, *vhd_out;
+
+       err      = 0;
+       raw_in   = NULL;
+       vhd_in   = NULL;
+       vhd_out  = NULL;
+
+       memset(&src, 0, sizeof(src));
+       memset(&ctx, 0, sizeof(ctx));
+
+       ctx.src_raw = -1;
+
+       if (!argc || !argv)
+               goto usage;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "i:I:o:ph")) != -1) {
+               switch (c) {
+               case 'i':
+                       raw_in = optarg;
+                       break;
+               case 'I':
+                       vhd_in = optarg;
+                       break;
+               case 'o':
+                       vhd_out = optarg;
+                       break;
+               case 'p':
+                       ctx.progress.display = 1;
+                       break;
+               case 'h':
+               default:
+                       goto usage;
+               }
+       }
+
+       if (optind != argc)
+               goto usage;
+
+       if (!raw_in || !vhd_in || !vhd_out)
+               goto usage;
+
+       ctx.src_raw = open(raw_in, O_RDONLY | O_LARGEFILE | O_DIRECT);
+       if (ctx.src_raw == -1) {
+               err = -errno;
+               fprintf(stderr, "error opening %s: %d\n", raw_in, err);
+               goto out;
+       }
+
+       err = vhd_open(&src, vhd_in, VHD_OPEN_RDONLY);
+       if (err) {
+               fprintf(stderr, "error opening %s: %d\n", vhd_in, err);
+               goto out;
+       }
+
+       ctx.src_vhd = &src;
+
+       err = vhd_util_dm_decrypt_open_output(&ctx, vhd_out);
+       if (err)
+               goto out;
+
+       err = __vhd_util_dm_decrypt(&ctx);
+       if (err)
+               goto out;
+
+out:
+       vhd_close(&src);
+       if (ctx.src_raw != -1)
+               close(ctx.src_raw);
+       if (ctx.dst_vhd)
+               vhd_close(ctx.dst_vhd);
+
+       if (err && vhd_out && strcmp(vhd_out, "-"))
+               unlink(vhd_out);
+
+       return err;
+
+usage:
+       printf("vhd-util dm-decrypt reads the allocated data of a given vhd "
+              "dm target and writes it to a new vhd.\n"
+              "Options:\n"
+              "-h          Print this help message.\n"
+              "-p          Display progress.\n"
+              "-o NAME     NAME of output VHD to create ('-' for stdout).\n"
+              "-i NAME     NAME of input device to read.\n"
+              "-I NAME     NAME of input vhd to read.\n");
+       return EINVAL;
+}
index d5cda4de863fd262d28a7a4f26d5425b8c40efcc..7f01c4e6ff19d9e3e5381b62f2c67768d7375467 100644 (file)
@@ -64,6 +64,7 @@ struct command commands[] = {
        { .name = "check",       .func = vhd_util_check         },
        { .name = "revert",      .func = vhd_util_revert        },
        { .name = "dm-encrypt",  .func = vhd_util_dm_encrypt    },
+       { .name = "dm-decrypt",  .func = vhd_util_dm_decrypt    },
        { .name = "clone-metadata", .func = vhd_util_clone_metadata },
        { .name = "stream-coalesce", .func = vhd_util_stream_coalesce },
 };