disk: convert to ThisError and sort

BUG=b:197143586
TEST=cargo check --features=composite-disk

Change-Id: Ibd06b85b959d28f6cc5948be30220fa268034dcb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3105077
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Daniel Verkamp 2021-08-18 14:21:17 -07:00 committed by Commit Bot
parent 5225377caf
commit e6ff5376e1
4 changed files with 71 additions and 132 deletions

View file

@ -5,7 +5,6 @@
// https://android.googlesource.com/platform/system/core/+/7b444f0/libsparse/sparse_format.h
use std::collections::BTreeMap;
use std::fmt::{self, Display};
use std::fs::File;
use std::io::{self, ErrorKind, Read, Seek, SeekFrom};
use std::mem;
@ -17,29 +16,19 @@ use base::{
};
use data_model::{DataInit, Le16, Le32, VolatileSlice};
use remain::sorted;
use thiserror::Error;
#[sorted]
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum Error {
#[error("invalid magic header for android sparse format")]
InvalidMagicHeader,
#[error("invalid specification: \"{0}\"")]
InvalidSpecification(String),
#[error("failed to read specification: \"{0}\"")]
ReadSpecificationError(io::Error),
}
impl Display for Error {
#[remain::check]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
#[sorted]
match self {
InvalidMagicHeader => write!(f, "invalid magic header for android sparse format"),
InvalidSpecification(s) => write!(f, "invalid specification: \"{}\"", s),
ReadSpecificationError(e) => write!(f, "failed to read specification: \"{}\"", e),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
pub const SPARSE_HEADER_MAGIC: u32 = 0xed26ff3a;

View file

@ -5,7 +5,6 @@
use std::cmp::{max, min};
use std::collections::HashSet;
use std::convert::TryInto;
use std::fmt::{self, Display};
use std::fs::{File, OpenOptions};
use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
use std::ops::Range;
@ -20,6 +19,7 @@ use data_model::VolatileSlice;
use protobuf::Message;
use protos::cdisk_spec::{self, ComponentDisk, CompositeDisk, ReadWriteCapability};
use remain::sorted;
use thiserror::Error;
use uuid::Uuid;
use crate::gpt::{
@ -44,62 +44,42 @@ const LINUX_FILESYSTEM_GUID: Uuid = Uuid::from_u128(0x0FC63DAF_8483_4772_8E79_3D
const EFI_SYSTEM_PARTITION_GUID: Uuid = Uuid::from_u128(0xC12A7328_F81F_11D2_BA4B_00A0C93EC93B);
#[sorted]
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum Error {
#[error("failed to use underlying disk: \"{0}\"")]
DiskError(Box<crate::Error>),
#[error("duplicate GPT partition label \"{0}\"")]
DuplicatePartitionLabel(String),
#[error("failed to write GPT header: \"{0}\"")]
GptError(gpt::Error),
#[error("invalid magic header for composite disk format")]
InvalidMagicHeader,
#[error("invalid partition path {0:?}")]
InvalidPath(PathBuf),
#[error("failed to parse specification proto: \"{0}\"")]
InvalidProto(protobuf::ProtobufError),
#[error("invalid specification: \"{0}\"")]
InvalidSpecification(String),
#[error("no image files for partition {0:?}")]
NoImageFiles(PartitionInfo),
#[error("failed to open component file \"{1}\": \"{0}\"")]
OpenFile(io::Error, String),
#[error("failed to read specification: \"{0}\"")]
ReadSpecificationError(io::Error),
#[error("Read-write partition {0:?} size is not a multiple of {}.", 1 << PARTITION_SIZE_SHIFT)]
UnalignedReadWrite(PartitionInfo),
#[error("unknown version {0} in specification")]
UnknownVersion(u64),
#[error("unsupported component disk type \"{0:?}\"")]
UnsupportedComponent(ImageType),
#[error("failed to write composite disk header: \"{0}\"")]
WriteHeader(io::Error),
#[error("failed to write specification proto: \"{0}\"")]
WriteProto(protobuf::ProtobufError),
#[error("failed to write zero filler: \"{0}\"")]
WriteZeroFiller(io::Error),
}
impl Display for Error {
#[remain::check]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
#[sorted]
match self {
DiskError(e) => write!(f, "failed to use underlying disk: \"{}\"", e),
DuplicatePartitionLabel(label) => {
write!(f, "duplicate GPT partition label \"{}\"", label)
}
GptError(e) => write!(f, "failed to write GPT header: \"{}\"", e),
InvalidMagicHeader => write!(f, "invalid magic header for composite disk format"),
InvalidPath(path) => write!(f, "invalid partition path {:?}", path),
InvalidProto(e) => write!(f, "failed to parse specification proto: \"{}\"", e),
InvalidSpecification(s) => write!(f, "invalid specification: \"{}\"", s),
NoImageFiles(partition) => write!(f, "no image files for partition {:?}", partition),
OpenFile(e, p) => write!(f, "failed to open component file \"{}\": \"{}\"", p, e),
ReadSpecificationError(e) => write!(f, "failed to read specification: \"{}\"", e),
UnalignedReadWrite(partition) => write!(
f,
"Read-write partition {:?} size is not a multiple of {}.",
partition,
1 << PARTITION_SIZE_SHIFT
),
UnknownVersion(v) => write!(f, "unknown version {} in specification", v),
UnsupportedComponent(c) => write!(f, "unsupported component disk type \"{:?}\"", c),
WriteHeader(e) => write!(f, "failed to write composite disk header: \"{}\"", e),
WriteProto(e) => write!(f, "failed to write specification proto: \"{}\"", e),
WriteZeroFiller(e) => write!(f, "failed to write zero filler: \"{}\"", e),
}
}
}
impl std::error::Error for Error {}
impl From<gpt::Error> for Error {
fn from(e: gpt::Error) -> Self {
Self::GptError(e)

View file

@ -13,9 +13,9 @@ use base::{
use data_model::{VolatileMemory, VolatileSlice};
use libc::{EINVAL, ENOSPC, ENOTSUP};
use remain::sorted;
use thiserror::Error;
use std::cmp::{max, min};
use std::fmt::{self, Display};
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::size_of;
@ -28,103 +28,86 @@ use crate::qcow::vec_cache::{CacheMap, Cacheable, VecCache};
use crate::{create_disk_file, DiskFile, DiskGetLen};
#[sorted]
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum Error {
#[error("backing file io error: {0}")]
BackingFileIo(io::Error),
#[error("backing file open error: {0}")]
BackingFileOpen(Box<crate::Error>),
#[error("backing file name is too long: {0} bytes over")]
BackingFileTooLong(usize),
#[error("compressed blocks not supported")]
CompressedBlocksNotSupported,
#[error("failed to evict cache: {0}")]
EvictingCache(io::Error),
#[error("file larger than max of {}: {0}", MAX_QCOW_FILE_SIZE)]
FileTooBig(u64),
#[error("failed to get file size: {0}")]
GettingFileSize(io::Error),
#[error("failed to get refcount: {0}")]
GettingRefcount(refcount::Error),
#[error("failed to parse filename: {0}")]
InvalidBackingFileName(str::Utf8Error),
#[error("invalid cluster index")]
InvalidClusterIndex,
#[error("invalid cluster size")]
InvalidClusterSize,
#[error("invalid index")]
InvalidIndex,
#[error("invalid L1 table offset")]
InvalidL1TableOffset,
#[error("invalid L1 table size {0}")]
InvalidL1TableSize(u32),
#[error("invalid magic")]
InvalidMagic,
#[error("invalid offset")]
InvalidOffset(u64),
#[error("invalid refcount table offset")]
InvalidRefcountTableOffset,
#[error("invalid refcount table size: {0}")]
InvalidRefcountTableSize(u64),
#[error("no free clusters")]
NoFreeClusters,
#[error("no refcount clusters")]
NoRefcountClusters,
#[error("not enough space for refcounts")]
NotEnoughSpaceForRefcounts,
#[error("failed to open file: {0}")]
OpeningFile(io::Error),
#[error("failed to open file: {0}")]
ReadingHeader(io::Error),
#[error("failed to read pointers: {0}")]
ReadingPointers(io::Error),
#[error("failed to read ref count block: {0}")]
ReadingRefCountBlock(refcount::Error),
#[error("failed to read ref counts: {0}")]
ReadingRefCounts(io::Error),
#[error("failed to rebuild ref counts: {0}")]
RebuildingRefCounts(io::Error),
#[error("refcount table offset past file end")]
RefcountTableOffEnd,
#[error("too many clusters specified for refcount table")]
RefcountTableTooLarge,
#[error("failed to seek file: {0}")]
SeekingFile(io::Error),
#[error("failed to set refcount refcount: {0}")]
SettingRefcountRefcount(io::Error),
#[error("size too small for number of clusters")]
SizeTooSmallForNumberOfClusters,
#[error("l1 entry table too large: {0}")]
TooManyL1Entries(u64),
#[error("ref count table too large: {0}")]
TooManyRefcounts(u64),
#[error("unsupported refcount order")]
UnsupportedRefcountOrder,
#[error("unsupported version: {0}")]
UnsupportedVersion(u32),
#[error("failed to write header: {0}")]
WritingHeader(io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Display for Error {
#[remain::check]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
#[sorted]
match self {
BackingFileIo(e) => write!(f, "backing file io error: {}", e),
BackingFileOpen(e) => write!(f, "backing file open error: {}", *e),
BackingFileTooLong(len) => {
write!(f, "backing file name is too long: {} bytes over", len)
}
CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"),
EvictingCache(e) => write!(f, "failed to evict cache: {}", e),
FileTooBig(size) => write!(
f,
"file larger than max of {}: {}",
MAX_QCOW_FILE_SIZE, size
),
GettingFileSize(e) => write!(f, "failed to get file size: {}", e),
GettingRefcount(e) => write!(f, "failed to get refcount: {}", e),
InvalidBackingFileName(e) => write!(f, "failed to parse filename: {}", e),
InvalidClusterIndex => write!(f, "invalid cluster index"),
InvalidClusterSize => write!(f, "invalid cluster size"),
InvalidIndex => write!(f, "invalid index"),
InvalidL1TableOffset => write!(f, "invalid L1 table offset"),
InvalidL1TableSize(size) => write!(f, "invalid L1 table size {}", size),
InvalidMagic => write!(f, "invalid magic"),
InvalidOffset(_) => write!(f, "invalid offset"),
InvalidRefcountTableOffset => write!(f, "invalid refcount table offset"),
InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {}", size),
NoFreeClusters => write!(f, "no free clusters"),
NoRefcountClusters => write!(f, "no refcount clusters"),
NotEnoughSpaceForRefcounts => write!(f, "not enough space for refcounts"),
OpeningFile(e) => write!(f, "failed to open file: {}", e),
ReadingHeader(e) => write!(f, "failed to read header: {}", e),
ReadingPointers(e) => write!(f, "failed to read pointers: {}", e),
ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {}", e),
ReadingRefCounts(e) => write!(f, "failed to read ref counts: {}", e),
RebuildingRefCounts(e) => write!(f, "failed to rebuild ref counts: {}", e),
RefcountTableOffEnd => write!(f, "refcount table offset past file end"),
RefcountTableTooLarge => write!(f, "too many clusters specified for refcount table"),
SeekingFile(e) => write!(f, "failed to seek file: {}", e),
SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {}", e),
SizeTooSmallForNumberOfClusters => write!(f, "size too small for number of clusters"),
TooManyL1Entries(count) => write!(f, "l1 entry table too large: {}", count),
TooManyRefcounts(count) => write!(f, "ref count table too large: {}", count),
UnsupportedRefcountOrder => write!(f, "unsupported refcount order"),
UnsupportedVersion(v) => write!(f, "unsupported version: {}", v),
WritingHeader(e) => write!(f, "failed to write header: {}", e),
}
}
}
// Maximum data size supported.
const MAX_QCOW_FILE_SIZE: u64 = 0x01 << 44; // 16 TB.

View file

@ -2,50 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::fmt::{self, Display};
use std::io;
use libc::EINVAL;
use remain::sorted;
use thiserror::Error;
use crate::qcow::qcow_raw_file::QcowRawFile;
use crate::qcow::vec_cache::{CacheMap, Cacheable, VecCache};
#[derive(Debug)]
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
/// `EvictingCache` - Error writing a refblock from the cache to disk.
#[error("failed to write a refblock from the cache to disk: {0}")]
EvictingRefCounts(io::Error),
/// `InvalidIndex` - Address requested isn't within the range of the disk.
#[error("address requested is not within the range of the disk")]
InvalidIndex,
/// `NeedCluster` - Handle this error by reading the cluster and calling the function again.
#[error("cluster with addr={0} needs to be read")]
NeedCluster(u64),
/// `NeedNewCluster` - Handle this error by allocating a cluster and calling the function again.
#[error("new cluster needs to be allocated for refcounts")]
NeedNewCluster,
/// `ReadingRefCounts` - Error reading the file in to the refcount cache.
#[error("failed to read the file into the refcount cache: {0}")]
ReadingRefCounts(io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
match self {
EvictingRefCounts(e) => write!(
f,
"failed to write a refblock from the cache to disk: {}",
e
),
InvalidIndex => write!(f, "address requested is not within the range of the disk"),
NeedCluster(addr) => write!(f, "cluster with addr={} needs to be read", addr),
NeedNewCluster => write!(f, "new cluster needs to be allocated for refcounts"),
ReadingRefCounts(e) => {
write!(f, "failed to read the file into the refcount cache: {}", e)
}
}
}
}
/// Represents the refcount entries for an open qcow file.
#[derive(Debug)]
pub struct RefCount {