Daniel P. Berrange e3a592
From 57482ca0be29e9e92e242c9acb577e0b770c01d1 Mon Sep 17 00:00:00 2001
Daniel P. Berrange e3a592
From: Daniel P. Berrange <berrange@redhat.com>
Daniel P. Berrange e3a592
Date: Tue, 15 Jun 2010 14:58:10 +0100
Daniel P. Berrange e3a592
Subject: [PATCH 03/11] Refactor virStorageFileGetMetadataFromFD to separate functionality
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
The virStorageFileGetMetadataFromFD did two jobs in one. First
Daniel P. Berrange e3a592
it probed for storage type, then it extracted metadata for the
Daniel P. Berrange e3a592
type. It is desirable to be able to separate these jobs, allowing
Daniel P. Berrange e3a592
probing without querying metadata, and querying metadata without
Daniel P. Berrange e3a592
probing.
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
To prepare for this, split out probing code into a new pair of
Daniel P. Berrange e3a592
methods
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
  virStorageFileProbeFormatFromFD
Daniel P. Berrange e3a592
  virStorageFileProbeFormat
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
* src/util/storage_file.c, src/util/storage_file.h,
Daniel P. Berrange e3a592
  src/libvirt_private.syms: Introduce virStorageFileProbeFormat
Daniel P. Berrange e3a592
  and virStorageFileProbeFormatFromFD
Daniel P. Berrange e3a592
---
Daniel P. Berrange e3a592
 src/libvirt_private.syms |    2 +
Daniel P. Berrange e3a592
 src/util/storage_file.c  |  460 +++++++++++++++++++++++++++++++++-------------
Daniel P. Berrange e3a592
 src/util/storage_file.h  |    4 +
Daniel P. Berrange e3a592
 3 files changed, 335 insertions(+), 131 deletions(-)
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
Daniel P. Berrange e3a592
index 778ceb1..4607f49 100644
Daniel P. Berrange e3a592
--- a/src/libvirt_private.syms
Daniel P. Berrange e3a592
+++ b/src/libvirt_private.syms
Daniel P. Berrange e3a592
@@ -628,6 +628,8 @@ virStorageGenerateQcowPassphrase;
Daniel P. Berrange e3a592
 # storage_file.h
Daniel P. Berrange e3a592
 virStorageFileFormatTypeToString;
Daniel P. Berrange e3a592
 virStorageFileFormatTypeFromString;
Daniel P. Berrange e3a592
+virStorageFileProbeFormat;
Daniel P. Berrange e3a592
+virStorageFileProbeFormatFromFD;
Daniel P. Berrange e3a592
 virStorageFileGetMetadata;
Daniel P. Berrange e3a592
 virStorageFileGetMetadataFromFD;
Daniel P. Berrange e3a592
 virStorageFileIsSharedFS;
