Mark McLoughlin f9c1b7
From 5bb2da190bc6d5a36952315dd48a00709f88c3c2 Mon Sep 17 00:00:00 2001
Mark McLoughlin f9c1b7
From: Mark McLoughlin <markmc@redhat.com>
Mark McLoughlin f9c1b7
Date: Fri, 25 Sep 2009 14:20:13 +0100
Mark McLoughlin f9c1b7
Subject: [PATCH] Re-label image file backing stores
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
Use virStorageFileGetMetadata() to find any backing stores for images
Mark McLoughlin f9c1b7
and re-label them
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
Without this, qemu cannot access qcow2 backing files, see:
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  https://bugzilla.redhat.com/497131
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
* src/security/security_selinux.c: re-label backing store files in
Mark McLoughlin f9c1b7
  SELinuxSetSecurityImageLabel()
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
(cherry picked from commit fe627697a3830cd2db0efcc201d8caa9e171263d)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
Includes the following commits:
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  util.h needs libvirt.h for virConnectPtr
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Seems standard to include internal.h in order to pull in libvirt.h
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/util/util.h: include internal.h
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  (cherry picked from commit 25e2857c219e7fb91412746f7919931552c4e07a)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Move file format enum to libvirt_util
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Rename virStorageVolFormatFileSystem to virStorageFileFormat and
Mark McLoughlin f9c1b7
  move to src/util/storage_file.[ch]
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/Makefile.am: add src/util/storage_file.[ch]
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/conf/storage_conf.[ch]: move enum from here ...
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/util/storage_file.[ch]: .. to here
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/libvirt_private.syms: update To/FromString exports
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/storage/storage_backend.c, src/storage/storage_backend_fs.c,
Mark McLoughlin f9c1b7
    src/vbox/vbox_tmpl.c: update for above changes
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  (cherry picked from commit 00fd3ff49bb1e4578756a32a812fdbf5ee335d8c)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Split virStorageGetMetadataFromFD() from virStorageBackendProbeTarget()
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Prepare the code probing a file's format and associated metadata for
Mark McLoughlin f9c1b7
  moving into libvirt_util.
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/storage/storage_backend_fs.c: re-factor the format and metadata
Mark McLoughlin f9c1b7
    probing code in preparation for moving it
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  (cherry picked from commit f5fc670638d94776a4eba55f5affa69f69ba1ae2)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Introduce virStorageFileMetadata structure
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Introduce a metadata structure and make virStorageGetMetadataFromFD()
Mark McLoughlin f9c1b7
  fill it in.
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/util/storage_file.h: add virStorageFileMetadata
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/backend/storage_backend_fs.c: virStorageGetMetadataFromFD() now
Mark McLoughlin f9c1b7
    fills in the virStorageFileMetadata structure
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  (cherry picked from commit 5fede0a90be565e1c44b7c8236cb8910fd06b52f)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Move virStorageGetMetadataFromFD() to libvirt_util
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Finally, we get to the point of all this.
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Move virStorageGetMetadataFromFD() to virStorageFileGetMetadataFromFD()
Mark McLoughlin f9c1b7
  and move to src/util/storage_file.[ch]
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  There's no functional changes in this patch, just code movement
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/storage/storage_backend_fs.c: move code from here ...
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/util/storage_file.[ch]: ... to here
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/libvirt_private.syms: export virStorageFileGetMetadataFromFD()
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  (cherry picked from commit a010fb58d6bce026852d611e32302da7687639e5)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  Add virStorageFileGetMetadata() helper
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  * src/util/storage_file.c: add virStorageFileGetMetadata() so that
Mark McLoughlin f9c1b7
    the caller does not need to open the file
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
  (cherry picked from commit 295fd6e8330c7416e2d97634364f2890133c28fa)
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
Fedora-patch: libvirt-svirt-relabel-qcow2-backing-files.patch
Mark McLoughlin f9c1b7
---
Mark McLoughlin f9c1b7
 src/Makefile.am          |    1 +
Mark McLoughlin f9c1b7
 src/libvirt_private.syms |    7 +-
Mark McLoughlin f9c1b7
 src/security_selinux.c   |   28 +++
Mark McLoughlin f9c1b7
 src/storage_backend.c    |   17 +-
Mark McLoughlin f9c1b7
 src/storage_backend_fs.c |  418 +++++----------------------------------------
Mark McLoughlin f9c1b7
 src/storage_conf.c       |   25 +--
Mark McLoughlin f9c1b7
 src/storage_conf.h       |   17 --
Mark McLoughlin f9c1b7
 src/storage_file.c       |  424 ++++++++++++++++++++++++++++++++++++++++++++++
Mark McLoughlin f9c1b7
 src/storage_file.h       |   62 +++++++
Mark McLoughlin f9c1b7
 src/util.h               |    1 +
Mark McLoughlin f9c1b7
 src/vbox/vbox_tmpl.c     |   15 +-
Mark McLoughlin f9c1b7
 11 files changed, 591 insertions(+), 424 deletions(-)
Mark McLoughlin f9c1b7
 create mode 100644 src/storage_file.c
Mark McLoughlin f9c1b7
 create mode 100644 src/storage_file.h
Mark McLoughlin f9c1b7
Mark McLoughlin f9c1b7
diff --git a/src/Makefile.am b/src/Makefile.am
Mark McLoughlin f9c1b7
index 463252e..3d279f2 100644
Mark McLoughlin f9c1b7
--- a/src/Makefile.am
Mark McLoughlin f9c1b7
+++ b/src/Makefile.am
Mark McLoughlin f9c1b7
@@ -54,6 +54,7 @@ UTIL_SOURCES =							\
Mark McLoughlin f9c1b7
 		hostusb.c hostusb.h				\
Mark McLoughlin f9c1b7
 		qparams.c qparams.h				\
Mark McLoughlin f9c1b7
 		storage_encryption_conf.h storage_encryption_conf.c	\
Mark McLoughlin f9c1b7
+		storage_file.c storage_file.h			\
Mark McLoughlin f9c1b7
 		threads.c threads.h				\
Mark McLoughlin f9c1b7
 		threads-pthread.h				\
Mark McLoughlin f9c1b7
 		threads-win32.h					\
Mark McLoughlin f9c1b7
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
Mark McLoughlin f9c1b7
index 867678f..500c209 100644
Mark McLoughlin f9c1b7
--- a/src/libvirt_private.syms
Mark McLoughlin f9c1b7
+++ b/src/libvirt_private.syms
Mark McLoughlin f9c1b7
@@ -359,8 +359,6 @@ virStorageVolDefParseNode;
Mark McLoughlin f9c1b7
 virStoragePoolFormatDiskTypeToString;
Mark McLoughlin f9c1b7
 virStoragePoolFormatFileSystemTypeToString;
Mark McLoughlin f9c1b7
 virStoragePoolFormatFileSystemNetTypeToString;
Mark McLoughlin f9c1b7
-virStorageVolFormatFileSystemTypeToString;
Mark McLoughlin f9c1b7
-virStorageVolFormatFileSystemTypeFromString;
Mark McLoughlin f9c1b7
 virStoragePoolTypeFromString;
Mark McLoughlin f9c1b7
 virStoragePartedFsTypeTypeToString;
Mark McLoughlin f9c1b7
 virStoragePoolObjLock;
Mark McLoughlin f9c1b7
@@ -373,6 +371,11 @@ virStorageEncryptionParseNode;
Mark McLoughlin f9c1b7
 virStorageEncryptionFormat;
Mark McLoughlin f9c1b7
 virStorageGenerateQcowPassphrase;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
+# storage_file.h
Mark McLoughlin f9c1b7
+virStorageFileFormatTypeToString;
Mark McLoughlin f9c1b7
+virStorageFileFormatTypeFromString;
Mark McLoughlin f9c1b7
+virStorageFileGetMetadata;
Mark McLoughlin f9c1b7
+virStorageFileGetMetadataFromFD;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
 # threads.h
Mark McLoughlin f9c1b7
 virMutexInit;
Mark McLoughlin f9c1b7
diff --git a/src/security_selinux.c b/src/security_selinux.c
Mark McLoughlin f9c1b7
index b4dc153..600fc75 100644
Mark McLoughlin f9c1b7
--- a/src/security_selinux.c
Mark McLoughlin f9c1b7
+++ b/src/security_selinux.c
Mark McLoughlin f9c1b7
@@ -27,6 +27,7 @@
Mark McLoughlin f9c1b7
 #include "logging.h"
Mark McLoughlin f9c1b7
 #include "pci.h"
Mark McLoughlin f9c1b7
 #include "hostusb.h"
