blob: d732c0e0e2d0fbda40a3edb670c161076a8eb695 [file] [log] [blame]
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::*;
let path = self.path.display();
match self.kind {
OpenFile => write!(formatter, "failed to open file `{}`", path),
CreateFile => write!(formatter, "failed to create file `{}`", path),
CreateDir => write!(formatter, "failed to create directory `{}`", path),
SyncFile => write!(formatter, "failed to sync file `{}`", path),
SetLen => write!(formatter, "failed to set length of file `{}`", path),
Metadata => write!(formatter, "failed to query metadata of file `{}`", path),
Clone => write!(formatter, "failed to clone handle for file `{}`", path),
SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path),
Read => write!(formatter, "failed to read from file `{}`", path),
Seek => write!(formatter, "failed to seek in file `{}`", path),
Write => write!(formatter, "failed to write to file `{}`", path),
Flush => write!(formatter, "failed to flush file `{}`", path),
ReadDir => write!(formatter, "failed to read directory `{}`", path),
RemoveFile => write!(formatter, "failed to remove file `{}`", path),
RemoveDir => write!(formatter, "failed to remove directory `{}`", path),
Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path),
ReadLink => write!(formatter, "failed to read symbolic link `{}`", path),
SymlinkMetadata => write!(formatter, "failed to query metadata of symlink `{}`", path),
FileExists => write!(formatter, "failed to check file existance `{}`", path),
#[cfg(windows)]
SeekRead => write!(formatter, "failed to seek and read from `{}`", path),
#[cfg(windows)]
SeekWrite => write!(formatter, "failed to seek and write to `{}`", path),
#[cfg(unix)]
ReadAt => write!(formatter, "failed to read with offset from `{}`", path),
#[cfg(unix)]
WriteAt => write!(formatter, "failed to write with offset to `{}`", path),
}
}
}
impl StdError for Error {
fn cause(&self) -> Option<&dyn StdError> {
self.source()
}
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)
}
}
}
}
impl StdError for SourceDestError {
fn cause(&self) -> Option<&dyn StdError> {
self.source()
}
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.source)
}
}