| use std::error::Error as StdError; | |
| use std::fmt; | |
| use std::io; | |
| use std::path::PathBuf; | |
| #[derive(Debug, Clone, Copy)] | |
| pub(crate) enum ErrorKind { | |
| OpenFile, | |
| CreateFile, | |
| CreateDir, | |
| SyncFile, | |
| SetLen, | |
| Metadata, | |
| Clone, | |
| SetPermissions, | |
| Read, | |
| Seek, | |
| Write, | |
| Flush, | |
| ReadDir, | |
| RemoveFile, | |
| RemoveDir, | |
| Canonicalize, | |
| ReadLink, | |
| SymlinkMetadata, | |
| #[allow(dead_code)] | |
| FileExists, | |
| #[cfg(windows)] | |
| SeekRead, | |
| #[cfg(windows)] | |
| SeekWrite, | |
| #[cfg(unix)] | |
| ReadAt, | |
| #[cfg(unix)] | |
| WriteAt, | |
| } | |
| /// Contains an IO error that has a file path attached. | |
| /// | |
| /// This type is never returned directly, but is instead wrapped inside yet | |
| /// another IO error. | |
| #[derive(Debug)] | |
| pub(crate) struct Error { | |
| kind: ErrorKind, | |
| source: io::Error, | |
| path: PathBuf, | |
| } | |
| impl Error { | |
| pub fn build(source: io::Error, kind: ErrorKind, path: impl Into<PathBuf>) -> io::Error { | |
| io::Error::new( | |
| source.kind(), | |
| Self { | |
| kind, | |
| source, | |
| path: path.into(), | |
| }, | |
| ) | |
| } | |
| } | |
| impl fmt::Display for Error { | |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
| use ErrorKind as E; | |
| let path = self.path.display(); | |
| match self.kind { | |
| E::OpenFile => write!(formatter, "failed to open file `{}`", path), | |
| E::CreateFile => write!(formatter, "failed to create file `{}`", path), | |
| E::CreateDir => write!(formatter, "failed to create directory `{}`", path), | |
| E::SyncFile => write!(formatter, "failed to sync file `{}`", path), | |
| E::SetLen => write!(formatter, "failed to set length of file `{}`", path), | |
| E::Metadata => write!(formatter, "failed to query metadata of file `{}`", path), | |
| E::Clone => write!(formatter, "failed to clone handle for file `{}`", path), | |
| E::SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path), | |
| E::Read => write!(formatter, "failed to read from file `{}`", path), | |
| E::Seek => write!(formatter, "failed to seek in file `{}`", path), | |
| E::Write => write!(formatter, "failed to write to file `{}`", path), | |
| E::Flush => write!(formatter, "failed to flush file `{}`", path), | |
| E::ReadDir => write!(formatter, "failed to read directory `{}`", path), | |
| E::RemoveFile => write!(formatter, "failed to remove file `{}`", path), | |
| E::RemoveDir => write!(formatter, "failed to remove directory `{}`", path), | |
| E::Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path), | |
| E::ReadLink => write!(formatter, "failed to read symbolic link `{}`", path), | |
| E::SymlinkMetadata => { | |
| write!(formatter, "failed to query metadata of symlink `{}`", path) | |
| } | |
| E::FileExists => write!(formatter, "failed to check file existence `{}`", path), | |
| #[cfg(windows)] | |
| E::SeekRead => write!(formatter, "failed to seek and read from `{}`", path), | |
| #[cfg(windows)] | |
| E::SeekWrite => write!(formatter, "failed to seek and write to `{}`", path), | |
| #[cfg(unix)] | |
| E::ReadAt => write!(formatter, "failed to read with offset from `{}`", path), | |
| #[cfg(unix)] | |
| E::WriteAt => write!(formatter, "failed to write with offset to `{}`", path), | |
| }?; | |
| // The `expose_original_error` feature indicates the caller should display the original error | |
| #[cfg(not(feature = "expose_original_error"))] | |
| write!(formatter, ": {}", self.source)?; | |
| Ok(()) | |
| } | |
| } | |
| impl StdError for Error { | |
| fn cause(&self) -> Option<&dyn StdError> { | |
| self.source() | |
| } | |
| #[cfg(not(feature = "expose_original_error"))] | |
| fn source(&self) -> Option<&(dyn StdError + 'static)> { | |
| None | |
| } | |
| #[cfg(feature = "expose_original_error")] | |
| fn source(&self) -> Option<&(dyn StdError + 'static)> { | |
| Some(&self.source) | |
| } | |
| } | |
| #[derive(Debug, Clone, Copy)] | |
| pub(crate) enum SourceDestErrorKind { | |
| Copy, | |
| HardLink, | |
| Rename, | |
| SoftLink, | |
| #[cfg(unix)] | |
| Symlink, | |
| #[cfg(windows)] | |
| SymlinkDir, | |
| #[cfg(windows)] | |
| SymlinkFile, | |
| } | |
| /// Error type used by functions like `fs::copy` that holds two paths. | |
| #[derive(Debug)] | |
| pub(crate) struct SourceDestError { | |
| kind: SourceDestErrorKind, | |
| source: io::Error, | |
| from_path: PathBuf, | |
| to_path: PathBuf, | |
| } | |
| impl SourceDestError { | |
| pub fn build( | |
| source: io::Error, | |
| kind: SourceDestErrorKind, | |
| from_path: impl Into<PathBuf>, | |
| to_path: impl Into<PathBuf>, | |
| ) -> io::Error { | |
| io::Error::new( | |
| source.kind(), | |
| Self { | |
| kind, | |
| source, | |
| from_path: from_path.into(), | |
| to_path: to_path.into(), | |
| }, | |
| ) | |
| } | |
| } | |
| impl fmt::Display for SourceDestError { | |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
| let from = self.from_path.display(); | |
| let to = self.to_path.display(); | |
| match self.kind { | |
| SourceDestErrorKind::Copy => { | |
| write!(formatter, "failed to copy file from {} to {}", from, to) | |
| } | |
| SourceDestErrorKind::HardLink => { | |
| write!(formatter, "failed to hardlink file from {} to {}", from, to) | |
| } | |
| SourceDestErrorKind::Rename => { | |
| write!(formatter, "failed to rename file from {} to {}", from, to) | |
| } | |
| SourceDestErrorKind::SoftLink => { | |
| write!(formatter, "failed to softlink file from {} to {}", from, to) | |
| } | |
| #[cfg(unix)] | |
| SourceDestErrorKind::Symlink => { | |
| write!(formatter, "failed to symlink file from {} to {}", from, to) | |
| } | |
| #[cfg(windows)] | |
| SourceDestErrorKind::SymlinkFile => { | |
| write!(formatter, "failed to symlink file from {} to {}", from, to) | |
| } | |
| #[cfg(windows)] | |
| SourceDestErrorKind::SymlinkDir => { | |
| write!(formatter, "failed to symlink dir from {} to {}", from, to) | |
| } | |
| }?; | |
| // The `expose_original_error` feature indicates the caller should display the original error | |
| #[cfg(not(feature = "expose_original_error"))] | |
| write!(formatter, ": {}", self.source)?; | |
| Ok(()) | |
| } | |
| } | |
| impl StdError for SourceDestError { | |
| fn cause(&self) -> Option<&dyn StdError> { | |
| self.source() | |
| } | |
| #[cfg(not(feature = "expose_original_error"))] | |
| fn source(&self) -> Option<&(dyn StdError + 'static)> { | |
| None | |
| } | |
| #[cfg(feature = "expose_original_error")] | |
| fn source(&self) -> Option<&(dyn StdError + 'static)> { | |
| Some(&self.source) | |
| } | |
| } |