Mark McLoughlin f9c1b7
+#include "storage_file.h"
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
 #define VIR_FROM_THIS VIR_FROM_SECURITY
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
@@ -403,10 +404,37 @@ SELinuxSetSecurityImageLabel(virConnectPtr conn,
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
 {
Mark McLoughlin f9c1b7
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
Mark McLoughlin f9c1b7
+    const char *path;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
     if (!disk->src)
Mark McLoughlin f9c1b7
         return 0;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
+    path = disk->src;
Mark McLoughlin f9c1b7
+    do {
Mark McLoughlin f9c1b7
+        virStorageFileMetadata meta;
Mark McLoughlin f9c1b7
+        int ret;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        memset(&meta, 0, sizeof(meta));
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        ret = virStorageFileGetMetadata(conn, path, &meta);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        if (path != disk->src)
Mark McLoughlin f9c1b7
+            VIR_FREE(path);
Mark McLoughlin f9c1b7
+        path = NULL;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        if (ret < 0)
Mark McLoughlin f9c1b7
+            return -1;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        if (meta.backingStore != NULL &&
Mark McLoughlin f9c1b7
+            SELinuxSetFilecon(conn, meta.backingStore,
Mark McLoughlin f9c1b7
+                              default_content_context) < 0) {
Mark McLoughlin f9c1b7
+            VIR_FREE(meta.backingStore);
Mark McLoughlin f9c1b7
+            return -1;
Mark McLoughlin f9c1b7
+        }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        path = meta.backingStore;
Mark McLoughlin f9c1b7
+    } while (path != NULL);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
     if (disk->shared) {
Mark McLoughlin f9c1b7
         return SELinuxSetFilecon(conn, disk->src, default_image_context);
Mark McLoughlin f9c1b7
     } else if (disk->readonly) {
Mark McLoughlin f9c1b7
diff --git a/src/storage_backend.c b/src/storage_backend.c
Mark McLoughlin f9c1b7
index 800d4ea..1b65c5d 100644
Mark McLoughlin f9c1b7
--- a/src/storage_backend.c
Mark McLoughlin f9c1b7
+++ b/src/storage_backend.c
Mark McLoughlin f9c1b7
@@ -51,6 +51,7 @@
Mark McLoughlin f9c1b7
 #include "internal.h"
Mark McLoughlin f9c1b7
 #include "secret_conf.h"
Mark McLoughlin f9c1b7
 #include "uuid.h"
Mark McLoughlin f9c1b7
+#include "storage_file.h"
Mark McLoughlin f9c1b7
 #include "storage_backend.h"
Mark McLoughlin f9c1b7
 #include "logging.h"
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
@@ -462,16 +463,16 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
Mark McLoughlin f9c1b7
     char *create_tool;
Mark McLoughlin f9c1b7
     short use_kvmimg;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-    const char *type = virStorageVolFormatFileSystemTypeToString(vol->target.format);
Mark McLoughlin f9c1b7
+    const char *type = virStorageFileFormatTypeToString(vol->target.format);
Mark McLoughlin f9c1b7
     const char *backingType = vol->backingStore.path ?
Mark McLoughlin f9c1b7
-        virStorageVolFormatFileSystemTypeToString(vol->backingStore.format) : NULL;
Mark McLoughlin f9c1b7
+        virStorageFileFormatTypeToString(vol->backingStore.format) : NULL;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
     const char *inputBackingPath = (inputvol ? inputvol->backingStore.path
Mark McLoughlin f9c1b7
                                              : NULL);
Mark McLoughlin f9c1b7
     const char *inputPath = inputvol ? inputvol->target.path : NULL;
Mark McLoughlin f9c1b7
     /* Treat input block devices as 'raw' format */
Mark McLoughlin f9c1b7
     const char *inputType = inputPath ?
Mark McLoughlin f9c1b7
-                            virStorageVolFormatFileSystemTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_VOL_FILE_RAW : inputvol->target.format) :
Mark McLoughlin f9c1b7
+                            virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) :
Mark McLoughlin f9c1b7
                             NULL;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
     const char **imgargv;
Mark McLoughlin f9c1b7
@@ -552,8 +553,8 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
Mark McLoughlin f9c1b7
     if (vol->target.encryption != NULL) {
Mark McLoughlin f9c1b7
         virStorageEncryptionPtr enc;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-        if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW &&
Mark McLoughlin f9c1b7
-            vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) {
Mark McLoughlin f9c1b7
+        if (vol->target.format != VIR_STORAGE_FILE_QCOW &&
Mark McLoughlin f9c1b7
+            vol->target.format != VIR_STORAGE_FILE_QCOW2) {
Mark McLoughlin f9c1b7
             virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
Mark McLoughlin f9c1b7
                                   _("qcow volume encryption unsupported with "
Mark McLoughlin f9c1b7
                                     "volume format %s"), type);
Mark McLoughlin f9c1b7
@@ -644,7 +645,7 @@ virStorageBackendCreateQcowCreate(virConnectPtr conn,
Mark McLoughlin f9c1b7
         return -1;
Mark McLoughlin f9c1b7
     }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-    if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) {
Mark McLoughlin f9c1b7
+    if (vol->target.format != VIR_STORAGE_FILE_QCOW2) {
Mark McLoughlin f9c1b7
         virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
Mark McLoughlin f9c1b7
                               _("unsupported storage vol type %d"),
Mark McLoughlin f9c1b7
                               vol->target.format);
Mark McLoughlin f9c1b7
@@ -735,9 +736,9 @@ virStorageBackendGetBuildVolFromFunction(virConnectPtr conn,
Mark McLoughlin f9c1b7
      * tool for converting
Mark McLoughlin f9c1b7
      */
Mark McLoughlin f9c1b7
     if ((vol->type == VIR_STORAGE_VOL_FILE &&
Mark McLoughlin f9c1b7
-         vol->target.format != VIR_STORAGE_VOL_FILE_RAW) ||
Mark McLoughlin f9c1b7
+         vol->target.format != VIR_STORAGE_FILE_RAW) ||
Mark McLoughlin f9c1b7
         (inputvol->type == VIR_STORAGE_VOL_FILE &&
Mark McLoughlin f9c1b7
-         inputvol->target.format != VIR_STORAGE_VOL_FILE_RAW)) {
Mark McLoughlin f9c1b7
+         inputvol->target.format != VIR_STORAGE_FILE_RAW)) {
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
         if ((tool_type = virStorageBackendFindFSImageTool(NULL)) < 0) {
Mark McLoughlin f9c1b7
             virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
Mark McLoughlin f9c1b7
diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c
Mark McLoughlin f9c1b7
index 01cb171..6816da8 100644
Mark McLoughlin f9c1b7
--- a/src/storage_backend_fs.c
Mark McLoughlin f9c1b7
+++ b/src/storage_backend_fs.c
Mark McLoughlin f9c1b7
@@ -41,259 +41,24 @@
Mark McLoughlin f9c1b7
 #include "virterror_internal.h"
Mark McLoughlin f9c1b7
 #include "storage_backend_fs.h"
Mark McLoughlin f9c1b7
 #include "storage_conf.h"
Mark McLoughlin f9c1b7
+#include "storage_file.h"
Mark McLoughlin f9c1b7
 #include "util.h"
Mark McLoughlin f9c1b7
 #include "memory.h"
Mark McLoughlin f9c1b7
 #include "xml.h"
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-enum lv_endian {
Mark McLoughlin f9c1b7
-    LV_LITTLE_ENDIAN = 1, /* 1234 */
Mark McLoughlin f9c1b7
-    LV_BIG_ENDIAN         /* 4321 */
Mark McLoughlin f9c1b7
-};
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-enum {
Mark McLoughlin f9c1b7
-    BACKING_STORE_OK,
Mark McLoughlin f9c1b7
-    BACKING_STORE_INVALID,
Mark McLoughlin f9c1b7
-    BACKING_STORE_ERROR,
Mark McLoughlin f9c1b7
-};
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-static int cowGetBackingStore(virConnectPtr, char **,
Mark McLoughlin f9c1b7
-                              const unsigned char *, size_t);
Mark McLoughlin f9c1b7
-static int qcowXGetBackingStore(virConnectPtr, char **,
Mark McLoughlin f9c1b7
-                                const unsigned char *, size_t);
Mark McLoughlin f9c1b7
-static int vmdk4GetBackingStore(virConnectPtr, char **,
Mark McLoughlin f9c1b7
-                                const unsigned char *, size_t);
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-/* Either 'magic' or 'extension' *must* be provided */
Mark McLoughlin f9c1b7
-struct FileTypeInfo {
Mark McLoughlin f9c1b7
-    int type;           /* One of the constants above */
Mark McLoughlin f9c1b7
-    const char *magic;  /* Optional string of file magic
Mark McLoughlin f9c1b7
-                         * to check at head of file */
Mark McLoughlin f9c1b7
-    const char *extension; /* Optional file extension to check */
Mark McLoughlin f9c1b7
-    enum lv_endian endian; /* Endianness of file format */
Mark McLoughlin f9c1b7
-    int versionOffset;    /* Byte offset from start of file
Mark McLoughlin f9c1b7
-                           * where we find version number,
Mark McLoughlin f9c1b7
-                           * -1 to skip version test */
Mark McLoughlin f9c1b7
-    int versionNumber;    /* Version number to validate */
Mark McLoughlin f9c1b7
-    int sizeOffset;       /* Byte offset from start of file
Mark McLoughlin f9c1b7
-                           * where we find capacity info,
Mark McLoughlin f9c1b7
-                           * -1 to use st_size as capacity */
Mark McLoughlin f9c1b7
-    int sizeBytes;        /* Number of bytes for size field */
Mark McLoughlin f9c1b7
-    int sizeMultiplier;   /* A scaling factor if size is not in bytes */
Mark McLoughlin f9c1b7
-                          /* Store a COW base image path (possibly relative),
Mark McLoughlin f9c1b7
-                           * or NULL if there is no COW base image, to RES;
Mark McLoughlin f9c1b7
-                           * return BACKING_STORE_* */
Mark McLoughlin f9c1b7
-    int qcowCryptOffset;  /* Byte offset from start of file
Mark McLoughlin f9c1b7
-                           * where to find encryption mode,
Mark McLoughlin f9c1b7
-                           * -1 if encryption is not used */
Mark McLoughlin f9c1b7
-    int (*getBackingStore)(virConnectPtr conn, char **res,
Mark McLoughlin f9c1b7
-                           const unsigned char *buf, size_t buf_size);
Mark McLoughlin f9c1b7
-};
Mark McLoughlin f9c1b7
-struct FileTypeInfo const fileTypeInfo[] = {
Mark McLoughlin f9c1b7
-    /* Bochs */
Mark McLoughlin f9c1b7
-    /* XXX Untested
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_BOCHS, "Bochs Virtual HD Image", NULL,
Mark McLoughlin f9c1b7
-      LV_LITTLE_ENDIAN, 64, 0x20000,
Mark McLoughlin f9c1b7
-      32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/
Mark McLoughlin f9c1b7
-    /* CLoop */
Mark McLoughlin f9c1b7
-    /* XXX Untested
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL,
Mark McLoughlin f9c1b7
-      LV_LITTLE_ENDIAN, -1, 0,
Mark McLoughlin f9c1b7
-      -1, 0, 0, -1, NULL }, */
Mark McLoughlin f9c1b7
-    /* Cow */
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_COW, "OOOM", NULL,
Mark McLoughlin f9c1b7
-      LV_BIG_ENDIAN, 4, 2,
Mark McLoughlin f9c1b7
-      4+4+1024+4, 8, 1, -1, cowGetBackingStore },
Mark McLoughlin f9c1b7
-    /* DMG */
Mark McLoughlin f9c1b7
-    /* XXX QEMU says there's no magic for dmg, but we should check... */
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_DMG, NULL, ".dmg",
Mark McLoughlin f9c1b7
-      0, -1, 0,
Mark McLoughlin f9c1b7
-      -1, 0, 0, -1, NULL },
Mark McLoughlin f9c1b7
-    /* XXX there's probably some magic for iso we can validate too... */
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_ISO, NULL, ".iso",
Mark McLoughlin f9c1b7
-      0, -1, 0,
Mark McLoughlin f9c1b7
-      -1, 0, 0, -1, NULL },
Mark McLoughlin f9c1b7
-    /* Parallels */
Mark McLoughlin f9c1b7
-    /* XXX Untested
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_PARALLELS, "WithoutFreeSpace", NULL,
Mark McLoughlin f9c1b7
-      LV_LITTLE_ENDIAN, 16, 2,
Mark McLoughlin f9c1b7
-      16+4+4+4+4, 4, 512, -1, NULL },
Mark McLoughlin f9c1b7
-    */
Mark McLoughlin f9c1b7
-    /* QCow */
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_QCOW, "QFI", NULL,
Mark McLoughlin f9c1b7
-      LV_BIG_ENDIAN, 4, 1,
Mark McLoughlin f9c1b7
-      4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore },
Mark McLoughlin f9c1b7
-    /* QCow 2 */
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_QCOW2, "QFI", NULL,
Mark McLoughlin f9c1b7
-      LV_BIG_ENDIAN, 4, 2,
Mark McLoughlin f9c1b7
-      4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore },
Mark McLoughlin f9c1b7
-    /* VMDK 3 */
Mark McLoughlin f9c1b7
-    /* XXX Untested
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_VMDK, "COWD", NULL,
Mark McLoughlin f9c1b7
-      LV_LITTLE_ENDIAN, 4, 1,
Mark McLoughlin f9c1b7
-      4+4+4, 4, 512, -1, NULL },
Mark McLoughlin f9c1b7
-    */
Mark McLoughlin f9c1b7
-    /* VMDK 4 */
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_VMDK, "KDMV", NULL,
Mark McLoughlin f9c1b7
-      LV_LITTLE_ENDIAN, 4, 1,
Mark McLoughlin f9c1b7
-      4+4+4, 8, 512, -1, vmdk4GetBackingStore },
Mark McLoughlin f9c1b7
-    /* Connectix / VirtualPC */
Mark McLoughlin f9c1b7
-    /* XXX Untested
Mark McLoughlin f9c1b7
-    { VIR_STORAGE_VOL_FILE_VPC, "conectix", NULL,
Mark McLoughlin f9c1b7
-      LV_BIG_ENDIAN, -1, 0,
Mark McLoughlin f9c1b7
-      -1, 0, 0, -1, NULL},
Mark McLoughlin f9c1b7
-    */
Mark McLoughlin f9c1b7
-};
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
 #define VIR_FROM_THIS VIR_FROM_STORAGE
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
 static int
