From 8a0d508f5a04f930e9945131db4f70591fd02e12 Mon Sep 17 00:00:00 2001 From: Victor Mocanu Date: Mon, 16 Apr 2018 17:14:45 +0200 Subject: [vbox] add support for VirtualBox --- src/main/java/org/openslx/util/vm/DiskImage.java | 117 ++++++++++++++++++----- 1 file changed, 91 insertions(+), 26 deletions(-) (limited to 'src/main/java/org/openslx/util/vm/DiskImage.java') diff --git a/src/main/java/org/openslx/util/vm/DiskImage.java b/src/main/java/org/openslx/util/vm/DiskImage.java index 80eec2a..622c1a4 100644 --- a/src/main/java/org/openslx/util/vm/DiskImage.java +++ b/src/main/java/org/openslx/util/vm/DiskImage.java @@ -5,16 +5,19 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; +import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.Virtualizer; import org.openslx.util.Util; public class DiskImage { - /** * Big endian representation of the 4 bytes 'KDMV' */ private static final int VMDK_MAGIC = 0x4b444d56; + private static final String VDI_PREFIX = "<<< "; + private static final String VDI_SUFFIX = "Disk Image >>>"; + private static final String QEMU = "QFI"; public enum ImageFormat { @@ -42,6 +45,8 @@ public class DiskImage return VMDK; if ( virtId.equals( "virtualbox" ) ) return VDI; + if ( virtId.equals( "qemukvm" ) ) + return QCOW2; return null; } } @@ -53,32 +58,94 @@ public class DiskImage public final String subFormat; public final int hwVersion; - public DiskImage( File disk ) throws FileNotFoundException, IOException, - UnknownImageFormatException + public ImageFormat getImageFormat() + { + return format; + } + + public DiskImage( File disk ) throws FileNotFoundException, IOException, UnknownImageFormatException { - // For now we only support VMDK... try ( RandomAccessFile file = new RandomAccessFile( disk, "r" ) ) { - if ( file.readInt() != VMDK_MAGIC ) - throw new UnknownImageFormatException(); - file.seek( 512 ); - byte[] buffer = new byte[ 2048 ]; - file.readFully( buffer ); - VmwareConfig config = new VmwareConfig( buffer, findNull( buffer ) ); - subFormat = config.get( "createType" ); - String parent = config.get( "parentCID" ); - this.isStandalone = isStandaloneCreateType( subFormat, parent ); - this.isCompressed = subFormat != null - && subFormat.equalsIgnoreCase( "streamOptimized" ); - this.isSnapshot = parent != null - && !parent.equalsIgnoreCase( "ffffffff" ); - this.format = ImageFormat.VMDK; - String hwv = config.get( "ddb.virtualHWVersion" ); - if (hwv == null ) { - this.hwVersion = 10; - } else { - this.hwVersion = Util.parseInt( hwv, 10 ); + // vmdk + if ( file.readInt() == VMDK_MAGIC ) { + file.seek( 512 ); + byte[] buffer = new byte[ 2048 ]; + file.readFully( buffer ); + VmwareConfig config; + try { + config = new VmwareConfig( buffer, findNull( buffer ) ); + } catch ( UnsupportedVirtualizerFormatException e ) { + config = null; + } + if ( config != null ) { + subFormat = config.get( "createType" ); + String parent = config.get( "parentCID" ); + this.isStandalone = isStandaloneCreateType( subFormat, parent ); + this.isCompressed = subFormat != null && subFormat.equalsIgnoreCase( "streamOptimized" ); + this.isSnapshot = parent != null && !parent.equalsIgnoreCase( "ffffffff" ); + this.format = ImageFormat.VMDK; + String hwv = config.get( "ddb.virtualHWVersion" ); + if ( hwv == null ) { + this.hwVersion = 10; + } else { + this.hwVersion = Util.parseInt( hwv, 10 ); + } + return; + } + } + // vdi + file.seek( 0 ); + byte[] prefixBuffer = new byte[ VDI_PREFIX.length() ]; + file.readFully( prefixBuffer ); + String prefixString = new String( prefixBuffer ); + if ( VDI_PREFIX.equals( prefixString ) ) { + + byte[] localBuffer = new byte[ 1 ]; + byte[] suffixBuffer = new byte[ VDI_SUFFIX.length() - 1 ]; + // 30 in this case would be the remaining length of the vdi header + // the longest string to date would be "<<< QEMU VM Virtual Disk Image >>>" + // if the loop doesn't find the first letter of the VID_SUFFIX then we have another format on our hands and should throw exception + for ( int i = 0; i < 30; i++ ) { + file.readFully( localBuffer ); + String localString = new String( localBuffer ); + + if ( !localString.equals( VDI_SUFFIX.substring( 0, 1 ) ) ) { + continue; + } + file.readFully( suffixBuffer ); + String suffixString = new String( suffixBuffer ); + if ( suffixString.equals( VDI_SUFFIX.substring( 1 ) ) ) { + // TODO still don't know where they are found in a .vdi file + this.isStandalone = true; + this.isCompressed = false; + this.isSnapshot = false; + this.format = ImageFormat.VDI; + this.subFormat = ""; + this.hwVersion = 0; + return; + } else { + // this will ensure the search doesn't stop at the first D we find + file.seek( i + VDI_PREFIX.length() + 1 ); + } + } + } + //qcow + file.seek( 0 ); + byte[] qcowBuffer = new byte[ QEMU.length() ]; + file.readFully( qcowBuffer ); + String qcowString = new String( qcowBuffer ); + if ( QEMU.equals( qcowString ) ) { + // dummy values + this.isStandalone = true; + this.isCompressed = false; + this.isSnapshot = false; + this.format = ImageFormat.QCOW2; + this.subFormat = ""; + this.hwVersion = 0; + return; } } + throw new UnknownImageFormatException(); } private int findNull( byte[] buffer ) @@ -96,13 +163,11 @@ public class DiskImage return false; if ( parent != null && !parent.equalsIgnoreCase( "ffffffff" ) ) return false; - return type.equalsIgnoreCase( "streamOptimized" ) - || type.equalsIgnoreCase( "monolithicSparse" ); + return type.equalsIgnoreCase( "streamOptimized" ) || type.equalsIgnoreCase( "monolithicSparse" ); } public static class UnknownImageFormatException extends Exception { private static final long serialVersionUID = -6647935235475007171L; } - } -- cgit v1.2.3-55-g7522