VHDx IO write routine: requires relative sector index and count for the requested data.
(
f: &mut File,
buf: &[u8],
disk_spec: &mut DiskSpec,
bat_offset: u64,
bat: &mut [BatEntry],
mut sector_index: u64,
mut sector_count: u64,
)
| 139 | /// VHDx IO write routine: requires relative sector index and count for the |
| 140 | /// requested data. |
| 141 | pub fn write( |
| 142 | f: &mut File, |
| 143 | buf: &[u8], |
| 144 | disk_spec: &mut DiskSpec, |
| 145 | bat_offset: u64, |
| 146 | bat: &mut [BatEntry], |
| 147 | mut sector_index: u64, |
| 148 | mut sector_count: u64, |
| 149 | ) -> Result<usize> { |
| 150 | if disk_spec.has_parent { |
| 151 | return Err(VhdxIoError::UnsupportedMode); |
| 152 | } |
| 153 | |
| 154 | let mut write_count: usize = 0; |
| 155 | while sector_count > 0 { |
| 156 | let sector = Sector::new(disk_spec, bat, sector_index, sector_count)?; |
| 157 | |
| 158 | let bat_entry = match bat.get(sector.bat_index as usize) { |
| 159 | Some(entry) => entry.0, |
| 160 | None => { |
| 161 | return Err(VhdxIoError::InvalidBatIndex); |
| 162 | } |
| 163 | }; |
| 164 | |
| 165 | match bat_entry & vhdx_bat::BAT_STATE_BIT_MASK { |
| 166 | vhdx_bat::PAYLOAD_BLOCK_NOT_PRESENT |
| 167 | | vhdx_bat::PAYLOAD_BLOCK_UNDEFINED |
| 168 | | vhdx_bat::PAYLOAD_BLOCK_UNMAPPED |
| 169 | | vhdx_bat::PAYLOAD_BLOCK_ZERO => { |
| 170 | let file_offset = |
| 171 | align!(disk_spec.image_size, vhdx_metadata::BLOCK_SIZE_MIN as u64); |
| 172 | let new_size = file_offset |
| 173 | .checked_add(disk_spec.block_size as u64) |
| 174 | .ok_or(VhdxIoError::InvalidDiskSize)?; |
| 175 | |
| 176 | f.set_len(new_size).map_err(VhdxIoError::ResizeFile)?; |
| 177 | disk_spec.image_size = new_size; |
| 178 | |
| 179 | let new_bat_entry = file_offset |
| 180 | | (vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT & vhdx_bat::BAT_STATE_BIT_MASK); |
| 181 | bat[sector.bat_index as usize] = BatEntry(new_bat_entry); |
| 182 | BatEntry::write_bat_entries(f, bat_offset, bat).map_err(VhdxIoError::WriteBat)?; |
| 183 | |
| 184 | if file_offset < vhdx_metadata::BLOCK_SIZE_MIN as u64 { |
| 185 | break; |
| 186 | } |
| 187 | |
| 188 | f.seek(SeekFrom::Start(file_offset)) |
| 189 | .map_err(VhdxIoError::ReadSectorBlock)?; |
| 190 | f.write_all( |
| 191 | &buf[write_count..(write_count + (sector.free_sectors * SECTOR_SIZE) as usize)], |
| 192 | ) |
| 193 | .map_err(VhdxIoError::ReadSectorBlock)?; |
| 194 | } |
| 195 | vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT => { |
| 196 | if sector.file_offset < vhdx_metadata::BLOCK_SIZE_MIN as u64 { |
| 197 | break; |
| 198 | } |