Changeset View
Changeset View
Standalone View
Standalone View
rust/hg-core/src/vfs.rs
use crate::errors::{HgError, IoErrorContext, IoResultExt}; | use crate::errors::{HgError, IoErrorContext, IoResultExt}; | ||||
use memmap2::{Mmap, MmapOptions}; | use memmap2::{Mmap, MmapOptions}; | ||||
use std::io::ErrorKind; | use std::io::ErrorKind; | ||||
use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||
/// Filesystem access abstraction for the contents of a given "base" diretory | /// Filesystem access abstraction for the contents of a given "base" diretory | ||||
#[derive(Clone, Copy)] | #[derive(Clone, Copy)] | ||||
pub struct Vfs<'a> { | pub struct Vfs<'a> { | ||||
pub(crate) base: &'a Path, | pub(crate) base: &'a Path, | ||||
} | } | ||||
struct FileNotFound(std::io::Error, PathBuf); | |||||
impl Vfs<'_> { | impl Vfs<'_> { | ||||
pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { | pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { | ||||
self.base.join(relative_path) | self.base.join(relative_path) | ||||
} | } | ||||
pub fn read( | pub fn read( | ||||
&self, | &self, | ||||
relative_path: impl AsRef<Path>, | relative_path: impl AsRef<Path>, | ||||
) -> Result<Vec<u8>, HgError> { | ) -> Result<Vec<u8>, HgError> { | ||||
let path = self.join(relative_path); | let path = self.join(relative_path); | ||||
std::fs::read(&path).when_reading_file(&path) | std::fs::read(&path).when_reading_file(&path) | ||||
} | } | ||||
pub fn mmap_open( | fn mmap_open_gen( | ||||
&self, | &self, | ||||
relative_path: impl AsRef<Path>, | relative_path: impl AsRef<Path>, | ||||
) -> Result<Mmap, HgError> { | ) -> Result<Result<Mmap, FileNotFound>, HgError> { | ||||
let path = self.base.join(relative_path); | let path = self.join(relative_path); | ||||
let file = std::fs::File::open(&path).when_reading_file(&path)?; | let file = match std::fs::File::open(&path) { | ||||
Err(err) => { | |||||
if let ErrorKind::NotFound = err.kind() { | |||||
return Ok(Err(FileNotFound(err, path))); | |||||
}; | |||||
return (Err(err)).when_reading_file(&path); | |||||
} | |||||
Ok(file) => file, | |||||
}; | |||||
// TODO: what are the safety requirements here? | // TODO: what are the safety requirements here? | ||||
let mmap = unsafe { MmapOptions::new().map(&file) } | let mmap = unsafe { MmapOptions::new().map(&file) } | ||||
.when_reading_file(&path)?; | .when_reading_file(&path)?; | ||||
Ok(mmap) | Ok(Ok(mmap)) | ||||
} | |||||
pub fn mmap_open_opt( | |||||
&self, | |||||
relative_path: impl AsRef<Path>, | |||||
) -> Result<Option<Mmap>, HgError> { | |||||
self.mmap_open_gen(relative_path).map(|res| res.ok()) | |||||
} | |||||
pub fn mmap_open( | |||||
&self, | |||||
relative_path: impl AsRef<Path>, | |||||
) -> Result<Mmap, HgError> { | |||||
match self.mmap_open_gen(relative_path)? { | |||||
Err(FileNotFound(err, path)) => Err(err).when_reading_file(&path), | |||||
Ok(res) => Ok(res), | |||||
} | |||||
} | } | ||||
pub fn rename( | pub fn rename( | ||||
&self, | &self, | ||||
relative_from: impl AsRef<Path>, | relative_from: impl AsRef<Path>, | ||||
relative_to: impl AsRef<Path>, | relative_to: impl AsRef<Path>, | ||||
) -> Result<(), HgError> { | ) -> Result<(), HgError> { | ||||
let from = self.join(relative_from); | let from = self.join(relative_from); | ||||
Show All 31 Lines |