Mark McLoughlin f9c1b7
-cowGetBackingStore(virConnectPtr conn,
Mark McLoughlin f9c1b7
-                   char **res,
Mark McLoughlin f9c1b7
-                   const unsigned char *buf,
Mark McLoughlin f9c1b7
-                   size_t buf_size)
Mark McLoughlin f9c1b7
-{
Mark McLoughlin f9c1b7
-#define COW_FILENAME_MAXLEN 1024
Mark McLoughlin f9c1b7
-    *res = NULL;
Mark McLoughlin f9c1b7
-    if (buf_size < 4+4+ COW_FILENAME_MAXLEN)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */
Mark McLoughlin f9c1b7
-        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    *res = strndup ((const char*)buf + 4+4, COW_FILENAME_MAXLEN);
Mark McLoughlin f9c1b7
-    if (*res == NULL) {
Mark McLoughlin f9c1b7
-        virReportOOMError(conn);
Mark McLoughlin f9c1b7
-        return BACKING_STORE_ERROR;
Mark McLoughlin f9c1b7
-    }
Mark McLoughlin f9c1b7
-    return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-}
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-static int
Mark McLoughlin f9c1b7
-qcowXGetBackingStore(virConnectPtr conn,
Mark McLoughlin f9c1b7
-                     char **res,
Mark McLoughlin f9c1b7
-                     const unsigned char *buf,
Mark McLoughlin f9c1b7
-                     size_t buf_size)
Mark McLoughlin f9c1b7
-{
Mark McLoughlin f9c1b7
-    unsigned long long offset;
Mark McLoughlin f9c1b7
-    unsigned long size;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    *res = NULL;
Mark McLoughlin f9c1b7
-    if (buf_size < 4+4+8+4)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    offset = (((unsigned long long)buf[4+4] << 56)
Mark McLoughlin f9c1b7
-              | ((unsigned long long)buf[4+4+1] << 48)
Mark McLoughlin f9c1b7
-              | ((unsigned long long)buf[4+4+2] << 40)
Mark McLoughlin f9c1b7
-              | ((unsigned long long)buf[4+4+3] << 32)
Mark McLoughlin f9c1b7
-              | ((unsigned long long)buf[4+4+4] << 24)
Mark McLoughlin f9c1b7
-              | ((unsigned long long)buf[4+4+5] << 16)
Mark McLoughlin f9c1b7
-              | ((unsigned long long)buf[4+4+6] << 8)
Mark McLoughlin f9c1b7
-              | buf[4+4+7]); /* QCowHeader.backing_file_offset */
Mark McLoughlin f9c1b7
-    if (offset > buf_size)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    size = ((buf[4+4+8] << 24)
Mark McLoughlin f9c1b7
-            | (buf[4+4+8+1] << 16)
Mark McLoughlin f9c1b7
-            | (buf[4+4+8+2] << 8)
Mark McLoughlin f9c1b7
-            | buf[4+4+8+3]); /* QCowHeader.backing_file_size */
Mark McLoughlin f9c1b7
-    if (size == 0)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-    if (offset + size > buf_size || offset + size < offset)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    if (size + 1 == 0)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    if (VIR_ALLOC_N(*res, size + 1) < 0) {
Mark McLoughlin f9c1b7
-        virReportOOMError(conn);
Mark McLoughlin f9c1b7
-        return BACKING_STORE_ERROR;
Mark McLoughlin f9c1b7
-    }
Mark McLoughlin f9c1b7
-    memcpy(*res, buf + offset, size);
Mark McLoughlin f9c1b7
-    (*res)[size] = '\0';
Mark McLoughlin f9c1b7
-    return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-}
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-static int
Mark McLoughlin f9c1b7
-vmdk4GetBackingStore(virConnectPtr conn,
Mark McLoughlin f9c1b7
-                     char **res,
Mark McLoughlin f9c1b7
-                     const unsigned char *buf,
Mark McLoughlin f9c1b7
-                     size_t buf_size)
Mark McLoughlin f9c1b7
-{
Mark McLoughlin f9c1b7
-    static const char prefix[] = "parentFileNameHint=\"";
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    char desc[20*512 + 1], *start, *end;
Mark McLoughlin f9c1b7
-    size_t len;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    *res = NULL;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    if (buf_size <= 0x200)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    len = buf_size - 0x200;
Mark McLoughlin f9c1b7
-    if (len > sizeof(desc) - 1)
Mark McLoughlin f9c1b7
-        len = sizeof(desc) - 1;
Mark McLoughlin f9c1b7
-    memcpy(desc, buf + 0x200, len);
Mark McLoughlin f9c1b7
-    desc[len] = '\0';
Mark McLoughlin f9c1b7
-    start = strstr(desc, prefix);
Mark McLoughlin f9c1b7
-    if (start == NULL)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-    start += strlen(prefix);
Mark McLoughlin f9c1b7
-    end = strchr(start, '"');
Mark McLoughlin f9c1b7
-    if (end == NULL)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
-    if (end == start)
Mark McLoughlin f9c1b7
-        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-    *end = '\0';
Mark McLoughlin f9c1b7
-    *res = strdup(start);
Mark McLoughlin f9c1b7
-    if (*res == NULL) {
Mark McLoughlin f9c1b7
-        virReportOOMError(conn);
Mark McLoughlin f9c1b7
-        return BACKING_STORE_ERROR;
Mark McLoughlin f9c1b7
-    }
Mark McLoughlin f9c1b7
-    return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
-}
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-/**
Mark McLoughlin f9c1b7
- * Return an absolute path corresponding to PATH, which is absolute or relative
Mark McLoughlin f9c1b7
- * to the directory containing BASE_FILE, or NULL on error
Mark McLoughlin f9c1b7
- */
Mark McLoughlin f9c1b7
-static char *absolutePathFromBaseFile(const char *base_file, const char *path)
Mark McLoughlin f9c1b7
+virStorageBackendProbeTarget(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                             virStorageVolTargetPtr target,
Mark McLoughlin f9c1b7
+                             char **backingStore,
Mark McLoughlin f9c1b7
+                             unsigned long long *allocation,
Mark McLoughlin f9c1b7
+                             unsigned long long *capacity,
Mark McLoughlin f9c1b7
+                             virStorageEncryptionPtr *encryption)
Mark McLoughlin f9c1b7
 {
Mark McLoughlin f9c1b7
-    size_t base_size, path_size;
Mark McLoughlin f9c1b7
-    char *res, *p;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    if (*path == '/')
Mark McLoughlin f9c1b7
-        return strdup(path);
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    base_size = strlen(base_file) + 1;
Mark McLoughlin f9c1b7
-    path_size = strlen(path) + 1;
Mark McLoughlin f9c1b7
-    if (VIR_ALLOC_N(res, base_size - 1 + path_size) < 0)
Mark McLoughlin f9c1b7
-        return NULL;
Mark McLoughlin f9c1b7
-    memcpy(res, base_file, base_size);
Mark McLoughlin f9c1b7
-    p = strrchr(res, '/');
Mark McLoughlin f9c1b7
-    if (p != NULL)
Mark McLoughlin f9c1b7
-        p++;
Mark McLoughlin f9c1b7
-    else
Mark McLoughlin f9c1b7
-        p = res;
Mark McLoughlin f9c1b7
-    memcpy(p, path, path_size);
Mark McLoughlin f9c1b7
-    if (VIR_REALLOC_N(res, (p + path_size) - res) < 0) {
Mark McLoughlin f9c1b7
-        /* Ignore failure */
Mark McLoughlin f9c1b7
-    }
Mark McLoughlin f9c1b7
-    return res;
Mark McLoughlin f9c1b7
-}
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-/**
Mark McLoughlin f9c1b7
- * Probe the header of a file to determine what type of disk image
Mark McLoughlin f9c1b7
- * it is, and info about its capacity if available.
Mark McLoughlin f9c1b7
- */
Mark McLoughlin f9c1b7
-static int virStorageBackendProbeTarget(virConnectPtr conn,
Mark McLoughlin f9c1b7
-                                        virStorageVolTargetPtr target,
Mark McLoughlin f9c1b7
-                                        char **backingStore,
Mark McLoughlin f9c1b7
-                                        unsigned long long *allocation,
Mark McLoughlin f9c1b7
-                                        unsigned long long *capacity,
Mark McLoughlin f9c1b7
-                                        virStorageEncryptionPtr *encryption) {
Mark McLoughlin f9c1b7
-    int fd;
Mark McLoughlin f9c1b7
-    unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
Mark McLoughlin f9c1b7
-    int len, i, ret;
Mark McLoughlin f9c1b7
+    int fd, ret;
Mark McLoughlin f9c1b7
+    virStorageFileMetadata meta;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-    if (backingStore)
Mark McLoughlin f9c1b7
-        *backingStore = NULL;
Mark McLoughlin f9c1b7
     if (encryption)
Mark McLoughlin f9c1b7
         *encryption = NULL;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
@@ -311,148 +76,51 @@ static int virStorageBackendProbeTarget(virConnectPtr conn,
Mark McLoughlin f9c1b7
         return ret; /* Take care to propagate ret, it is not always -1 */
Mark McLoughlin f9c1b7
     }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-    if ((len = read(fd, head, sizeof(head))) < 0) {
Mark McLoughlin f9c1b7
-        virReportSystemError(conn, errno,
Mark McLoughlin f9c1b7
-                             _("cannot read header '%s'"),
Mark McLoughlin f9c1b7
-                             target->path);
Mark McLoughlin f9c1b7
+    memset(&meta, 0, sizeof(meta));
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    if (virStorageFileGetMetadataFromFD(conn, target->path, fd, &meta) < 0) {
Mark McLoughlin f9c1b7
         close(fd);
Mark McLoughlin f9c1b7
         return -1;
Mark McLoughlin f9c1b7
     }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
     close(fd);
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-    /* First check file magic */
Mark McLoughlin f9c1b7
-    for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
Mark McLoughlin f9c1b7
-        int mlen;
Mark McLoughlin f9c1b7
-        bool encrypted_qcow = false;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        if (fileTypeInfo[i].magic == NULL)
Mark McLoughlin f9c1b7
-            continue;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        /* Validate magic data */
Mark McLoughlin f9c1b7
-        mlen = strlen(fileTypeInfo[i].magic);
Mark McLoughlin f9c1b7
-        if (mlen > len)
Mark McLoughlin f9c1b7
-            continue;
Mark McLoughlin f9c1b7
-        if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
Mark McLoughlin f9c1b7
-            continue;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        /* Validate version number info */
Mark McLoughlin f9c1b7
-        if (fileTypeInfo[i].versionNumber != -1) {
Mark McLoughlin f9c1b7
-            int version;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-            if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
Mark McLoughlin f9c1b7
-                version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
Mark McLoughlin f9c1b7
-                    (head[fileTypeInfo[i].versionOffset+2] << 16) |
Mark McLoughlin f9c1b7
-                    (head[fileTypeInfo[i].versionOffset+1] << 8) |
Mark McLoughlin f9c1b7
-                    head[fileTypeInfo[i].versionOffset];
Mark McLoughlin f9c1b7
-            } else {
Mark McLoughlin f9c1b7
-                version = (head[fileTypeInfo[i].versionOffset] << 24) |
Mark McLoughlin f9c1b7
-                    (head[fileTypeInfo[i].versionOffset+1] << 16) |
Mark McLoughlin f9c1b7
-                    (head[fileTypeInfo[i].versionOffset+2] << 8) |
Mark McLoughlin f9c1b7
-                    head[fileTypeInfo[i].versionOffset+3];
Mark McLoughlin f9c1b7
-            }
Mark McLoughlin f9c1b7
-            if (version != fileTypeInfo[i].versionNumber)
Mark McLoughlin f9c1b7
-                continue;
Mark McLoughlin f9c1b7
-        }
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        /* Optionally extract capacity from file */
Mark McLoughlin f9c1b7
-        if (fileTypeInfo[i].sizeOffset != -1 && capacity) {
Mark McLoughlin f9c1b7
-            if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
Mark McLoughlin f9c1b7
-                *capacity =
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
Mark McLoughlin f9c1b7
-            } else {
Mark McLoughlin f9c1b7
-                *capacity =
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) |
Mark McLoughlin f9c1b7
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
Mark McLoughlin f9c1b7
-            }
Mark McLoughlin f9c1b7
-            /* Avoid unlikely, but theoretically possible overflow */
Mark McLoughlin f9c1b7
-            if (*capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
Mark McLoughlin f9c1b7
-                continue;
Mark McLoughlin f9c1b7
-            *capacity *= fileTypeInfo[i].sizeMultiplier;
Mark McLoughlin f9c1b7
-        }
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        if (fileTypeInfo[i].qcowCryptOffset != -1) {
Mark McLoughlin f9c1b7
-            int crypt_format;
Mark McLoughlin f9c1b7
+    target->format = meta.format;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-            crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) |
Mark McLoughlin f9c1b7
-                (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) |
Mark McLoughlin f9c1b7
-                (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) |
Mark McLoughlin f9c1b7
-                head[fileTypeInfo[i].qcowCryptOffset+3];
Mark McLoughlin f9c1b7
-            encrypted_qcow = crypt_format != 0;
Mark McLoughlin f9c1b7
-        }
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        /* Validation passed, we know the file format now */
Mark McLoughlin f9c1b7
-        target->format = fileTypeInfo[i].type;
Mark McLoughlin f9c1b7
-        if (fileTypeInfo[i].getBackingStore != NULL && backingStore) {
Mark McLoughlin f9c1b7
-            char *base;
Mark McLoughlin f9c1b7
+    if (backingStore) {
Mark McLoughlin f9c1b7
+        *backingStore = meta.backingStore;
Mark McLoughlin f9c1b7
+        meta.backingStore = NULL;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-            switch (fileTypeInfo[i].getBackingStore(conn, &base, head, len)) {
Mark McLoughlin f9c1b7
-            case BACKING_STORE_OK:
Mark McLoughlin f9c1b7
-                break;
Mark McLoughlin f9c1b7
+    VIR_FREE(meta.backingStore);
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-            case BACKING_STORE_INVALID:
Mark McLoughlin f9c1b7
-                continue;
Mark McLoughlin f9c1b7
+    if (capacity && meta.capacity)
Mark McLoughlin f9c1b7
+        *capacity = meta.capacity;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-            case BACKING_STORE_ERROR:
Mark McLoughlin f9c1b7
-                return -1;
Mark McLoughlin f9c1b7
-            }
Mark McLoughlin f9c1b7
-            if (base != NULL) {
Mark McLoughlin f9c1b7
-                *backingStore
Mark McLoughlin f9c1b7
-                    = absolutePathFromBaseFile(target->path, base);
Mark McLoughlin f9c1b7
-                VIR_FREE(base);
Mark McLoughlin f9c1b7
-                if (*backingStore == NULL) {
Mark McLoughlin f9c1b7
-                    virReportOOMError(conn);
Mark McLoughlin f9c1b7
-                    return -1;
Mark McLoughlin f9c1b7
-                }
Mark McLoughlin f9c1b7
-            }
Mark McLoughlin f9c1b7
+    if (encryption != NULL && meta.encrypted) {
Mark McLoughlin f9c1b7
+        if (VIR_ALLOC(*encryption) < 0) {
Mark McLoughlin f9c1b7
+            virReportOOMError(conn);
Mark McLoughlin f9c1b7
+            if (backingStore)
Mark McLoughlin f9c1b7
+                VIR_FREE(*backingStore);
Mark McLoughlin f9c1b7
+            return -1;
Mark McLoughlin f9c1b7
         }
Mark McLoughlin f9c1b7
-        if (encryption != NULL && encrypted_qcow) {
Mark McLoughlin f9c1b7
-            virStorageEncryptionPtr enc;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-            if (VIR_ALLOC(enc) < 0) {
Mark McLoughlin f9c1b7
-                virReportOOMError(conn);
Mark McLoughlin f9c1b7
-                if (backingStore)
Mark McLoughlin f9c1b7
-                    VIR_FREE(*backingStore);
Mark McLoughlin f9c1b7
-                return -1;
Mark McLoughlin f9c1b7
-            }
Mark McLoughlin f9c1b7
-            enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
Mark McLoughlin f9c1b7
-            *encryption = enc;
Mark McLoughlin f9c1b7
-            /* XXX ideally we'd fill in secret UUID here
Mark McLoughlin f9c1b7
-             * but we cannot guarentee 'conn' is non-NULL
Mark McLoughlin f9c1b7
-             * at this point in time :-(  So we only fill
Mark McLoughlin f9c1b7
-             * in secrets when someone first queries a vol
Mark McLoughlin f9c1b7
-             */
Mark McLoughlin f9c1b7
+        switch (target->format) {
Mark McLoughlin f9c1b7
+        case VIR_STORAGE_FILE_QCOW:
Mark McLoughlin f9c1b7
+        case VIR_STORAGE_FILE_QCOW2:
Mark McLoughlin f9c1b7
+            (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
Mark McLoughlin f9c1b7
+            break;
Mark McLoughlin f9c1b7
+        default:
Mark McLoughlin f9c1b7
+            break;
Mark McLoughlin f9c1b7
         }
Mark McLoughlin f9c1b7
-        return 0;
Mark McLoughlin f9c1b7
-    }
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-    /* No magic, so check file extension */
Mark McLoughlin f9c1b7
-    for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
Mark McLoughlin f9c1b7
-        if (fileTypeInfo[i].extension == NULL)
Mark McLoughlin f9c1b7
-            continue;
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-        if (!virFileHasSuffix(target->path, fileTypeInfo[i].extension))
Mark McLoughlin f9c1b7
-            continue;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-        target->format = fileTypeInfo[i].type;
Mark McLoughlin f9c1b7
-        return 0;
Mark McLoughlin f9c1b7
+        /* XXX ideally we'd fill in secret UUID here
Mark McLoughlin f9c1b7
+         * but we cannot guarentee 'conn' is non-NULL
Mark McLoughlin f9c1b7
+         * at this point in time :-(  So we only fill
Mark McLoughlin f9c1b7
+         * in secrets when someone first queries a vol
Mark McLoughlin f9c1b7
+         */
Mark McLoughlin f9c1b7
     }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-    /* All fails, so call it a raw file */
Mark McLoughlin f9c1b7
-    target->format = VIR_STORAGE_VOL_FILE_RAW;
Mark McLoughlin f9c1b7
     return 0;
Mark McLoughlin f9c1b7
 }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
@@ -891,7 +559,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn,
Mark McLoughlin f9c1b7
             goto no_memory;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
         vol->type = VIR_STORAGE_VOL_FILE;
Mark McLoughlin f9c1b7
-        vol->target.format = VIR_STORAGE_VOL_FILE_RAW; /* Real value is filled in during probe */
Mark McLoughlin f9c1b7
+        vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
Mark McLoughlin f9c1b7
         if (virAsprintf(&vol->target.path, "%s/%s",
Mark McLoughlin f9c1b7
                         pool->def->target.path,
Mark McLoughlin f9c1b7
                         vol->name) == -1)
Mark McLoughlin f9c1b7
@@ -918,7 +586,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn,
Mark McLoughlin f9c1b7
         }
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
         if (backingStore != NULL) {
Mark McLoughlin f9c1b7
-            if (vol->target.format == VIR_STORAGE_VOL_FILE_QCOW2 &&
Mark McLoughlin f9c1b7
+            if (vol->target.format == VIR_STORAGE_FILE_QCOW2 &&
Mark McLoughlin f9c1b7
                 STRPREFIX("fmt:", backingStore)) {
Mark McLoughlin f9c1b7
                 char *fmtstr = backingStore + 4;
Mark McLoughlin f9c1b7
                 char *path = strchr(fmtstr, ':');
Mark McLoughlin f9c1b7
@@ -927,7 +595,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn,
Mark McLoughlin f9c1b7
                 } else {
Mark McLoughlin f9c1b7
                     *path = '\0';
Mark McLoughlin f9c1b7
                     if ((vol->backingStore.format =
Mark McLoughlin f9c1b7
-                         virStorageVolFormatFileSystemTypeFromString(fmtstr)) < 0) {
Mark McLoughlin f9c1b7
+                         virStorageFileFormatTypeFromString(fmtstr)) < 0) {
Mark McLoughlin f9c1b7
                         VIR_FREE(backingStore);
Mark McLoughlin f9c1b7
                     } else {
Mark McLoughlin f9c1b7
                         memmove(backingStore, path, strlen(path) + 1);
Mark McLoughlin f9c1b7
@@ -1121,9 +789,9 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn,
Mark McLoughlin f9c1b7
                                                                inputvol);
Mark McLoughlin f9c1b7
         if (!create_func)
Mark McLoughlin f9c1b7
             return -1;
Mark McLoughlin f9c1b7
-    } else if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW) {
Mark McLoughlin f9c1b7
+    } else if (vol->target.format == VIR_STORAGE_FILE_RAW) {
Mark McLoughlin f9c1b7
         create_func = virStorageBackendCreateRaw;
Mark McLoughlin f9c1b7
-    } else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) {
Mark McLoughlin f9c1b7
+    } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
Mark McLoughlin f9c1b7
         create_func = createFileDir;
Mark McLoughlin f9c1b7
     } else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
Mark McLoughlin f9c1b7
         create_func = virStorageBackendFSImageToolTypeToFunc(conn, tool_type);
Mark McLoughlin f9c1b7
diff --git a/src/storage_conf.c b/src/storage_conf.c
Mark McLoughlin f9c1b7
index cb063cc..788de15 100644
Mark McLoughlin f9c1b7
--- a/src/storage_conf.c
Mark McLoughlin f9c1b7
+++ b/src/storage_conf.c
Mark McLoughlin f9c1b7
@@ -36,6 +36,7 @@
Mark McLoughlin f9c1b7
 #include "virterror_internal.h"
Mark McLoughlin f9c1b7
 #include "datatypes.h"
Mark McLoughlin f9c1b7
 #include "storage_conf.h"
Mark McLoughlin f9c1b7
+#include "storage_file.h"
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
 #include "xml.h"
Mark McLoughlin f9c1b7
 #include "uuid.h"
Mark McLoughlin f9c1b7
@@ -82,12 +83,6 @@ VIR_ENUM_IMPL(virStorageVolFormatDisk,
Mark McLoughlin f9c1b7
               "linux-lvm", "linux-raid",
Mark McLoughlin f9c1b7
               "extended")
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-VIR_ENUM_IMPL(virStorageVolFormatFileSystem,
Mark McLoughlin f9c1b7
-              VIR_STORAGE_VOL_FILE_LAST,
Mark McLoughlin f9c1b7
-              "raw", "dir", "bochs",
Mark McLoughlin f9c1b7
-              "cloop", "cow", "dmg", "iso",
Mark McLoughlin f9c1b7
-              "qcow", "qcow2", "vmdk", "vpc")
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
 VIR_ENUM_IMPL(virStoragePartedFsType,
Mark McLoughlin f9c1b7
               VIR_STORAGE_PARTED_FS_TYPE_LAST,
Mark McLoughlin f9c1b7
               "ext2", "ext2", "fat16",
Mark McLoughlin f9c1b7
@@ -150,9 +145,9 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
Mark McLoughlin f9c1b7
     },
