This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 7f13beb36a7 Check Qcow2 version before using --bitmaps (#10896)
7f13beb36a7 is described below

commit 7f13beb36a7b024449a8ed1e2edfbde1d41ab2dd
Author: João Jandre <[email protected]>
AuthorDate: Fri Jun 13 15:30:46 2025 -0300

    Check Qcow2 version before using --bitmaps (#10896)
    
    * check version before using --bitmaps
    
    * use cloudruntimeexception
---
 .../org/apache/cloudstack/utils/qemu/QemuImg.java  |  5 +++-
 .../storage/formatinspector/Qcow2Inspector.java    | 28 ++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git 
a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java
 
b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java
index 751a16a1554..608ad3c69cb 100644
--- 
a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java
+++ 
b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
 
+import org.apache.cloudstack.storage.formatinspector.Qcow2Inspector;
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.commons.lang3.StringUtils;
 import org.libvirt.LibvirtException;
@@ -53,6 +54,8 @@ public class QemuImg {
     public static final long QEMU_2_10 = 2010000;
     public static final long QEMU_5_10 = 5010000;
 
+    public static final int MIN_BITMAP_VERSION = 3;
+
     /* The qemu-img binary. We expect this to be in $PATH */
     public String _qemuImgPath = "qemu-img";
     private String cloudQemuImgPath = "cloud-qemu-img";
@@ -466,7 +469,7 @@ public class QemuImg {
             script.add(srcFile.getFileName());
         }
 
-        if (this.version >= QEMU_5_10 && keepBitmaps) {
+        if (this.version >= QEMU_5_10 && keepBitmaps && 
Qcow2Inspector.validateQcow2Version(srcFile.getFileName(), MIN_BITMAP_VERSION)) 
{
             script.add("--bitmaps");
         }
 
diff --git 
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java
 
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java
index 9d80064d292..bc06d749078 100644
--- 
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java
+++ 
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java
@@ -18,6 +18,7 @@
 package org.apache.cloudstack.storage.formatinspector;
 
 import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -25,6 +26,7 @@ import org.apache.logging.log4j.Logger;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -108,6 +110,32 @@ public class Qcow2Inspector {
         return result;
     }
 
+
+    /**
+     * Validates if the file has a minimum version.
+     * @param filePath Path of the file to be validated.
+     * @param minVersion the minimum version that it should contain.
+     * @throws RuntimeException If a IOException is thrown.
+     * @return true if file version is >= minVersion, false otherwise.
+     */
+    public static boolean validateQcow2Version(String filePath, int 
minVersion) {
+        try (InputStream inputStream = new FileInputStream(filePath)) {
+            for (Qcow2HeaderField qcow2Header : Qcow2HeaderField.values()) {
+                if (qcow2Header != Qcow2HeaderField.VERSION) {
+                    skipHeader(inputStream, qcow2Header, filePath);
+                    continue;
+                }
+
+                byte[] headerValue = readHeader(inputStream, qcow2Header, 
filePath);
+                int version = new BigInteger(headerValue).intValue();
+                return version >= minVersion;
+            }
+        } catch (IOException ex) {
+            throw new CloudRuntimeException(String.format("Unable to validate 
file [%s] due to: ", filePath), ex);
+        }
+        return false;
+    }
+
     /**
      * Skips the field's length in the InputStream.
      * @param qcow2InputStream InputStream of the QCOW2 being unraveled.

Reply via email to