block: qcow: Use BeUint for header field I/O
Update QcowHeader and other related places to use BeUint methods internally for reading/writing header fields. This removes the byteorder dependency from mod.rs and consolidates all big-endian file I/O through the shared BeUint trait. Suggested-by: Rob Bradford <rbradford@rivosinc.com> Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
parent
8cdc3b53c0
commit
87e8ac3f1f
1 changed files with 62 additions and 81 deletions
|
|
@ -19,7 +19,6 @@ use std::os::fd::{AsRawFd, RawFd};
|
|||
use std::str::{self, FromStr};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use libc::{EINVAL, EIO, ENOSPC};
|
||||
use log::error;
|
||||
use remain::sorted;
|
||||
|
|
@ -30,7 +29,7 @@ use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt};
|
|||
|
||||
use crate::BlockBackend;
|
||||
use crate::qcow::decoder::{Decoder, ZlibDecoder, ZstdDecoder};
|
||||
use crate::qcow::qcow_raw_file::QcowRawFile;
|
||||
use crate::qcow::qcow_raw_file::{BeUint, QcowRawFile};
|
||||
pub use crate::qcow::raw_file::RawFile;
|
||||
use crate::qcow::refcount::RefCount;
|
||||
use crate::qcow::vec_cache::{CacheMap, Cacheable, VecCache};
|
||||
|
|
@ -376,12 +375,12 @@ impl QcowHeader {
|
|||
.map_err(Error::ReadingHeader)?;
|
||||
|
||||
loop {
|
||||
let ext_type = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let ext_type = u32::read_be(f).map_err(Error::ReadingHeader)?;
|
||||
if ext_type == HEADER_EXT_END {
|
||||
break;
|
||||
}
|
||||
|
||||
let ext_length = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let ext_length = u32::read_be(f).map_err(Error::ReadingHeader)?;
|
||||
|
||||
match ext_type {
|
||||
HEADER_EXT_BACKING_FORMAT => {
|
||||
|
|
@ -428,67 +427,55 @@ impl QcowHeader {
|
|||
/// Creates a QcowHeader from a reference to a file.
|
||||
pub fn new(f: &mut RawFile) -> Result<QcowHeader> {
|
||||
f.rewind().map_err(Error::ReadingHeader)?;
|
||||
let magic = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let magic = u32::read_be(f).map_err(Error::ReadingHeader)?;
|
||||
if magic != QCOW_MAGIC {
|
||||
return Err(Error::InvalidMagic);
|
||||
}
|
||||
|
||||
// Reads the next u32 from the file.
|
||||
fn read_u32_from_file(f: &mut RawFile) -> Result<u32> {
|
||||
f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)
|
||||
fn read_u32_be(f: &mut RawFile) -> Result<u32> {
|
||||
u32::read_be(f).map_err(Error::ReadingHeader)
|
||||
}
|
||||
|
||||
// Reads the next u64 from the file.
|
||||
fn read_u64_from_file(f: &mut RawFile) -> Result<u64> {
|
||||
f.read_u64::<BigEndian>().map_err(Error::ReadingHeader)
|
||||
fn read_u64_be(f: &mut RawFile) -> Result<u64> {
|
||||
u64::read_be(f).map_err(Error::ReadingHeader)
|
||||
}
|
||||
|
||||
let version = read_u32_from_file(f)?;
|
||||
let version = read_u32_be(f)?;
|
||||
|
||||
let mut header = QcowHeader {
|
||||
magic,
|
||||
version,
|
||||
backing_file_offset: read_u64_from_file(f)?,
|
||||
backing_file_size: read_u32_from_file(f)?,
|
||||
cluster_bits: read_u32_from_file(f)?,
|
||||
size: read_u64_from_file(f)?,
|
||||
crypt_method: read_u32_from_file(f)?,
|
||||
l1_size: read_u32_from_file(f)?,
|
||||
l1_table_offset: read_u64_from_file(f)?,
|
||||
refcount_table_offset: read_u64_from_file(f)?,
|
||||
refcount_table_clusters: read_u32_from_file(f)?,
|
||||
nb_snapshots: read_u32_from_file(f)?,
|
||||
snapshots_offset: read_u64_from_file(f)?,
|
||||
incompatible_features: if version == 2 {
|
||||
0
|
||||
} else {
|
||||
read_u64_from_file(f)?
|
||||
},
|
||||
compatible_features: if version == 2 {
|
||||
0
|
||||
} else {
|
||||
read_u64_from_file(f)?
|
||||
},
|
||||
autoclear_features: if version == 2 {
|
||||
0
|
||||
} else {
|
||||
read_u64_from_file(f)?
|
||||
},
|
||||
backing_file_offset: read_u64_be(f)?,
|
||||
backing_file_size: read_u32_be(f)?,
|
||||
cluster_bits: read_u32_be(f)?,
|
||||
size: read_u64_be(f)?,
|
||||
crypt_method: read_u32_be(f)?,
|
||||
l1_size: read_u32_be(f)?,
|
||||
l1_table_offset: read_u64_be(f)?,
|
||||
refcount_table_offset: read_u64_be(f)?,
|
||||
refcount_table_clusters: read_u32_be(f)?,
|
||||
nb_snapshots: read_u32_be(f)?,
|
||||
snapshots_offset: read_u64_be(f)?,
|
||||
incompatible_features: if version == 2 { 0 } else { read_u64_be(f)? },
|
||||
compatible_features: if version == 2 { 0 } else { read_u64_be(f)? },
|
||||
autoclear_features: if version == 2 { 0 } else { read_u64_be(f)? },
|
||||
refcount_order: if version == 2 {
|
||||
DEFAULT_REFCOUNT_ORDER
|
||||
} else {
|
||||
read_u32_from_file(f)?
|
||||
read_u32_be(f)?
|
||||
},
|
||||
header_size: if version == 2 {
|
||||
V2_BARE_HEADER_SIZE
|
||||
} else {
|
||||
read_u32_from_file(f)?
|
||||
read_u32_be(f)?
|
||||
},
|
||||
compression_type: CompressionType::Zlib,
|
||||
backing_file: None,
|
||||
};
|
||||
if version == 3 && header.header_size > V3_BARE_HEADER_SIZE {
|
||||
let raw_compression_type = read_u64_from_file(f)? >> (64 - 8);
|
||||
let raw_compression_type = read_u64_be(f)? >> (64 - 8);
|
||||
header.compression_type = if raw_compression_type == COMPRESSION_TYPE_ZLIB {
|
||||
Ok(CompressionType::Zlib)
|
||||
} else if raw_compression_type == COMPRESSION_TYPE_ZSTD {
|
||||
|
|
@ -620,44 +607,42 @@ impl QcowHeader {
|
|||
/// Write the header to `file`.
|
||||
pub fn write_to<F: Write + Seek>(&self, file: &mut F) -> Result<()> {
|
||||
// Writes the next u32 to the file.
|
||||
fn write_u32_to_file<F: Write>(f: &mut F, value: u32) -> Result<()> {
|
||||
f.write_u32::<BigEndian>(value)
|
||||
.map_err(Error::WritingHeader)
|
||||
fn write_u32_be<F: Write>(f: &mut F, value: u32) -> Result<()> {
|
||||
u32::write_be(f, value).map_err(Error::WritingHeader)
|
||||
}
|
||||
|
||||
// Writes the next u64 to the file.
|
||||
fn write_u64_to_file<F: Write>(f: &mut F, value: u64) -> Result<()> {
|
||||
f.write_u64::<BigEndian>(value)
|
||||
.map_err(Error::WritingHeader)
|
||||
fn write_u64_be<F: Write>(f: &mut F, value: u64) -> Result<()> {
|
||||
u64::write_be(f, value).map_err(Error::WritingHeader)
|
||||
}
|
||||
|
||||
write_u32_to_file(file, self.magic)?;
|
||||
write_u32_to_file(file, self.version)?;
|
||||
write_u64_to_file(file, self.backing_file_offset)?;
|
||||
write_u32_to_file(file, self.backing_file_size)?;
|
||||
write_u32_to_file(file, self.cluster_bits)?;
|
||||
write_u64_to_file(file, self.size)?;
|
||||
write_u32_to_file(file, self.crypt_method)?;
|
||||
write_u32_to_file(file, self.l1_size)?;
|
||||
write_u64_to_file(file, self.l1_table_offset)?;
|
||||
write_u64_to_file(file, self.refcount_table_offset)?;
|
||||
write_u32_to_file(file, self.refcount_table_clusters)?;
|
||||
write_u32_to_file(file, self.nb_snapshots)?;
|
||||
write_u64_to_file(file, self.snapshots_offset)?;
|
||||
write_u32_be(file, self.magic)?;
|
||||
write_u32_be(file, self.version)?;
|
||||
write_u64_be(file, self.backing_file_offset)?;
|
||||
write_u32_be(file, self.backing_file_size)?;
|
||||
write_u32_be(file, self.cluster_bits)?;
|
||||
write_u64_be(file, self.size)?;
|
||||
write_u32_be(file, self.crypt_method)?;
|
||||
write_u32_be(file, self.l1_size)?;
|
||||
write_u64_be(file, self.l1_table_offset)?;
|
||||
write_u64_be(file, self.refcount_table_offset)?;
|
||||
write_u32_be(file, self.refcount_table_clusters)?;
|
||||
write_u32_be(file, self.nb_snapshots)?;
|
||||
write_u64_be(file, self.snapshots_offset)?;
|
||||
|
||||
if self.version == 3 {
|
||||
write_u64_to_file(file, self.incompatible_features)?;
|
||||
write_u64_to_file(file, self.compatible_features)?;
|
||||
write_u64_to_file(file, self.autoclear_features)?;
|
||||
write_u32_to_file(file, self.refcount_order)?;
|
||||
write_u32_to_file(file, self.header_size)?;
|
||||
write_u64_be(file, self.incompatible_features)?;
|
||||
write_u64_be(file, self.compatible_features)?;
|
||||
write_u64_be(file, self.autoclear_features)?;
|
||||
write_u32_be(file, self.refcount_order)?;
|
||||
write_u32_be(file, self.header_size)?;
|
||||
|
||||
if self.header_size > V3_BARE_HEADER_SIZE {
|
||||
write_u64_to_file(file, 0)?; // no compression
|
||||
write_u64_be(file, 0)?; // no compression
|
||||
}
|
||||
|
||||
write_u32_to_file(file, 0)?; // header extension type: end of header extension area
|
||||
write_u32_to_file(file, 0)?; // length of header extension data: 0
|
||||
write_u32_be(file, 0)?; // header extension type: end of header extension area
|
||||
write_u32_be(file, 0)?; // length of header extension data: 0
|
||||
}
|
||||
|
||||
if let Some(backing_file_path) = self.backing_file.as_ref().map(|bf| &bf.path) {
|
||||
|
|
@ -689,8 +674,7 @@ impl QcowHeader {
|
|||
}
|
||||
file.seek(SeekFrom::Start(V2_BARE_HEADER_SIZE as u64))
|
||||
.map_err(Error::WritingHeader)?;
|
||||
file.write_u64::<BigEndian>(self.incompatible_features)
|
||||
.map_err(Error::WritingHeader)?;
|
||||
u64::write_be(file, self.incompatible_features).map_err(Error::WritingHeader)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -909,12 +893,11 @@ impl QcowFile {
|
|||
let mut refcount_rebuild_required = true;
|
||||
file.seek(SeekFrom::Start(header.refcount_table_offset))
|
||||
.map_err(Error::SeekingFile)?;
|
||||
let first_refblock_addr = file.read_u64::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let first_refblock_addr = u64::read_be(&mut file).map_err(Error::ReadingHeader)?;
|
||||
if first_refblock_addr != 0 {
|
||||
file.seek(SeekFrom::Start(first_refblock_addr))
|
||||
.map_err(Error::SeekingFile)?;
|
||||
let first_cluster_refcount =
|
||||
file.read_u16::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let first_cluster_refcount = u16::read_be(&mut file).map_err(Error::ReadingHeader)?;
|
||||
if first_cluster_refcount != 0 {
|
||||
refcount_rebuild_required = false;
|
||||
}
|
||||
|
|
@ -2371,7 +2354,7 @@ pub fn convert(
|
|||
pub fn detect_image_type(file: &mut RawFile) -> Result<ImageType> {
|
||||
let orig_seek = file.stream_position().map_err(Error::SeekingFile)?;
|
||||
file.rewind().map_err(Error::SeekingFile)?;
|
||||
let magic = file.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let magic = u32::read_be(file).map_err(Error::ReadingHeader)?;
|
||||
let image_type = if magic == QCOW_MAGIC {
|
||||
ImageType::Qcow2
|
||||
} else {
|
||||
|
|
@ -2607,10 +2590,8 @@ mod unit_tests {
|
|||
disk_file
|
||||
.seek(SeekFrom::Start(header.header_size as u64))
|
||||
.unwrap();
|
||||
disk_file.write_u32::<BigEndian>(ext_type).unwrap();
|
||||
disk_file
|
||||
.write_u32::<BigEndian>(ext_data.len() as u32)
|
||||
.unwrap();
|
||||
u32::write_be(&mut disk_file, ext_type).unwrap();
|
||||
u32::write_be(&mut disk_file, ext_data.len() as u32).unwrap();
|
||||
disk_file.write_all(ext_data).unwrap();
|
||||
|
||||
// Add padding to 8-byte boundary
|
||||
|
|
@ -2619,7 +2600,7 @@ mod unit_tests {
|
|||
disk_file.write_all(&vec![0u8; padding]).unwrap();
|
||||
}
|
||||
|
||||
disk_file.write_u32::<BigEndian>(HEADER_EXT_END).unwrap();
|
||||
u32::write_be(&mut disk_file, HEADER_EXT_END).unwrap();
|
||||
|
||||
disk_file.rewind().unwrap();
|
||||
|
||||
|
|
@ -3910,7 +3891,7 @@ mod unit_tests {
|
|||
disk_file
|
||||
.seek(SeekFrom::Start(V2_BARE_HEADER_SIZE as u64))
|
||||
.unwrap();
|
||||
let features_before = disk_file.read_u64::<BigEndian>().unwrap();
|
||||
let features_before = u64::read_be(&mut disk_file).unwrap();
|
||||
assert_eq!(
|
||||
features_before & IncompatFeatures::DIRTY.bits(),
|
||||
0,
|
||||
|
|
@ -3926,7 +3907,7 @@ mod unit_tests {
|
|||
disk_file
|
||||
.seek(SeekFrom::Start(V2_BARE_HEADER_SIZE as u64))
|
||||
.unwrap();
|
||||
let features_during = disk_file.read_u64::<BigEndian>().unwrap();
|
||||
let features_during = u64::read_be(&mut disk_file).unwrap();
|
||||
assert_ne!(
|
||||
features_during & IncompatFeatures::DIRTY.bits(),
|
||||
0,
|
||||
|
|
@ -3940,7 +3921,7 @@ mod unit_tests {
|
|||
disk_file
|
||||
.seek(SeekFrom::Start(V2_BARE_HEADER_SIZE as u64))
|
||||
.unwrap();
|
||||
let features_after = disk_file.read_u64::<BigEndian>().unwrap();
|
||||
let features_after = u64::read_be(&mut disk_file).unwrap();
|
||||
assert_eq!(
|
||||
features_after & IncompatFeatures::DIRTY.bits(),
|
||||
0,
|
||||
|
|
@ -4003,7 +3984,7 @@ mod unit_tests {
|
|||
verify_raw
|
||||
.seek(SeekFrom::Start(V2_BARE_HEADER_SIZE as u64))
|
||||
.unwrap();
|
||||
let features = verify_raw.read_u64::<BigEndian>().unwrap();
|
||||
let features = u64::read_be(&mut verify_raw).unwrap();
|
||||
assert_eq!(
|
||||
features & IncompatFeatures::DIRTY.bits(),
|
||||
0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue