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