Daniel P. Berrange e3a592
From 953440bd12608a20007ee5da5ab69fbbe910bd28 Mon Sep 17 00:00:00 2001
Daniel P. Berrange e3a592
From: Daniel P. Berrange <berrange@redhat.com>
Daniel P. Berrange e3a592
Date: Mon, 14 Jun 2010 15:53:59 +0100
Daniel P. Berrange e3a592
Subject: [PATCH 01/11] Extract the backing store format as well as name, if available
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
When QEMU opens a backing store for a QCow2 file, it will
Daniel P. Berrange e3a592
normally auto-probe for the format of the backing store,
Daniel P. Berrange e3a592
rather than assuming it has the same format as the referencing
Daniel P. Berrange e3a592
file. There is a QCow2 extension that allows an explicit format
Daniel P. Berrange e3a592
for the backing store to be embedded in the referencing file.
Daniel P. Berrange e3a592
This closes the auto-probing security hole in QEMU.
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
This backing store format can be useful for libvirt users
Daniel P. Berrange e3a592
of virStorageFileGetMetadata, so extract this data and report
Daniel P. Berrange e3a592
it.
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
QEMU does not require disk image backing store files to be in
Daniel P. Berrange e3a592
the same format the file linkee. It will auto-probe the disk
Daniel P. Berrange e3a592
format for the backing store when opening it. If the backing
Daniel P. Berrange e3a592
store was intended to be a raw file this could be a security
Daniel P. Berrange e3a592
hole, because a guest may have written data into its disk that
Daniel P. Berrange e3a592
then makes the backing store look like a qcow2 file. If it can
Daniel P. Berrange e3a592
trick QEMU into thinking the raw file is a qcow2 file, it can
Daniel P. Berrange e3a592
access arbitrary files on the host by adding further backing
Daniel P. Berrange e3a592
store links.
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
To address this, callers of virStorageFileGetMeta need to be
Daniel P. Berrange e3a592
told of the backing store format. If no format is declared,
Daniel P. Berrange e3a592
they can make a decision whether to allow format probing or
Daniel P. Berrange e3a592
not.
Daniel P. Berrange e3a592
---
Daniel P. Berrange e3a592
 src/util/storage_file.c |  206 +++++++++++++++++++++++++++++++++++++++++------
Daniel P. Berrange e3a592
 src/util/storage_file.h |    2 +
Daniel P. Berrange e3a592
 2 files changed, 183 insertions(+), 25 deletions(-)
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
Daniel P. Berrange e3a592
index 0adea40..80f743e 100644
Daniel P. Berrange e3a592
--- a/src/util/storage_file.c
Daniel P. Berrange e3a592
+++ b/src/util/storage_file.c
Daniel P. Berrange e3a592
@@ -78,12 +78,33 @@ struct FileTypeInfo {
Daniel P. Berrange e3a592
     int qcowCryptOffset;  /* Byte offset from start of file
Daniel P. Berrange e3a592
                            * where to find encryption mode,
Daniel P. Berrange e3a592
                            * -1 if encryption is not used */
Daniel P. Berrange e3a592
-    int (*getBackingStore)(char **res, const unsigned char *buf, size_t buf_size);
Daniel P. Berrange e3a592
+    int (*getBackingStore)(char **res, int *format,
Daniel P. Berrange e3a592
+                           const unsigned char *buf, size_t buf_size);
Daniel P. Berrange e3a592
 };
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-static int cowGetBackingStore(char **, const unsigned char *, size_t);
Daniel P. Berrange e3a592
-static int qcowXGetBackingStore(char **, const unsigned char *, size_t);
Daniel P. Berrange e3a592
-static int vmdk4GetBackingStore(char **, const unsigned char *, size_t);
Daniel P. Berrange e3a592
+static int cowGetBackingStore(char **, int *,
Daniel P. Berrange e3a592
+                              const unsigned char *, size_t);
Daniel P. Berrange e3a592
+static int qcow1GetBackingStore(char **, int *,
Daniel P. Berrange e3a592
+                                const unsigned char *, size_t);
Daniel P. Berrange e3a592
+static int qcow2GetBackingStore(char **, int *,
Daniel P. Berrange e3a592
+                                const unsigned char *, size_t);
Daniel P. Berrange e3a592
+static int vmdk4GetBackingStore(char **, int *,
Daniel P. Berrange e3a592
+                                const unsigned char *, size_t);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+#define QCOWX_HDR_VERSION (4)
Daniel P. Berrange e3a592
+#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4)
Daniel P. Berrange e3a592
+#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8)
Daniel P. Berrange e3a592
+#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4)
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1)
Daniel P. Berrange e3a592
+#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8)
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8)
Daniel P. Berrange e3a592
+#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8)
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+#define QCOW2_HDR_EXTENSION_END 0
Daniel P. Berrange e3a592
+#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 static struct FileTypeInfo const fileTypeInfo[] = {
Daniel P. Berrange e3a592
@@ -119,11 +140,11 @@ static struct FileTypeInfo const fileTypeInfo[] = {
Daniel P. Berrange e3a592
     /* QCow */
Daniel P. Berrange e3a592
     { VIR_STORAGE_FILE_QCOW, "QFI", NULL,
Daniel P. Berrange e3a592
       LV_BIG_ENDIAN, 4, 1,
Daniel P. Berrange e3a592
-      4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore },
Daniel P. Berrange e3a592
+      QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore },
Daniel P. Berrange e3a592
     /* QCow 2 */
