mountpoint_s3_fs/metablock/
error.rs1use anyhow::anyhow;
2use mountpoint_s3_client::error_metadata::ProvideErrorMetadata;
3use std::ffi::OsString;
4use thiserror::Error;
5
6use crate::fs::error_metadata::{ErrorMetadata, MOUNTPOINT_ERROR_CLIENT};
7#[cfg(feature = "manifest")]
8use crate::manifest::ManifestError;
9use crate::metablock::S3Location;
10use crate::sync::Arc;
11use crate::upload::UploadError;
12
13use super::InodeNo;
14
15#[derive(Debug, Error, Clone)]
16pub enum InodeError {
17 #[error("error from ObjectClient")]
19 ClientError {
20 source: Arc<anyhow::Error>,
21 metadata: Box<ErrorMetadata>,
22 },
23 #[error("file {0:?} does not exist in parent inode {1}")]
24 FileDoesNotExist(String, InodeErrorInfo),
25 #[error("inode {0} does not exist")]
26 InodeDoesNotExist(InodeNo),
27 #[error("invalid file name {0:?}")]
28 InvalidFileName(OsString),
29 #[error("inode {0} is not a directory")]
30 NotADirectory(InodeErrorInfo),
31 #[error("inode {0} is a directory")]
32 IsDirectory(InodeErrorInfo),
33 #[error("file already exists at inode {0}")]
34 FileAlreadyExists(InodeErrorInfo),
35 #[error("inode {0} is not writable")]
36 InodeNotWritable(InodeErrorInfo),
37 #[error("Invalid state of inode {0} to be written. Aborting the write.")]
38 InodeInvalidWriteStatus(InodeErrorInfo),
39 #[error("inode {0} is already being written")]
40 InodeAlreadyWriting(InodeErrorInfo),
41 #[error("inode {0} is not readable while being written")]
42 InodeNotReadableWhileWriting(InodeErrorInfo),
43 #[error("inode {0} is not writable while being read")]
44 InodeNotWritableWhileReading(InodeErrorInfo),
45 #[error("remote directory cannot be removed at inode {0}")]
46 CannotRemoveRemoteDirectory(InodeErrorInfo),
47 #[error("non-empty directory cannot be removed at inode {0}")]
48 DirectoryNotEmpty(InodeErrorInfo),
49 #[error("inode {0} cannot be unlinked while being written")]
50 UnlinkNotPermittedWhileWriting(InodeErrorInfo),
51 #[error("inode {0} is a directory and cannot be renamed")]
52 CannotRenameDirectory(InodeErrorInfo),
53 #[error("inode {0} cannot be renamed while being written")]
54 RenameNotPermittedWhileWriting(InodeErrorInfo),
55 #[error("rename destination {dest_key:?} already exists, cannot rename inode {src_inode}")]
56 RenameDestinationExists {
57 dest_key: String,
58 src_inode: InodeErrorInfo,
59 },
60 #[error("rename is not supported on this bucket")]
61 RenameNotSupported(),
62 #[error("S3 key {0:?} was too long")]
63 NameTooLong(String),
64 #[error("corrupted metadata for inode {0}")]
65 CorruptedMetadata(InodeErrorInfo),
66 #[error("inode {0} is a remote inode and its attributes cannot be modified")]
67 SetAttrNotPermittedOnRemoteInode(InodeErrorInfo),
68 #[error("inode {old_inode} for remote key {remote_key:?} is stale, replaced by inode {new_inode}")]
69 StaleInode {
70 remote_key: String,
71 old_inode: InodeErrorInfo,
72 new_inode: InodeErrorInfo,
73 },
74 #[cfg(feature = "manifest")]
75 #[error("manifest error")]
76 ManifestError(#[source] Arc<ManifestError>),
77 #[error("operation not supported on virtual inode {ino}")]
78 OperationNotSupportedOnSyntheticInode { ino: InodeNo },
79 #[error("out-of-order readdir, expected offset {expected} but got {actual} on dir handle {fh}")]
80 OutOfOrderReadDir { expected: i64, actual: i64, fh: u64 },
81 #[error("invalid directory handle {fh}")]
82 NoSuchDirHandle { fh: u64 },
83 #[error("objects in flexible retrieval storage classes are not accessible")]
84 FlexibleRetrievalObjectNotAccessible(InodeErrorInfo),
85}
86
87impl InodeError {
88 pub fn client_error<E>(err: E, context: &'static str, bucket: &str, key: &str) -> Self
95 where
96 E: ProvideErrorMetadata + std::error::Error + Send + Sync + 'static,
97 {
98 let metadata = ErrorMetadata {
99 client_error_meta: err.meta(),
100 error_code: Some(MOUNTPOINT_ERROR_CLIENT.to_string()),
101 s3_bucket_name: Some(bucket.to_string()),
102 s3_object_key: Some(key.to_string()),
103 };
104 let metadata = Box::new(metadata);
105 InodeError::ClientError {
106 source: Arc::new(anyhow!(err).context(context)),
107 metadata,
108 }
109 }
110
111 pub fn upload_error<E>(err: UploadError<E>, key: S3Location) -> Self
112 where
113 E: ProvideErrorMetadata + std::error::Error + Send + Sync + 'static,
114 {
115 let metadata = ErrorMetadata {
116 client_error_meta: err.meta(),
117 error_code: Some(MOUNTPOINT_ERROR_CLIENT.to_string()),
118 s3_bucket_name: Some(key.bucket_name().to_string()),
119 s3_object_key: Some(key.full_key().to_string()),
120 };
121 let metadata = Box::new(metadata);
122 InodeError::ClientError {
123 source: Arc::new(anyhow!(err)),
124 metadata,
125 }
126 }
127}
128
129impl InodeError {
130 pub fn meta(&self) -> ErrorMetadata {
131 match self {
132 Self::ClientError { source: _, metadata } => (**metadata).clone(),
133 _ => Default::default(),
134 }
135 }
136}
137
138#[cfg(feature = "manifest")]
139impl From<ManifestError> for InodeError {
140 fn from(value: ManifestError) -> Self {
141 Self::ManifestError(Arc::new(value))
142 }
143}
144
145#[derive(Debug, Clone)]
148pub struct InodeErrorInfo {
149 pub ino: InodeNo,
150 pub key: Box<str>,
151 pub bucket: Option<Box<str>>,
152}
153
154impl std::fmt::Display for InodeErrorInfo {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 if let Some(bucket) = &self.bucket {
157 write!(f, "{} (bucket {:?}, full key {:?})", self.ino, bucket, self.key)
158 } else {
159 write!(f, "{} (partial key {:?})", self.ino, self.key)
160 }
161 }
162}