mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: qcow: Classify errors in parse_qcow and BackingFile::new
Replace remaining automatic From conversions in parse_qcow and BackingFile::new with explicit BlockError::new calls carrying the appropriate BlockErrorKind at every error site. Internal functions that still return qcow::Result (QcowHeader::new, offset_is_cluster_boundary, clear_autoclear_features and others) are wrapped with map_err at the boundary. These functions stay on qcow::Result as they are internal to the qcow module and the classification belongs at the call site rather than inside the function itself. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
be9ef116aa
commit
524e620240
+64
-28
@@ -205,7 +205,12 @@ impl BackingFile {
|
|||||||
let backing_raw_file = OpenOptions::new()
|
let backing_raw_file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(&config.path)
|
.open(&config.path)
|
||||||
.map_err(|e| Error::BackingFileIo(config.path.clone(), e))?;
|
.map_err(|e| {
|
||||||
|
BlockError::new(
|
||||||
|
BlockErrorKind::Io,
|
||||||
|
Error::BackingFileIo(config.path.clone(), e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut raw_file = RawFile::new(backing_raw_file, direct_io);
|
let mut raw_file = RawFile::new(backing_raw_file, direct_io);
|
||||||
|
|
||||||
@@ -217,12 +222,18 @@ impl BackingFile {
|
|||||||
|
|
||||||
let (kind, virtual_size) = match backing_format {
|
let (kind, virtual_size) = match backing_format {
|
||||||
ImageType::Raw => {
|
ImageType::Raw => {
|
||||||
let size = raw_file
|
let size = raw_file.seek(SeekFrom::End(0)).map_err(|e| {
|
||||||
.seek(SeekFrom::End(0))
|
BlockError::new(
|
||||||
.map_err(|e| Error::BackingFileIo(config.path.clone(), e))?;
|
BlockErrorKind::Io,
|
||||||
raw_file
|
Error::BackingFileIo(config.path.clone(), e),
|
||||||
.rewind()
|
)
|
||||||
.map_err(|e| Error::BackingFileIo(config.path.clone(), e))?;
|
})?;
|
||||||
|
raw_file.rewind().map_err(|e| {
|
||||||
|
BlockError::new(
|
||||||
|
BlockErrorKind::Io,
|
||||||
|
Error::BackingFileIo(config.path.clone(), e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
(BackingKind::Raw(raw_file), size)
|
(BackingKind::Raw(raw_file), size)
|
||||||
}
|
}
|
||||||
ImageType::Qcow2 => {
|
ImageType::Qcow2 => {
|
||||||
@@ -404,9 +415,12 @@ pub(crate) fn parse_qcow(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Validate refcount order to be 0..6
|
// Validate refcount order to be 0..6
|
||||||
let refcount_bits: u64 = 0x01u64
|
let refcount_bits: u64 = 0x01u64.checked_shl(header.refcount_order).ok_or_else(|| {
|
||||||
.checked_shl(header.refcount_order)
|
BlockError::new(
|
||||||
.ok_or(Error::UnsupportedRefcountOrder)?;
|
BlockErrorKind::UnsupportedFeature,
|
||||||
|
Error::UnsupportedRefcountOrder,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
if refcount_bits > 64 {
|
if refcount_bits > 64 {
|
||||||
return Err(BlockError::new(
|
return Err(BlockError::new(
|
||||||
BlockErrorKind::UnsupportedFeature,
|
BlockErrorKind::UnsupportedFeature,
|
||||||
@@ -421,11 +435,17 @@ pub(crate) fn parse_qcow(
|
|||||||
Error::NoRefcountClusters,
|
Error::NoRefcountClusters,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
offset_is_cluster_boundary(header.l1_table_offset, header.cluster_bits)?;
|
offset_is_cluster_boundary(header.l1_table_offset, header.cluster_bits)
|
||||||
offset_is_cluster_boundary(header.snapshots_offset, header.cluster_bits)?;
|
.map_err(|e| BlockError::new(BlockErrorKind::CorruptImage, e))?;
|
||||||
|
offset_is_cluster_boundary(header.snapshots_offset, header.cluster_bits)
|
||||||
|
.map_err(|e| BlockError::new(BlockErrorKind::CorruptImage, e))?;
|
||||||
// refcount table must be a cluster boundary, and within the file's virtual or actual size.
|
// refcount table must be a cluster boundary, and within the file's virtual or actual size.
|
||||||
offset_is_cluster_boundary(header.refcount_table_offset, header.cluster_bits)?;
|
offset_is_cluster_boundary(header.refcount_table_offset, header.cluster_bits)
|
||||||
let file_size = file.metadata().map_err(Error::GettingFileSize)?.len();
|
.map_err(|e| BlockError::new(BlockErrorKind::CorruptImage, e))?;
|
||||||
|
let file_size = file
|
||||||
|
.metadata()
|
||||||
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::GettingFileSize(e)))?
|
||||||
|
.len();
|
||||||
if header.refcount_table_offset > max(file_size, header.size) {
|
if header.refcount_table_offset > max(file_size, header.size) {
|
||||||
return Err(BlockError::new(
|
return Err(BlockError::new(
|
||||||
BlockErrorKind::CorruptImage,
|
BlockErrorKind::CorruptImage,
|
||||||
@@ -437,12 +457,14 @@ pub(crate) fn parse_qcow(
|
|||||||
// this is an old file with broken refcounts, which requires a rebuild.
|
// this is an old file with broken refcounts, which requires a rebuild.
|
||||||
let mut refcount_rebuild_required = true;
|
let mut refcount_rebuild_required = true;
|
||||||
file.seek(SeekFrom::Start(header.refcount_table_offset))
|
file.seek(SeekFrom::Start(header.refcount_table_offset))
|
||||||
.map_err(Error::SeekingFile)?;
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::SeekingFile(e)))?;
|
||||||
let first_refblock_addr = u64::read_be(&mut file).map_err(Error::ReadingHeader)?;
|
let first_refblock_addr = u64::read_be(&mut file)
|
||||||
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingHeader(e)))?;
|
||||||
if first_refblock_addr != 0 {
|
if first_refblock_addr != 0 {
|
||||||
file.seek(SeekFrom::Start(first_refblock_addr))
|
file.seek(SeekFrom::Start(first_refblock_addr))
|
||||||
.map_err(Error::SeekingFile)?;
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::SeekingFile(e)))?;
|
||||||
let first_cluster_refcount = u16::read_be(&mut file).map_err(Error::ReadingHeader)?;
|
let first_cluster_refcount = u16::read_be(&mut file)
|
||||||
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingHeader(e)))?;
|
||||||
if first_cluster_refcount != 0 {
|
if first_cluster_refcount != 0 {
|
||||||
refcount_rebuild_required = false;
|
refcount_rebuild_required = false;
|
||||||
}
|
}
|
||||||
@@ -452,8 +474,8 @@ pub(crate) fn parse_qcow(
|
|||||||
refcount_rebuild_required = true;
|
refcount_rebuild_required = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut raw_file =
|
let mut raw_file = QcowRawFile::from(file, cluster_size, refcount_bits)
|
||||||
QcowRawFile::from(file, cluster_size, refcount_bits).ok_or(Error::InvalidClusterSize)?;
|
.ok_or_else(|| BlockError::new(BlockErrorKind::InvalidFormat, Error::InvalidClusterSize))?;
|
||||||
let is_writable = raw_file.file().is_writable();
|
let is_writable = raw_file.file().is_writable();
|
||||||
|
|
||||||
if header.is_corrupt() {
|
if header.is_corrupt() {
|
||||||
@@ -499,7 +521,7 @@ pub(crate) fn parse_qcow(
|
|||||||
num_l2_clusters,
|
num_l2_clusters,
|
||||||
Some(L1_TABLE_OFFSET_MASK),
|
Some(L1_TABLE_OFFSET_MASK),
|
||||||
)
|
)
|
||||||
.map_err(Error::ReadingHeader)?,
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingHeader(e)))?,
|
||||||
);
|
);
|
||||||
|
|
||||||
let num_clusters = div_round_up_u64(header.size, cluster_size);
|
let num_clusters = div_round_up_u64(header.size, cluster_size);
|
||||||
@@ -530,7 +552,7 @@ pub(crate) fn parse_qcow(
|
|||||||
cluster_size,
|
cluster_size,
|
||||||
refcount_bits,
|
refcount_bits,
|
||||||
)
|
)
|
||||||
.map_err(Error::ReadingRefCounts)?;
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::ReadingRefCounts(e)))?;
|
||||||
|
|
||||||
let l2_entries = cluster_size / size_of::<u64>() as u64;
|
let l2_entries = cluster_size / size_of::<u64>() as u64;
|
||||||
|
|
||||||
@@ -539,23 +561,30 @@ pub(crate) fn parse_qcow(
|
|||||||
header
|
header
|
||||||
.l1_table_offset
|
.l1_table_offset
|
||||||
.checked_add(l1_index * size_of::<u64>() as u64)
|
.checked_add(l1_index * size_of::<u64>() as u64)
|
||||||
.ok_or(Error::InvalidL1TableOffset)?;
|
.ok_or_else(|| {
|
||||||
|
BlockError::new(BlockErrorKind::CorruptImage, Error::InvalidL1TableOffset)
|
||||||
|
})?;
|
||||||
header
|
header
|
||||||
.refcount_table_offset
|
.refcount_table_offset
|
||||||
.checked_add(u64::from(header.refcount_table_clusters) * cluster_size)
|
.checked_add(u64::from(header.refcount_table_clusters) * cluster_size)
|
||||||
.ok_or(Error::InvalidRefcountTableOffset)?;
|
.ok_or_else(|| {
|
||||||
|
BlockError::new(
|
||||||
|
BlockErrorKind::CorruptImage,
|
||||||
|
Error::InvalidRefcountTableOffset,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
// Find available (refcount == 0) clusters for the free list.
|
// Find available (refcount == 0) clusters for the free list.
|
||||||
let file_size = raw_file
|
let file_size = raw_file
|
||||||
.file_mut()
|
.file_mut()
|
||||||
.metadata()
|
.metadata()
|
||||||
.map_err(Error::GettingFileSize)?
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::GettingFileSize(e)))?
|
||||||
.len();
|
.len();
|
||||||
let mut avail_clusters = Vec::new();
|
let mut avail_clusters = Vec::new();
|
||||||
for i in (0..file_size).step_by(cluster_size as usize) {
|
for i in (0..file_size).step_by(cluster_size as usize) {
|
||||||
let refcount = refcounts
|
let refcount = refcounts
|
||||||
.get_cluster_refcount(&mut raw_file, i)
|
.get_cluster_refcount(&mut raw_file, i)
|
||||||
.map_err(Error::GettingRefcount)?;
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, Error::GettingRefcount(e)))?;
|
||||||
if refcount == 0 {
|
if refcount == 0 {
|
||||||
avail_clusters.push(i);
|
avail_clusters.push(i);
|
||||||
}
|
}
|
||||||
@@ -567,10 +596,17 @@ pub(crate) fn parse_qcow(
|
|||||||
{
|
{
|
||||||
header
|
header
|
||||||
.set_dirty_bit(raw_file.file_mut(), true)
|
.set_dirty_bit(raw_file.file_mut(), true)
|
||||||
.map_err(|e| Error::WritingHeader(io::Error::other(e)))?;
|
.map_err(|e| {
|
||||||
|
BlockError::new(
|
||||||
|
BlockErrorKind::Io,
|
||||||
|
Error::WritingHeader(io::Error::other(e)),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
header.clear_autoclear_features(raw_file.file_mut())?;
|
header
|
||||||
|
.clear_autoclear_features(raw_file.file_mut())
|
||||||
|
.map_err(|e| BlockError::new(BlockErrorKind::Io, e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inner = metadata::QcowState {
|
let inner = metadata::QcowState {
|
||||||
|
|||||||
Reference in New Issue
Block a user