Daniel P. Berrange e3a592
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
Daniel P. Berrange e3a592
index df0e3a1..221268b 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
@@ -104,6 +104,9 @@ static int vmdk4GetBackingStore(char **, int *,
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
+/* VMDK needs at least this to find backing store,
Daniel P. Berrange e3a592
+ * other formats are less */
Daniel P. Berrange e3a592
+#define STORAGE_MAX_HEAD (20*512)
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 static struct FileTypeInfo const fileTypeInfo[] = {
Daniel P. Berrange e3a592
@@ -349,9 +352,14 @@ vmdk4GetBackingStore(char **res,
Daniel P. Berrange e3a592
                      size_t buf_size)
Daniel P. Berrange e3a592
 {
Daniel P. Berrange e3a592
     static const char prefix[] = "parentFileNameHint=\"";
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-    char desc[20*512 + 1], *start, *end;
Daniel P. Berrange e3a592
+    char *desc, *start, *end;
Daniel P. Berrange e3a592
     size_t len;
Daniel P. Berrange e3a592
+    int ret = BACKING_STORE_ERROR;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (VIR_ALLOC_N(desc, STORAGE_MAX_HEAD + 1) < 0) {
Daniel P. Berrange e3a592
+        virReportOOMError();
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     *res = NULL;
Daniel P. Berrange e3a592
     /*
Daniel P. Berrange e3a592
@@ -363,29 +371,42 @@ vmdk4GetBackingStore(char **res,
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
+    if (buf_size <= 0x200) {
Daniel P. Berrange e3a592
+        ret = BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
     len = buf_size - 0x200;
Daniel P. Berrange e3a592
-    if (len > sizeof(desc) - 1)
Daniel P. Berrange e3a592
-        len = sizeof(desc) - 1;
Daniel P. Berrange e3a592
+    if (len > STORAGE_MAX_HEAD)
Daniel P. Berrange e3a592
+        len = STORAGE_MAX_HEAD;
Daniel P. Berrange e3a592
     memcpy(desc, buf + 0x200, len);
Daniel P. Berrange e3a592
     desc[len] = '\0';
Daniel P. Berrange e3a592
     start = strstr(desc, prefix);
Daniel P. Berrange e3a592
-    if (start == NULL)
Daniel P. Berrange e3a592
-        return BACKING_STORE_OK;
Daniel P. Berrange e3a592
+    if (start == NULL) {
Daniel P. Berrange e3a592
+        ret = BACKING_STORE_OK;
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
     start += strlen(prefix);
Daniel P. Berrange e3a592
     end = strchr(start, '"');
Daniel P. Berrange e3a592
-    if (end == NULL)
Daniel P. Berrange e3a592
-        return BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
-    if (end == start)
Daniel P. Berrange e3a592
-        return BACKING_STORE_OK;
Daniel P. Berrange e3a592
+    if (end == NULL) {
Daniel P. Berrange e3a592
+        ret = BACKING_STORE_INVALID;
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+    if (end == start) {
Daniel P. Berrange e3a592
+        ret = BACKING_STORE_OK;
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
     *end = '\0';
Daniel P. Berrange e3a592
     *res = strdup(start);
Daniel P. Berrange e3a592
     if (*res == NULL) {
Daniel P. Berrange e3a592
         virReportOOMError();
Daniel P. Berrange e3a592
-        return BACKING_STORE_ERROR;
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
-    return BACKING_STORE_OK;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    ret = BACKING_STORE_OK;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+cleanup:
Daniel P. Berrange e3a592
+    VIR_FREE(desc);
Daniel P. Berrange e3a592
+    return ret;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
 /**
Daniel P. Berrange e3a592
@@ -411,148 +432,325 @@ absolutePathFromBaseFile(const char *base_file, const char *path)
Daniel P. Berrange e3a592
     return res;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-/**
Daniel P. Berrange e3a592
- * Probe the header of a file to determine what type of disk image
Daniel P. Berrange e3a592
- * it is, and info about its capacity if available.
Daniel P. Berrange e3a592
- */
Daniel P. Berrange e3a592
-int
Daniel P. Berrange e3a592
-virStorageFileGetMetadataFromFD(const char *path,
Daniel P. Berrange e3a592
-                                int fd,
Daniel P. Berrange e3a592
-                                virStorageFileMetadata *meta)
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static bool
Daniel P. Berrange e3a592
+virStorageFileMatchesMagic(int format,
Daniel P. Berrange e3a592
+                           unsigned char *buf,
Daniel P. Berrange e3a592
+                           size_t buflen)
Daniel P. Berrange e3a592
 {
Daniel P. Berrange e3a592
-    unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
Daniel P. Berrange e3a592
-    int len, i;
Daniel P. Berrange e3a592
+    int mlen;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    memset(meta, 0, sizeof (*meta));
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].magic == NULL)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    /* If all else fails, call it a raw file */
Daniel P. Berrange e3a592
-    meta->format = VIR_STORAGE_FILE_RAW;
Daniel P. Berrange e3a592
+    /* Validate magic data */
Daniel P. Berrange e3a592
+    mlen = strlen(fileTypeInfo[format].magic);
Daniel P. Berrange e3a592
+    if (mlen > buflen)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    if ((len = read(fd, head, sizeof(head))) < 0) {
Daniel P. Berrange e3a592
-        virReportSystemError(errno, _("cannot read header '%s'"), path);
Daniel P. Berrange e3a592
-        return -1;
Daniel P. Berrange e3a592
+    if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    return true;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static bool
Daniel P. Berrange e3a592
+virStorageFileMatchesExtension(int format,
Daniel P. Berrange e3a592
+                               const char *path)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].extension == NULL)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (virFileHasSuffix(path, fileTypeInfo[format].extension))
Daniel P. Berrange e3a592
+        return true;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    return false;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static bool
Daniel P. Berrange e3a592
+virStorageFileMatchesVersion(int format,
Daniel P. Berrange e3a592
+                             unsigned char *buf,
Daniel P. Berrange e3a592
+                             size_t buflen)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    int version;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    /* Validate version number info */
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].versionOffset == -1)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if ((fileTypeInfo[format].versionOffset + 4) > buflen)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) {
Daniel P. Berrange e3a592
+        version =
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset+3] << 24) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset+2] << 16) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset+1] << 8) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset]);
Daniel P. Berrange e3a592
+    } else {
Daniel P. Berrange e3a592
+        version =
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset] << 24) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset+1] << 16) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset+2] << 8) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].versionOffset+3]);
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
+    if (version != fileTypeInfo[format].versionNumber)
Daniel P. Berrange e3a592
+        return false;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    /* First check file magic */
Daniel P. Berrange e3a592
-    for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
Daniel P. Berrange e3a592
-        int mlen;
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-        if (fileTypeInfo[i].magic == NULL)
Daniel P. Berrange e3a592
-            continue;
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-        /* Validate magic data */
Daniel P. Berrange e3a592
-        mlen = strlen(fileTypeInfo[i].magic);
Daniel P. Berrange e3a592
-        if (mlen > len)
Daniel P. Berrange e3a592
-            continue;
Daniel P. Berrange e3a592
-        if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
Daniel P. Berrange e3a592
-            continue;
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-        /* Validate version number info */
Daniel P. Berrange e3a592
-        if (fileTypeInfo[i].versionNumber != -1) {
Daniel P. Berrange e3a592
-            int version;
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-            if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
Daniel P. Berrange e3a592
-                version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
Daniel P. Berrange e3a592
-                    (head[fileTypeInfo[i].versionOffset+2] << 16) |
Daniel P. Berrange e3a592
-                    (head[fileTypeInfo[i].versionOffset+1] << 8) |
Daniel P. Berrange e3a592
-                    head[fileTypeInfo[i].versionOffset];
Daniel P. Berrange e3a592
-            } else {
Daniel P. Berrange e3a592
-                version = (head[fileTypeInfo[i].versionOffset] << 24) |
Daniel P. Berrange e3a592
-                    (head[fileTypeInfo[i].versionOffset+1] << 16) |
Daniel P. Berrange e3a592
-                    (head[fileTypeInfo[i].versionOffset+2] << 8) |
Daniel P. Berrange e3a592
-                    head[fileTypeInfo[i].versionOffset+3];
Daniel P. Berrange e3a592
-            }
Daniel P. Berrange e3a592
-            if (version != fileTypeInfo[i].versionNumber)
Daniel P. Berrange e3a592
-                continue;
Daniel P. Berrange e3a592
-        }
Daniel P. Berrange e3a592
+    return true;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-        /* Optionally extract capacity from file */
Daniel P. Berrange e3a592
-        if (fileTypeInfo[i].sizeOffset != -1) {
Daniel P. Berrange e3a592
-            if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
Daniel P. Berrange e3a592
-                meta->capacity =
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
Daniel P. Berrange e3a592
-            } else {
Daniel P. Berrange e3a592
-                meta->capacity =
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) |
Daniel P. Berrange e3a592
-                    ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
Daniel P. Berrange e3a592
-            }
Daniel P. Berrange e3a592
-            /* Avoid unlikely, but theoretically possible overflow */
Daniel P. Berrange e3a592
-            if (meta->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
Daniel P. Berrange e3a592
-                continue;
Daniel P. Berrange e3a592
-            meta->capacity *= fileTypeInfo[i].sizeMultiplier;
Daniel P. Berrange e3a592
-        }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-        if (fileTypeInfo[i].qcowCryptOffset != -1) {
Daniel P. Berrange e3a592
-            int crypt_format;
Daniel P. Berrange e3a592
+static int
Daniel P. Berrange e3a592
+virStorageFileGetMetadataFromBuf(int format,
Daniel P. Berrange e3a592
+                                 const char *path,
Daniel P. Berrange e3a592
+                                 unsigned char *buf,
Daniel P. Berrange e3a592
+                                 size_t buflen,
Daniel P. Berrange e3a592
+                                 virStorageFileMetadata *meta)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    /* XXX we should consider moving virStorageBackendUpdateVolInfo
Daniel P. Berrange e3a592
+     * code into this method, for non-magic files
Daniel P. Berrange e3a592
+     */
Daniel P. Berrange e3a592
+    if (!fileTypeInfo[format].magic) {
Daniel P. Berrange e3a592
+        return 0;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-            crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) |
Daniel P. Berrange e3a592
-                (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) |
Daniel P. Berrange e3a592
-                (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) |
Daniel P. Berrange e3a592
-                head[fileTypeInfo[i].qcowCryptOffset+3];
Daniel P. Berrange e3a592
-            meta->encrypted = crypt_format != 0;
Daniel P. Berrange e3a592
+    /* Optionally extract capacity from file */
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].sizeOffset != -1) {
Daniel P. Berrange e3a592
+        if ((fileTypeInfo[format].sizeOffset + 8) > buflen)
Daniel P. Berrange e3a592
+            return 1;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) {
Daniel P. Berrange e3a592
+            meta->capacity =
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7] << 56) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 48) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 40) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 32) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 24) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 16) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 8) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset]);
Daniel P. Berrange e3a592
+        } else {
Daniel P. Berrange e3a592
+            meta->capacity =
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset] << 56) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 48) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 40) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 32) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 24) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 16) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 8) |
Daniel P. Berrange e3a592
+                ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7]);
Daniel P. Berrange e3a592
         }
