pub fn new(f: &mut File, region_start: u64, entry_count: u32) -> Result<RegionInfo> {
        let mut bat_entry: Option<RegionTableEntry> = None;
        let mut mdr_entry: Option<RegionTableEntry> = None;

        let mut offset = 0;
        let mut region_entries = BTreeMap::new();

        let mut buffer = [0; REGION_SIZE as usize];
        // Seek after the Region Table Header
        f.seek(SeekFrom::Start(
            region_start + size_of::<RegionTableHeader>() as u64,
        ))
        .map_err(VhdxHeaderError::SeekRegionTableEntries)?;
        f.read_exact(&mut buffer)
            .map_err(VhdxHeaderError::ReadRegionTableEntries)?;

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

            offset += size_of::<RegionTableEntry>();
            let start = entry.file_offset;
            let end = start + entry.length as u64;

            for (region_ent_start, region_ent_end) in region_entries.iter() {
                if !((start >= *region_ent_start) || (end <= *region_ent_end)) {
                    return Err(VhdxHeaderError::RegionOverlap);
                }
            }

            region_entries.insert(entry.file_offset, entry.file_offset + entry.length as u64);

            if entry.guid == Uuid::parse_str(BAT_GUID).map_err(VhdxHeaderError::InvalidUuid)? {
                if bat_entry.is_none() {
                    bat_entry = Some(entry);
                    continue;
                }
                return Err(VhdxHeaderError::DuplicateBATEntry);
            }

            if entry.guid == Uuid::parse_str(MDR_GUID).map_err(VhdxHeaderError::InvalidUuid)? {
                if mdr_entry.is_none() {
                    mdr_entry = Some(entry);
                    continue;
                }
                return Err(VhdxHeaderError::DuplicateMDREntry);
            }

            if (entry.required & REGION_ENTRY_REQUIRED) == 1 {
                // This implementation doesn't recognize this field.
                // Therefore, accoding to the spec, we are throwing an error.
                return Err(VhdxHeaderError::UnrecognizedRegionEntry);
            }
        }

        if bat_entry.is_none() || mdr_entry.is_none() {
            region_entries.clear();
            return Err(VhdxHeaderError::RegionEntryCollectionFailed);
        }

        // It's safe to unwrap as we checked both entries have been filled.
        // Otherwise, an error is already returned.
        let bat_entry = bat_entry.unwrap();
        let mdr_entry = mdr_entry.unwrap();

        Ok(RegionInfo {
            bat_entry,
            mdr_entry,
            region_entries,
        })
    }
/// Collect all entries in a BTreeMap from the Region Table and identifies
/// BAT and metadata regions
Collect all entries in a BTreeMap from the Region Table and identifies
BAT and metadata regions
Collect all entries in a BTreeMap from the Region Table and identifies BAT and metadata regions
pub fn new(f: &mut File, region_start: u64, entry_count: u32) -> Result<RegionInfo> {
        let mut bat_entry: Option<RegionTableEntry> = None;
        let mut mdr_entry: Option<RegionTableEntry> = None;
        let mut offset = 0;
        let mut region_entries = BTreeMap::new();
        let mut buffer = [0; REGION_SIZE as usize];
        // Seek after the Region Table Header
        f.seek(SeekFrom::Start(
            region_start + size_of::<RegionTableHeader>() as u64,
        ))
        .map_err(VhdxHeaderError::SeekRegionTableEntries)?;
        f.read_exact(&mut buffer)
            .map_err(VhdxHeaderError::ReadRegionTableEntries)?;
        for _ in 0..entry_count {
            let entry =
                RegionTableEntry::new(&buffer[offset..offset + size_of::<RegionTableEntry>()])?;
            offset += size_of::<RegionTableEntry>();
            let start = entry.file_offset;
            let end = start + entry.length as u64;
            for (region_ent_start, region_ent_end) in region_entries.iter() {
                if !((start >= *region_ent_start) || (end <= *region_ent_end)) {
                    return Err(VhdxHeaderError::RegionOverlap);
                }
            }
            region_entries.insert(entry.file_offset, entry.file_offset + entry.length as u64);
            if entry.guid == Uuid::parse_str(BAT_GUID).map_err(VhdxHeaderError::InvalidUuid)? {
                if bat_entry.is_none() {
                    bat_entry = Some(entry);
                    continue;
                }
                return Err(VhdxHeaderError::DuplicateBATEntry);
            }
            if entry.guid == Uuid::parse_str(MDR_GUID).map_err(VhdxHeaderError::InvalidUuid)? {
                if mdr_entry.is_none() {
                    mdr_entry = Some(entry);
                    continue;
                }
                return Err(VhdxHeaderError::DuplicateMDREntry);
            }
            if (entry.required & REGION_ENTRY_REQUIRED) == 1 {
                // This implementation doesn't recognize this field.
                // Therefore, accoding to the spec, we are throwing an error.
                return Err(VhdxHeaderError::UnrecognizedRegionEntry);
            }
        }
        if bat_entry.is_none() || mdr_entry.is_none() {
            region_entries.clear();
            return Err(VhdxHeaderError::RegionEntryCollectionFailed);
        }
        // It's safe to unwrap as we checked both entries have been filled.
        // Otherwise, an error is already returned.
        let bat_entry = bat_entry.unwrap();
        let mdr_entry = mdr_entry.unwrap();
        Ok(RegionInfo {
            bat_entry,
            mdr_entry,
            region_entries,
        })
    }
