Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-core/src/vfs.rs @ 47980:9cd35c8c6044
rust: Move VFS code to its own module
It was previously in the hg::repo module, but both repo code and vfs
will likely grow in the future.
Differential Revision: https://phab.mercurial-scm.org/D11394
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 06 Sep 2021 11:39:59 +0200 |
parents | |
children | e834b79def74 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/vfs.rs Mon Sep 06 11:39:59 2021 +0200 @@ -0,0 +1,73 @@ +use crate::errors::{HgError, IoErrorContext, IoResultExt}; +use memmap::{Mmap, MmapOptions}; +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())) +}