Mark McLoughlin f9c1b7
     { .poolType = VIR_STORAGE_POOL_DIR,
Mark McLoughlin f9c1b7
       .volOptions = {
Mark McLoughlin f9c1b7
-            .defaultFormat = VIR_STORAGE_VOL_FILE_RAW,
Mark McLoughlin f9c1b7
-            .formatFromString = virStorageVolFormatFileSystemTypeFromString,
Mark McLoughlin f9c1b7
-            .formatToString = virStorageVolFormatFileSystemTypeToString,
Mark McLoughlin f9c1b7
+            .defaultFormat = VIR_STORAGE_FILE_RAW,
Mark McLoughlin f9c1b7
+            .formatFromString = virStorageFileFormatTypeFromString,
Mark McLoughlin f9c1b7
+            .formatToString = virStorageFileFormatTypeToString,
Mark McLoughlin f9c1b7
         },
Mark McLoughlin f9c1b7
     },
Mark McLoughlin f9c1b7
     { .poolType = VIR_STORAGE_POOL_FS,
Mark McLoughlin f9c1b7
@@ -162,9 +157,9 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
Mark McLoughlin f9c1b7
             .formatToString = virStoragePoolFormatFileSystemTypeToString,
Mark McLoughlin f9c1b7
         },
Mark McLoughlin f9c1b7
       .volOptions = {
Mark McLoughlin f9c1b7
-            .defaultFormat = VIR_STORAGE_VOL_FILE_RAW,
Mark McLoughlin f9c1b7
-            .formatFromString = virStorageVolFormatFileSystemTypeFromString,
Mark McLoughlin f9c1b7
-            .formatToString = virStorageVolFormatFileSystemTypeToString,
Mark McLoughlin f9c1b7
+            .defaultFormat = VIR_STORAGE_FILE_RAW,
Mark McLoughlin f9c1b7
+            .formatFromString = virStorageFileFormatTypeFromString,
Mark McLoughlin f9c1b7
+            .formatToString = virStorageFileFormatTypeToString,
Mark McLoughlin f9c1b7
         },
Mark McLoughlin f9c1b7
     },
Mark McLoughlin f9c1b7
     { .poolType = VIR_STORAGE_POOL_NETFS,
Mark McLoughlin f9c1b7
@@ -176,9 +171,9 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
Mark McLoughlin f9c1b7
             .formatToString = virStoragePoolFormatFileSystemNetTypeToString,
Mark McLoughlin f9c1b7
         },
Mark McLoughlin f9c1b7
       .volOptions = {
Mark McLoughlin f9c1b7
-            .defaultFormat = VIR_STORAGE_VOL_FILE_RAW,
Mark McLoughlin f9c1b7
-            .formatFromString = virStorageVolFormatFileSystemTypeFromString,
Mark McLoughlin f9c1b7
-            .formatToString = virStorageVolFormatFileSystemTypeToString,
Mark McLoughlin f9c1b7
+            .defaultFormat = VIR_STORAGE_FILE_RAW,
Mark McLoughlin f9c1b7
+            .formatFromString = virStorageFileFormatTypeFromString,
Mark McLoughlin f9c1b7
+            .formatToString = virStorageFileFormatTypeToString,
Mark McLoughlin f9c1b7
         },
Mark McLoughlin f9c1b7
     },
