use std::path::Path;
use std::fs;
use std::io::{self, Read, ErrorKind};
use super::timestamp::TimeStamp;
pub enum FileReaderError {
NotFound(String),
OtherError(String),
}
pub trait FileReader {
fn read_file(&self, path: &Path, contents: &mut Vec<u8>) -> Result<(), FileReaderError>;
}
pub trait DiskInterface: FileReader {
fn make_dir(&self, path: &Path) -> Result<(), io::Error>;
fn make_dirs(&self, path: &Path) -> Result<(), io::Error>;
fn stat(&self, path: &Path) -> Result<TimeStamp, String>;
fn write_file(&self, path: &Path, contents: &[u8]) -> Result<(), ()>;
fn remove_file(&self, path: &Path) -> Result<bool, io::Error>;
}
pub struct RealDiskInterface {}
impl FileReader for RealDiskInterface {
fn read_file(&self, path: &Path, contents: &mut Vec<u8>) -> Result<(), FileReaderError> {
let mut file = fs::File::open(path).map_err(|err| {
let c = if err.kind() == ErrorKind::NotFound {
FileReaderError::NotFound
} else {
FileReaderError::OtherError
};
c(format!("{}", err))
})?;
file.read_to_end(contents).map_err(|err| {
FileReaderError::OtherError(format!("{}", err))
})?;
Ok(())
}
}
impl DiskInterface for RealDiskInterface {
fn make_dir(&self, path: &Path) -> Result<(), io::Error> {
fs::DirBuilder::new().recursive(false).create(path)?;
Ok(())
}
fn make_dirs(&self, path: &Path) -> Result<(), io::Error> {
fs::DirBuilder::new().recursive(true).create(path)?;
Ok(())
}
#[cfg(unix)]
fn stat(&self, path: &Path) -> Result<TimeStamp, String> {
use std::os::unix::fs::MetadataExt;
metric_record!("node stat");
path.metadata()
.map(|m| TimeStamp(m.mtime() as isize))
.or_else(|e| if e.kind() == ErrorKind::NotFound {
Ok(TimeStamp(0))
} else {
Err(format!("Stat({}): {}", path.display(), e))
})
}
#[cfg(windows)]
fn stat(&self, path: &Path) -> Result<TimeStamp, String> {
use std::os::windows::fs::MetadataExt;
metric_record!("node stat");
path.metadata()
.map(|m| TimeStamp(m.last_write_time() as isize))
.or_else(|e| if e.kind() == ErrorKind::NotFound {
Ok(TimeStamp(0))
} else {
Err(format!("Stat({}): {}", path.display(), e))
})
}
fn write_file(&self, path: &Path, contents: &[u8]) -> Result<(), ()> {
unimplemented!()
}
fn remove_file(&self, path: &Path) -> Result<bool, io::Error> {
use std::fs::remove_file;
match remove_file(path) {
Ok(()) => Ok(true),
Err(ref e) if e.kind() == ErrorKind::NotFound => Ok(false),
Err(e) => Err(e),
}
}
}
impl RealDiskInterface {
pub fn allow_stat_cache(&self, allow: bool) {
return;
unimplemented!()
}
}