1use std::error::Error as StdError;
2use std::fmt;
3use std::io;
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Copy)]
7pub(crate) enum ErrorKind {
8 OpenFile,
9 CreateFile,
10 CreateDir,
11 SyncFile,
12 SetLen,
13 Metadata,
14 Clone,
15 SetPermissions,
16 Read,
17 Seek,
18 Write,
19 Flush,
20 ReadDir,
21 RemoveFile,
22 RemoveDir,
23 Canonicalize,
24 ReadLink,
25 SymlinkMetadata,
26 #[allow(dead_code)]
27 FileExists,
28 Lock,
29 Unlock,
30
31 #[cfg(windows)]
32 SeekRead,
33 #[cfg(windows)]
34 SeekWrite,
35
36 #[cfg(unix)]
37 ReadAt,
38 #[cfg(unix)]
39 WriteAt,
40}
41
42#[derive(Debug)]
47pub(crate) struct Error {
48 kind: ErrorKind,
49 source: io::Error,
50 path: PathBuf,
51}
52
53impl Error {
54 pub fn build(source: io::Error, kind: ErrorKind, path: impl Into<PathBuf>) -> io::Error {
55 io::Error::new(
56 source.kind(),
57 Self {
58 kind,
59 source,
60 path: path.into(),
61 },
62 )
63 }
64}
65
66impl fmt::Display for Error {
67 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
68 use ErrorKind as E;
69
70 let path = self.path.display();
71
72 match self.kind {
73 E::OpenFile => write!(formatter, "failed to open file `{}`", path),
74 E::CreateFile => write!(formatter, "failed to create file `{}`", path),
75 E::CreateDir => write!(formatter, "failed to create directory `{}`", path),
76 E::SyncFile => write!(formatter, "failed to sync file `{}`", path),
77 E::SetLen => write!(formatter, "failed to set length of file `{}`", path),
78 E::Metadata => write!(formatter, "failed to query metadata of file `{}`", path),
79 E::Clone => write!(formatter, "failed to clone handle for file `{}`", path),
80 E::SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path),
81 E::Read => write!(formatter, "failed to read from file `{}`", path),
82 E::Seek => write!(formatter, "failed to seek in file `{}`", path),
83 E::Write => write!(formatter, "failed to write to file `{}`", path),
84 E::Flush => write!(formatter, "failed to flush file `{}`", path),
85 E::ReadDir => write!(formatter, "failed to read directory `{}`", path),
86 E::RemoveFile => write!(formatter, "failed to remove file `{}`", path),
87 E::RemoveDir => write!(formatter, "failed to remove directory `{}`", path),
88 E::Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path),
89 E::ReadLink => write!(formatter, "failed to read symbolic link `{}`", path),
90 E::SymlinkMetadata => {
91 write!(formatter, "failed to query metadata of symlink `{}`", path)
92 }
93 E::FileExists => write!(formatter, "failed to check file existence `{}`", path),
94 E::Lock => write!(formatter, "failed to lock `{}`", path),
95 E::Unlock => write!(formatter, "failed to unlock `{}`", path),
96
97 #[cfg(windows)]
98 E::SeekRead => write!(formatter, "failed to seek and read from `{}`", path),
99 #[cfg(windows)]
100 E::SeekWrite => write!(formatter, "failed to seek and write to `{}`", path),
101
102 #[cfg(unix)]
103 E::ReadAt => write!(formatter, "failed to read with offset from `{}`", path),
104 #[cfg(unix)]
105 E::WriteAt => write!(formatter, "failed to write with offset to `{}`", path),
106 }?;
107
108 #[cfg(not(feature = "expose_original_error"))]
110 write!(formatter, ": {}", self.source)?;
111
112 Ok(())
113 }
114}
115
116impl StdError for Error {
117 fn cause(&self) -> Option<&dyn StdError> {
118 self.source()
119 }
120
121 #[cfg(not(feature = "expose_original_error"))]
122 fn source(&self) -> Option<&(dyn StdError + 'static)> {
123 None
124 }
125
126 #[cfg(feature = "expose_original_error")]
127 fn source(&self) -> Option<&(dyn StdError + 'static)> {
128 Some(&self.source)
129 }
130}
131
132#[derive(Debug, Clone, Copy)]
133pub(crate) enum SourceDestErrorKind {
134 Copy,
135 HardLink,
136 Rename,
137 SoftLink,
138
139 #[cfg(unix)]
140 Symlink,
141
142 #[cfg(windows)]
143 SymlinkDir,
144 #[cfg(windows)]
145 SymlinkFile,
146}
147
148#[derive(Debug)]
150pub(crate) struct SourceDestError {
151 kind: SourceDestErrorKind,
152 source: io::Error,
153 from_path: PathBuf,
154 to_path: PathBuf,
155}
156
157impl SourceDestError {
158 pub fn build(
159 source: io::Error,
160 kind: SourceDestErrorKind,
161 from_path: impl Into<PathBuf>,
162 to_path: impl Into<PathBuf>,
163 ) -> io::Error {
164 io::Error::new(
165 source.kind(),
166 Self {
167 kind,
168 source,
169 from_path: from_path.into(),
170 to_path: to_path.into(),
171 },
172 )
173 }
174}
175
176impl fmt::Display for SourceDestError {
177 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
178 let from = self.from_path.display();
179 let to = self.to_path.display();
180 match self.kind {
181 SourceDestErrorKind::Copy => {
182 write!(formatter, "failed to copy file from {} to {}", from, to)
183 }
184 SourceDestErrorKind::HardLink => {
185 write!(formatter, "failed to hardlink file from {} to {}", from, to)
186 }
187 SourceDestErrorKind::Rename => {
188 write!(formatter, "failed to rename file from {} to {}", from, to)
189 }
190 SourceDestErrorKind::SoftLink => {
191 write!(formatter, "failed to softlink file from {} to {}", from, to)
192 }
193
194 #[cfg(unix)]
195 SourceDestErrorKind::Symlink => {
196 write!(formatter, "failed to symlink file from {} to {}", from, to)
197 }
198
199 #[cfg(windows)]
200 SourceDestErrorKind::SymlinkFile => {
201 write!(formatter, "failed to symlink file from {} to {}", from, to)
202 }
203 #[cfg(windows)]
204 SourceDestErrorKind::SymlinkDir => {
205 write!(formatter, "failed to symlink dir from {} to {}", from, to)
206 }
207 }?;
208
209 #[cfg(not(feature = "expose_original_error"))]
211 write!(formatter, ": {}", self.source)?;
212
213 Ok(())
214 }
215}
216
217impl StdError for SourceDestError {
218 fn cause(&self) -> Option<&dyn StdError> {
219 self.source()
220 }
221
222 #[cfg(not(feature = "expose_original_error"))]
223 fn source(&self) -> Option<&(dyn StdError + 'static)> {
224 None
225 }
226
227 #[cfg(feature = "expose_original_error")]
228 fn source(&self) -> Option<&(dyn StdError + 'static)> {
229 Some(&self.source)
230 }
231}