fs_err/
errors.rs

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
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)]
45pub(crate) struct Error {
46    kind: ErrorKind,
47    source: io::Error,
48    path: PathBuf,
49}
50
51impl Error {
52    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
64impl fmt::Display for Error {
65    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
104impl StdError for Error {
105    fn cause(&self) -> Option<&dyn StdError> {
106        self.source()
107    }
108
109    fn source(&self) -> Option<&(dyn StdError + 'static)> {
110        Some(&self.source)
111    }
112}
113
114#[derive(Debug, Clone, Copy)]
115pub(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)]
132pub(crate) struct SourceDestError {
133    kind: SourceDestErrorKind,
134    source: io::Error,
135    from_path: PathBuf,
136    to_path: PathBuf,
137}
138
139impl SourceDestError {
140    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
158impl fmt::Display for SourceDestError {
159    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
193impl StdError for SourceDestError {
194    fn cause(&self) -> Option<&dyn StdError> {
195        self.source()
196    }
197
198    fn source(&self) -> Option<&(dyn StdError + 'static)> {
199        Some(&self.source)
200    }
201}