use std::path::{Path, PathBuf};
use_enabled_fs_module!();
mod copy;
mod r#move;
mod progress;
mod remove;
mod size;
pub use copy::*;
pub use progress::*;
pub use r#move::*;
pub use remove::*;
pub use size::*;
use crate::{directory::try_exists_without_follow, error::FileError};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum CollidingFileBehaviour {
Abort,
Skip,
Overwrite,
}
pub(crate) struct ValidatedSourceFilePath {
pub(crate) source_file_path: PathBuf,
pub(crate) original_was_symlink_to_file: bool,
}
fn validate_source_file_path(
source_file_path: &Path,
) -> Result<ValidatedSourceFilePath, FileError> {
let source_file_exists = match try_exists_without_follow(source_file_path) {
Ok(exists) => exists,
Err(error) => {
return Err(FileError::UnableToAccessSourceFile {
path: source_file_path.to_path_buf(),
error,
});
}
};
if !source_file_exists {
return Err(FileError::SourceFileNotFound {
path: source_file_path.to_path_buf(),
});
}
if !source_file_path.is_file() {
return Err(FileError::SourcePathNotAFile {
path: source_file_path.to_path_buf(),
});
}
let canonical_path = fs::canonicalize(source_file_path).map_err(|error| {
FileError::UnableToAccessSourceFile {
path: source_file_path.to_path_buf(),
error,
}
})?;
#[cfg(feature = "dunce")]
{
let de_unced_canonical_path = dunce::simplified(&canonical_path).to_path_buf();
Ok(ValidatedSourceFilePath {
source_file_path: de_unced_canonical_path,
original_was_symlink_to_file: true,
})
}
#[cfg(not(feature = "dunce"))]
{
Ok(ValidatedSourceFilePath {
source_file_path: canonical_path,
original_was_symlink_to_file: true,
})
}
}
pub(crate) struct ValidatedDestinationFilePath {
pub(crate) destination_file_path: PathBuf,
pub(crate) exists: bool,
}
pub(crate) enum DestinationValidationAction {
SkipCopyOrMove,
Continue(ValidatedDestinationFilePath),
}
fn validate_destination_file_path(
validated_source_file_path: &ValidatedSourceFilePath,
destination_file_path: &Path,
colliding_file_behaviour: CollidingFileBehaviour,
) -> Result<DestinationValidationAction, FileError> {
let destination_file_exists =
try_exists_without_follow(destination_file_path).map_err(|error| {
FileError::UnableToAccessDestinationFile {
path: destination_file_path.to_path_buf(),
error,
}
})?;
if destination_file_exists {
let canonical_destination_path = {
let canonical_destination_path =
destination_file_path.canonicalize().map_err(|error| {
FileError::UnableToAccessDestinationFile {
path: destination_file_path.to_path_buf(),
error,
}
})?;
#[cfg(feature = "dunce")]
{
dunce::simplified(&canonical_destination_path).to_path_buf()
}
#[cfg(not(feature = "dunce"))]
{
canonical_destination_path
}
};
if validated_source_file_path
.source_file_path
.eq(&canonical_destination_path)
{
return Err(FileError::SourceAndDestinationAreTheSame {
path: canonical_destination_path,
});
}
if destination_file_exists {
match colliding_file_behaviour {
CollidingFileBehaviour::Abort => {
return Err(FileError::DestinationPathAlreadyExists {
path: destination_file_path.to_path_buf(),
})
}
CollidingFileBehaviour::Skip => {
return Ok(DestinationValidationAction::SkipCopyOrMove);
}
CollidingFileBehaviour::Overwrite => {}
};
}
Ok(DestinationValidationAction::Continue(ValidatedDestinationFilePath {
destination_file_path: canonical_destination_path,
exists: true,
}))
} else {
Ok(DestinationValidationAction::Continue(ValidatedDestinationFilePath {
destination_file_path: destination_file_path.to_path_buf(),
exists: false,
}))
}
}