Mark McLoughlin f9c1b7
     { .poolType = VIR_STORAGE_POOL_ISCSI,
Mark McLoughlin f9c1b7
diff --git a/src/storage_conf.h b/src/storage_conf.h
Mark McLoughlin f9c1b7
index 421d305..9fedb12 100644
Mark McLoughlin f9c1b7
--- a/src/storage_conf.h
Mark McLoughlin f9c1b7
+++ b/src/storage_conf.h
Mark McLoughlin f9c1b7
@@ -429,23 +429,6 @@ enum virStoragePoolFormatLogical {
Mark McLoughlin f9c1b7
 };
Mark McLoughlin f9c1b7
 VIR_ENUM_DECL(virStoragePoolFormatLogical)
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
-enum virStorageVolFormatFileSystem {
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_RAW = 0,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_DIR,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_BOCHS,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_CLOOP,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_COW,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_DMG,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_ISO,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_QCOW,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_QCOW2,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_VMDK,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_VPC,
Mark McLoughlin f9c1b7
-    VIR_STORAGE_VOL_FILE_LAST,
Mark McLoughlin f9c1b7
-};
Mark McLoughlin f9c1b7
-VIR_ENUM_DECL(virStorageVolFormatFileSystem)
Mark McLoughlin f9c1b7
-
Mark McLoughlin f9c1b7
 /*
Mark McLoughlin f9c1b7
  * XXX these are basically partition types.
Mark McLoughlin f9c1b7
  *
Mark McLoughlin f9c1b7
diff --git a/src/storage_file.c b/src/storage_file.c
Mark McLoughlin f9c1b7
new file mode 100644
Mark McLoughlin f9c1b7
index 0000000..44057d2
Mark McLoughlin f9c1b7
--- /dev/null
Mark McLoughlin f9c1b7
+++ b/src/storage_file.c
Mark McLoughlin f9c1b7
@@ -0,0 +1,424 @@
Mark McLoughlin f9c1b7
+/*
Mark McLoughlin f9c1b7
+ * storage_file.c: file utility functions for FS storage backend
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * Copyright (C) 2007-2009 Red Hat, Inc.
Mark McLoughlin f9c1b7
+ * Copyright (C) 2007-2008 Daniel P. Berrange
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * This library is free software; you can redistribute it and/or
Mark McLoughlin f9c1b7
+ * modify it under the terms of the GNU Lesser General Public
Mark McLoughlin f9c1b7
+ * License as published by the Free Software Foundation; either
Mark McLoughlin f9c1b7
+ * version 2.1 of the License, or (at your option) any later version.
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * This library is distributed in the hope that it will be useful,
Mark McLoughlin f9c1b7
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Mark McLoughlin f9c1b7
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Mark McLoughlin f9c1b7
+ * Lesser General Public License for more details.
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * You should have received a copy of the GNU Lesser General Public
Mark McLoughlin f9c1b7
+ * License along with this library; if not, write to the Free Software
Mark McLoughlin f9c1b7
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * Author: Daniel P. Berrange <berrange@redhat.com>
Mark McLoughlin f9c1b7
+ */
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+#include <config.h>
Mark McLoughlin f9c1b7
+#include "storage_file.h"
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+#include <unistd.h>
Mark McLoughlin f9c1b7
+#include <fcntl.h>
Mark McLoughlin f9c1b7
+#include "memory.h"
Mark McLoughlin f9c1b7
+#include "virterror_internal.h"
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+#define VIR_FROM_THIS VIR_FROM_STORAGE
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+VIR_ENUM_IMPL(virStorageFileFormat,
Mark McLoughlin f9c1b7
+              VIR_STORAGE_FILE_LAST,
Mark McLoughlin f9c1b7
+              "raw", "dir", "bochs",
Mark McLoughlin f9c1b7
+              "cloop", "cow", "dmg", "iso",
Mark McLoughlin f9c1b7
+              "qcow", "qcow2", "vmdk", "vpc")
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+enum lv_endian {
Mark McLoughlin f9c1b7
+    LV_LITTLE_ENDIAN = 1, /* 1234 */
Mark McLoughlin f9c1b7
+    LV_BIG_ENDIAN         /* 4321 */
Mark McLoughlin f9c1b7
+};
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+enum {
Mark McLoughlin f9c1b7
+    BACKING_STORE_OK,
Mark McLoughlin f9c1b7
+    BACKING_STORE_INVALID,
Mark McLoughlin f9c1b7
+    BACKING_STORE_ERROR,
Mark McLoughlin f9c1b7
+};
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+/* Either 'magic' or 'extension' *must* be provided */
Mark McLoughlin f9c1b7
+struct FileTypeInfo {
Mark McLoughlin f9c1b7
+    int type;           /* One of the constants above */
Mark McLoughlin f9c1b7
+    const char *magic;  /* Optional string of file magic
Mark McLoughlin f9c1b7
+                         * to check at head of file */
Mark McLoughlin f9c1b7
+    const char *extension; /* Optional file extension to check */
Mark McLoughlin f9c1b7
+    enum lv_endian endian; /* Endianness of file format */
Mark McLoughlin f9c1b7
+    int versionOffset;    /* Byte offset from start of file
Mark McLoughlin f9c1b7
+                           * where we find version number,
Mark McLoughlin f9c1b7
+                           * -1 to skip version test */
Mark McLoughlin f9c1b7
+    int versionNumber;    /* Version number to validate */
Mark McLoughlin f9c1b7
+    int sizeOffset;       /* Byte offset from start of file
Mark McLoughlin f9c1b7
+                           * where we find capacity info,
Mark McLoughlin f9c1b7
+                           * -1 to use st_size as capacity */
Mark McLoughlin f9c1b7
+    int sizeBytes;        /* Number of bytes for size field */
Mark McLoughlin f9c1b7
+    int sizeMultiplier;   /* A scaling factor if size is not in bytes */
Mark McLoughlin f9c1b7
+                          /* Store a COW base image path (possibly relative),
Mark McLoughlin f9c1b7
+                           * or NULL if there is no COW base image, to RES;
Mark McLoughlin f9c1b7
+                           * return BACKING_STORE_* */
Mark McLoughlin f9c1b7
+    int qcowCryptOffset;  /* Byte offset from start of file
Mark McLoughlin f9c1b7
+                           * where to find encryption mode,
Mark McLoughlin f9c1b7
+                           * -1 if encryption is not used */
Mark McLoughlin f9c1b7
+    int (*getBackingStore)(virConnectPtr conn, char **res,
Mark McLoughlin f9c1b7
+                           const unsigned char *buf, size_t buf_size);
Mark McLoughlin f9c1b7
+};
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+static int cowGetBackingStore(virConnectPtr, char **,
Mark McLoughlin f9c1b7
+                              const unsigned char *, size_t);
Mark McLoughlin f9c1b7
+static int qcowXGetBackingStore(virConnectPtr, char **,
Mark McLoughlin f9c1b7
+                                const unsigned char *, size_t);
Mark McLoughlin f9c1b7
+static int vmdk4GetBackingStore(virConnectPtr, char **,
Mark McLoughlin f9c1b7
+                                const unsigned char *, size_t);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+static struct FileTypeInfo const fileTypeInfo[] = {
Mark McLoughlin f9c1b7
+    /* Bochs */
Mark McLoughlin f9c1b7
+    /* XXX Untested
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_BOCHS, "Bochs Virtual HD Image", NULL,
Mark McLoughlin f9c1b7
+      LV_LITTLE_ENDIAN, 64, 0x20000,
Mark McLoughlin f9c1b7
+      32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/
Mark McLoughlin f9c1b7
+    /* CLoop */
Mark McLoughlin f9c1b7
+    /* XXX Untested
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL,
Mark McLoughlin f9c1b7
+      LV_LITTLE_ENDIAN, -1, 0,
Mark McLoughlin f9c1b7
+      -1, 0, 0, -1, NULL }, */
Mark McLoughlin f9c1b7
+    /* Cow */
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_COW, "OOOM", NULL,
Mark McLoughlin f9c1b7
+      LV_BIG_ENDIAN, 4, 2,
Mark McLoughlin f9c1b7
+      4+4+1024+4, 8, 1, -1, cowGetBackingStore },
Mark McLoughlin f9c1b7
+    /* DMG */
Mark McLoughlin f9c1b7
+    /* XXX QEMU says there's no magic for dmg, but we should check... */
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_DMG, NULL, ".dmg",
Mark McLoughlin f9c1b7
+      0, -1, 0,
Mark McLoughlin f9c1b7
+      -1, 0, 0, -1, NULL },
Mark McLoughlin f9c1b7
+    /* XXX there's probably some magic for iso we can validate too... */
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_ISO, NULL, ".iso",
Mark McLoughlin f9c1b7
+      0, -1, 0,
Mark McLoughlin f9c1b7
+      -1, 0, 0, -1, NULL },
Mark McLoughlin f9c1b7
+    /* Parallels */
Mark McLoughlin f9c1b7
+    /* XXX Untested
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_PARALLELS, "WithoutFreeSpace", NULL,
Mark McLoughlin f9c1b7
+      LV_LITTLE_ENDIAN, 16, 2,
Mark McLoughlin f9c1b7
+      16+4+4+4+4, 4, 512, -1, NULL },
Mark McLoughlin f9c1b7
+    */
Mark McLoughlin f9c1b7
+    /* QCow */
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_QCOW, "QFI", NULL,
Mark McLoughlin f9c1b7
+      LV_BIG_ENDIAN, 4, 1,
Mark McLoughlin f9c1b7
+      4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore },
Mark McLoughlin f9c1b7
+    /* QCow 2 */
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_QCOW2, "QFI", NULL,
Mark McLoughlin f9c1b7
+      LV_BIG_ENDIAN, 4, 2,
Mark McLoughlin f9c1b7
+      4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore },
Mark McLoughlin f9c1b7
+    /* VMDK 3 */
Mark McLoughlin f9c1b7
+    /* XXX Untested
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_VMDK, "COWD", NULL,
Mark McLoughlin f9c1b7
+      LV_LITTLE_ENDIAN, 4, 1,
Mark McLoughlin f9c1b7
+      4+4+4, 4, 512, -1, NULL },
Mark McLoughlin f9c1b7
+    */
Mark McLoughlin f9c1b7
+    /* VMDK 4 */
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_VMDK, "KDMV", NULL,
Mark McLoughlin f9c1b7
+      LV_LITTLE_ENDIAN, 4, 1,
Mark McLoughlin f9c1b7
+      4+4+4, 8, 512, -1, vmdk4GetBackingStore },
Mark McLoughlin f9c1b7
+    /* Connectix / VirtualPC */
Mark McLoughlin f9c1b7
+    /* XXX Untested
Mark McLoughlin f9c1b7
+    { VIR_STORAGE_FILE_VPC, "conectix", NULL,
Mark McLoughlin f9c1b7
+      LV_BIG_ENDIAN, -1, 0,
Mark McLoughlin f9c1b7
+      -1, 0, 0, -1, NULL},
Mark McLoughlin f9c1b7
+    */
Mark McLoughlin f9c1b7
+};
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+static int
Mark McLoughlin f9c1b7
+cowGetBackingStore(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                   char **res,
Mark McLoughlin f9c1b7
+                   const unsigned char *buf,
Mark McLoughlin f9c1b7
+                   size_t buf_size)
Mark McLoughlin f9c1b7
+{
Mark McLoughlin f9c1b7
+#define COW_FILENAME_MAXLEN 1024
Mark McLoughlin f9c1b7
+    *res = NULL;
Mark McLoughlin f9c1b7
+    if (buf_size < 4+4+ COW_FILENAME_MAXLEN)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */
Mark McLoughlin f9c1b7
+        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    *res = strndup ((const char*)buf + 4+4, COW_FILENAME_MAXLEN);
Mark McLoughlin f9c1b7
+    if (*res == NULL) {
Mark McLoughlin f9c1b7
+        virReportOOMError(conn);
Mark McLoughlin f9c1b7
+        return BACKING_STORE_ERROR;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+    return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+}
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+static int
Mark McLoughlin f9c1b7
+qcowXGetBackingStore(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                     char **res,
Mark McLoughlin f9c1b7
+                     const unsigned char *buf,
Mark McLoughlin f9c1b7
+                     size_t buf_size)
Mark McLoughlin f9c1b7
+{
Mark McLoughlin f9c1b7
+    unsigned long long offset;
Mark McLoughlin f9c1b7
+    unsigned long size;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    *res = NULL;
Mark McLoughlin f9c1b7
+    if (buf_size < 4+4+8+4)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    offset = (((unsigned long long)buf[4+4] << 56)
Mark McLoughlin f9c1b7
+              | ((unsigned long long)buf[4+4+1] << 48)
Mark McLoughlin f9c1b7
+              | ((unsigned long long)buf[4+4+2] << 40)
Mark McLoughlin f9c1b7
+              | ((unsigned long long)buf[4+4+3] << 32)
Mark McLoughlin f9c1b7
+              | ((unsigned long long)buf[4+4+4] << 24)
Mark McLoughlin f9c1b7
+              | ((unsigned long long)buf[4+4+5] << 16)
Mark McLoughlin f9c1b7
+              | ((unsigned long long)buf[4+4+6] << 8)
Mark McLoughlin f9c1b7
+              | buf[4+4+7]); /* QCowHeader.backing_file_offset */
Mark McLoughlin f9c1b7
+    if (offset > buf_size)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    size = ((buf[4+4+8] << 24)
Mark McLoughlin f9c1b7
+            | (buf[4+4+8+1] << 16)
Mark McLoughlin f9c1b7
+            | (buf[4+4+8+2] << 8)
Mark McLoughlin f9c1b7
+            | buf[4+4+8+3]); /* QCowHeader.backing_file_size */
Mark McLoughlin f9c1b7
+    if (size == 0)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+    if (offset + size > buf_size || offset + size < offset)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    if (size + 1 == 0)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    if (VIR_ALLOC_N(*res, size + 1) < 0) {
Mark McLoughlin f9c1b7
+        virReportOOMError(conn);
Mark McLoughlin f9c1b7
+        return BACKING_STORE_ERROR;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+    memcpy(*res, buf + offset, size);
Mark McLoughlin f9c1b7
+    (*res)[size] = '\0';
Mark McLoughlin f9c1b7
+    return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+}
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+static int
Mark McLoughlin f9c1b7
+vmdk4GetBackingStore(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                     char **res,
Mark McLoughlin f9c1b7
+                     const unsigned char *buf,
Mark McLoughlin f9c1b7
+                     size_t buf_size)
Mark McLoughlin f9c1b7
+{
Mark McLoughlin f9c1b7
+    static const char prefix[] = "parentFileNameHint=\"";
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    char desc[20*512 + 1], *start, *end;
Mark McLoughlin f9c1b7
+    size_t len;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    *res = NULL;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    if (buf_size <= 0x200)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    len = buf_size - 0x200;
Mark McLoughlin f9c1b7
+    if (len > sizeof(desc) - 1)
Mark McLoughlin f9c1b7
+        len = sizeof(desc) - 1;
Mark McLoughlin f9c1b7
+    memcpy(desc, buf + 0x200, len);
Mark McLoughlin f9c1b7
+    desc[len] = '\0';
Mark McLoughlin f9c1b7
+    start = strstr(desc, prefix);
Mark McLoughlin f9c1b7
+    if (start == NULL)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+    start += strlen(prefix);
Mark McLoughlin f9c1b7
+    end = strchr(start, '"');
Mark McLoughlin f9c1b7
+    if (end == NULL)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_INVALID;
Mark McLoughlin f9c1b7
+    if (end == start)
Mark McLoughlin f9c1b7
+        return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+    *end = '\0';
Mark McLoughlin f9c1b7
+    *res = strdup(start);
Mark McLoughlin f9c1b7
+    if (*res == NULL) {
Mark McLoughlin f9c1b7
+        virReportOOMError(conn);
Mark McLoughlin f9c1b7
+        return BACKING_STORE_ERROR;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+    return BACKING_STORE_OK;
Mark McLoughlin f9c1b7
+}
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+/**
Mark McLoughlin f9c1b7
+ * Return an absolute path corresponding to PATH, which is absolute or relative
Mark McLoughlin f9c1b7
+ * to the directory containing BASE_FILE, or NULL on error
Mark McLoughlin f9c1b7
+ */
Mark McLoughlin f9c1b7
+static char *
Mark McLoughlin f9c1b7
+absolutePathFromBaseFile(const char *base_file, const char *path)
Mark McLoughlin f9c1b7
+{
Mark McLoughlin f9c1b7
+    size_t base_size, path_size;
Mark McLoughlin f9c1b7
+    char *res, *p;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    if (*path == '/')
Mark McLoughlin f9c1b7
+        return strdup(path);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    base_size = strlen(base_file) + 1;
Mark McLoughlin f9c1b7
+    path_size = strlen(path) + 1;
Mark McLoughlin f9c1b7
+    if (VIR_ALLOC_N(res, base_size - 1 + path_size) < 0)
Mark McLoughlin f9c1b7
+        return NULL;
Mark McLoughlin f9c1b7
+    memcpy(res, base_file, base_size);
Mark McLoughlin f9c1b7
+    p = strrchr(res, '/');
Mark McLoughlin f9c1b7
+    if (p != NULL)
Mark McLoughlin f9c1b7
+        p++;
Mark McLoughlin f9c1b7
+    else
Mark McLoughlin f9c1b7
+        p = res;
Mark McLoughlin f9c1b7
+    memcpy(p, path, path_size);
Mark McLoughlin f9c1b7
+    if (VIR_REALLOC_N(res, (p + path_size) - res) < 0) {
Mark McLoughlin f9c1b7
+        /* Ignore failure */
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+    return res;
Mark McLoughlin f9c1b7
+}
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+/**
Mark McLoughlin f9c1b7
+ * Probe the header of a file to determine what type of disk image
Mark McLoughlin f9c1b7
+ * it is, and info about its capacity if available.
Mark McLoughlin f9c1b7
+ */
Mark McLoughlin f9c1b7
+int
Mark McLoughlin f9c1b7
+virStorageFileGetMetadataFromFD(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                                const char *path,
Mark McLoughlin f9c1b7
+                                int fd,
Mark McLoughlin f9c1b7
+                                virStorageFileMetadata *meta)
Mark McLoughlin f9c1b7
+{
Mark McLoughlin f9c1b7
+    unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
Mark McLoughlin f9c1b7
+    int len, i;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    /* If all else fails, call it a raw file */
Mark McLoughlin f9c1b7
+    meta->format = VIR_STORAGE_FILE_RAW;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    if ((len = read(fd, head, sizeof(head))) < 0) {
Mark McLoughlin f9c1b7
+        virReportSystemError(conn, errno, _("cannot read header '%s'"), path);
Mark McLoughlin f9c1b7
+        return -1;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    /* First check file magic */
Mark McLoughlin f9c1b7
+    for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
Mark McLoughlin f9c1b7
+        int mlen;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        if (fileTypeInfo[i].magic == NULL)
Mark McLoughlin f9c1b7
+            continue;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        /* Validate magic data */
Mark McLoughlin f9c1b7
+        mlen = strlen(fileTypeInfo[i].magic);
Mark McLoughlin f9c1b7
+        if (mlen > len)
Mark McLoughlin f9c1b7
+            continue;
Mark McLoughlin f9c1b7
+        if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
Mark McLoughlin f9c1b7
+            continue;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        /* Validate version number info */
Mark McLoughlin f9c1b7
+        if (fileTypeInfo[i].versionNumber != -1) {
Mark McLoughlin f9c1b7
+            int version;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+            if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
Mark McLoughlin f9c1b7
+                version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
Mark McLoughlin f9c1b7
+                    (head[fileTypeInfo[i].versionOffset+2] << 16) |
Mark McLoughlin f9c1b7
+                    (head[fileTypeInfo[i].versionOffset+1] << 8) |
Mark McLoughlin f9c1b7
+                    head[fileTypeInfo[i].versionOffset];
Mark McLoughlin f9c1b7
+            } else {
Mark McLoughlin f9c1b7
+                version = (head[fileTypeInfo[i].versionOffset] << 24) |
Mark McLoughlin f9c1b7
+                    (head[fileTypeInfo[i].versionOffset+1] << 16) |
Mark McLoughlin f9c1b7
+                    (head[fileTypeInfo[i].versionOffset+2] << 8) |
Mark McLoughlin f9c1b7
+                    head[fileTypeInfo[i].versionOffset+3];
Mark McLoughlin f9c1b7
+            }
Mark McLoughlin f9c1b7
+            if (version != fileTypeInfo[i].versionNumber)
Mark McLoughlin f9c1b7
+                continue;
Mark McLoughlin f9c1b7
+        }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        /* Optionally extract capacity from file */
Mark McLoughlin f9c1b7
+        if (fileTypeInfo[i].sizeOffset != -1) {
Mark McLoughlin f9c1b7
+            if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
Mark McLoughlin f9c1b7
+                meta->capacity =
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
Mark McLoughlin f9c1b7
+            } else {
Mark McLoughlin f9c1b7
+                meta->capacity =
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) |
Mark McLoughlin f9c1b7
+                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
Mark McLoughlin f9c1b7
+            }
Mark McLoughlin f9c1b7
+            /* Avoid unlikely, but theoretically possible overflow */
Mark McLoughlin f9c1b7
+            if (meta->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
Mark McLoughlin f9c1b7
+                continue;
Mark McLoughlin f9c1b7
+            meta->capacity *= fileTypeInfo[i].sizeMultiplier;
Mark McLoughlin f9c1b7
+        }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        if (fileTypeInfo[i].qcowCryptOffset != -1) {
Mark McLoughlin f9c1b7
+            int crypt_format;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+            crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) |
Mark McLoughlin f9c1b7
+                (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) |
Mark McLoughlin f9c1b7
+                (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) |
Mark McLoughlin f9c1b7
+                head[fileTypeInfo[i].qcowCryptOffset+3];
Mark McLoughlin f9c1b7
+            meta->encrypted = crypt_format != 0;
Mark McLoughlin f9c1b7
+        }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        /* Validation passed, we know the file format now */
Mark McLoughlin f9c1b7
+        meta->format = fileTypeInfo[i].type;
Mark McLoughlin f9c1b7
+        if (fileTypeInfo[i].getBackingStore != NULL) {
Mark McLoughlin f9c1b7
+            char *base;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+            switch (fileTypeInfo[i].getBackingStore(conn, &base, head, len)) {
Mark McLoughlin f9c1b7
+            case BACKING_STORE_OK:
Mark McLoughlin f9c1b7
+                break;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+            case BACKING_STORE_INVALID:
Mark McLoughlin f9c1b7
+                continue;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+            case BACKING_STORE_ERROR:
Mark McLoughlin f9c1b7
+                return -1;
Mark McLoughlin f9c1b7
+            }
Mark McLoughlin f9c1b7
+            if (base != NULL) {
Mark McLoughlin f9c1b7
+                meta->backingStore = absolutePathFromBaseFile(path, base);
Mark McLoughlin f9c1b7
+                VIR_FREE(base);
Mark McLoughlin f9c1b7
+                if (meta->backingStore == NULL) {
Mark McLoughlin f9c1b7
+                    virReportOOMError(conn);
Mark McLoughlin f9c1b7
+                    return -1;
Mark McLoughlin f9c1b7
+                }
Mark McLoughlin f9c1b7
+            }
Mark McLoughlin f9c1b7
+        }
Mark McLoughlin f9c1b7
+        return 0;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    /* No magic, so check file extension */
Mark McLoughlin f9c1b7
+    for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
Mark McLoughlin f9c1b7
+        if (fileTypeInfo[i].extension == NULL)
Mark McLoughlin f9c1b7
+            continue;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
Mark McLoughlin f9c1b7
+            continue;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+        meta->format = fileTypeInfo[i].type;
Mark McLoughlin f9c1b7
+        return 0;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    return 0;
Mark McLoughlin f9c1b7
+}
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+int
Mark McLoughlin f9c1b7
+virStorageFileGetMetadata(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                          const char *path,
Mark McLoughlin f9c1b7
+                          virStorageFileMetadata *meta)
Mark McLoughlin f9c1b7
+{
Mark McLoughlin f9c1b7
+    int fd, ret;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    if ((fd = open(path, O_RDONLY)) < 0) {
Mark McLoughlin f9c1b7
+        virReportSystemError(conn, errno, _("cannot open file '%s'"), path);
Mark McLoughlin f9c1b7
+        return -1;
Mark McLoughlin f9c1b7
+    }
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    ret = virStorageFileGetMetadataFromFD(conn, path, fd, meta);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    close(fd);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+    return ret;
Mark McLoughlin f9c1b7
+}
Mark McLoughlin f9c1b7
diff --git a/src/storage_file.h b/src/storage_file.h
Mark McLoughlin f9c1b7
new file mode 100644
Mark McLoughlin f9c1b7
index 0000000..b0abcaf
Mark McLoughlin f9c1b7
--- /dev/null
Mark McLoughlin f9c1b7
+++ b/src/storage_file.h
Mark McLoughlin f9c1b7
@@ -0,0 +1,62 @@
Mark McLoughlin f9c1b7
+/*
Mark McLoughlin f9c1b7
+ * storage_file.c: file utility functions for FS storage backend
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * Copyright (C) 2007-2009 Red Hat, Inc.
Mark McLoughlin f9c1b7
+ * Copyright (C) 2007-2008 Daniel P. Berrange
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * This library is free software; you can redistribute it and/or
Mark McLoughlin f9c1b7
+ * modify it under the terms of the GNU Lesser General Public
Mark McLoughlin f9c1b7
+ * License as published by the Free Software Foundation; either
Mark McLoughlin f9c1b7
+ * version 2.1 of the License, or (at your option) any later version.
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * This library is distributed in the hope that it will be useful,
Mark McLoughlin f9c1b7
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Mark McLoughlin f9c1b7
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Mark McLoughlin f9c1b7
+ * Lesser General Public License for more details.
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * You should have received a copy of the GNU Lesser General Public
Mark McLoughlin f9c1b7
+ * License along with this library; if not, write to the Free Software
Mark McLoughlin f9c1b7
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
Mark McLoughlin f9c1b7
+ *
Mark McLoughlin f9c1b7
+ * Author: Daniel P. Berrange <berrange@redhat.com>
Mark McLoughlin f9c1b7
+ */
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+#ifndef __VIR_STORAGE_FILE_H__
Mark McLoughlin f9c1b7
+#define __VIR_STORAGE_FILE_H__
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+#include "util.h"
Mark McLoughlin f9c1b7
+#include <stdbool.h>
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+enum virStorageFileFormat {
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_RAW = 0,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_DIR,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_BOCHS,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_CLOOP,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_COW,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_DMG,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_ISO,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_QCOW,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_QCOW2,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_VMDK,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_VPC,
Mark McLoughlin f9c1b7
+    VIR_STORAGE_FILE_LAST,
Mark McLoughlin f9c1b7
+};
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+VIR_ENUM_DECL(virStorageFileFormat);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+typedef struct _virStorageFileMetadata {
Mark McLoughlin f9c1b7
+    int format;
Mark McLoughlin f9c1b7
+    char *backingStore;
Mark McLoughlin f9c1b7
+    unsigned long long capacity;
Mark McLoughlin f9c1b7
+    bool encrypted;
Mark McLoughlin f9c1b7
+} virStorageFileMetadata;
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+int virStorageFileGetMetadata(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                              const char *path,
Mark McLoughlin f9c1b7
+                              virStorageFileMetadata *meta);
Mark McLoughlin f9c1b7
+int virStorageFileGetMetadataFromFD(virConnectPtr conn,
Mark McLoughlin f9c1b7
+                                    const char *path,
Mark McLoughlin f9c1b7
+                                    int fd,
Mark McLoughlin f9c1b7
+                                    virStorageFileMetadata *meta);
Mark McLoughlin f9c1b7
+
Mark McLoughlin f9c1b7
+#endif /* __VIR_STORAGE_FILE_H__ */
Mark McLoughlin f9c1b7
diff --git a/src/util.h b/src/util.h
Mark McLoughlin f9c1b7
index f9715ab..75afecc 100644
Mark McLoughlin f9c1b7
--- a/src/util.h
Mark McLoughlin f9c1b7
+++ b/src/util.h
Mark McLoughlin f9c1b7
@@ -26,6 +26,7 @@
Mark McLoughlin f9c1b7
 #define __VIR_UTIL_H__
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
 #include "verify.h"
Mark McLoughlin f9c1b7
+#include "internal.h"
Mark McLoughlin f9c1b7
 #include <sys/select.h>
Mark McLoughlin f9c1b7
 #include <sys/types.h>
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
Mark McLoughlin f9c1b7
index 7270710..783a216 100644
Mark McLoughlin f9c1b7
--- a/src/vbox/vbox_tmpl.c
Mark McLoughlin f9c1b7
+++ b/src/vbox/vbox_tmpl.c
Mark McLoughlin f9c1b7
@@ -45,6 +45,7 @@
Mark McLoughlin f9c1b7
 #include "virterror_internal.h"
Mark McLoughlin f9c1b7
 #include "domain_event.h"
Mark McLoughlin f9c1b7
 #include "storage_conf.h"
Mark McLoughlin f9c1b7
+#include "storage_file.h"
Mark McLoughlin f9c1b7
 #include "uuid.h"
Mark McLoughlin f9c1b7
 #include "event.h"
Mark McLoughlin f9c1b7
 #include "memory.h"
Mark McLoughlin f9c1b7
@@ -5980,14 +5981,14 @@ static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
         /* TODO: for now only the vmdk, vpc and vdi type harddisk
Mark McLoughlin f9c1b7
          * variants can be created, also since there is no vdi
Mark McLoughlin f9c1b7
-         * type in enum virStorageVolFormatFileSystem {} the default
Mark McLoughlin f9c1b7
+         * type in enum virStorageFileFormat {} the default
Mark McLoughlin f9c1b7
          * will be to create vdi if nothing is specified in
Mark McLoughlin f9c1b7
          * def->target.format
Mark McLoughlin f9c1b7
          */
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-        if (def->target.format == VIR_STORAGE_VOL_FILE_VMDK) {
Mark McLoughlin f9c1b7
+        if (def->target.format == VIR_STORAGE_FILE_VMDK) {
Mark McLoughlin f9c1b7
             data->pFuncs->pfnUtf8ToUtf16("VMDK", &hddFormatUtf16);
Mark McLoughlin f9c1b7
-        } else if (def->target.format == VIR_STORAGE_VOL_FILE_VPC) {
Mark McLoughlin f9c1b7
+        } else if (def->target.format == VIR_STORAGE_FILE_VPC) {
Mark McLoughlin f9c1b7
             data->pFuncs->pfnUtf8ToUtf16("VHD", &hddFormatUtf16);
Mark McLoughlin f9c1b7
         } else {
Mark McLoughlin f9c1b7
             data->pFuncs->pfnUtf8ToUtf16("VDI", &hddFormatUtf16);
Mark McLoughlin f9c1b7
@@ -6302,13 +6303,13 @@ static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags A
Mark McLoughlin f9c1b7
                             DEBUG("Storage Volume Format: %s", hddFormatUtf8);
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
                             if (STRCASEEQ("vmdk", hddFormatUtf8))
Mark McLoughlin f9c1b7
-                                def.target.format = VIR_STORAGE_VOL_FILE_VMDK;
Mark McLoughlin f9c1b7
+                                def.target.format = VIR_STORAGE_FILE_VMDK;
Mark McLoughlin f9c1b7
                             else if (STRCASEEQ("vhd", hddFormatUtf8))
Mark McLoughlin f9c1b7
-                                def.target.format = VIR_STORAGE_VOL_FILE_VPC;
Mark McLoughlin f9c1b7
+                                def.target.format = VIR_STORAGE_FILE_VPC;
Mark McLoughlin f9c1b7
                             else
Mark McLoughlin f9c1b7
-                                def.target.format = VIR_STORAGE_VOL_FILE_RAW;
Mark McLoughlin f9c1b7
+                                def.target.format = VIR_STORAGE_FILE_RAW;
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-                            /* TODO: need to add vdi to enum virStorageVolFormatFileSystem {}
Mark McLoughlin f9c1b7
+                            /* TODO: need to add vdi to enum virStorageFileFormat {}
Mark McLoughlin f9c1b7
                              * and then add it here
Mark McLoughlin f9c1b7
                              */
Mark McLoughlin f9c1b7
 
Mark McLoughlin f9c1b7
-- 
Mark McLoughlin f9c1b7
1.6.2.5
Mark McLoughlin f9c1b7