pub fn new(f: &mut File, metadata_region: &RegionTableEntry) -> Result<DiskSpec> {
        let mut disk_spec = DiskSpec::default();
        let mut metadata_presence: u16 = 0;
        let mut offset = 0;
        let metadata = f.metadata().map_err(VhdxMetadataError::ReadMetadata)?;
        disk_spec.image_size = metadata.len();

        let mut buffer = [0u8; METADATA_TABLE_MAX_SIZE];
        f.seek(SeekFrom::Start(metadata_region.file_offset))
            .map_err(VhdxMetadataError::ReadMetadata)?;
        f.read_exact(&mut buffer)
            .map_err(VhdxMetadataError::ReadMetadata)?;

        let metadata_header =
            MetadataTableHeader::new(&buffer[0..size_of::<MetadataTableHeader>()])?;

        offset += size_of::<MetadataTableHeader>();
        for _ in 0..metadata_header.entry_count {
            let metadata_entry =
                MetadataTableEntry::new(&buffer[offset..offset + size_of::<MetadataTableEntry>()])?;

            f.seek(SeekFrom::Start(
                metadata_region.file_offset + metadata_entry.offset as u64,
            ))
            .map_err(VhdxMetadataError::ReadMetadata)?;

            if metadata_entry.item_id
                == Uuid::parse_str(METADATA_FILE_PARAMETER)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.block_size = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;

                // MUST be at least 1 MiB and not greater than 256 MiB
                if disk_spec.block_size < BLOCK_SIZE_MIN && disk_spec.block_size > BLOCK_SIZE_MAX {
                    return Err(VhdxMetadataError::InvalidBlockSize);
                }

                // MUST be power of 2
                if !disk_spec.block_size.is_power_of_two() {
                    return Err(VhdxMetadataError::InvalidBlockSize);
                }

                let bits = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                if bits & BLOCK_HAS_PARENT != 0 {
                    disk_spec.has_parent = true;
                } else {
                    disk_spec.has_parent = false;
                }

                metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_VIRTUAL_DISK_SIZE)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.virtual_disk_size = f
                    .read_u64::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;

                metadata_presence |= METADATA_VIRTUAL_DISK_SIZE_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_VIRTUAL_DISK_ID)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.disk_id = f
                    .read_u128::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;

                metadata_presence |= METADATA_VIRTUAL_DISK_ID_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_LOGICAL_SECTOR_SIZE)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.logical_sector_size = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                if !(disk_spec.logical_sector_size == 512 || disk_spec.logical_sector_size == 4096)
                {
                    return Err(VhdxMetadataError::InvalidLogicalSectorSize);
                }

                metadata_presence |= METADATA_LOGICAL_SECTOR_SIZE_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_PHYSICAL_SECTOR_SIZE)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.physical_sector_size = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                if !(disk_spec.physical_sector_size == 512
                    || disk_spec.physical_sector_size == 4096)
                {
                    return Err(VhdxMetadataError::InvalidPhysicalSectorSize);
                }

                metadata_presence |= METADATA_PHYSICAL_SECTOR_SIZE_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_PARENT_LOCATOR)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                metadata_presence |= METADATA_PARENT_LOCATOR_PRESENT;
            } else {
                return Err(VhdxMetadataError::InvalidMetadataItem);
            }

            if (metadata_entry.flag_bits & METADATA_FLAGS_IS_REQUIRED) == 0 {
                return Err(VhdxMetadataError::UnsupportedFlag);
            }
            offset += size_of::<MetadataTableEntry>();
        }

        // Check if all required metadata are present
        if metadata_presence != METADATA_ALL_PRESENT {
            return Err(VhdxMetadataError::MissingMetadata);
        }
        // Check if the virtual disk size is a multiple of the logical sector
        // size.
        if ((metadata_presence & METADATA_LOGICAL_SECTOR_SIZE_PRESENT) != 0)
            && (disk_spec.virtual_disk_size % disk_spec.logical_sector_size as u64 != 0)
        {
            return Err(VhdxMetadataError::InvalidBlockSize);
        }

        disk_spec.sectors_per_block =
            DiskSpec::sectors_per_block(disk_spec.block_size, disk_spec.logical_sector_size)?;

        disk_spec.chunk_ratio =
            DiskSpec::chunk_ratio(disk_spec.block_size, disk_spec.logical_sector_size)?;

        disk_spec.total_sectors =
            disk_spec.virtual_disk_size / disk_spec.logical_sector_size as u64;

        Ok(disk_spec)
    }
