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
27 #[cfg(windows)]
28 SeekRead,
29 #[cfg(windows)]
30 SeekWrite,
31
32 #[cfg(unix)]
33 ReadAt,
34 #[cfg(unix)]
35 WriteAt,
36}
37
38/// Contains an IO error that has a file path attached.
39///
40/// This type is never returned directly, but is instead wrapped inside yet
41/// another IO error.
42#[derive(Debug)]
43pub(crate) struct Error {
44 kind: ErrorKind,
45 source: io::Error,
46 path: PathBuf,
47}
48
49impl Error {
50 pub fn build(source: io::Error, kind: ErrorKind, path: impl Into<PathBuf>) -> io::Error {
51 io::Error::new(
52 source.kind(),
53 Self {
54 kind,
55 source,
56 path: path.into(),
57 },
58 )
59 }
60}
61
62impl fmt::Display for Error {
63 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
64 use ErrorKind::*;
65
66 let path = self.path.display();
67
68 match self.kind {
69 OpenFile => write!(formatter, "failed to open file `{}`", path),
70 CreateFile => write!(formatter, "failed to create file `{}`", path),
71 CreateDir => write!(formatter, "failed to create directory `{}`", path),
72 SyncFile => write!(formatter, "failed to sync file `{}`", path),
73 SetLen => write!(formatter, "failed to set length of file `{}`", path),
74 Metadata => write!(formatter, "failed to query metadata of file `{}`", path),
75 Clone => write!(formatter, "failed to clone handle for file `{}`", path),
76 SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path),
77 Read => write!(formatter, "failed to read from file `{}`", path),
78 Seek => write!(formatter, "failed to seek in file `{}`", path),
79 Write => write!(formatter, "failed to write to file `{}`", path),
80 Flush => write!(formatter, "failed to flush file `{}`", path),
81 ReadDir => write!(formatter, "failed to read directory `{}`", path),
82 RemoveFile => write!(formatter, "failed to remove file `{}`", path),
83 RemoveDir => write!(formatter, "failed to remove directory `{}`", path),
84 Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path),
85 ReadLink => write!(formatter, "failed to read symbolic link `{}`", path),
86 SymlinkMetadata => write!(formatter, "failed to query metadata of symlink `{}`", path),
87
88 #[cfg(windows)]
89 SeekRead => write!(formatter, "failed to seek and read from `{}`", path),
90 #[cfg(windows)]
91 SeekWrite => write!(formatter, "failed to seek and write to `{}`", path),
92
93 #[cfg(unix)]
94 ReadAt => write!(formatter, "failed to read with offset from `{}`", path),
95 #[cfg(unix)]
96 WriteAt => write!(formatter, "failed to write with offset to `{}`", path),
97 }
98 }
99}
100
101impl StdError for Error {
102 fn cause(&self) -> Option<&dyn StdError> {
103 self.source()
104 }
105
106 fn source(&self) -> Option<&(dyn StdError + 'static)> {
107 Some(&self.source)
108 }
109}
110
111#[derive(Debug, Clone, Copy)]
112pub(crate) enum SourceDestErrorKind {
113 Copy,
114 HardLink,
115 Rename,
116 SoftLink,
117
118 #[cfg(unix)]
119 Symlink,
120
121 #[cfg(windows)]
122 SymlinkDir,
123 #[cfg(windows)]
124 SymlinkFile,
125}
126
127/// Error type used by functions like `fs::copy` that holds two paths.
128#[derive(Debug)]
129pub(crate) struct SourceDestError {
130 kind: SourceDestErrorKind,
131 source: io::Error,
132 from_path: PathBuf,
133 to_path: PathBuf,
134}
135
136impl SourceDestError {
137 pub fn build(
138 source: io::Error,
139 kind: SourceDestErrorKind,
140 from_path: impl Into<PathBuf>,
141 to_path: impl Into<PathBuf>,
142 ) -> io::Error {
143 io::Error::new(
144 source.kind(),
145 Self {
146 kind,
147 source,
148 from_path: from_path.into(),
149 to_path: to_path.into(),
150 },
151 )
152 }
153}
154
155impl fmt::Display for SourceDestError {
156 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
157 let from = self.from_path.display();
158 let to = self.to_path.display();
159 match self.kind {
160 SourceDestErrorKind::Copy => {
161 write!(formatter, "failed to copy file from {} to {}", from, to)
162 }
163 SourceDestErrorKind::HardLink => {
164 write!(formatter, "failed to hardlink file from {} to {}", from, to)
165 }
166 SourceDestErrorKind::Rename => {
167 write!(formatter, "failed to rename file from {} to {}", from, to)
168 }
169 SourceDestErrorKind::SoftLink => {
170 write!(formatter, "failed to softlink file from {} to {}", from, to)
171 }
172
173 #[cfg(unix)]
174 SourceDestErrorKind::Symlink => {
175 write!(formatter, "failed to symlink file from {} to {}", from, to)
176 }
177
178 #[cfg(windows)]
179 SourceDestErrorKind::SymlinkFile => {
180 write!(formatter, "failed to symlink file from {} to {}", from, to)
181 }
182 #[cfg(windows)]
183 SourceDestErrorKind::SymlinkDir => {
184 write!(formatter, "failed to symlink dir from {} to {}", from, to)
185 }
186 }
187 }
188}
189
190impl StdError for SourceDestError {
191 fn cause(&self) -> Option<&dyn StdError> {
192 self.source()
193 }
194
195 fn source(&self) -> Option<&(dyn StdError + 'static)> {
196 Some(&self.source)
197 }
198}
199