Skip to main content

iris_format/
error.rs

1//! What can go wrong while reading a container.
2
3use iris_abi::Tag;
4
5/// Why a container could not be read, or could not be trusted once it was read.
6///
7/// Every variant carries enough to put in a log line without going back to the file. An operator
8/// who gets one of these should be able to say what is wrong with the dataset without opening a hex
9/// editor, because the alternative is that they open a hex editor.
10#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
11#[non_exhaustive]
12pub enum Error {
13    /// The file does not start with the container magic.
14    #[error("this is not an iris container: it starts with {found:02x?} and not {expected:02x?}")]
15    NotAContainer {
16        /// The first eight bytes of the file, or fewer if the file is shorter than that.
17        found: Vec<u8>,
18        /// What those bytes should have been.
19        expected: Vec<u8>,
20    },
21    /// The file starts correctly but ends somewhere unexpected.
22    #[error("the container is truncated: {what} needs {needed} bytes and there are {available}")]
23    Truncated {
24        /// Which part of the file ran out.
25        what: &'static str,
26        /// How many bytes that part needed.
27        needed: u64,
28        /// How many were there.
29        available: u64,
30    },
31    /// The container was written by a newer major version.
32    #[error(
33        "this container is format {major}.{minor} and this build reads format {supported_major}.x"
34    )]
35    UnsupportedFormat {
36        /// The major version in the file.
37        major: u16,
38        /// The minor version in the file.
39        minor: u16,
40        /// The major version this build understands.
41        supported_major: u16,
42    },
43    /// A reserved field was not zero.
44    ///
45    /// Reserved fields are the only place a future version can put a change that older readers must
46    /// not ignore, so an older reader has to refuse rather than carry on.
47    #[error(
48        "a reserved field in the {what} is not zero, so this container uses something this build does not know about"
49    )]
50    Reserved {
51        /// Which part of the container the field is in.
52        what: &'static str,
53    },
54    /// A section points somewhere that is not inside the payload area.
55    #[error(
56        "section {id} covers bytes {offset}..{end} which is not inside the payload area of a {file_len} byte container"
57    )]
58    SectionOutOfBounds {
59        /// Which section.
60        id: u32,
61        /// Where it claims to start.
62        offset: u64,
63        /// Where it claims to end, saturated at `u64::MAX`.
64        end: u64,
65        /// How long the file actually is.
66        file_len: u64,
67    },
68    /// Two sections claim the same identifier.
69    #[error("section id {id} is used twice, so a reference to it is ambiguous")]
70    DuplicateSection {
71        /// The repeated identifier.
72        id: u32,
73    },
74    /// A required footer record was missing.
75    #[error("the footer has no {0} record")]
76    MissingRecord(Tag),
77    /// A footer record appeared more times than it is allowed to.
78    #[error("the footer has more than one {0} record")]
79    RepeatedRecord(Tag),
80    /// A known footer record was written at a version this build does not read.
81    #[error("the footer has a {tag} record at version {version}, which this build does not read")]
82    UnsupportedRecord {
83        /// Which record.
84        tag: Tag,
85        /// The version on it.
86        version: u16,
87    },
88    /// A digest did not match the bytes it covers.
89    #[error(
90        "the {what} digest does not match: the footer says {expected} and the bytes hash to {actual}"
91    )]
92    DigestMismatch {
93        /// Which digest.
94        what: String,
95        /// What the container claims.
96        expected: String,
97        /// What the bytes actually hash to.
98        actual: String,
99    },
100    /// The bytes inside the footer did not parse.
101    #[error("the footer is malformed: {0}")]
102    Footer(#[from] iris_abi::Error),
103    /// Something in the container is bigger than this build can address.
104    ///
105    /// On a 64 bit host this cannot happen. It is here so that a 32 bit host gets a sentence
106    /// instead of a panic.
107    #[error(
108        "the container declares {needed} bytes for {what}, which does not fit in this build's address space"
109    )]
110    TooLarge {
111        /// Which part of the container.
112        what: &'static str,
113        /// How many bytes it asked for.
114        needed: u64,
115    },
116}
117
118/// The result of reading a container.
119pub type Result<T> = core::result::Result<T, Error>;