use std::path::Path;
use super::header::{MAGIC, SECTOR_SIZE, VERSION, VERSION_STREAM_OPT};
const DESCRIPTOR_OFFSET: u64 = 1;
const DESCRIPTOR_SECTORS: u64 = 20;
const GD_SECTOR: u64 = DESCRIPTOR_OFFSET + DESCRIPTOR_SECTORS; const RGD_SECTOR: u64 = GD_SECTOR + 1; const GT_SECTOR: u64 = RGD_SECTOR + 1; const GT_SECTORS: u64 = 4; const GRAIN_SECTOR: u64 = GT_SECTOR + GT_SECTORS;
pub const GRAIN_SIZE_SECTORS: u64 = 8;
pub const GRAIN_SIZE_BYTES: usize = GRAIN_SIZE_SECTORS as usize * SECTOR_SIZE as usize;
const NUM_GTES_PER_GT: u32 = 512;
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn test_sparse_vmdk(sector_data: &[u8]) -> Vec<u8> {
let mut grain = vec![0u8; GRAIN_SIZE_BYTES];
let copy_len = sector_data.len().min(GRAIN_SIZE_BYTES);
grain[..copy_len].copy_from_slice(§or_data[..copy_len]);
let mut hdr = vec![0u8; 512];
hdr[0..4].copy_from_slice(&MAGIC.to_le_bytes());
hdr[4..8].copy_from_slice(&VERSION.to_le_bytes());
hdr[8..12].copy_from_slice(&0u32.to_le_bytes()); hdr[12..20].copy_from_slice(&GRAIN_SIZE_SECTORS.to_le_bytes()); hdr[20..28].copy_from_slice(&GRAIN_SIZE_SECTORS.to_le_bytes()); hdr[28..36].copy_from_slice(&DESCRIPTOR_OFFSET.to_le_bytes());
hdr[36..44].copy_from_slice(&DESCRIPTOR_SECTORS.to_le_bytes());
hdr[44..48].copy_from_slice(&NUM_GTES_PER_GT.to_le_bytes());
hdr[48..56].copy_from_slice(&RGD_SECTOR.to_le_bytes()); hdr[56..64].copy_from_slice(&GD_SECTOR.to_le_bytes()); hdr[64..72].copy_from_slice(&GRAIN_SECTOR.to_le_bytes()); hdr[72] = 0; hdr[73] = b'\n';
hdr[74] = b' ';
hdr[75] = b'\r';
hdr[76] = b'\n';
hdr[77..79].copy_from_slice(&0u16.to_le_bytes());
let mut desc = vec![0u8; DESCRIPTOR_SECTORS as usize * SECTOR_SIZE as usize];
let s = "# Disk DescriptorFile\nversion=1\nCID=fffffffe\nparentCID=ffffffff\ncreateType=\"monolithicSparse\"\n";
let n = s.len().min(desc.len());
desc[..n].copy_from_slice(&s.as_bytes()[..n]);
let mut gd = vec![0u8; SECTOR_SIZE as usize];
gd[0..4].copy_from_slice(&(GT_SECTOR as u32).to_le_bytes());
let rgd = gd.clone();
let mut gt = vec![0u8; GT_SECTORS as usize * SECTOR_SIZE as usize];
gt[0..4].copy_from_slice(&(GRAIN_SECTOR as u32).to_le_bytes());
let mut vmdk = Vec::new();
vmdk.extend_from_slice(&hdr);
vmdk.extend_from_slice(&desc);
vmdk.extend_from_slice(&gd);
vmdk.extend_from_slice(&rgd);
vmdk.extend_from_slice(>);
vmdk.extend_from_slice(&grain);
vmdk
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn test_sparse_vmdk_sparse_then_allocated(grain1_data: &[u8]) -> Vec<u8> {
let mut grain = vec![0u8; GRAIN_SIZE_BYTES];
let copy_len = grain1_data.len().min(GRAIN_SIZE_BYTES);
grain[..copy_len].copy_from_slice(&grain1_data[..copy_len]);
let mut hdr = vec![0u8; 512];
hdr[0..4].copy_from_slice(&MAGIC.to_le_bytes());
hdr[4..8].copy_from_slice(&VERSION.to_le_bytes());
hdr[12..20].copy_from_slice(&(2 * GRAIN_SIZE_SECTORS).to_le_bytes()); hdr[20..28].copy_from_slice(&GRAIN_SIZE_SECTORS.to_le_bytes()); hdr[28..36].copy_from_slice(&DESCRIPTOR_OFFSET.to_le_bytes());
hdr[36..44].copy_from_slice(&DESCRIPTOR_SECTORS.to_le_bytes());
hdr[44..48].copy_from_slice(&NUM_GTES_PER_GT.to_le_bytes());
hdr[48..56].copy_from_slice(&RGD_SECTOR.to_le_bytes());
hdr[56..64].copy_from_slice(&GD_SECTOR.to_le_bytes());
hdr[64..72].copy_from_slice(&GRAIN_SECTOR.to_le_bytes());
hdr[73] = b'\n';
hdr[74] = b' ';
hdr[75] = b'\r';
hdr[76] = b'\n';
let mut desc = vec![0u8; DESCRIPTOR_SECTORS as usize * SECTOR_SIZE as usize];
let s = "# Disk DescriptorFile\nversion=1\nCID=fffffffe\nparentCID=ffffffff\ncreateType=\"monolithicSparse\"\n";
let n = s.len().min(desc.len());
desc[..n].copy_from_slice(&s.as_bytes()[..n]);
let mut gd = vec![0u8; SECTOR_SIZE as usize];
gd[0..4].copy_from_slice(&(GT_SECTOR as u32).to_le_bytes());
let rgd = gd.clone();
let mut gt = vec![0u8; GT_SECTORS as usize * SECTOR_SIZE as usize];
gt[4..8].copy_from_slice(&(GRAIN_SECTOR as u32).to_le_bytes());
let mut vmdk = Vec::new();
vmdk.extend_from_slice(&hdr);
vmdk.extend_from_slice(&desc);
vmdk.extend_from_slice(&gd);
vmdk.extend_from_slice(&rgd);
vmdk.extend_from_slice(>);
vmdk.extend_from_slice(&grain);
vmdk
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn test_sesparse_vmdk(sector_data: &[u8]) -> Vec<u8> {
use super::sesparse::{SE_CONST_MAGIC, SE_GTES_PER_GT, SE_GT_SECTORS, SE_VERSION};
const GRAIN_SECTORS: u64 = 8;
const GRAIN_BYTES: usize = GRAIN_SECTORS as usize * SECTOR_SIZE as usize;
const VOL_SECTOR: u64 = 1;
const GD_SECTOR: u64 = 2;
const GT_OFFSET: u64 = 3;
const GRAIN_SECTOR: u64 = GT_OFFSET + SE_GT_SECTORS; const CAPACITY: u64 = GRAIN_SECTORS;
const GD_ALLOCATED: u64 = 0x1000_0000_0000_0000; const GT_ALLOCATED_GRAIN0: u64 = 0x3000_0000_0000_0000;
let mut grain = vec![0u8; GRAIN_BYTES];
let copy_len = sector_data.len().min(GRAIN_BYTES);
grain[..copy_len].copy_from_slice(§or_data[..copy_len]);
let mut const_hdr = vec![0u8; 512];
const_hdr[0..8].copy_from_slice(&SE_CONST_MAGIC.to_le_bytes());
const_hdr[8..16].copy_from_slice(&SE_VERSION.to_le_bytes());
const_hdr[16..24].copy_from_slice(&CAPACITY.to_le_bytes());
const_hdr[24..32].copy_from_slice(&GRAIN_SECTORS.to_le_bytes()); const_hdr[32..40].copy_from_slice(&SE_GT_SECTORS.to_le_bytes()); const_hdr[80..88].copy_from_slice(&VOL_SECTOR.to_le_bytes()); const_hdr[88..96].copy_from_slice(&1u64.to_le_bytes()); const_hdr[128..136].copy_from_slice(&GD_SECTOR.to_le_bytes()); const_hdr[136..144].copy_from_slice(&1u64.to_le_bytes()); const_hdr[144..152].copy_from_slice(>_OFFSET.to_le_bytes()); const_hdr[152..160].copy_from_slice(&SE_GT_SECTORS.to_le_bytes()); const_hdr[192..200].copy_from_slice(&GRAIN_SECTOR.to_le_bytes()); const_hdr[200..208].copy_from_slice(&GRAIN_SECTORS.to_le_bytes());
let mut vol_hdr = vec![0u8; 512];
vol_hdr[0..8].copy_from_slice(&0x0000_0000_CAFE_CAFEu64.to_le_bytes());
let mut gd = vec![0u8; SECTOR_SIZE as usize];
gd[0..8].copy_from_slice(&GD_ALLOCATED.to_le_bytes());
let mut gt = vec![0u8; SE_GTES_PER_GT as usize * 8];
gt[0..8].copy_from_slice(>_ALLOCATED_GRAIN0.to_le_bytes());
let mut vmdk = Vec::new();
vmdk.extend_from_slice(&const_hdr); vmdk.extend_from_slice(&vol_hdr); vmdk.extend_from_slice(&gd); vmdk.extend_from_slice(>); vmdk.extend_from_slice(&grain); vmdk
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn test_sparse_vmdk_with_descriptor(sector_data: &[u8], descriptor_text: &str) -> Vec<u8> {
let mut grain = vec![0u8; GRAIN_SIZE_BYTES];
let copy_len = sector_data.len().min(GRAIN_SIZE_BYTES);
grain[..copy_len].copy_from_slice(§or_data[..copy_len]);
let mut hdr = vec![0u8; 512];
hdr[0..4].copy_from_slice(&MAGIC.to_le_bytes());
hdr[4..8].copy_from_slice(&VERSION.to_le_bytes());
hdr[12..20].copy_from_slice(&GRAIN_SIZE_SECTORS.to_le_bytes());
hdr[20..28].copy_from_slice(&GRAIN_SIZE_SECTORS.to_le_bytes());
hdr[28..36].copy_from_slice(&DESCRIPTOR_OFFSET.to_le_bytes());
hdr[36..44].copy_from_slice(&DESCRIPTOR_SECTORS.to_le_bytes());
hdr[44..48].copy_from_slice(&NUM_GTES_PER_GT.to_le_bytes());
hdr[48..56].copy_from_slice(&RGD_SECTOR.to_le_bytes());
hdr[56..64].copy_from_slice(&GD_SECTOR.to_le_bytes());
hdr[64..72].copy_from_slice(&GRAIN_SECTOR.to_le_bytes());
hdr[72] = 0;
hdr[73] = b'\n';
hdr[74] = b' ';
hdr[75] = b'\r';
hdr[76] = b'\n';
hdr[77..79].copy_from_slice(&0u16.to_le_bytes());
let mut desc = vec![0u8; DESCRIPTOR_SECTORS as usize * SECTOR_SIZE as usize];
let n = descriptor_text.len().min(desc.len());
desc[..n].copy_from_slice(&descriptor_text.as_bytes()[..n]);
let mut gd = vec![0u8; SECTOR_SIZE as usize];
gd[0..4].copy_from_slice(&(GT_SECTOR as u32).to_le_bytes());
let rgd = gd.clone();
let mut gt = vec![0u8; GT_SECTORS as usize * SECTOR_SIZE as usize];
gt[0..4].copy_from_slice(&(GRAIN_SECTOR as u32).to_le_bytes());
let mut vmdk = Vec::new();
vmdk.extend_from_slice(&hdr);
vmdk.extend_from_slice(&desc);
vmdk.extend_from_slice(&gd);
vmdk.extend_from_slice(&rgd);
vmdk.extend_from_slice(>);
vmdk.extend_from_slice(&grain);
vmdk
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn write_chain_to_dir(
dir: &Path,
base_data: &[u8],
) -> (std::path::PathBuf, std::path::PathBuf) {
use std::io::Write as _;
let base_desc = "# Disk DescriptorFile\nversion=1\nCID=00000001\nparentCID=ffffffff\ncreateType=\"monolithicSparse\"\n";
let base_bytes = test_sparse_vmdk_with_descriptor(base_data, base_desc);
let base_path = dir.join("base.vmdk");
std::fs::File::create(&base_path)
.expect("create base.vmdk")
.write_all(&base_bytes)
.expect("write base.vmdk");
let delta_desc = "# Disk DescriptorFile\nversion=1\nCID=00000002\nparentCID=00000001\nparentFileNameHint=\"base.vmdk\"\ncreateType=\"monolithicSparse\"\n";
let mut delta_bytes = test_sparse_vmdk_with_descriptor(&[], delta_desc);
let gt_offset = (GT_SECTOR as usize) * SECTOR_SIZE as usize;
delta_bytes[gt_offset..gt_offset + 4].copy_from_slice(&0u32.to_le_bytes());
let delta_path = dir.join("delta.vmdk");
std::fs::File::create(&delta_path)
.expect("create delta.vmdk")
.write_all(&delta_bytes)
.expect("write delta.vmdk");
(base_path, delta_path)
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn test_cowd_vmdk(sector_data: &[u8]) -> Vec<u8> {
const COWD_MAGIC: u32 = 0x434F_5744;
const GRAIN_SIZE: u32 = 8; const GTES_PER_GT: u32 = 4096;
const GD_SECTOR: u32 = 4;
const GT_SECTOR: u32 = 5;
const GRAIN_SECTOR: u32 = GT_SECTOR + GTES_PER_GT * 4 / 512;
let grain_size_bytes = GRAIN_SIZE as usize * SECTOR_SIZE as usize;
let mut grain = vec![0u8; grain_size_bytes];
let copy_len = sector_data.len().min(grain_size_bytes);
grain[..copy_len].copy_from_slice(§or_data[..copy_len]);
let mut hdr = vec![0u8; 512];
hdr[0..4].copy_from_slice(&COWD_MAGIC.to_be_bytes()); hdr[4..8].copy_from_slice(&1u32.to_le_bytes()); hdr[8..12].copy_from_slice(&3u32.to_le_bytes()); hdr[12..16].copy_from_slice(&GRAIN_SIZE.to_le_bytes()); hdr[16..20].copy_from_slice(&GRAIN_SIZE.to_le_bytes()); hdr[20..24].copy_from_slice(&GD_SECTOR.to_le_bytes()); hdr[24..28].copy_from_slice(&1u32.to_le_bytes()); hdr[28..32].copy_from_slice(&(GRAIN_SECTOR + GRAIN_SIZE).to_le_bytes());
let padding = vec![0u8; 3 * SECTOR_SIZE as usize];
let mut gd = vec![0u8; SECTOR_SIZE as usize];
gd[0..4].copy_from_slice(>_SECTOR.to_le_bytes());
let mut gt = vec![0u8; GTES_PER_GT as usize * 4];
gt[0..4].copy_from_slice(&GRAIN_SECTOR.to_le_bytes());
let mut cowd = Vec::new();
cowd.extend_from_slice(&hdr);
cowd.extend_from_slice(&padding);
cowd.extend_from_slice(&gd);
cowd.extend_from_slice(>);
cowd.extend_from_slice(&grain);
cowd
}
const GAE_CAPACITY: u64 = 2048; const GAE_GRAIN_SIZE: u64 = 128; const GAE_NUM_GTES: u32 = 512;
const GAE_DESC_OFFSET: u64 = 1;
const GAE_DESC_SIZE: u64 = 20;
const GAE_GT_SECTOR: u64 = 21;
const GAE_GD_SECTOR: u64 = 25; const GAE_TOTAL_SECTORS: u64 = 28;
fn write_stream_opt_hdr(h: &mut [u8; 512], gd_off: u64) {
h[0..4].copy_from_slice(&MAGIC.to_le_bytes());
h[4..8].copy_from_slice(&VERSION_STREAM_OPT.to_le_bytes());
h[8..12].copy_from_slice(&0u32.to_le_bytes()); h[12..20].copy_from_slice(&GAE_CAPACITY.to_le_bytes());
h[20..28].copy_from_slice(&GAE_GRAIN_SIZE.to_le_bytes());
h[28..36].copy_from_slice(&GAE_DESC_OFFSET.to_le_bytes());
h[36..44].copy_from_slice(&GAE_DESC_SIZE.to_le_bytes());
h[44..48].copy_from_slice(&GAE_NUM_GTES.to_le_bytes());
h[48..56].copy_from_slice(&0u64.to_le_bytes()); h[56..64].copy_from_slice(&gd_off.to_le_bytes());
h[64..72].copy_from_slice(&GAE_GD_SECTOR.to_le_bytes()); h[72] = 0; h[73] = b'\n';
h[74] = b' ';
h[75] = b'\r';
h[76] = b'\n';
h[77..79].copy_from_slice(&1u16.to_le_bytes()); }
const COM_CAPACITY: u64 = 128; const COM_GRAIN_SIZE: u64 = 128; const COM_NUM_GTES: u32 = 512;
const COM_GD_SECTOR: u64 = 26;
const COM_GT_SECTOR: u64 = 27;
const COM_GRAIN_SECTOR: u64 = 128;
const COM_MARKER_BYTES: usize = 12;
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn compressed_vmdk_with_oversized_marker(marker_data_size: u32) -> Vec<u8> {
let total = COM_GRAIN_SECTOR as usize * SECTOR_SIZE as usize + COM_MARKER_BYTES;
let mut vmdk = vec![0u8; total];
{
let h = &mut vmdk[0..512];
h[0..4].copy_from_slice(&MAGIC.to_le_bytes());
h[4..8].copy_from_slice(&VERSION_STREAM_OPT.to_le_bytes());
h[12..20].copy_from_slice(&COM_CAPACITY.to_le_bytes());
h[20..28].copy_from_slice(&COM_GRAIN_SIZE.to_le_bytes());
h[44..48].copy_from_slice(&COM_NUM_GTES.to_le_bytes());
h[56..64].copy_from_slice(&COM_GD_SECTOR.to_le_bytes()); h[64..72].copy_from_slice(&COM_GRAIN_SECTOR.to_le_bytes()); h[73] = b'\n';
h[74] = b' ';
h[75] = b'\r';
h[76] = b'\n';
h[77..79].copy_from_slice(&1u16.to_le_bytes()); }
let gd = COM_GD_SECTOR as usize * SECTOR_SIZE as usize;
vmdk[gd..gd + 4].copy_from_slice(&(COM_GT_SECTOR as u32).to_le_bytes());
let gt = COM_GT_SECTOR as usize * SECTOR_SIZE as usize;
vmdk[gt..gt + 4].copy_from_slice(&(COM_GRAIN_SECTOR as u32).to_le_bytes());
let marker = COM_GRAIN_SECTOR as usize * SECTOR_SIZE as usize;
vmdk[marker + 8..marker + 12].copy_from_slice(&marker_data_size.to_le_bytes());
vmdk
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn compressed_vmdk_with_bomb_grain(decompressed_len: usize) -> Vec<u8> {
use std::io::Write as _;
let payload = {
let mut enc =
flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
enc.write_all(&vec![0u8; decompressed_len]).expect("compress");
enc.finish().expect("finish")
};
let marker = COM_GRAIN_SECTOR as usize * SECTOR_SIZE as usize;
let total = marker + COM_MARKER_BYTES + payload.len();
let mut vmdk = vec![0u8; total];
{
let h = &mut vmdk[0..512];
h[0..4].copy_from_slice(&MAGIC.to_le_bytes());
h[4..8].copy_from_slice(&VERSION_STREAM_OPT.to_le_bytes());
h[12..20].copy_from_slice(&COM_CAPACITY.to_le_bytes());
h[20..28].copy_from_slice(&COM_GRAIN_SIZE.to_le_bytes());
h[44..48].copy_from_slice(&COM_NUM_GTES.to_le_bytes());
h[56..64].copy_from_slice(&COM_GD_SECTOR.to_le_bytes());
h[64..72].copy_from_slice(&COM_GRAIN_SECTOR.to_le_bytes());
h[73] = b'\n';
h[74] = b' ';
h[75] = b'\r';
h[76] = b'\n';
h[77..79].copy_from_slice(&1u16.to_le_bytes());
}
let gd = COM_GD_SECTOR as usize * SECTOR_SIZE as usize;
vmdk[gd..gd + 4].copy_from_slice(&(COM_GT_SECTOR as u32).to_le_bytes());
let gt = COM_GT_SECTOR as usize * SECTOR_SIZE as usize;
vmdk[gt..gt + 4].copy_from_slice(&(COM_GRAIN_SECTOR as u32).to_le_bytes());
vmdk[marker + 8..marker + 12].copy_from_slice(&(payload.len() as u32).to_le_bytes());
vmdk[marker + COM_MARKER_BYTES..marker + COM_MARKER_BYTES + payload.len()]
.copy_from_slice(&payload);
vmdk
}
#[cfg_attr(not(any(test, feature = "test-helpers")), allow(dead_code))]
pub fn gd_at_end_stream_opt_vmdk() -> Vec<u8> {
let total_bytes = GAE_TOTAL_SECTORS * SECTOR_SIZE;
let mut vmdk = vec![0u8; total_bytes as usize];
let mut hdr = [0u8; 512];
write_stream_opt_hdr(&mut hdr, u64::MAX);
vmdk[0..512].copy_from_slice(&hdr);
let desc = b"# Disk DescriptorFile\nversion=1\nCID=fffffffe\nparentCID=ffffffff\ncreateType=\"streamOptimized\"\n";
let desc_start = GAE_DESC_OFFSET as usize * SECTOR_SIZE as usize;
let copy_len = desc
.len()
.min(GAE_DESC_SIZE as usize * SECTOR_SIZE as usize);
vmdk[desc_start..desc_start + copy_len].copy_from_slice(&desc[..copy_len]);
let gd_start = GAE_GD_SECTOR as usize * SECTOR_SIZE as usize;
vmdk[gd_start..gd_start + 4].copy_from_slice(&(GAE_GT_SECTOR as u32).to_le_bytes());
let footer_start = (GAE_TOTAL_SECTORS - 2) as usize * SECTOR_SIZE as usize;
let mut footer = [0u8; 512];
write_stream_opt_hdr(&mut footer, GAE_GD_SECTOR);
vmdk[footer_start..footer_start + 512].copy_from_slice(&footer);
vmdk
}