Skip to main content

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    #[error("Inconsistent encryption policy")]
56    InconsistentEncryptionPolicy,
57}
58
59impl FxfsError {
60    /// A helper to match against this FxfsError against the root cause of an anyhow::Error.
61    ///
62    /// The main application of this helper is to allow us to match an anyhow::Error against a
63    /// specific case of FxfsError in a boolean expression, such as:
64    ///
65    /// let result: Result<(), anyhow:Error> = foo();
66    /// match result {
67    ///   Ok(foo) => Ok(foo),
68    ///   Err(e) if &FxfsError::NotFound.matches(e) => { ... }
69    ///   Err(e) => Err(e)
70    /// }
71    pub fn matches(&self, error: &anyhow::Error) -> bool {
72        if let Some(root_cause) = error.root_cause().downcast_ref::<FxfsError>() {
73            self == root_cause
74        } else {
75            false
76        }
77    }
78}
79
80#[cfg(target_os = "fuchsia")]
81mod fuchsia {
82    use super::*;
83    use zx::Status;
84
85    impl From<FxfsError> for Status {
86        fn from(err: FxfsError) -> Status {
87            match err {
88                FxfsError::AlreadyExists => Status::ALREADY_EXISTS,
89                FxfsError::Inconsistent => Status::IO_DATA_INTEGRITY,
90                FxfsError::Internal => Status::INTERNAL,
91                FxfsError::NotDir => Status::NOT_DIR,
92                FxfsError::NotFile => Status::NOT_FILE,
93                FxfsError::NotFound => Status::NOT_FOUND,
94                FxfsError::NotEmpty => Status::NOT_EMPTY,
95                FxfsError::ReadOnlyFilesystem => Status::ACCESS_DENIED,
96                FxfsError::NoSpace => Status::NO_SPACE,
97                FxfsError::Deleted => Status::ACCESS_DENIED,
98                FxfsError::InvalidArgs => Status::INVALID_ARGS,
99                FxfsError::TooBig => Status::FILE_BIG,
100                FxfsError::InvalidVersion => Status::NOT_SUPPORTED,
101                FxfsError::JournalFlushError => Status::IO,
102                FxfsError::NotSupported => Status::NOT_SUPPORTED,
103                FxfsError::AccessDenied => Status::ACCESS_DENIED,
104                FxfsError::OutOfRange => Status::OUT_OF_RANGE,
105                FxfsError::AlreadyBound => Status::ALREADY_BOUND,
106                FxfsError::BadPath => Status::BAD_PATH,
107                FxfsError::WrongType => Status::WRONG_TYPE,
108                FxfsError::IntegrityError => Status::IO_DATA_INTEGRITY,
109                FxfsError::Unavailable => Status::UNAVAILABLE,
110                FxfsError::NoKey => Status::ACCESS_DENIED,
111                FxfsError::InconsistentEncryptionPolicy => Status::BAD_STATE,
112            }
113        }
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::FxfsError;
120    use anyhow::{Context, anyhow};
121
122    #[test]
123    fn test_matches() {
124        // We make heavy use of Context, so make sure that works.
125        let err: anyhow::Error = FxfsError::AlreadyBound.into();
126        let result: Result<(), anyhow::Error> = Err(err);
127        let result = result.context("Foo");
128        let err = result.err().unwrap();
129        assert!(FxfsError::AlreadyBound.matches(&err));
130
131        // `anyhow!` will plumb through source, so this should work just fine.
132        let err = anyhow!(FxfsError::AlreadyBound).context("Foo");
133        assert!(FxfsError::AlreadyBound.matches(&err));
134
135        // `bail!(anyhow!(...).context("blah"))` is quite common and boils down to
136        // `anyhow!(anyhow!(..))`, so check that too.
137        let err = anyhow!(anyhow!(FxfsError::AlreadyBound).context("Foo"));
138        assert!(FxfsError::AlreadyBound.matches(&err));
139    }
140}