/// Parse all meatadata from the provided file and store info in DiskSpec
/// structure.
Parse all meatadata from the provided file and store info in DiskSpec
structure.
Parse all meatadata from the provided file and store info in DiskSpec structure .
pub fn new(f: &mut File, metadata_region: &RegionTableEntry) -> Result<DiskSpec> {
        let mut disk_spec = DiskSpec::default();
        let mut metadata_presence: u16 = 0;
        let mut offset = 0;
        let metadata = f.metadata().map_err(VhdxMetadataError::ReadMetadata)?;
        disk_spec.image_size = metadata.len();
        let mut buffer = [0u8; METADATA_TABLE_MAX_SIZE];
        f.seek(SeekFrom::Start(metadata_region.file_offset))
            .map_err(VhdxMetadataError::ReadMetadata)?;
        f.read_exact(&mut buffer)
            .map_err(VhdxMetadataError::ReadMetadata)?;
        let metadata_header =
            MetadataTableHeader::new(&buffer[0..size_of::<MetadataTableHeader>()])?;
        offset += size_of::<MetadataTableHeader>();
        for _ in 0..metadata_header.entry_count {
            let metadata_entry =
                MetadataTableEntry::new(&buffer[offset..offset + size_of::<MetadataTableEntry>()])?;
            f.seek(SeekFrom::Start(
                metadata_region.file_offset + metadata_entry.offset as u64,
            ))
            .map_err(VhdxMetadataError::ReadMetadata)?;
            if metadata_entry.item_id
                == Uuid::parse_str(METADATA_FILE_PARAMETER)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.block_size = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                // MUST be at least 1 MiB and not greater than 256 MiB
                if disk_spec.block_size < BLOCK_SIZE_MIN && disk_spec.block_size > BLOCK_SIZE_MAX {
                    return Err(VhdxMetadataError::InvalidBlockSize);
                }
                // MUST be power of 2
                if !disk_spec.block_size.is_power_of_two() {
                    return Err(VhdxMetadataError::InvalidBlockSize);
                }
                let bits = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                if bits & BLOCK_HAS_PARENT != 0 {
                    disk_spec.has_parent = true;
                } else {
                    disk_spec.has_parent = false;
                }
                metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_VIRTUAL_DISK_SIZE)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.virtual_disk_size = f
                    .read_u64::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                metadata_presence |= METADATA_VIRTUAL_DISK_SIZE_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_VIRTUAL_DISK_ID)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.disk_id = f
                    .read_u128::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                metadata_presence |= METADATA_VIRTUAL_DISK_ID_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_LOGICAL_SECTOR_SIZE)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.logical_sector_size = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                if !(disk_spec.logical_sector_size == 512 || disk_spec.logical_sector_size == 4096)
                {
                    return Err(VhdxMetadataError::InvalidLogicalSectorSize);
                }
                metadata_presence |= METADATA_LOGICAL_SECTOR_SIZE_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_PHYSICAL_SECTOR_SIZE)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                disk_spec.physical_sector_size = f
                    .read_u32::<LittleEndian>()
                    .map_err(VhdxMetadataError::ReadMetadata)?;
                if !(disk_spec.physical_sector_size == 512
                    || disk_spec.physical_sector_size == 4096)
                {
                    return Err(VhdxMetadataError::InvalidPhysicalSectorSize);
                }
                metadata_presence |= METADATA_PHYSICAL_SECTOR_SIZE_PRESENT;
            } else if metadata_entry.item_id
                == Uuid::parse_str(METADATA_PARENT_LOCATOR)
                    .map_err(VhdxMetadataError::InvalidUuid)?
            {
                metadata_presence |= METADATA_PARENT_LOCATOR_PRESENT;
            } else {
                return Err(VhdxMetadataError::InvalidMetadataItem);
            }
            if (metadata_entry.flag_bits & METADATA_FLAGS_IS_REQUIRED) == 0 {
                return Err(VhdxMetadataError::UnsupportedFlag);
            }
            offset += size_of::<MetadataTableEntry>();
        }
        // Check if all required metadata are present
        if metadata_presence != METADATA_ALL_PRESENT {
            return Err(VhdxMetadataError::MissingMetadata);
        }
        // Check if the virtual disk size is a multiple of the logical sector
        // size.
        if ((metadata_presence & METADATA_LOGICAL_SECTOR_SIZE_PRESENT) != 0)
            && (disk_spec.virtual_disk_size % disk_spec.logical_sector_size as u64 != 0)
        {
            return Err(VhdxMetadataError::InvalidBlockSize);
        }
        disk_spec.sectors_per_block =
            DiskSpec::sectors_per_block(disk_spec.block_size, disk_spec.logical_sector_size)?;
        disk_spec.chunk_ratio =
            DiskSpec::chunk_ratio(disk_spec.block_size, disk_spec.logical_sector_size)?;
        disk_spec.total_sectors =
            disk_spec.virtual_disk_size / disk_spec.logical_sector_size as u64;
        Ok(disk_spec)
    }
