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.