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