Daniel P. Berrange e3a592
+        /* Avoid unlikely, but theoretically possible overflow */
Daniel P. Berrange e3a592
+        if (meta->capacity > (ULLONG_MAX / fileTypeInfo[format].sizeMultiplier))
Daniel P. Berrange e3a592
+            return 1;
Daniel P. Berrange e3a592
+        meta->capacity *= fileTypeInfo[format].sizeMultiplier;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-        /* Validation passed, we know the file format now */
Daniel P. Berrange e3a592
-        meta->format = i;
Daniel P. Berrange e3a592
-        if (fileTypeInfo[i].getBackingStore != NULL) {
Daniel P. Berrange e3a592
-            char *backing;
Daniel P. Berrange e3a592
-            int backingFormat;
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].qcowCryptOffset != -1) {
Daniel P. Berrange e3a592
+        int crypt_format;
Daniel P. Berrange e3a592
 
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
+        crypt_format =
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].qcowCryptOffset] << 24) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].qcowCryptOffset+1] << 16) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].qcowCryptOffset+2] << 8) |
Daniel P. Berrange e3a592
+            (buf[fileTypeInfo[format].qcowCryptOffset+3]);
Daniel P. Berrange e3a592
+        meta->encrypted = crypt_format != 0;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-            case BACKING_STORE_INVALID:
Daniel P. Berrange e3a592
-                continue;
Daniel P. Berrange e3a592
+    if (fileTypeInfo[format].getBackingStore != NULL) {
Daniel P. Berrange e3a592
+        char *backing;
Daniel P. Berrange e3a592
+        int backingFormat;
Daniel P. Berrange e3a592
+        int ret = fileTypeInfo[format].getBackingStore(&backing,
Daniel P. Berrange e3a592
+                                                       &backingFormat,
Daniel P. Berrange e3a592
+                                                       buf, buflen);
Daniel P. Berrange e3a592
+        if (ret == BACKING_STORE_INVALID)
Daniel P. Berrange e3a592
+            return 1;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        if (ret == BACKING_STORE_ERROR)
Daniel P. Berrange e3a592
+            return -1;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-            case BACKING_STORE_ERROR:
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
-            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
+            meta->backingStoreFormat = backingFormat;
Daniel P. Berrange e3a592
+        } else {
Daniel P. Berrange e3a592
+            meta->backingStore = NULL;
Daniel P. Berrange e3a592
+            meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
Daniel P. Berrange e3a592
+        }
Daniel P. Berrange e3a592
+    }
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
+virStorageFileProbeFormatFromBuf(const char *path,
Daniel P. Berrange e3a592
+                                 unsigned char *buf,
Daniel P. Berrange e3a592
+                                 size_t buflen)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    int format = VIR_STORAGE_FILE_RAW;
Daniel P. Berrange e3a592
+    int i;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    /* First check file magic */
Daniel P. Berrange e3a592
+    for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) {
Daniel P. Berrange e3a592
+        if (virStorageFileMatchesMagic(i, buf, buflen) &&
Daniel P. Berrange e3a592
+            virStorageFileMatchesVersion(i, buf, buflen)) {
Daniel P. Berrange e3a592
+            format = i;
Daniel P. Berrange e3a592
+            goto cleanup;
Daniel P. Berrange e3a592
         }
Daniel P. Berrange e3a592
-        return 0;
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     /* No magic, so check file extension */
Daniel P. Berrange e3a592
-    for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
Daniel P. Berrange e3a592
-        if (fileTypeInfo[i].extension == NULL)
Daniel P. Berrange e3a592
-            continue;
Daniel P. Berrange e3a592
+    for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) {
Daniel P. Berrange e3a592
+        if (virStorageFileMatchesExtension(i, path)) {
Daniel P. Berrange e3a592
+            format = i;
Daniel P. Berrange e3a592
+            goto cleanup;
Daniel P. Berrange e3a592
+        }
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-        if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
Daniel P. Berrange e3a592
-            continue;
Daniel P. Berrange e3a592
+cleanup:
Daniel P. Berrange e3a592
+    return format;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-        meta->format = i;
Daniel P. Berrange e3a592
-        return 0;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+/**
Daniel P. Berrange e3a592
+ * virStorageFileProbeFormatFromFD:
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Probe for the format of 'fd' (which is an open file descriptor
Daniel P. Berrange e3a592
+ * pointing to 'path'), returning the detected disk format.
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Callers are advised never to trust the returned 'format'
Daniel P. Berrange e3a592
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
Daniel P. Berrange e3a592
+ * malicious guest can turn a file into any other non-raw
Daniel P. Berrange e3a592
+ * format at will.
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Best option: Don't use this function
Daniel P. Berrange e3a592
+ */
Daniel P. Berrange e3a592
+int
Daniel P. Berrange e3a592
+virStorageFileProbeFormatFromFD(const char *path, int fd)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    unsigned char *head;
Daniel P. Berrange e3a592
+    ssize_t len = STORAGE_MAX_HEAD;
Daniel P. Berrange e3a592
+    int ret = -1;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (VIR_ALLOC_N(head, len) < 0) {
Daniel P. Berrange e3a592
+        virReportOOMError();
Daniel P. Berrange e3a592
+        return -1;
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    return 0;
Daniel P. Berrange e3a592
+    if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
Daniel P. Berrange e3a592
+        virReportSystemError(errno, _("cannot set to start of '%s'"), path);
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if ((len = read(fd, head, len)) < 0) {
Daniel P. Berrange e3a592
+        virReportSystemError(errno, _("cannot read header '%s'"), path);
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    ret = virStorageFileProbeFormatFromBuf(path, head, len);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+cleanup:
Daniel P. Berrange e3a592
+    VIR_FREE(head);
Daniel P. Berrange e3a592
+    return ret;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+/**
Daniel P. Berrange e3a592
+ * virStorageFileProbeFormat:
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Probe for the format of 'path', returning the detected
Daniel P. Berrange e3a592
+ * disk format.
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Callers are advised never to trust the returned 'format'
Daniel P. Berrange e3a592
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
Daniel P. Berrange e3a592
+ * malicious guest can turn a raw file into any other non-raw
Daniel P. Berrange e3a592
+ * format at will.
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Best option: Don't use this function
Daniel P. Berrange e3a592
+ */
Daniel P. Berrange e3a592
+int
Daniel P. Berrange e3a592
+virStorageFileProbeFormat(const char *path)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    int fd, ret;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if ((fd = open(path, O_RDONLY)) < 0) {
Daniel P. Berrange e3a592
+        virReportSystemError(errno, _("cannot open file '%s'"), path);
Daniel P. Berrange e3a592
+        return -1;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    ret = virStorageFileProbeFormatFromFD(path, fd);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    close(fd);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    return ret;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
+/**
Daniel P. Berrange e3a592
+ * virStorageFileGetMetadataFromFD:
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Probe for the format of 'fd' (which is an open file descriptor
Daniel P. Berrange e3a592
+ * for the file 'path'), filling 'meta' with the detected
Daniel P. Berrange e3a592
+ * format and other associated metadata.
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Callers are advised never to trust the returned 'meta->format'
Daniel P. Berrange e3a592
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
Daniel P. Berrange e3a592
+ * malicious guest can turn a raw file into any other non-raw
Daniel P. Berrange e3a592
+ * format at will.
Daniel P. Berrange e3a592
+ */
Daniel P. Berrange e3a592
+int
Daniel P. Berrange e3a592
+virStorageFileGetMetadataFromFD(const char *path,
Daniel P. Berrange e3a592
+                                int fd,
Daniel P. Berrange e3a592
+                                virStorageFileMetadata *meta)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    unsigned char *head;
Daniel P. Berrange e3a592
+    ssize_t len = STORAGE_MAX_HEAD;
Daniel P. Berrange e3a592
+    int ret = -1;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (VIR_ALLOC_N(head, len) < 0) {
Daniel P. Berrange e3a592
+        virReportOOMError();
Daniel P. Berrange e3a592
+        return -1;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    memset(meta, 0, sizeof (*meta));
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
Daniel P. Berrange e3a592
+        virReportSystemError(errno, _("cannot set to start of '%s'"), path);
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if ((len = read(fd, head, len)) < 0) {
Daniel P. Berrange e3a592
+        virReportSystemError(errno, _("cannot read header '%s'"), path);
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    meta->format = virStorageFileProbeFormatFromBuf(path, head, len);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+cleanup:
Daniel P. Berrange e3a592
+    VIR_FREE(head);
Daniel P. Berrange e3a592
+    return ret;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+/**
Daniel P. Berrange e3a592
+ * virStorageFileGetMetadata:
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Probe for the format of 'path', filling 'meta' with the detected
Daniel P. Berrange e3a592
+ * format and other associated metadata.
Daniel P. Berrange e3a592
+ *
Daniel P. Berrange e3a592
+ * Callers are advised never to trust the returned 'meta->format'
Daniel P. Berrange e3a592
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
Daniel P. Berrange e3a592
+ * malicious guest can turn a raw file into any other non-raw
Daniel P. Berrange e3a592
+ * format at will.
Daniel P. Berrange e3a592
+ */
Daniel P. Berrange e3a592
 int
Daniel P. Berrange e3a592
 virStorageFileGetMetadata(const char *path,
Daniel P. Berrange e3a592
                           virStorageFileMetadata *meta)
Daniel P. Berrange e3a592
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
Daniel P. Berrange e3a592
index 6328ba7..3420d44 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
@@ -57,6 +57,10 @@ typedef struct _virStorageFileMetadata {
Daniel P. Berrange e3a592
 #  define DEV_BSIZE 512
Daniel P. Berrange e3a592
 # endif
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
+int virStorageFileProbeFormat(const char *path);
Daniel P. Berrange e3a592
+int virStorageFileProbeFormatFromFD(const char *path,
Daniel P. Berrange e3a592
+                                    int fd);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
 int virStorageFileGetMetadata(const char *path,
Daniel P. Berrange e3a592
                               virStorageFileMetadata *meta);
Daniel P. Berrange e3a592
 int virStorageFileGetMetadataFromFD(const char *path,
Daniel P. Berrange e3a592
-- 
Daniel P. Berrange e3a592
1.7.1.1
Daniel P. Berrange e3a592