Read header extensions, optionally collecting feature names for error reporting.
(
f: &mut RawFile,
header: &mut QcowHeader,
mut feature_table: Option<&mut Vec<(u8, String)>>,
)
| 210 | impl QcowHeader { |
| 211 | /// Read header extensions, optionally collecting feature names for error reporting. |
| 212 | pub(super) fn read_header_extensions( |
| 213 | f: &mut RawFile, |
| 214 | header: &mut QcowHeader, |
| 215 | mut feature_table: Option<&mut Vec<(u8, String)>>, |
| 216 | ) -> Result<()> { |
| 217 | // Extensions start directly after the header |
| 218 | f.seek(SeekFrom::Start(header.header_size as u64)) |
| 219 | .map_err(Error::ReadingHeader)?; |
| 220 | |
| 221 | loop { |
| 222 | let ext_type = u32::read_be(f).map_err(Error::ReadingHeader)?; |
| 223 | if ext_type == HEADER_EXT_END { |
| 224 | break; |
| 225 | } |
| 226 | |
| 227 | let ext_length = u32::read_be(f).map_err(Error::ReadingHeader)?; |
| 228 | |
| 229 | match ext_type { |
| 230 | HEADER_EXT_BACKING_FORMAT => { |
| 231 | let mut format_bytes = vec![0u8; ext_length as usize]; |
| 232 | f.read_exact(&mut format_bytes) |
| 233 | .map_err(Error::ReadingHeader)?; |
| 234 | let format_str = String::from_utf8(format_bytes) |
| 235 | .map_err(|err| Error::InvalidBackingFileName(err.utf8_error()))?; |
| 236 | if let Some(backing_file) = &mut header.backing_file { |
| 237 | backing_file.format = Some(format_str.parse()?); |
| 238 | } |
| 239 | } |
| 240 | HEADER_EXT_FEATURE_NAME_TABLE if feature_table.is_some() => { |
| 241 | const FEATURE_NAME_ENTRY_SIZE: usize = 1 + 1 + 46; // type + bit + name |
| 242 | let mut data = vec![0u8; ext_length as usize]; |
| 243 | f.read_exact(&mut data).map_err(Error::ReadingHeader)?; |
| 244 | let table = feature_table.as_mut().unwrap(); |
| 245 | for entry in data.chunks_exact(FEATURE_NAME_ENTRY_SIZE) { |
| 246 | if entry[0] == FEAT_TYPE_INCOMPATIBLE { |
| 247 | let bit_number = entry[1]; |
| 248 | let name_bytes = &entry[2..]; |
| 249 | let name_len = name_bytes.iter().position(|&b| b == 0).unwrap_or(46); |
| 250 | let name = String::from_utf8_lossy(&name_bytes[..name_len]).to_string(); |
| 251 | table.push((bit_number, name)); |
| 252 | } |
| 253 | } |
| 254 | } |
| 255 | _ => { |
| 256 | // Skip unknown extension |
| 257 | f.seek(SeekFrom::Current(ext_length as i64)) |
| 258 | .map_err(Error::ReadingHeader)?; |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | // Skip to the next 8 byte boundary |
| 263 | let padding = (8 - (ext_length % 8)) % 8; |
| 264 | f.seek(SeekFrom::Current(padding as i64)) |
| 265 | .map_err(Error::ReadingHeader)?; |
| 266 | } |
| 267 | |
| 268 | Ok(()) |
| 269 | } |