vfs.rs
73 lines
| 2.3 KiB
| application/rls-services+xml
|
RustLexer
Simon Sapin
|
r48764 | use crate::errors::{HgError, IoErrorContext, IoResultExt}; | ||
Simon Sapin
|
r48767 | use memmap2::{Mmap, MmapOptions}; | ||
Simon Sapin
|
r48764 | use std::io::ErrorKind; | ||
use std::path::{Path, PathBuf}; | ||||
/// Filesystem access abstraction for the contents of a given "base" diretory | ||||
#[derive(Clone, Copy)] | ||||
pub struct Vfs<'a> { | ||||
pub(crate) base: &'a Path, | ||||
} | ||||
impl Vfs<'_> { | ||||
pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { | ||||
self.base.join(relative_path) | ||||
} | ||||
pub fn read( | ||||
&self, | ||||
relative_path: impl AsRef<Path>, | ||||
) -> Result<Vec<u8>, HgError> { | ||||
let path = self.join(relative_path); | ||||
std::fs::read(&path).when_reading_file(&path) | ||||
} | ||||
pub fn mmap_open( | ||||
&self, | ||||
relative_path: impl AsRef<Path>, | ||||
) -> Result<Mmap, HgError> { | ||||
let path = self.base.join(relative_path); | ||||
let file = std::fs::File::open(&path).when_reading_file(&path)?; | ||||
// TODO: what are the safety requirements here? | ||||
let mmap = unsafe { MmapOptions::new().map(&file) } | ||||
.when_reading_file(&path)?; | ||||
Ok(mmap) | ||||
} | ||||
pub fn rename( | ||||
&self, | ||||
relative_from: impl AsRef<Path>, | ||||
relative_to: impl AsRef<Path>, | ||||
) -> Result<(), HgError> { | ||||
let from = self.join(relative_from); | ||||
let to = self.join(relative_to); | ||||
std::fs::rename(&from, &to) | ||||
.with_context(|| IoErrorContext::RenamingFile { from, to }) | ||||
} | ||||
} | ||||
fn fs_metadata( | ||||
path: impl AsRef<Path>, | ||||
) -> Result<Option<std::fs::Metadata>, HgError> { | ||||
let path = path.as_ref(); | ||||
match std::fs::metadata(path) { | ||||
Ok(meta) => Ok(Some(meta)), | ||||
Err(error) => match error.kind() { | ||||
// TODO: when we require a Rust version where `NotADirectory` is | ||||
// stable, invert this logic and return None for it and `NotFound` | ||||
// and propagate any other error. | ||||
ErrorKind::PermissionDenied => Err(error).with_context(|| { | ||||
IoErrorContext::ReadingMetadata(path.to_owned()) | ||||
}), | ||||
_ => Ok(None), | ||||
}, | ||||
} | ||||
} | ||||
pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> { | ||||
Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir())) | ||||
} | ||||
pub(crate) fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> { | ||||
Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file())) | ||||
} | ||||