Daniel P. Berrange e3a592
     { VIR_STORAGE_FILE_QCOW2, "QFI", NULL,
Daniel P. Berrange e3a592
       LV_BIG_ENDIAN, 4, 2,
Daniel P. Berrange e3a592
-      4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore },
Daniel P. Berrange e3a592
+      QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore },
Daniel P. Berrange e3a592
     /* VMDK 3 */
Daniel P. Berrange e3a592
     /* XXX Untested
Daniel P. Berrange e3a592
     { VIR_STORAGE_FILE_VMDK, "COWD", NULL,
Daniel P. Berrange e3a592
@@ -142,11 +163,14 @@ static struct FileTypeInfo const fileTypeInfo[] = {
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 static int
Daniel P. Berrange e3a592
 cowGetBackingStore(char **res,
Daniel P. Berrange e3a592
+                   int *format,
Daniel P. Berrange e3a592
                    const unsigned char *buf,
Daniel P. Berrange e3a592
                    size_t buf_size)
Daniel P. Berrange e3a592
 {
Daniel P. Berrange e3a592
 #define COW_FILENAME_MAXLEN 1024
Daniel P. Berrange e3a592
     *res = NULL;
Daniel P. Berrange e3a592
+    *format = VIR_STORAGE_FILE_AUTO;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
     if (buf_size < 4+4+ COW_FILENAME_MAXLEN)
Daniel P. Berrange e3a592
         return BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
     if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */
