use std::{fs, io};
use std::ffi::{OsStr, OsString};
use std::fs::{File, Metadata};
use std::path::{Path, PathBuf};
use log::error;
use crate::error::Failed;
#[derive(Clone, Debug)]
pub struct DirEntry {
path: PathBuf,
metadata: Metadata,
file_name: OsString,
}
impl DirEntry {
pub fn path(&self) -> &Path {
&self.path
}
pub fn into_path(self) -> PathBuf {
self.path
}
pub fn metadata(&self) -> &Metadata {
&self.metadata
}
pub fn file_name(&self) -> &OsStr {
&self.file_name
}
pub fn into_file_name(self) -> OsString {
self.file_name
}
pub fn into_name_and_path(self) -> (OsString, PathBuf) {
(self.file_name, self.path)
}
pub fn is_file(&self) -> bool {
self.metadata.is_file()
}
pub fn is_dir(&self) -> bool {
self.metadata.is_dir()
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u64 {
self.metadata.len()
}
}
#[derive(Debug)]
pub struct ReadDir<'a> {
path: &'a Path,
iter: fs::ReadDir,
}
impl<'a> Iterator for ReadDir<'a> {
type Item = Result<DirEntry, Failed>;
fn next(&mut self) -> Option<Self::Item> {
let entry = match self.iter.next()? {
Ok(entry) => entry,
Err(err) => {
error!(
"Fatal: failed to read directory {}: {}",
self.path.display(), err
);
return Some(Err(Failed))
}
};
let metadata = match entry.metadata() {
Ok(metadata) => metadata,
Err(err) => {
error!(
"Fatal: failed to read directory {}: {}",
self.path.display(), err
);
return Some(Err(Failed))
}
};
Some(Ok(DirEntry {
path: entry.path(),
metadata,
file_name: entry.file_name()
}))
}
}
pub fn read_dir(path: &Path) -> Result<ReadDir, Failed> {
match fs::read_dir(path) {
Ok(iter) => Ok(ReadDir { path, iter }),
Err(err) => {
error!(
"Fatal: failed to open directory {}: {}",
path.display(), err
);
Err(Failed)
}
}
}
pub fn read_existing_dir(path: &Path) -> Result<Option<ReadDir>, Failed> {
match fs::read_dir(path) {
Ok(iter) => Ok(Some(ReadDir { path, iter })),
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
Err(err) => {
error!(
"Fatal: failed to open directory {}: {}",
path.display(), err
);
Err(Failed)
}
}
}
pub fn create_dir_all(path: &Path) -> Result<(), Failed> {
fs::create_dir_all(path).map_err(|err| {
error!(
"Fatal: failed to create directory {}: {}",
path.display(), err
);
Failed
})
}
pub fn create_parent_all(path: &Path) -> Result<(), Failed> {
if let Some(path) = path.parent() {
fs::create_dir_all(path).map_err(|err| {
error!(
"Fatal: failed to create directory {}: {}",
path.display(), err
);
Failed
})?
}
Ok(())
}
pub fn remove_dir_all(path: &Path) -> Result<(), Failed> {
fs::remove_dir_all(path).map_err(|err| {
error!(
"Fatal: failed to remove directory tree {}: {}",
path.display(), err
);
Failed
})
}
pub fn remove_file(path: &Path) -> Result<(), Failed> {
if let Err(err) = fs::remove_file(path) {
if err.kind() != io::ErrorKind::NotFound {
error!(
"Fatal: failed to remove file {}: {}",
path.display(), err
);
return Err(Failed)
}
}
Ok(())
}
pub fn rename(source: &Path, target: &Path) -> Result<(), Failed> {
fs::rename(source, target).map_err(|err| {
error!(
"Fatal: failed to move {} to {}: {}",
source.display(), target.display(), err
);
Failed
})
}
pub fn open_file(path: &Path) -> Result<File, Failed> {
File::open(path).map_err(|err| {
error!(
"Fatal: failed to open file {}: {}",
path.display(), err
);
Failed
})
}
pub fn read_file(path: &Path) -> Result<Vec<u8>, Failed> {
fs::read(path).map_err(|err| {
error!(
"Fatal: failed to read file {}: {}",
path.display(), err
);
Failed
})
}
pub fn read_existing_file(path: &Path) -> Result<Option<Vec<u8>>, Failed> {
match fs::read(path) {
Ok(some) => Ok(Some(some)),
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
Err(err) => {
error!(
"Fatal: failed to read file {}: {}",
path.display(), err
);
Err(Failed)
}
}
}
pub fn write_file(path: &Path, contents: &[u8]) -> Result<(), Failed> {
fs::write(path, contents).map_err(|err| {
error!(
"Fatal: failed to write file {}: {}",
path.display(), err
);
Failed
})
}