From e6ff5376e1e2e336b3e3a1b992aa9e93428b6c59 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Wed, 18 Aug 2021 14:21:17 -0700 Subject: [PATCH] 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 Tested-by: kokoro Commit-Queue: Daniel Verkamp --- disk/src/android_sparse.rs | 21 ++------- disk/src/composite.rs | 56 ++++++++-------------- disk/src/qcow/mod.rs | 95 ++++++++++++++++---------------------- disk/src/qcow/refcount.rs | 31 ++++--------- 4 files changed, 71 insertions(+), 132 deletions(-) diff --git a/disk/src/android_sparse.rs b/disk/src/android_sparse.rs index 2c0fd34e0a..b191155bd6 100644 --- a/disk/src/android_sparse.rs +++ b/disk/src/android_sparse.rs @@ -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 = std::result::Result; pub const SPARSE_HEADER_MAGIC: u32 = 0xed26ff3a; diff --git a/disk/src/composite.rs b/disk/src/composite.rs index 32d6edfe53..45db6806c3 100644 --- a/disk/src/composite.rs +++ b/disk/src/composite.rs @@ -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), + #[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 for Error { fn from(e: gpt::Error) -> Self { Self::GptError(e) diff --git a/disk/src/qcow/mod.rs b/disk/src/qcow/mod.rs index addf22873c..fb2c3679e0 100644 --- a/disk/src/qcow/mod.rs +++ b/disk/src/qcow/mod.rs @@ -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), + #[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 = std::result::Result; -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. diff --git a/disk/src/qcow/refcount.rs b/disk/src/qcow/refcount.rs index d7f89579ec..2be2579922 100644 --- a/disk/src/qcow/refcount.rs +++ b/disk/src/qcow/refcount.rs @@ -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 = std::result::Result; -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 {