Skip to content

Commit

Permalink
Use FsPath for mountpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
TimeEngineer committed Nov 10, 2023
1 parent 0f20636 commit 2a19091
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 211 deletions.
26 changes: 15 additions & 11 deletions libparsec/crates/platform_mountpoint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub(crate) use unix as platform;
#[cfg(target_os = "windows")]
pub(crate) use windows as platform;

use libparsec_types::{anyhow, EntryName, FileDescriptor, VlobID};
use libparsec_types::{anyhow, EntryName, FileDescriptor, FsPath, VlobID};

pub use error::{MountpointError, MountpointResult};
pub use memfs::MemFS;
Expand Down Expand Up @@ -89,29 +89,33 @@ impl<T: MountpointInterface> FileSystemWrapper<T> {

pub trait MountpointInterface {
// Rights check
fn check_read_rights(&self, path: &Path) -> MountpointResult<()>;
fn check_write_rights(&self, path: &Path) -> MountpointResult<()>;
fn check_read_rights(&self, path: &FsPath) -> MountpointResult<()>;
fn check_write_rights(&self, path: &FsPath) -> MountpointResult<()>;

// Entry transactions

fn entry_info(&self, path: &Path) -> MountpointResult<EntryInfo>;
fn entry_info(&self, path: &FsPath) -> MountpointResult<EntryInfo>;
fn entry_rename(
&self,
source: &Path,
destination: &Path,
source: &FsPath,
destination: &FsPath,
overwrite: bool,
) -> MountpointResult<()>;

// Directory transactions

fn dir_create(&self, path: &Path) -> MountpointResult<()>;
fn dir_delete(&self, path: &Path) -> MountpointResult<()>;
fn dir_create(&self, path: &FsPath) -> MountpointResult<()>;
fn dir_delete(&self, path: &FsPath) -> MountpointResult<()>;

// File transactions

fn file_create(&self, path: &Path, open: bool) -> MountpointResult<FileDescriptor>;
fn file_open(&self, path: &Path, write_mode: bool) -> MountpointResult<Option<FileDescriptor>>;
fn file_delete(&self, path: &Path) -> MountpointResult<()>;
fn file_create(&self, path: &FsPath, open: bool) -> MountpointResult<FileDescriptor>;
fn file_open(
&self,
path: &FsPath,
write_mode: bool,
) -> MountpointResult<Option<FileDescriptor>>;
fn file_delete(&self, path: &FsPath) -> MountpointResult<()>;

// File descriptor transactions

Expand Down
144 changes: 58 additions & 86 deletions libparsec/crates/platform_mountpoint/src/memfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@
use chrono::Utc;
use std::{
collections::HashMap,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};

use libparsec_types::{EntryName, FileDescriptor, VlobID};
use libparsec_types::{FileDescriptor, FsPath, VlobID};

use crate::{
EntryInfo, EntryInfoType, MountpointError, MountpointInterface, MountpointResult, WriteMode,
};

type Entries = Mutex<HashMap<PathBuf, (EntryInfo, Option<Arc<Mutex<Vec<u8>>>>)>>;
type Entries = Mutex<HashMap<FsPath, (EntryInfo, Option<Arc<Mutex<Vec<u8>>>>)>>;

pub struct MemFS {
entries: Entries,
Expand All @@ -25,7 +24,7 @@ pub struct MemFS {
}

struct FileData {
path: PathBuf,
path: FsPath,
data: Arc<Mutex<Vec<u8>>>,
}

Expand All @@ -35,7 +34,7 @@ impl Default for MemFS {
let now = Utc::now();

entries.insert(
PathBuf::from("/"),
"/".parse().expect("unreachable"),
(
EntryInfo::new(VlobID::default(), EntryInfoType::Dir, now),
None,
Expand Down Expand Up @@ -72,15 +71,15 @@ impl MemFS {
}

impl MountpointInterface for MemFS {
fn check_read_rights(&self, _path: &Path) -> MountpointResult<()> {
fn check_read_rights(&self, _path: &FsPath) -> MountpointResult<()> {
Ok(())
}

fn check_write_rights(&self, _path: &Path) -> MountpointResult<()> {
fn check_write_rights(&self, _path: &FsPath) -> MountpointResult<()> {
Ok(())
}

fn entry_info(&self, path: &Path) -> MountpointResult<EntryInfo> {
fn entry_info(&self, path: &FsPath) -> MountpointResult<EntryInfo> {
self.entries
.lock()
.expect("Mutex is poisoned")
Expand All @@ -91,19 +90,16 @@ impl MountpointInterface for MemFS {

fn entry_rename(
&self,
source: &Path,
destination: &Path,
source: &FsPath,
destination: &FsPath,
overwrite: bool,
) -> MountpointResult<()> {
let mut entries = self.entries.lock().expect("Mutex is poisoned");
let source_str = source.to_str().ok_or(MountpointError::NotFound)?;
let destination_str = destination.to_str().ok_or(MountpointError::InvalidName)?;
let root = Path::new("/");

// Source is root
// Destination is root
// Cross-directory renaming is not supported
if source == root || destination == root || source.parent() != destination.parent() {
if source.is_root() || destination.is_root() || source.parent() != destination.parent() {
return Err(MountpointError::AccessDenied);
}

Expand All @@ -118,55 +114,43 @@ impl MountpointInterface for MemFS {
}
}

let iter_entries = entries
.keys()
.filter_map(|path| match path.to_str() {
Some(path) if path.starts_with(source_str) => Some(path.to_string()),
_ => None,
*entries = entries
.drain()
.map(|(path, info)| {
if path.starts_with(source) {
(
path.replace_parent(source.parts().len(), destination.clone()),
info,
)
} else {
(path, info)
}
})
.collect::<Vec<String>>();

for entry_path in iter_entries {
let new_entry_path = PathBuf::from(entry_path.replacen(source_str, destination_str, 1));

let entry = entries
.remove(Path::new(&entry_path))
.ok_or(MountpointError::NotFound)?;
entries.insert(new_entry_path, entry);
}
.collect();

let (parent, _) = entries
.get_mut(source.parent().expect("Can't be root"))
.get_mut(&source.parent())
.ok_or(MountpointError::NotFound)?;
let id = parent
.children
.remove(&EntryName::try_from(
source
.file_name()
.ok_or(MountpointError::InvalidName)?
.to_str()
.ok_or(MountpointError::InvalidName)?,
)?)
.remove(source.name().ok_or(MountpointError::InvalidName)?)
.ok_or(MountpointError::NotFound)?;

let (parent, _) = entries
.get_mut(destination.parent().expect("Can't be root"))
.get_mut(&destination.parent())
.ok_or(MountpointError::NotFound)?;
parent.children.insert(
EntryName::try_from(
destination
.file_name()
.ok_or(MountpointError::InvalidName)?
.to_str()
.ok_or(MountpointError::InvalidName)?,
)?,
destination
.name()
.ok_or(MountpointError::InvalidName)?
.clone(),
id,
);

Ok(())
}

fn file_create(&self, path: &Path, _open: bool) -> MountpointResult<FileDescriptor> {
fn file_create(&self, path: &FsPath, _open: bool) -> MountpointResult<FileDescriptor> {
let mut entries = self.entries.lock().expect("Mutex is poisoned");

if entries.contains_key(path) {
Expand All @@ -178,24 +162,20 @@ impl MountpointInterface for MemFS {
let id = VlobID::default();
let now = Utc::now();
let fd = self.create_file_descriptor(FileData {
path: path.into(),
path: path.clone(),
data: data.clone(),
});

let (parent, _) = entries
.get_mut(path.parent().expect("Can't be root"))
.get_mut(&path.parent())
.ok_or(MountpointError::NotFound)?;

let file_name = path
.file_name()
.ok_or(MountpointError::InvalidName)?
.to_str()
.ok_or(MountpointError::InvalidName)?;
let file_name = path.name().ok_or(MountpointError::InvalidName)?;

parent.children.insert(EntryName::try_from(file_name)?, id);
parent.children.insert(file_name.clone(), id);

entries.insert(
path.to_path_buf(),
path.clone(),
(
EntryInfo::new(VlobID::default(), EntryInfoType::File, now),
Some(data),
Expand All @@ -207,7 +187,7 @@ impl MountpointInterface for MemFS {

fn file_open(
&self,
path: &Path,
path: &FsPath,
_write_mode: bool,
) -> MountpointResult<Option<FileDescriptor>> {
let entries = self.entries.lock().expect("Mutex is poisoned");
Expand All @@ -216,27 +196,24 @@ impl MountpointInterface for MemFS {

if let Some(data) = data {
Ok(Some(self.create_file_descriptor(FileData {
path: path.into(),
path: path.clone(),
data: data.clone(),
})))
} else {
Ok(None)
}
}

fn file_delete(&self, path: &Path) -> MountpointResult<()> {
fn file_delete(&self, path: &FsPath) -> MountpointResult<()> {
let mut entries = self.entries.lock().expect("Mutex is poisoned");

let (parent, _) = entries
.get_mut(path.parent().expect("Can't be root"))
.get_mut(&path.parent())
.ok_or(MountpointError::NotFound)?;

parent.children.remove(&EntryName::try_from(
path.file_name()
.ok_or(MountpointError::InvalidName)?
.to_str()
.ok_or(MountpointError::InvalidName)?,
)?);
parent
.children
.remove(path.name().ok_or(MountpointError::InvalidName)?);

entries.remove(path).ok_or(MountpointError::NotFound)?;

Expand Down Expand Up @@ -344,7 +321,7 @@ impl MountpointInterface for MemFS {
Ok(transferred_length)
}

fn dir_create(&self, path: &Path) -> MountpointResult<()> {
fn dir_create(&self, path: &FsPath) -> MountpointResult<()> {
let mut entries = self.entries.lock().expect("Mutex is poisoned");

if entries.contains_key(path) {
Expand All @@ -355,47 +332,42 @@ impl MountpointInterface for MemFS {
let now = Utc::now();

let (parent, _) = entries
.get_mut(path.parent().expect("Can't be root"))
.get_mut(&path.parent())
.ok_or(MountpointError::NotFound)?;

parent.children.insert(
EntryName::try_from(
path.file_name()
.ok_or(MountpointError::InvalidName)?
.to_str()
.ok_or(MountpointError::InvalidName)?,
)?,
id,
);
parent
.children
.insert(path.name().ok_or(MountpointError::InvalidName)?.clone(), id);

entries.insert(
path.to_path_buf(),
path.clone(),
(EntryInfo::new(id, EntryInfoType::Dir, now), None),
);

Ok(())
}

fn dir_delete(&self, path: &Path) -> MountpointResult<()> {
fn dir_delete(&self, path: &FsPath) -> MountpointResult<()> {
let mut entries = self.entries.lock().expect("Mutex is poisoned");

if entries.keys().any(|entry| entry.parent() == Some(path)) {
if entries.keys().any(|entry| &entry.parent() == path) {
return Err(MountpointError::DirNotEmpty);
}

let (parent, _) = entries
.get_mut(path.parent().expect("Can't be root"))
.get_mut(&path.parent())
.ok_or(MountpointError::NotFound)?;

parent.children.remove(&EntryName::try_from(
path.file_name()
.ok_or(MountpointError::InvalidName)?
.to_str()
.ok_or(MountpointError::InvalidName)?,
)?);
parent
.children
.remove(path.name().ok_or(MountpointError::InvalidName)?);

entries.remove(path).ok_or(MountpointError::NotFound)?;

Ok(())
}
}

#[cfg(all(test, target_os = "windows"))]
#[path = "../tests/unit/winfsp.rs"]
mod tests;
Loading

0 comments on commit 2a19091

Please sign in to comment.