summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/virtualization/disk/DiskImageVdi.java
blob: 1e5b20b5445d8afab29c0dc681f3c1427d718a80 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package org.openslx.virtualization.disk;

import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import org.openslx.virtualization.Version;

/**
 * VDI disk image for virtual machines.
 * 
 * @author Manuel Bentele
 * @version 1.0
 */
public class DiskImageVdi extends DiskImage
{
	/**
	 * Big endian representation of the little endian VDI magic bytes (signature).
	 */
	private static final int VDI_MAGIC = 0x7f10dabe;
	/**
	 * Just 16 null-bytes
	 */
	private static final byte[] ZERO_UUID = new byte[16];

	/**
	 * Creates a new VDI disk image from an existing VDI image file.
	 * 
	 * @param diskImage file to a VDI disk storing the image content.
	 */
	DiskImageVdi( RandomAccessFile diskImage )
	{
		super( diskImage );
	}

	/**
	 * Probe specified file with unknown format to be a VDI disk image file.
	 * 
	 * @param diskImage file with unknown format that should be probed.
	 * @return state whether file is a VDI disk image or not.
	 * 
	 * @throws DiskImageException cannot probe specified file with unknown format.
	 */
	public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
	{
		final boolean isVdiImageFormat;

		// goto the beginning of the disk image to read the magic bytes
		// skip first 64 bytes (opening tag)
		final int diskImageMagic = DiskImageUtils.readInt( diskImage, 64 );

		// check if disk image's magic bytes can be found
		if ( diskImageMagic == DiskImageVdi.VDI_MAGIC ) {
			isVdiImageFormat = true;
		} else {
			isVdiImageFormat = false;
		}

		return isVdiImageFormat;
	}

	@Override
	public boolean isStandalone() throws DiskImageException
	{
		// VDI does not seem to support split VDI files, so VDI files are always standalone
		return true;
	}

	@Override
	public boolean isCompressed() throws DiskImageException
	{
		// compression is done by sparsifying the disk files, there is no flag for it
		return false;
	}

	@Override
	public boolean isSnapshot() throws DiskImageException
	{
		final RandomAccessFile diskFile = this.getDiskImage();

		// if parent UUID is set, the VDI file is a snapshot
		byte[] parentUuid = DiskImageUtils.readBytesAsArray( diskFile, 440, 16 );

		return !Arrays.equals( ZERO_UUID, parentUuid );
	}

	@Override
	public Version getVersion() throws DiskImageException
	{
		final RandomAccessFile diskFile = this.getDiskImage();

		final short vdiVersionMajor = Short.reverseBytes( DiskImageUtils.readShort( diskFile, 68 ) );
		final short vdiVersionMinor = Short.reverseBytes( DiskImageUtils.readShort( diskFile, 70 ) );

		return new Version( vdiVersionMajor, vdiVersionMinor );
	}

	@Override
	public String getDescription() throws DiskImageException
	{
		final RandomAccessFile diskFile = this.getDiskImage();
		byte[] data = DiskImageUtils.readBytesAsArray( diskFile, 84, 256 );
		// This will replace invalid chars. Maybe use CharsetDecoder and fall back to latin1 on error
		return new String( data, StandardCharsets.UTF_8 );
	}

	@Override
	public ImageFormat getFormat()
	{
		return ImageFormat.VDI;
	}
}