Daniel P. Berrange e3a592
@@ -160,31 +184,98 @@ cowGetBackingStore(char **res,
Daniel P. Berrange e3a592
     return BACKING_STORE_OK;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static int
Daniel P. Berrange e3a592
+qcow2GetBackingStoreFormat(int *format,
Daniel P. Berrange e3a592
+                           const unsigned char *buf,
Daniel P. Berrange e3a592
+                           size_t buf_size,
Daniel P. Berrange e3a592
+                           size_t extension_start,
Daniel P. Berrange e3a592
+                           size_t extension_end)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    size_t offset = extension_start;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    /*
Daniel P. Berrange e3a592
+     * The extensions take format of
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * int32: magic
Daniel P. Berrange e3a592
+     * int32: length
Daniel P. Berrange e3a592
+     * byte[length]: payload
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * Unknown extensions can be ignored by skipping
Daniel P. Berrange e3a592
+     * over "length" bytes in the data stream.
Daniel P. Berrange e3a592
+     */
Daniel P. Berrange e3a592
+    while (offset < (buf_size-8) &&
Daniel P. Berrange e3a592
+           offset < (extension_end-8)) {
Daniel P. Berrange e3a592
+        unsigned int magic =
Daniel P. Berrange e3a592
+            (buf[offset] << 24) +
Daniel P. Berrange e3a592
+            (buf[offset+1] << 16) +
Daniel P. Berrange e3a592
+            (buf[offset+2] << 8) +
Daniel P. Berrange e3a592
+            (buf[offset+3]);
Daniel P. Berrange e3a592
+        unsigned int len =
Daniel P. Berrange e3a592
+            (buf[offset+4] << 24) +
Daniel P. Berrange e3a592
+            (buf[offset+5] << 16) +
Daniel P. Berrange e3a592
+            (buf[offset+6] << 8) +
Daniel P. Berrange e3a592
+            (buf[offset+7]);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        offset += 8;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        if ((offset + len) < offset)
Daniel P. Berrange e3a592
+            break;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        if ((offset + len) > buf_size)
Daniel P. Berrange e3a592
+            break;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        switch (magic) {
Daniel P. Berrange e3a592
+        case QCOW2_HDR_EXTENSION_END:
Daniel P. Berrange e3a592
+            goto done;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        case QCOW2_HDR_EXTENSION_BACKING_FORMAT:
Daniel P. Berrange e3a592
+            if (buf[offset+len] != '\0')
Daniel P. Berrange e3a592
+                break;
Daniel P. Berrange e3a592
+            *format = virStorageFileFormatTypeFromString(
Daniel P. Berrange e3a592
+                ((const char *)buf)+offset);
Daniel P. Berrange e3a592
+            break;
Daniel P. Berrange e3a592
+        }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        offset += len;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+done:
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    return 0;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
 static int
Daniel P. Berrange e3a592
 qcowXGetBackingStore(char **res,
Daniel P. Berrange e3a592
+                     int *format,
Daniel P. Berrange e3a592
                      const unsigned char *buf,
Daniel P. Berrange e3a592
-                     size_t buf_size)
Daniel P. Berrange e3a592
+                     size_t buf_size,
Daniel P. Berrange e3a592
+                     bool isQCow2)
Daniel P. Berrange e3a592
 {
Daniel P. Berrange e3a592
     unsigned long long offset;
Daniel P. Berrange e3a592
     unsigned long size;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     *res = NULL;
Daniel P. Berrange e3a592
-    if (buf_size < 4+4+8+4)
Daniel P. Berrange e3a592
+    if (format)
Daniel P. Berrange e3a592
+        *format = VIR_STORAGE_FILE_AUTO;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4)
Daniel P. Berrange e3a592
         return BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
-    offset = (((unsigned long long)buf[4+4] << 56)
Daniel P. Berrange e3a592
-              | ((unsigned long long)buf[4+4+1] << 48)
Daniel P. Berrange e3a592
-              | ((unsigned long long)buf[4+4+2] << 40)
Daniel P. Berrange e3a592
-              | ((unsigned long long)buf[4+4+3] << 32)
Daniel P. Berrange e3a592
-              | ((unsigned long long)buf[4+4+4] << 24)
Daniel P. Berrange e3a592
-              | ((unsigned long long)buf[4+4+5] << 16)
Daniel P. Berrange e3a592
-              | ((unsigned long long)buf[4+4+6] << 8)
Daniel P. Berrange e3a592
-              | buf[4+4+7]); /* QCowHeader.backing_file_offset */
Daniel P. Berrange e3a592
+    offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56)
Daniel P. Berrange e3a592
+              | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48)
Daniel P. Berrange e3a592
+              | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40)
Daniel P. Berrange e3a592
+              | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32)
Daniel P. Berrange e3a592
+              | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24)
Daniel P. Berrange e3a592
+              | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16)
Daniel P. Berrange e3a592
+              | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8)
Daniel P. Berrange e3a592
+              | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */
Daniel P. Berrange e3a592
     if (offset > buf_size)
Daniel P. Berrange e3a592
         return BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
-    size = ((buf[4+4+8] << 24)
Daniel P. Berrange e3a592
-            | (buf[4+4+8+1] << 16)
Daniel P. Berrange e3a592
-            | (buf[4+4+8+2] << 8)
Daniel P. Berrange e3a592
-            | buf[4+4+8+3]); /* QCowHeader.backing_file_size */
Daniel P. Berrange e3a592
+    size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24)
Daniel P. Berrange e3a592
+            | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16)
Daniel P. Berrange e3a592
+            | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8)
Daniel P. Berrange e3a592
+            | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */
Daniel P. Berrange e3a592
     if (size == 0)
