]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
storage file: add qcow2 data-file path parsing from header
authorNikolai Barybin <nikolai.barybin@virtuozzo.com>
Wed, 20 Nov 2024 15:48:41 +0000 (18:48 +0300)
committerPeter Krempa <pkrempa@redhat.com>
Mon, 25 Nov 2024 21:31:18 +0000 (22:31 +0100)
In qcow2 header data file is represented by incompitible feature bit
and its path is saved to header extension table.
Thus, we implement here the logic similar to backing file probing.

Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
src/conf/storage_source_conf.c
src/conf/storage_source_conf.h
src/storage_file/storage_file_probe.c

index d4e39b9b57fc6448c37d459f5c2d3d0f6681fcdd..2b658dd485c0c7ce341f3baae3f2ef9220e74539 100644 (file)
@@ -69,6 +69,7 @@ VIR_ENUM_IMPL(virStorageFileFeature,
               VIR_STORAGE_FILE_FEATURE_LAST,
               "lazy_refcounts",
               "extended_l2",
+              "data_file",
 );
 
 
index aa2aa680de3de5e4c2da53c6988efd3e217109f7..94637225181a8f4a6434ed4ca965669892074d6f 100644 (file)
@@ -88,6 +88,7 @@ VIR_ENUM_DECL(virStorageFileFormat);
 typedef enum {
     VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS = 0,
     VIR_STORAGE_FILE_FEATURE_EXTENDED_L2,
+    VIR_STORAGE_FILE_FEATURE_DATA_FILE,
 
     VIR_STORAGE_FILE_FEATURE_LAST
 } virStorageFileFeature;
index ad14350edc5a4178298e4add0051eba7f26f71c6..f5c50d4597bf390355adea4fe7b6f933b26d5d42 100644 (file)
@@ -106,6 +106,7 @@ qcow2GetClusterSize(const char *buf,
                     size_t buf_size);
 static int qcowXGetBackingStore(char **, int *,
                                 const char *, size_t);
+static int qcow2GetDataFile(char **, virBitmap *, char *, size_t);
 static int qcow2GetFeatures(virBitmap **features, int format,
                             char *buf, ssize_t len);
 static int vmdk4GetBackingStore(char **, int *,
@@ -127,6 +128,7 @@ qedGetBackingStore(char **, int *, const char *, size_t);
 
 #define QCOW2_HDR_EXTENSION_END 0
 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
+#define QCOW2_HDR_EXTENSION_DATA_FILE_NAME 0x44415441
 
 #define QCOW2v3_HDR_FEATURES_INCOMPATIBLE (QCOW2_HDR_TOTAL_SIZE)
 #define QCOW2v3_HDR_FEATURES_COMPATIBLE (QCOW2v3_HDR_FEATURES_INCOMPATIBLE+8)
@@ -314,7 +316,7 @@ static struct FileTypeInfo const fileTypeInfo[] = {
         qcow2EncryptionInfo,
         qcow2GetClusterSize,
         qcowXGetBackingStore,
-        NULL,
+        qcow2GetDataFile,
         qcow2GetFeatures
     },
     [VIR_STORAGE_FILE_QED] = {
@@ -361,7 +363,7 @@ enum qcow2IncompatibleFeature {
 static const virStorageFileFeature qcow2IncompatibleFeatureArray[] = {
     VIR_STORAGE_FILE_FEATURE_LAST, /* QCOW2_INCOMPATIBLE_FEATURE_DIRTY */
     VIR_STORAGE_FILE_FEATURE_LAST, /* QCOW2_INCOMPATIBLE_FEATURE_CORRUPT */
-    VIR_STORAGE_FILE_FEATURE_LAST, /* QCOW2_INCOMPATIBLE_FEATURE_DATA_FILE */
+    VIR_STORAGE_FILE_FEATURE_DATA_FILE, /* QCOW2_INCOMPATIBLE_FEATURE_DATA_FILE */
     VIR_STORAGE_FILE_FEATURE_LAST, /* QCOW2_INCOMPATIBLE_FEATURE_COMPRESSION */
     VIR_STORAGE_FILE_FEATURE_EXTENDED_L2, /* QCOW2_INCOMPATIBLE_FEATURE_EXTL2 */
 };
@@ -393,7 +395,8 @@ cowGetBackingStore(char **res,
 static int
 qcow2GetExtensions(const char *buf,
                    size_t buf_size,
-                   int *backingFormat)
+                   int *backingFormat,
+                   char **dataFilePath)
 {
     size_t offset;
     size_t extension_start;
@@ -488,6 +491,15 @@ qcow2GetExtensions(const char *buf,
             break;
         }
 
+        case QCOW2_HDR_EXTENSION_DATA_FILE_NAME: {
+            if (!dataFilePath)
+                break;
+
+            *dataFilePath = g_new0(char, len + 1);
+            memcpy(*dataFilePath, buf + offset, len);
+            break;
+        }
+
         case QCOW2_HDR_EXTENSION_END:
             return 0;
         }
@@ -554,9 +566,29 @@ qcowXGetBackingStore(char **res,
     memcpy(*res, buf + offset, size);
     (*res)[size] = '\0';
 
-    if (qcow2GetExtensions(buf, buf_size, format) < 0)
+    if (qcow2GetExtensions(buf, buf_size, format, NULL) < 0)
+        return 0;
+
+    return 0;
+}
+
+
+static int
+qcow2GetDataFile(char **res,
+                 virBitmap *features,
+                 char *buf,
+                 size_t buf_size)
+{
+    *res = NULL;
+
+    if (buf_size < QCOW2v3_HDR_FEATURES_INCOMPATIBLE + 8)
         return 0;
 
+    if (features && virBitmapIsBitSet(features, VIR_STORAGE_FILE_FEATURE_DATA_FILE)) {
+        if (qcow2GetExtensions(buf, buf_size, NULL, res) < 0)
+            return -1;
+    }
+
     return 0;
 }
 
@@ -968,6 +1000,12 @@ virStorageFileProbeGetMetadata(virStorageSource *meta,
         fileTypeInfo[meta->format].getFeatures(&meta->features, meta->format, buf, len) < 0)
         return -1;
 
+    VIR_FREE(meta->dataFileRaw);
+    if (fileTypeInfo[meta->format].getDataFile != NULL) {
+        fileTypeInfo[meta->format].getDataFile(&meta->dataFileRaw, meta->features,
+                                               buf, len);
+    }
+
     VIR_FREE(meta->compat);
     if (meta->format == VIR_STORAGE_FILE_QCOW2 && meta->features)
         meta->compat = g_strdup("1.1");