From 841f274356b388b9e36b36ec7c3208d168b4eae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Thu, 14 Jul 2022 12:01:27 -0400 Subject: [PATCH 1/7] Add logic for implementing random access in files. --- src/filesystem.rs | 4 ++- src/impls/altroot.rs | 4 +++ src/impls/memory.rs | 58 +++++++++++++++++++++++++++++++++++++++++++ src/impls/overlay.rs | 4 +++ src/impls/physical.rs | 9 +++++++ src/path.rs | 34 +++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 0d986b8..936344d 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,7 +1,7 @@ //! The filesystem trait definitions needed to implement new virtual filesystems use crate::error::VfsErrorKind; -use crate::{SeekAndRead, VfsMetadata, VfsPath, VfsResult}; +use crate::{SeekAndRead, SeekAndReadAndWrite, VfsMetadata, VfsPath, VfsResult}; use std::fmt::Debug; use std::io::Write; @@ -22,6 +22,8 @@ pub trait FileSystem: Debug + Sync + Send + 'static { fn create_dir(&self, path: &str) -> VfsResult<()>; /// Opens the file at this path for reading fn open_file(&self, path: &str) -> VfsResult>; + /// Opens the file at this path for reading and writing + fn update_file(&self, path: &str) -> VfsResult>; /// Creates a file at this path for writing fn create_file(&self, path: &str) -> VfsResult>; /// Opens the file at this path for appending diff --git a/src/impls/altroot.rs b/src/impls/altroot.rs index a966272..ca74078 100644 --- a/src/impls/altroot.rs +++ b/src/impls/altroot.rs @@ -50,6 +50,10 @@ impl FileSystem for AltrootFS { self.path(path)?.open_file() } + fn update_file(&self, path: &str) -> VfsResult> { + self.path(path)?.update_file() + } + fn create_file(&self, path: &str) -> VfsResult> { self.path(path)?.create_file() } diff --git a/src/impls/memory.rs b/src/impls/memory.rs index 5e8481e..0a441d2 100644 --- a/src/impls/memory.rs +++ b/src/impls/memory.rs @@ -119,6 +119,48 @@ impl Seek for ReadableFile { } } +struct WriteableAndReadableFile { + content: Cursor>, + destination: String, + fs: MemoryFsHandle, +} + +impl Write for WriteableAndReadableFile { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.content.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.content.flush() + } +} + +impl Read for WriteableAndReadableFile { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.content.read(buf) + } +} + +impl Seek for WriteableAndReadableFile { + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + self.content.seek(pos) + } +} + +impl Drop for WriteableAndReadableFile { + fn drop(&mut self) { + let mut content = vec![]; + swap(&mut content, self.content.get_mut()); + self.fs.write().unwrap().files.insert( + self.destination.clone(), + MemoryFile { + file_type: VfsFileType::File, + content: Arc::new(content), + }, + ); + } +} + impl FileSystem for MemoryFS { fn read_dir(&self, path: &str) -> VfsResult>> { let prefix = format!("{}/", path); @@ -169,6 +211,22 @@ impl FileSystem for MemoryFS { })) } + fn update_file(&self, path: &str) -> VfsResult> { + let handle = self.handle.read().unwrap(); + let file = handle + .files + .get(path) + .ok_or_else(|| VfsError::FileNotFound { + path: path.to_string(), + })?; + ensure_file(file)?; + Ok(Box::new(WriteableAndReadableFile { + content: Cursor::new(file.content.to_vec()), + destination: path.to_string(), + fs: self.handle.clone(), + })) + } + fn create_file(&self, path: &str) -> VfsResult> { self.ensure_has_parent(path)?; let content = Arc::new(Vec::::new()); diff --git a/src/impls/overlay.rs b/src/impls/overlay.rs index a758796..f170261 100644 --- a/src/impls/overlay.rs +++ b/src/impls/overlay.rs @@ -121,6 +121,10 @@ impl FileSystem for OverlayFS { self.read_path(path)?.open_file() } + fn update_file(&self, path: &str) -> VfsResult> { + self.read_path(path)?.update_file() + } + fn create_file(&self, path: &str) -> VfsResult> { self.ensure_has_parent(path)?; let result = self.write_path(path)?.create_file()?; diff --git a/src/impls/physical.rs b/src/impls/physical.rs index 3d8d2f5..aa0d2da 100644 --- a/src/impls/physical.rs +++ b/src/impls/physical.rs @@ -110,6 +110,15 @@ impl FileSystem for PhysicalFS { } Ok(()) } + + fn update_file(&self, path: &str) -> VfsResult> { + Ok(Box::new( + OpenOptions::new() + .write(true) + .read(true) + .open(self.get_path(path))?, + )) + } } #[cfg(test)] diff --git a/src/path.rs b/src/path.rs index a1ac33b..4e7ed91 100644 --- a/src/path.rs +++ b/src/path.rs @@ -14,6 +14,11 @@ pub trait SeekAndRead: Seek + Read {} impl SeekAndRead for T where T: Seek + Read {} +/// Trait combining Seek, Read and Write, return value for opening files with random access. +pub trait SeekAndReadAndWrite: Seek + Read + Write {} + +impl SeekAndReadAndWrite for T where T: Seek + Read + Write {} + /// Type of file #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum VfsFileType { @@ -296,6 +301,35 @@ impl VfsPath { }) } + /// Opens the file at this path for reading and writing + /// + /// ``` + /// # use std::io::{SeekFrom, Read}; + /// use vfs::{MemoryFS, VfsError, VfsPath}; + /// let path = VfsPath::new(MemoryFS::new()); + /// let file = path.join("foo.txt")?; + /// write!(file.create_file()?, "Hello, world!")?; + /// let mut result = String::new(); + /// + /// file.update_file()?.read_to_string(&mut result)?; + /// + /// assert_eq!(&result, "Hello, world!"); + /// + /// file.rewind()? + /// file.write(b"Goodnight, world.")?; + /// + /// file.read_to_string(&mut result)?; + /// + /// assert_eq!(&result, "Goodnight, world."); + /// # Ok::<(), VfsError>(()) + /// ``` + pub fn update_file(&self) -> VfsResult> { + self.fs + .fs + .update_file(&self.path) + .with_context(|| format!("Could not open file '{}'", &self.path)) + } + /// Checks whether parent is a directory fn get_parent(&self, action: &str) -> VfsResult<()> { let parent = self.parent(); From 13250587d77cd7989bb7f5a43bcb1f1c4d8759fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Thu, 14 Jul 2022 13:04:35 -0400 Subject: [PATCH 2/7] Fix tests, add for embedded and memory --- src/impls/embedded.rs | 4 ++++ src/impls/memory.rs | 4 +++- src/path.rs | 13 ++++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/impls/embedded.rs b/src/impls/embedded.rs index fadedd4..e399a32 100644 --- a/src/impls/embedded.rs +++ b/src/impls/embedded.rs @@ -106,6 +106,10 @@ where } } + fn update_file(&self, _path: &str) -> VfsResult> { + Err(VfsError::NotSupported) + } + fn create_file(&self, _path: &str) -> VfsResult> { Err(VfsErrorKind::NotSupported.into()) } diff --git a/src/impls/memory.rs b/src/impls/memory.rs index 0a441d2..e1414a8 100644 --- a/src/impls/memory.rs +++ b/src/impls/memory.rs @@ -220,8 +220,10 @@ impl FileSystem for MemoryFS { path: path.to_string(), })?; ensure_file(file)?; + let mut content = Cursor::new(file.content.as_ref().clone()); + content.seek(SeekFrom::Start(0))?; Ok(Box::new(WriteableAndReadableFile { - content: Cursor::new(file.content.to_vec()), + content, destination: path.to_string(), fs: self.handle.clone(), })) diff --git a/src/path.rs b/src/path.rs index 4e7ed91..7f32eec 100644 --- a/src/path.rs +++ b/src/path.rs @@ -311,16 +311,19 @@ impl VfsPath { /// write!(file.create_file()?, "Hello, world!")?; /// let mut result = String::new(); /// - /// file.update_file()?.read_to_string(&mut result)?; + /// let mut handle = file.update_file()?; + /// handle.read_to_string(&mut result)?; /// /// assert_eq!(&result, "Hello, world!"); /// - /// file.rewind()? - /// file.write(b"Goodnight, world.")?; + /// handle.rewind()?; + /// handle.write(b"Goodnight, world.")?; + /// handle.rewind()?; /// - /// file.read_to_string(&mut result)?; + /// let mut result2 = String::new(); + /// handle.read_to_string(&mut result2)?; /// - /// assert_eq!(&result, "Goodnight, world."); + /// assert_eq!(&result2, "Goodnight, world."); /// # Ok::<(), VfsError>(()) /// ``` pub fn update_file(&self) -> VfsResult> { From 4ea1e56d88422be6c69250b79644ba04275d6309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Mon, 25 Jul 2022 10:28:28 -0400 Subject: [PATCH 3/7] Add more necessary logic for bridging with rusqlite-vfs. --- src/filesystem.rs | 28 +++++++++++++++++++-- src/impls/memory.rs | 60 --------------------------------------------- src/path.rs | 12 +++++++-- 3 files changed, 36 insertions(+), 64 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 936344d..9a3f9fd 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -22,8 +22,6 @@ pub trait FileSystem: Debug + Sync + Send + 'static { fn create_dir(&self, path: &str) -> VfsResult<()>; /// Opens the file at this path for reading fn open_file(&self, path: &str) -> VfsResult>; - /// Opens the file at this path for reading and writing - fn update_file(&self, path: &str) -> VfsResult>; /// Creates a file at this path for writing fn create_file(&self, path: &str) -> VfsResult>; /// Opens the file at this path for appending @@ -48,6 +46,32 @@ pub trait FileSystem: Debug + Sync + Send + 'static { fn move_dir(&self, _src: &str, _dest: &str) -> VfsResult<()> { Err(VfsErrorKind::NotSupported.into()) } + + /// Informs the filesystem to 'flush' its potentially cached information. + /// + /// This is, by default, queries the current size. + fn size_hint(&self, path: &str) -> VfsResult { + self.metadata(path).map(|f| f.len) + } + + /// Informs the filesystem to 'flush' its potentially cached information. + /// + /// This is, by default, a no-op. + fn sync(&self, _path: &str) -> VfsResult<()> { + Ok(()) + } + + /// Set a size hint for the associated path. + /// + /// This is, by default, a no-op. + fn set_size_hint(&self, _hint: usize, _path: &str) -> VfsResult<()> { + Ok(()) + } + + /// Opens the file at this path for reading and writing + fn update_file(&self, _path: &str) -> VfsResult> { + Err(VfsError::NotSupported) + } } impl From for VfsPath { diff --git a/src/impls/memory.rs b/src/impls/memory.rs index e1414a8..5e8481e 100644 --- a/src/impls/memory.rs +++ b/src/impls/memory.rs @@ -119,48 +119,6 @@ impl Seek for ReadableFile { } } -struct WriteableAndReadableFile { - content: Cursor>, - destination: String, - fs: MemoryFsHandle, -} - -impl Write for WriteableAndReadableFile { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.content.write(buf) - } - - fn flush(&mut self) -> std::io::Result<()> { - self.content.flush() - } -} - -impl Read for WriteableAndReadableFile { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self.content.read(buf) - } -} - -impl Seek for WriteableAndReadableFile { - fn seek(&mut self, pos: SeekFrom) -> std::io::Result { - self.content.seek(pos) - } -} - -impl Drop for WriteableAndReadableFile { - fn drop(&mut self) { - let mut content = vec![]; - swap(&mut content, self.content.get_mut()); - self.fs.write().unwrap().files.insert( - self.destination.clone(), - MemoryFile { - file_type: VfsFileType::File, - content: Arc::new(content), - }, - ); - } -} - impl FileSystem for MemoryFS { fn read_dir(&self, path: &str) -> VfsResult>> { let prefix = format!("{}/", path); @@ -211,24 +169,6 @@ impl FileSystem for MemoryFS { })) } - fn update_file(&self, path: &str) -> VfsResult> { - let handle = self.handle.read().unwrap(); - let file = handle - .files - .get(path) - .ok_or_else(|| VfsError::FileNotFound { - path: path.to_string(), - })?; - ensure_file(file)?; - let mut content = Cursor::new(file.content.as_ref().clone()); - content.seek(SeekFrom::Start(0))?; - Ok(Box::new(WriteableAndReadableFile { - content, - destination: path.to_string(), - fs: self.handle.clone(), - })) - } - fn create_file(&self, path: &str) -> VfsResult> { self.ensure_has_parent(path)?; let content = Arc::new(Vec::::new()); diff --git a/src/path.rs b/src/path.rs index 7f32eec..1790b44 100644 --- a/src/path.rs +++ b/src/path.rs @@ -316,9 +316,9 @@ impl VfsPath { /// /// assert_eq!(&result, "Hello, world!"); /// - /// handle.rewind()?; + /// handle.seek(SeekFrom::Start(0))?; /// handle.write(b"Goodnight, world.")?; - /// handle.rewind()?; + /// handle.seek(SeekFrom::Start(0))?; /// /// let mut result2 = String::new(); /// handle.read_to_string(&mut result2)?; @@ -917,6 +917,14 @@ impl VfsPath { })?; Ok(()) } + + pub fn sync(&mut self) -> VfsResult<()> { + self.fs.fs.sync(&self.path) + } + + pub fn set_size_hint(&mut self, size_hint: usize) -> VfsResult<()> { + self.fs.fs.set_size_hint(size_hint, &self.path) + } } /// An iterator for recursively walking a file hierarchy From 36ae5b5b62e0cecea49a5a5bfdb14f52d0737a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Thu, 18 Aug 2022 13:29:32 -0400 Subject: [PATCH 4/7] Add logic for determining file access. In order to confirm R/W access, allowing a path to report if it can be written to or if it's only read-only helps. --- src/impls/embedded.rs | 6 ++-- src/impls/memory.rs | 76 ++++++++++++++++++++++++++++++++++++++++--- src/impls/physical.rs | 18 +++++++--- src/path.rs | 15 +++++++-- 4 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/impls/embedded.rs b/src/impls/embedded.rs index e399a32..594f859 100644 --- a/src/impls/embedded.rs +++ b/src/impls/embedded.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use rust_embed::RustEmbed; use crate::error::VfsErrorKind; -use crate::{FileSystem, SeekAndRead, VfsFileType, VfsMetadata, VfsResult}; +use crate::{FileSystem, SeekAndRead, VfsFileType, VfsMetadata, VfsResult, VfsAccess}; type EmbeddedPath = Cow<'static, str>; @@ -107,7 +107,7 @@ where } fn update_file(&self, _path: &str) -> VfsResult> { - Err(VfsError::NotSupported) + Err(VfsErrorKind::NotSupported) } fn create_file(&self, _path: &str) -> VfsResult> { @@ -124,12 +124,14 @@ where return Ok(VfsMetadata { file_type: VfsFileType::File, len: *len, + access: HashSet::from([VfsAccess::Read]) }); } if self.directory_map.contains_key(normalized_path) { return Ok(VfsMetadata { file_type: VfsFileType::Directory, len: 0, + access: HashSet::from([VfsAccess::Read]) }); } Err(VfsErrorKind::FileNotFound.into()) diff --git a/src/impls/memory.rs b/src/impls/memory.rs index 5e8481e..1e0a711 100644 --- a/src/impls/memory.rs +++ b/src/impls/memory.rs @@ -1,17 +1,16 @@ //! An ephemeral in-memory file system, intended mainly for unit tests use crate::error::VfsErrorKind; -use crate::VfsResult; -use crate::{FileSystem, VfsFileType}; -use crate::{SeekAndRead, VfsMetadata}; +use crate::{VfsResult, FileSystem, SeekAndRead, VfsFileType, VfsMetadata, VfsAccess}; use core::cmp; -use std::collections::HashMap; +use std::collections::{HashSet, HashMap}; use std::fmt; use std::fmt::{Debug, Formatter}; use std::io::{Cursor, Read, Seek, SeekFrom, Write}; use std::mem::swap; use std::sync::{Arc, RwLock}; + type MemoryFsHandle = Arc>; /// An ephemeral in-memory file system, intended mainly for unit tests @@ -119,6 +118,56 @@ impl Seek for ReadableFile { } } +struct RandomAccessFile { + content: Cursor>, + destination: String, + fs: MemoryFsHandle, +} + +impl RandomAccessFile { + fn from_file(value: Arc>, destination: String, fs: MemoryFsHandle) -> Self { + Self { + content: Cursor::new(value.to_vec()), + destination, + fs, + } + } +} + +impl Write for RandomAccessFile { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.content.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.content.flush() + } +} + +impl Read for RandomAccessFile { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.content.read(buf) + } +} +impl Seek for RandomAccessFile { + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + self.content.seek(pos) + } +} +impl Drop for RandomAccessFile { + fn drop(&mut self) { + let mut content = vec![]; + swap(&mut content, self.content.get_mut()); + self.fs.write().unwrap().files.insert( + self.destination.clone(), + MemoryFile { + file_type: VfsFileType::File, + content: Arc::new(content), + }, + ); + } +} + impl FileSystem for MemoryFS { fn read_dir(&self, path: &str) -> VfsResult>> { let prefix = format!("{}/", path); @@ -195,18 +244,35 @@ impl FileSystem for MemoryFS { let writer = WritableFile { content, destination: path.to_string(), - fs: self.handle.clone(), + fs: Arc::clone(&self.handle), }; Ok(Box::new(writer)) } + fn update_file(&self, path: &str) -> VfsResult> { + let handle = self.handle.read().unwrap(); + let file = handle + .files + .get(path) + .ok_or_else(|| VfsErrorKind::FileNotFound)?; + ensure_file(file)?; + + Ok(Box::new(RandomAccessFile::from_file( + Arc::clone(&file.content), + path.to_string(), + Arc::clone(&self.handle), + ))) + } + fn metadata(&self, path: &str) -> VfsResult { let guard = self.handle.read().unwrap(); let files = &guard.files; let file = files.get(path).ok_or(VfsErrorKind::FileNotFound)?; + Ok(VfsMetadata { file_type: file.file_type, len: file.content.len() as u64, + access: HashSet::from([VfsAccess::Read, VfsAccess::Write]), }) } diff --git a/src/impls/physical.rs b/src/impls/physical.rs index aa0d2da..888a8fb 100644 --- a/src/impls/physical.rs +++ b/src/impls/physical.rs @@ -1,13 +1,13 @@ //! A "physical" file system implementation using the underlying OS file system use crate::error::VfsErrorKind; -use crate::VfsResult; -use crate::{FileSystem, VfsMetadata}; -use crate::{SeekAndRead, VfsFileType}; +use crate::{SeekAndRead, VfsFileType, VfsResult, VfsAccess, FileSystem, VfsMetadata}; +use std::collections::HashSet; use std::fs::{File, OpenOptions}; use std::io::Write; use std::path::{Path, PathBuf}; + /// A physical filesystem implementation using the underlying OS file system #[derive(Debug)] pub struct PhysicalFS { @@ -63,16 +63,26 @@ impl FileSystem for PhysicalFS { } fn metadata(&self, path: &str) -> VfsResult { - let metadata = self.get_path(path).metadata()?; + let pb = self.get_path(path); + let metadata = pb.metadata()?; + let mut access = HashSet::new(); + access.insert(VfsAccess::Read); + + if !metadata.permissions().readonly() { + access.insert(VfsAccess::Write); + } + Ok(if metadata.is_dir() { VfsMetadata { file_type: VfsFileType::Directory, len: 0, + access, } } else { VfsMetadata { file_type: VfsFileType::File, len: metadata.len(), + access, } }) } diff --git a/src/path.rs b/src/path.rs index 1790b44..cd9d520 100644 --- a/src/path.rs +++ b/src/path.rs @@ -3,6 +3,7 @@ //! The virtual file system abstraction generalizes over file systems and allow using //! different VirtualFileSystem implementations (i.e. an in memory implementation for unit tests) +use std::collections::HashSet; use std::io::{Read, Seek, Write}; use std::sync::Arc; @@ -28,6 +29,15 @@ pub enum VfsFileType { Directory, } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum VfsAccess { + /// The resource at this path can be read from. + Read, + + /// The resource at this path can be written to. + Write, +} + /// File metadata information #[derive(Debug)] pub struct VfsMetadata { @@ -35,6 +45,8 @@ pub struct VfsMetadata { pub file_type: VfsFileType, /// Length of the file in bytes, 0 for directories pub len: u64, + /// Access levels available to this path. + pub access: HashSet, } #[derive(Debug)] @@ -330,7 +342,6 @@ impl VfsPath { self.fs .fs .update_file(&self.path) - .with_context(|| format!("Could not open file '{}'", &self.path)) } /// Checks whether parent is a directory @@ -621,7 +632,7 @@ impl VfsPath { /// Directories are visited before their children /// /// Note that the iterator items can contain errors, usually when directories are removed during the iteration. - /// The returned paths may also point to non-existant files if there is concurrent removal. + /// The returned paths may also point to non-existent files if there is concurrent removal. /// /// Also note that loops in the file system hierarchy may cause this iterator to never terminate. /// From 98638276f25963726478a61db1e34f685ce6f277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Thu, 18 Aug 2022 14:20:31 -0400 Subject: [PATCH 5/7] Correct impls for updating files. --- src/filesystem.rs | 2 +- src/impls/embedded.rs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 9a3f9fd..e3fcc7b 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -70,7 +70,7 @@ pub trait FileSystem: Debug + Sync + Send + 'static { /// Opens the file at this path for reading and writing fn update_file(&self, _path: &str) -> VfsResult> { - Err(VfsError::NotSupported) + Err(VfsErrorKind::NotSupported.into()) } } diff --git a/src/impls/embedded.rs b/src/impls/embedded.rs index 594f859..0828bf9 100644 --- a/src/impls/embedded.rs +++ b/src/impls/embedded.rs @@ -106,10 +106,6 @@ where } } - fn update_file(&self, _path: &str) -> VfsResult> { - Err(VfsErrorKind::NotSupported) - } - fn create_file(&self, _path: &str) -> VfsResult> { Err(VfsErrorKind::NotSupported.into()) } From e5cf42bbda1d91c12644b35c820a9ba3e9f253c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Thu, 18 Aug 2022 23:30:59 -0400 Subject: [PATCH 6/7] Update method signatures. --- src/filesystem.rs | 10 +++------- src/impls/altroot.rs | 12 ++++++++---- src/impls/memory.rs | 4 ++++ src/impls/physical.rs | 4 ++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index e3fcc7b..73d1742 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -47,19 +47,15 @@ pub trait FileSystem: Debug + Sync + Send + 'static { Err(VfsErrorKind::NotSupported.into()) } - /// Informs the filesystem to 'flush' its potentially cached information. + /// This obtains the potential size of the current path in the filesystem. /// - /// This is, by default, queries the current size. + /// This, by default, queries the current size. fn size_hint(&self, path: &str) -> VfsResult { self.metadata(path).map(|f| f.len) } /// Informs the filesystem to 'flush' its potentially cached information. - /// - /// This is, by default, a no-op. - fn sync(&self, _path: &str) -> VfsResult<()> { - Ok(()) - } + fn sync(&self, path: &str) -> VfsResult<()>; /// Set a size hint for the associated path. /// diff --git a/src/impls/altroot.rs b/src/impls/altroot.rs index ca74078..b036f34 100644 --- a/src/impls/altroot.rs +++ b/src/impls/altroot.rs @@ -50,10 +50,6 @@ impl FileSystem for AltrootFS { self.path(path)?.open_file() } - fn update_file(&self, path: &str) -> VfsResult> { - self.path(path)?.update_file() - } - fn create_file(&self, path: &str) -> VfsResult> { self.path(path)?.create_file() } @@ -86,6 +82,14 @@ impl FileSystem for AltrootFS { } self.path(src)?.copy_file(&self.path(dest)?) } + + fn update_file(&self, path: &str) -> VfsResult> { + self.path(path)?.update_file() + } + + fn sync(&self, path: &str) -> VfsResult<()> { + self.path(path)?.sync() + } } #[cfg(test)] diff --git a/src/impls/memory.rs b/src/impls/memory.rs index 1e0a711..308628c 100644 --- a/src/impls/memory.rs +++ b/src/impls/memory.rs @@ -300,6 +300,10 @@ impl FileSystem for MemoryFS { .ok_or(VfsErrorKind::FileNotFound)?; Ok(()) } + + fn sync(&self, path: &str) -> VfsResult<()> { + Ok(()) + } } struct MemoryFsImpl { diff --git a/src/impls/physical.rs b/src/impls/physical.rs index 888a8fb..6fe4682 100644 --- a/src/impls/physical.rs +++ b/src/impls/physical.rs @@ -129,6 +129,10 @@ impl FileSystem for PhysicalFS { .open(self.get_path(path))?, )) } + + fn sync(&self, path: &str) -> VfsResult<()> { + Ok(()) + } } #[cfg(test)] From c0807abbf71b99e7f6e819ffb758bbd137dd54aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacky=20Alcin=C3=A9?= Date: Fri, 19 Aug 2022 00:01:28 -0400 Subject: [PATCH 7/7] Update to require definition of 'sync'. --- src/impls/embedded.rs | 3 +++ src/impls/memory.rs | 2 +- src/impls/overlay.rs | 8 ++++++++ src/impls/physical.rs | 2 +- src/path.rs | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/impls/embedded.rs b/src/impls/embedded.rs index 0828bf9..7c23c4b 100644 --- a/src/impls/embedded.rs +++ b/src/impls/embedded.rs @@ -155,6 +155,9 @@ where fn remove_dir(&self, _path: &str) -> VfsResult<()> { Err(VfsErrorKind::NotSupported.into()) } + fn sync(&self, _path: &str) -> VfsResult<()> { + Ok(()) + } } fn normalize_path(path: &str) -> VfsResult<&str> { diff --git a/src/impls/memory.rs b/src/impls/memory.rs index 308628c..4bb02a2 100644 --- a/src/impls/memory.rs +++ b/src/impls/memory.rs @@ -301,7 +301,7 @@ impl FileSystem for MemoryFS { Ok(()) } - fn sync(&self, path: &str) -> VfsResult<()> { + fn sync(&self, _path: &str) -> VfsResult<()> { Ok(()) } } diff --git a/src/impls/overlay.rs b/src/impls/overlay.rs index f170261..353f3aa 100644 --- a/src/impls/overlay.rs +++ b/src/impls/overlay.rs @@ -31,6 +31,10 @@ impl OverlayFS { &self.layers[0] } + fn sync_path(&self,path:&str) -> VfsResult<()>{ + self.read_path(path).and_then(|p| p.sync()) + } + fn read_path(&self, path: &str) -> VfsResult { if path.is_empty() { return Ok(self.layers[0].clone()); @@ -186,6 +190,10 @@ impl FileSystem for OverlayFS { whiteout_path.create_file()?; Ok(()) } + + fn sync(&self, path: &str) -> VfsResult<()> { + self.sync_path(path) + } } #[cfg(test)] diff --git a/src/impls/physical.rs b/src/impls/physical.rs index 6fe4682..ea130e2 100644 --- a/src/impls/physical.rs +++ b/src/impls/physical.rs @@ -130,7 +130,7 @@ impl FileSystem for PhysicalFS { )) } - fn sync(&self, path: &str) -> VfsResult<()> { + fn sync(&self, _path: &str) -> VfsResult<()> { Ok(()) } } diff --git a/src/path.rs b/src/path.rs index cd9d520..f77625d 100644 --- a/src/path.rs +++ b/src/path.rs @@ -929,7 +929,7 @@ impl VfsPath { Ok(()) } - pub fn sync(&mut self) -> VfsResult<()> { + pub fn sync(&self) -> VfsResult<()> { self.fs.fs.sync(&self.path) }