Daniel P. Berrange e3a592
         return BACKING_STORE_OK;
Daniel P. Berrange e3a592
     if (offset + size > buf_size || offset + size < offset)
Daniel P. Berrange e3a592
@@ -197,12 +288,63 @@ qcowXGetBackingStore(char **res,
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
     memcpy(*res, buf + offset, size);
Daniel P. Berrange e3a592
     (*res)[size] = '\0';
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    /*
Daniel P. Berrange e3a592
+     * Traditionally QCow2 files had a layout of
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * [header]
Daniel P. Berrange e3a592
+     * [backingStoreName]
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * Although the backingStoreName typically followed
Daniel P. Berrange e3a592
+     * the header immediately, this was not required by
Daniel P. Berrange e3a592
+     * the format. By specifying a higher byte offset for
Daniel P. Berrange e3a592
+     * the backing file offset in the header, it was
Daniel P. Berrange e3a592
+     * possible to leave space between the header and
Daniel P. Berrange e3a592
+     * start of backingStore.
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * This hack is now used to store extensions to the
Daniel P. Berrange e3a592
+     * qcow2 format:
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * [header]
Daniel P. Berrange e3a592
+     * [extensions]
Daniel P. Berrange e3a592
+     * [backingStoreName]
Daniel P. Berrange e3a592
+     *
Daniel P. Berrange e3a592
+     * Thus the file region to search for extensions is
Daniel P. Berrange e3a592
+     * between the end of the header (QCOW2_HDR_TOTAL_SIZE)
Daniel P. Berrange e3a592
+     * and the start of the backingStoreName (offset)
Daniel P. Berrange e3a592
+     */
Daniel P. Berrange e3a592
+    if (isQCow2)
Daniel P. Berrange e3a592
+        qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, offset);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
     return BACKING_STORE_OK;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 static int
Daniel P. Berrange e3a592
+qcow1GetBackingStore(char **res,
Daniel P. Berrange e3a592
+                     int *format,
Daniel P. Berrange e3a592
+                     const unsigned char *buf,
Daniel P. Berrange e3a592
+                     size_t buf_size)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    /* QCow1 doesn't have the extensions capability
Daniel P. Berrange e3a592
+     * used to store backing format */
Daniel P. Berrange e3a592
+    *format = VIR_STORAGE_FILE_AUTO;
Daniel P. Berrange e3a592
+    return qcowXGetBackingStore(res, NULL, buf, buf_size, false);
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static int
Daniel P. Berrange e3a592
+qcow2GetBackingStore(char **res,
Daniel P. Berrange e3a592
+                     int *format,
Daniel P. Berrange e3a592
+                     const unsigned char *buf,
Daniel P. Berrange e3a592
+                     size_t buf_size)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    return qcowXGetBackingStore(res, format, buf, buf_size, true);
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static int
Daniel P. Berrange e3a592
 vmdk4GetBackingStore(char **res,
Daniel P. Berrange e3a592
+                     int *format,
Daniel P. Berrange e3a592
                      const unsigned char *buf,
Daniel P. Berrange e3a592
                      size_t buf_size)
