rust/hg-core/src/vfs.rs
changeset 47980 9cd35c8c6044
child 47983 e834b79def74
equal deleted inserted replaced
47979:cff41e168c25 47980:9cd35c8c6044
       
     1 use crate::errors::{HgError, IoErrorContext, IoResultExt};
       
     2 use memmap::{Mmap, MmapOptions};
       
     3 use std::io::ErrorKind;
       
     4 use std::path::{Path, PathBuf};
       
     5 
       
     6 /// Filesystem access abstraction for the contents of a given "base" diretory
       
     7 #[derive(Clone, Copy)]
       
     8 pub struct Vfs<'a> {
       
     9     pub(crate) base: &'a Path,
       
    10 }
       
    11 
       
    12 impl Vfs<'_> {
       
    13     pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
       
    14         self.base.join(relative_path)
       
    15     }
       
    16 
       
    17     pub fn read(
       
    18         &self,
       
    19         relative_path: impl AsRef<Path>,
       
    20     ) -> Result<Vec<u8>, HgError> {
       
    21         let path = self.join(relative_path);
       
    22         std::fs::read(&path).when_reading_file(&path)
       
    23     }
       
    24 
       
    25     pub fn mmap_open(
       
    26         &self,
       
    27         relative_path: impl AsRef<Path>,
       
    28     ) -> Result<Mmap, HgError> {
       
    29         let path = self.base.join(relative_path);
       
    30         let file = std::fs::File::open(&path).when_reading_file(&path)?;
       
    31         // TODO: what are the safety requirements here?
       
    32         let mmap = unsafe { MmapOptions::new().map(&file) }
       
    33             .when_reading_file(&path)?;
       
    34         Ok(mmap)
       
    35     }
       
    36 
       
    37     pub fn rename(
       
    38         &self,
       
    39         relative_from: impl AsRef<Path>,
       
    40         relative_to: impl AsRef<Path>,
       
    41     ) -> Result<(), HgError> {
       
    42         let from = self.join(relative_from);
       
    43         let to = self.join(relative_to);
       
    44         std::fs::rename(&from, &to)
       
    45             .with_context(|| IoErrorContext::RenamingFile { from, to })
       
    46     }
       
    47 }
       
    48 
       
    49 fn fs_metadata(
       
    50     path: impl AsRef<Path>,
       
    51 ) -> Result<Option<std::fs::Metadata>, HgError> {
       
    52     let path = path.as_ref();
       
    53     match std::fs::metadata(path) {
       
    54         Ok(meta) => Ok(Some(meta)),
       
    55         Err(error) => match error.kind() {
       
    56             // TODO: when we require a Rust version where `NotADirectory` is
       
    57             // stable, invert this logic and return None for it and `NotFound`
       
    58             // and propagate any other error.
       
    59             ErrorKind::PermissionDenied => Err(error).with_context(|| {
       
    60                 IoErrorContext::ReadingMetadata(path.to_owned())
       
    61             }),
       
    62             _ => Ok(None),
       
    63         },
       
    64     }
       
    65 }
       
    66 
       
    67 pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> {
       
    68     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir()))
       
    69 }
       
    70 
       
    71 pub(crate) fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> {
       
    72     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file()))
       
    73 }