Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overlay FileSystem #3677

Merged
merged 12 commits into from
Mar 16, 2023
Prev Previous commit
Next Next commit
renamed iter_filesystems() to filesystems()
  • Loading branch information
Michael-F-Bryan committed Mar 16, 2023

Unverified

No user is associated with the committer email.
commit b30024fc7f1f077b2a132f6b76add0b2a071d08c
26 changes: 14 additions & 12 deletions lib/vfs/src/filesystems.rs
Original file line number Diff line number Diff line change
@@ -2,11 +2,13 @@ use crate::FileSystem;

/// A chain of one or more [`FileSystem`]s.
pub trait FileSystems<'a>: 'a {
Michael-F-Bryan marked this conversation as resolved.
Show resolved Hide resolved
// FIXME(Michael-F-Bryan): Rewrite this to use GATs and an external iterator
// when we bump the MSRV to 1.65 or higher. That'll get rid of all the
// lifetimes and HRTBs.
// FIXME(Michael-F-Bryan): Rewrite this to use GATs when we bump the MSRV to
// 1.65 or higher. That'll get rid of all the lifetimes and HRTBs.
type Iter: IntoIterator<Item = &'a dyn FileSystem> + 'a;
fn iter_filesystems(&'a self) -> Self::Iter;

/// Get something that can be used to iterate over the underlying
/// filesystems.
fn filesystems(&'a self) -> Self::Iter;
}

impl<'a, 'b, S> FileSystems<'a> for &'b S
@@ -16,8 +18,8 @@ where
{
type Iter = S::Iter;

fn iter_filesystems(&'a self) -> Self::Iter {
(**self).iter_filesystems()
fn filesystems(&'a self) -> Self::Iter {
(**self).filesystems()
}
}

@@ -27,8 +29,8 @@ where
{
type Iter = <[T] as FileSystems<'a>>::Iter;

fn iter_filesystems(&'a self) -> Self::Iter {
self[..].iter_filesystems()
fn filesystems(&'a self) -> Self::Iter {
self[..].filesystems()
}
}

@@ -38,7 +40,7 @@ where
{
type Iter = [&'a dyn FileSystem; N];

fn iter_filesystems(&'a self) -> Self::Iter {
fn filesystems(&'a self) -> Self::Iter {
// TODO: rewrite this when array::each_ref() is stable
let mut i = 0;
[(); N].map(|_| {
@@ -55,15 +57,15 @@ where
{
type Iter = std::iter::Map<std::slice::Iter<'a, T>, fn(&T) -> &dyn FileSystem>;

fn iter_filesystems(&'a self) -> Self::Iter {
fn filesystems(&'a self) -> Self::Iter {
self.iter().map(|fs| fs as &dyn FileSystem)
}
}

impl<'a> FileSystems<'a> for () {
type Iter = std::iter::Empty<&'a dyn FileSystem>;

fn iter_filesystems(&'a self) -> Self::Iter {
fn filesystems(&'a self) -> Self::Iter {
std::iter::empty()
}
}
@@ -84,7 +86,7 @@ macro_rules! tuple_filesystems {
{
type Iter = [&'a dyn FileSystem; count!($first $($rest)*)];

fn iter_filesystems(&'a self) -> Self::Iter {
fn filesystems(&'a self) -> Self::Iter {
#[allow(non_snake_case)]
let ($first, $($rest),*) = self;

34 changes: 14 additions & 20 deletions lib/vfs/src/overlay_fs.rs
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ where
}

fn permission_error_or_not_found(&self, path: &Path) -> Result<(), FsError> {
for fs in self.secondaries.iter_filesystems() {
for fs in self.secondaries.filesystems() {
if fs.exists(path) {
return Err(FsError::PermissionDenied);
}
@@ -108,18 +108,11 @@ where
let mut entries = Vec::new();
let mut had_at_least_one_success = false;

match self.primary.read_dir(path) {
Ok(r) => {
for entry in r {
entries.push(entry?);
}
had_at_least_one_success = true;
}
Err(e) if should_continue(e) => {}
Err(e) => return Err(e),
}
let filesystems = std::iter::once(&self.primary as &dyn FileSystem)
.into_iter()
.chain(self.secondaries().filesystems());

for fs in self.secondaries.iter_filesystems() {
for fs in filesystems {
match fs.read_dir(path) {
Ok(r) => {
for entry in r {
@@ -133,10 +126,11 @@ where
}

if had_at_least_one_success {
// Note: this sort is guaranteed to be stable, so filesystems
// "higher up" the chain will be further towards the start.
entries.sort_by(|a, b| a.path.cmp(&b.path));
// Make sure later entries are removed in favour of earlier ones.
// Note: this sort is guaranteed to be stable, meaning filesystems
// "higher up" the chain will be further towards the start and kept
// when deduplicating.
entries.sort_by(|a, b| a.path.cmp(&b.path));
entries.dedup_by(|a, b| a.path == b.path);

Ok(ReadDir::new(entries))
@@ -179,7 +173,7 @@ where
Err(e) => return Err(e),
}

for fs in self.secondaries.iter_filesystems() {
for fs in self.secondaries.filesystems() {
match fs.metadata(path) {
Err(e) if should_continue(e) => continue,
other => return other,
@@ -227,7 +221,7 @@ where
if let Some(parent) = path.parent() {
let parent_exists_on_secondary_fs = self
.secondaries
.iter_filesystems()
.filesystems()
.into_iter()
.any(|fs| fs.is_dir(parent));
if parent_exists_on_secondary_fs {
@@ -250,7 +244,7 @@ where
return Err(FsError::PermissionDenied);
}

for fs in self.secondaries.iter_filesystems() {
for fs in self.secondaries.filesystems() {
match fs.new_open_options().options(conf.clone()).open(path) {
Err(e) if should_continue(e) => continue,
other => return other,
@@ -276,7 +270,7 @@ where
if conf.create {
// Would we create the file if it doesn't exist yet?
let already_exists = secondaries
.iter_filesystems()
.filesystems()
.into_iter()
.any(|fs| fs.is_file(path));

@@ -302,7 +296,7 @@ where
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_list();

for fs in self.0.iter_filesystems() {
for fs in self.0.filesystems() {
f.entry(&fs);
}