fxfs/
errors.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use thiserror::Error;
6
7#[derive(Eq, Error, Clone, Debug, PartialEq)]
8pub enum FxfsError {
9    #[error("Already exists")]
10    AlreadyExists,
11    #[error("Filesystem inconsistency")]
12    Inconsistent,
13    #[error("Internal error")]
14    Internal,
15    #[error("Expected directory")]
16    NotDir,
17    #[error("Expected file")]
18    NotFile,
19    #[error("Not found")]
20    NotFound,
21    #[error("Not empty")]
22    NotEmpty,
23    #[error("Read only filesystem")]
24    ReadOnlyFilesystem,
25    #[error("No space")]
26    NoSpace,
27    #[error("Deleted")]
28    Deleted,
29    #[error("Invalid arguments")]
30    InvalidArgs,
31    #[error("Too big")]
32    TooBig,
33    #[error("Invalid version")]
34    InvalidVersion,
35    #[error("Journal flush error")]
36    JournalFlushError,
37    #[error("Not supported")]
38    NotSupported,
39    #[error("Access denied")]
40    AccessDenied,
41    #[error("Out of range")]
42    OutOfRange,
43    #[error("Already bound")]
44    AlreadyBound,
45    #[error("Bad path")]
46    BadPath,
47    #[error("Wrong type")]
48    WrongType,
49    #[error("Data integrity error")]
50    IntegrityError,
51    #[error("Unavailable")]
52    Unavailable,
53    #[error("No key")]
54    NoKey,
55}
56
57impl FxfsError {
58    /// A helper to match against this FxfsError against the root cause of an anyhow::Error.
59    ///
60    /// The main application of this helper is to allow us to match an anyhow::Error against a
61    /// specific case of FxfsError in a boolean expression, such as:
62    ///
63    /// let result: Result<(), anyhow:Error> = foo();
64    /// match result {
65    ///   Ok(foo) => Ok(foo),
66    ///   Err(e) if &FxfsError::NotFound.matches(e) => { ... }
67    ///   Err(e) => Err(e)
68    /// }
69    pub fn matches(&self, error: &anyhow::Error) -> bool {
70        if let Some(root_cause) = error.root_cause().downcast_ref::<FxfsError>() {
71            self == root_cause
72        } else {
73            false
74        }
75    }
76}
77
78#[cfg(target_os = "fuchsia")]
79mod fuchsia {
80    use super::*;
81    use zx::Status;
82
83    impl From<FxfsError> for Status {
84        fn from(err: FxfsError) -> Status {
85            match err {
86                FxfsError::AlreadyExists => Status::ALREADY_EXISTS,
87                FxfsError::Inconsistent => Status::IO_DATA_INTEGRITY,
88                FxfsError::Internal => Status::INTERNAL,
89                FxfsError::NotDir => Status::NOT_DIR,
90                FxfsError::NotFile => Status::NOT_FILE,
91                FxfsError::NotFound => Status::NOT_FOUND,
92                FxfsError::NotEmpty => Status::NOT_EMPTY,
93                FxfsError::ReadOnlyFilesystem => Status::ACCESS_DENIED,
94                FxfsError::NoSpace => Status::NO_SPACE,
95                FxfsError::Deleted => Status::ACCESS_DENIED,
96                FxfsError::InvalidArgs => Status::INVALID_ARGS,
97                FxfsError::TooBig => Status::FILE_BIG,
98                FxfsError::InvalidVersion => Status::NOT_SUPPORTED,
99                FxfsError::JournalFlushError => Status::IO,
100                FxfsError::NotSupported => Status::NOT_SUPPORTED,
101                FxfsError::AccessDenied => Status::ACCESS_DENIED,
102                FxfsError::OutOfRange => Status::OUT_OF_RANGE,
103                FxfsError::AlreadyBound => Status::ALREADY_BOUND,
104                FxfsError::BadPath => Status::BAD_PATH,
105                FxfsError::WrongType => Status::WRONG_TYPE,
106                FxfsError::IntegrityError => Status::IO_DATA_INTEGRITY,
107                FxfsError::Unavailable => Status::UNAVAILABLE,
108                FxfsError::NoKey => Status::ACCESS_DENIED,
109            }
110        }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::FxfsError;
117    use anyhow::{anyhow, Context};
118
119    #[test]
120    fn test_matches() {
121        // We make heavy use of Context, so make sure that works.
122        let err: anyhow::Error = FxfsError::AlreadyBound.into();
123        let result: Result<(), anyhow::Error> = Err(err);
124        let result = result.context("Foo");
125        let err = result.err().unwrap();
126        assert!(FxfsError::AlreadyBound.matches(&err));
127
128        // `anyhow!` will plumb through source, so this should work just fine.
129        let err = anyhow!(FxfsError::AlreadyBound).context("Foo");
130        assert!(FxfsError::AlreadyBound.matches(&err));
131
132        // `bail!(anyhow!(...).context("blah"))` is quite common and boils down to
133        // `anyhow!(anyhow!(..))`, so check that too.
134        let err = anyhow!(anyhow!(FxfsError::AlreadyBound).context("Foo"));
135        assert!(FxfsError::AlreadyBound.matches(&err));
136    }
137}