Parse all metadata from the provided file and store info in DiskSpec structure.
(f: &mut File, metadata_region: &RegionTableEntry)
| 103 | /// Parse all metadata from the provided file and store info in DiskSpec |
| 104 | /// structure. |
| 105 | pub fn new(f: &mut File, metadata_region: &RegionTableEntry) -> Result<DiskSpec> { |
| 106 | let mut disk_spec = DiskSpec::default(); |
| 107 | let mut metadata_presence: u16 = 0; |
| 108 | let mut offset = 0; |
| 109 | let metadata = f.metadata().map_err(VhdxMetadataError::ReadMetadata)?; |
| 110 | disk_spec.image_size = metadata.len(); |
| 111 | |
| 112 | let mut buffer = [0u8; METADATA_TABLE_MAX_SIZE]; |
| 113 | f.seek(SeekFrom::Start(metadata_region.file_offset)) |
| 114 | .map_err(VhdxMetadataError::ReadMetadata)?; |
| 115 | f.read_exact(&mut buffer) |
| 116 | .map_err(VhdxMetadataError::ReadMetadata)?; |
| 117 | |
| 118 | let metadata_header = |
| 119 | MetadataTableHeader::new(&buffer[0..size_of::<MetadataTableHeader>()])?; |
| 120 | |
| 121 | offset += size_of::<MetadataTableHeader>(); |
| 122 | for _ in 0..metadata_header.entry_count { |
| 123 | let metadata_entry = |
| 124 | MetadataTableEntry::new(&buffer[offset..offset + size_of::<MetadataTableEntry>()])?; |
| 125 | |
| 126 | f.seek(SeekFrom::Start( |
| 127 | metadata_region.file_offset + metadata_entry.offset as u64, |
| 128 | )) |
| 129 | .map_err(VhdxMetadataError::ReadMetadata)?; |
| 130 | |
| 131 | if metadata_entry.item_id |
| 132 | == Uuid::parse_str(METADATA_FILE_PARAMETER) |
| 133 | .map_err(VhdxMetadataError::InvalidUuid)? |
| 134 | { |
| 135 | disk_spec.block_size = f |
| 136 | .read_u32::<LittleEndian>() |
| 137 | .map_err(VhdxMetadataError::ReadMetadata)?; |
| 138 | |
| 139 | // MUST be at least 1 MiB and not greater than 256 MiB |
| 140 | if disk_spec.block_size < BLOCK_SIZE_MIN || disk_spec.block_size > BLOCK_SIZE_MAX { |
| 141 | return Err(VhdxMetadataError::InvalidBlockSize); |
| 142 | } |
| 143 | |
| 144 | // MUST be power of 2 |
| 145 | if !disk_spec.block_size.is_power_of_two() { |
| 146 | return Err(VhdxMetadataError::InvalidBlockSize); |
| 147 | } |
| 148 | |
| 149 | let bits = f |
| 150 | .read_u32::<LittleEndian>() |
| 151 | .map_err(VhdxMetadataError::ReadMetadata)?; |
| 152 | disk_spec.has_parent = bits & BLOCK_HAS_PARENT != 0; |
| 153 | |
| 154 | metadata_presence |= METADATA_FILE_PARAMETER_PRESENT; |
| 155 | } else if metadata_entry.item_id |
| 156 | == Uuid::parse_str(METADATA_VIRTUAL_DISK_SIZE) |
| 157 | .map_err(VhdxMetadataError::InvalidUuid)? |
| 158 | { |
| 159 | disk_spec.virtual_disk_size = f |
| 160 | .read_u64::<LittleEndian>() |
| 161 | .map_err(VhdxMetadataError::ReadMetadata)?; |
| 162 |
nothing calls this directly
no test coverage detected