Daniel P. Berrange e3a592
 {
Daniel P. Berrange e3a592
@@ -212,6 +354,14 @@ vmdk4GetBackingStore(char **res,
Daniel P. Berrange e3a592
     size_t len;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     *res = NULL;
Daniel P. Berrange e3a592
+    /*
Daniel P. Berrange e3a592
+     * Technically this should have been VMDK, since
Daniel P. Berrange e3a592
+     * VMDK spec / VMWare impl only support VMDK backed
Daniel P. Berrange e3a592
+     * by VMDK. QEMU isn't following this though and
Daniel P. Berrange e3a592
+     * does probing on VMDK backing files, hence we set
Daniel P. Berrange e3a592
+     * AUTO
Daniel P. Berrange e3a592
+     */
Daniel P. Berrange e3a592
+    *format = VIR_STORAGE_FILE_AUTO;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     if (buf_size <= 0x200)
Daniel P. Berrange e3a592
         return BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
@@ -358,9 +508,12 @@ virStorageFileGetMetadataFromFD(const char *path,
Daniel P. Berrange e3a592
         /* Validation passed, we know the file format now */
Daniel P. Berrange e3a592
         meta->format = fileTypeInfo[i].type;
Daniel P. Berrange e3a592
         if (fileTypeInfo[i].getBackingStore != NULL) {
Daniel P. Berrange e3a592
-            char *base;
Daniel P. Berrange e3a592
+            char *backing;
Daniel P. Berrange e3a592
+            int backingFormat;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-            switch (fileTypeInfo[i].getBackingStore(&base, head, len)) {
Daniel P. Berrange e3a592
+            switch (fileTypeInfo[i].getBackingStore(&backing,
Daniel P. Berrange e3a592
+                                                    &backingFormat,
Daniel P. Berrange e3a592
+                                                    head, len)) {
Daniel P. Berrange e3a592
             case BACKING_STORE_OK:
Daniel P. Berrange e3a592
                 break;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
@@ -370,13 +523,16 @@ virStorageFileGetMetadataFromFD(const char *path,
Daniel P. Berrange e3a592
             case BACKING_STORE_ERROR:
Daniel P. Berrange e3a592
                 return -1;
Daniel P. Berrange e3a592
             }
Daniel P. Berrange e3a592
-            if (base != NULL) {
Daniel P. Berrange e3a592
-                meta->backingStore = absolutePathFromBaseFile(path, base);
Daniel P. Berrange e3a592
-                VIR_FREE(base);
Daniel P. Berrange e3a592
+            if (backing != NULL) {
Daniel P. Berrange e3a592
+                meta->backingStore = absolutePathFromBaseFile(path, backing);
Daniel P. Berrange e3a592
+                VIR_FREE(backing);
Daniel P. Berrange e3a592
                 if (meta->backingStore == NULL) {
Daniel P. Berrange e3a592
                     virReportOOMError();
Daniel P. Berrange e3a592
                     return -1;
Daniel P. Berrange e3a592
                 }
Daniel P. Berrange e3a592
+                meta->backingStoreFormat = backingFormat;
Daniel P. Berrange e3a592
+            } else {
Daniel P. Berrange e3a592
+                meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
Daniel P. Berrange e3a592
             }
Daniel P. Berrange e3a592
         }
Daniel P. Berrange e3a592
         return 0;
Daniel P. Berrange e3a592
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
Daniel P. Berrange e3a592
index 58533ee..6328ba7 100644
Daniel P. Berrange e3a592
--- a/src/util/storage_file.h
Daniel P. Berrange e3a592
+++ b/src/util/storage_file.h
Daniel P. Berrange e3a592
@@ -28,6 +28,7 @@
Daniel P. Berrange e3a592
 # include <stdbool.h>
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 enum virStorageFileFormat {
Daniel P. Berrange e3a592
+    VIR_STORAGE_FILE_AUTO = -1,
Daniel P. Berrange e3a592
     VIR_STORAGE_FILE_RAW = 0,
Daniel P. Berrange e3a592
     VIR_STORAGE_FILE_DIR,
Daniel P. Berrange e3a592
     VIR_STORAGE_FILE_BOCHS,
Daniel P. Berrange e3a592
@@ -47,6 +48,7 @@ VIR_ENUM_DECL(virStorageFileFormat);
Daniel P. Berrange e3a592
 typedef struct _virStorageFileMetadata {
Daniel P. Berrange e3a592
     int format;
Daniel P. Berrange e3a592
     char *backingStore;
Daniel P. Berrange e3a592
+    int backingStoreFormat;
Daniel P. Berrange e3a592
     unsigned long long capacity;
Daniel P. Berrange e3a592
     bool encrypted;
Daniel P. Berrange e3a592
 } virStorageFileMetadata;
Daniel P. Berrange e3a592
-- 
Daniel P. Berrange e3a592
1.7.1.1
Daniel P. Berrange e3a592