pub fn new ( f : & mut File , region_start : u64 , entry_count : u32 ) -> Result < RegionInfo > { let mut bat_entry : Option < RegionTableEntry > = None ; let mut mdr_entry : Option < RegionTableEntry > = None ; let mut offset = 0 ; let mut region_entries = BTreeMap :: new ( ) ; let mut buffer = [ 0 ; REGION_SIZE as usize ] ; // Seek after the Region Table Header f . seek ( SeekFrom :: Start ( region_start + size_of :: < RegionTableHeader > ( ) as u64 , ) ) . map_err ( VhdxHeaderError :: SeekRegionTableEntries ) ? ; f . read_exact ( & mut buffer ) . map_err ( VhdxHeaderError :: ReadRegionTableEntries ) ? ; for _ in 0 .. entry_count { let entry = RegionTableEntry :: new ( & buffer [ offset .. offset + size_of :: < RegionTableEntry > ( ) ] ) ? ; offset += size_of :: < RegionTableEntry > ( ) ; let start = entry . file_offset ; let end = start + entry . length as u64 ; for ( region_ent_start , region_ent_end ) in region_entries . iter ( ) { if ! ( ( start >= * region_ent_start ) || ( end <= * region_ent_end ) ) { return Err ( VhdxHeaderError :: RegionOverlap ) ; } } region_entries . insert ( entry . file_offset , entry . file_offset + entry . length as u64 ) ; if entry . guid == Uuid :: parse_str ( BAT_GUID ) . map_err ( VhdxHeaderError :: InvalidUuid ) ? { if bat_entry . is_none ( ) { bat_entry = Some ( entry ) ; continue ; } return Err ( VhdxHeaderError :: DuplicateBATEntry ) ; } if entry . guid == Uuid :: parse_str ( MDR_GUID ) . map_err ( VhdxHeaderError :: InvalidUuid ) ? { if mdr_entry . is_none ( ) { mdr_entry = Some ( entry ) ; continue ; } return Err ( VhdxHeaderError :: DuplicateMDREntry ) ; } if ( entry . required & REGION_ENTRY_REQUIRED ) == 1 { // This implementation doesn't recognize this field. // Therefore, accoding to the spec, we are throwing an error. return Err ( VhdxHeaderError :: UnrecognizedRegionEntry ) ; } } if bat_entry . is_none ( ) || mdr_entry . is_none ( ) { region_entries . clear ( ) ; return Err ( VhdxHeaderError :: RegionEntryCollectionFailed ) ; } // It's safe to unwrap as we checked both entries have been filled. // Otherwise, an error is already returned. let bat_entry = bat_entry . unwrap ( ) ; let mdr_entry = mdr_entry . unwrap ( ) ; Ok ( RegionInfo { bat_entry , mdr_entry , region_entries , } ) }
Collect all entries in a BTreeMap from the Region Table and identifies
BAT and metadata regions
Collect all entries in a BTreeMap from the Region Table and identifies BAT and metadata regions
f
&mut File
region_start
u64
entry_count
u32
f
&mut File
region_start
u64
entry_count
u32