pub fn new ( f : & mut File , metadata_region : & RegionTableEntry ) -> Result < DiskSpec > { let mut disk_spec = DiskSpec :: default ( ) ; let mut metadata_presence : u16 = 0 ; let mut offset = 0 ; let metadata = f . metadata ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; disk_spec . image_size = metadata . len ( ) ; let mut buffer = [ 0u8 ; METADATA_TABLE_MAX_SIZE ] ; f . seek ( SeekFrom :: Start ( metadata_region . file_offset ) ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; f . read_exact ( & mut buffer ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; let metadata_header = MetadataTableHeader :: new ( & buffer [ 0 .. size_of :: < MetadataTableHeader > ( ) ] ) ? ; offset += size_of :: < MetadataTableHeader > ( ) ; for _ in 0 .. metadata_header . entry_count { let metadata_entry = MetadataTableEntry :: new ( & buffer [ offset .. offset + size_of :: < MetadataTableEntry > ( ) ] ) ? ; f . seek ( SeekFrom :: Start ( metadata_region . file_offset + metadata_entry . offset as u64 , ) ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; if metadata_entry . item_id == Uuid :: parse_str ( METADATA_FILE_PARAMETER ) . map_err ( VhdxMetadataError :: InvalidUuid ) ? { disk_spec . block_size = f . read_u32 :: < LittleEndian > ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; // MUST be at least 1 MiB and not greater than 256 MiB if disk_spec . block_size < BLOCK_SIZE_MIN && disk_spec . block_size > BLOCK_SIZE_MAX { return Err ( VhdxMetadataError :: InvalidBlockSize ) ; } // MUST be power of 2 if ! disk_spec . block_size . is_power_of_two ( ) { return Err ( VhdxMetadataError :: InvalidBlockSize ) ; } let bits = f . read_u32 :: < LittleEndian > ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; if bits & BLOCK_HAS_PARENT != 0 { disk_spec . has_parent = true ; } else { disk_spec . has_parent = false ; } metadata_presence |= METADATA_FILE_PARAMETER_PRESENT ; } else if metadata_entry . item_id == Uuid :: parse_str ( METADATA_VIRTUAL_DISK_SIZE ) . map_err ( VhdxMetadataError :: InvalidUuid ) ? { disk_spec . virtual_disk_size = f . read_u64 :: < LittleEndian > ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; metadata_presence |= METADATA_VIRTUAL_DISK_SIZE_PRESENT ; } else if metadata_entry . item_id == Uuid :: parse_str ( METADATA_VIRTUAL_DISK_ID ) . map_err ( VhdxMetadataError :: InvalidUuid ) ? { disk_spec . disk_id = f . read_u128 :: < LittleEndian > ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; metadata_presence |= METADATA_VIRTUAL_DISK_ID_PRESENT ; } else if metadata_entry . item_id == Uuid :: parse_str ( METADATA_LOGICAL_SECTOR_SIZE ) . map_err ( VhdxMetadataError :: InvalidUuid ) ? { disk_spec . logical_sector_size = f . read_u32 :: < LittleEndian > ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; if ! ( disk_spec . logical_sector_size == 512 || disk_spec . logical_sector_size == 4096 ) { return Err ( VhdxMetadataError :: InvalidLogicalSectorSize ) ; } metadata_presence |= METADATA_LOGICAL_SECTOR_SIZE_PRESENT ; } else if metadata_entry . item_id == Uuid :: parse_str ( METADATA_PHYSICAL_SECTOR_SIZE ) . map_err ( VhdxMetadataError :: InvalidUuid ) ? { disk_spec . physical_sector_size = f . read_u32 :: < LittleEndian > ( ) . map_err ( VhdxMetadataError :: ReadMetadata ) ? ; if ! ( disk_spec . physical_sector_size == 512 || disk_spec . physical_sector_size == 4096 ) { return Err ( VhdxMetadataError :: InvalidPhysicalSectorSize ) ; } metadata_presence |= METADATA_PHYSICAL_SECTOR_SIZE_PRESENT ; } else if metadata_entry . item_id == Uuid :: parse_str ( METADATA_PARENT_LOCATOR ) . map_err ( VhdxMetadataError :: InvalidUuid ) ? { metadata_presence |= METADATA_PARENT_LOCATOR_PRESENT ; } else { return Err ( VhdxMetadataError :: InvalidMetadataItem ) ; } if ( metadata_entry . flag_bits & METADATA_FLAGS_IS_REQUIRED ) == 0 { return Err ( VhdxMetadataError :: UnsupportedFlag ) ; } offset += size_of :: < MetadataTableEntry > ( ) ; } // Check if all required metadata are present if metadata_presence != METADATA_ALL_PRESENT { return Err ( VhdxMetadataError :: MissingMetadata ) ; } // Check if the virtual disk size is a multiple of the logical sector // size. if ( ( metadata_presence & METADATA_LOGICAL_SECTOR_SIZE_PRESENT ) != 0 ) && ( disk_spec . virtual_disk_size % disk_spec . logical_sector_size as u64 != 0 ) { return Err ( VhdxMetadataError :: InvalidBlockSize ) ; } disk_spec . sectors_per_block = DiskSpec :: sectors_per_block ( disk_spec . block_size , disk_spec . logical_sector_size ) ? ; disk_spec . chunk_ratio = DiskSpec :: chunk_ratio ( disk_spec . block_size , disk_spec . logical_sector_size ) ? ; disk_spec . total_sectors = disk_spec . virtual_disk_size / disk_spec . logical_sector_size as u64 ; Ok ( disk_spec ) }
Parse all meatadata from the provided file and store info in DiskSpec
structure.
Parse all meatadata from the provided file and store info in DiskSpec structure .
f
&mut File
metadata_region
&RegionTableEntry
f
&mut File
metadata_region
&RegionTableEntry