Skip to content

Commit

Permalink
feat: windows base; use Generic instead of Boxes
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Oct 25, 2024
1 parent 0675cc2 commit 8024879
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 26 deletions.
177 changes: 167 additions & 10 deletions remotefs-fuse-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod webdav;
use std::path::PathBuf;

use argh::FromArgs;
use remotefs::RemoteFs;
use remotefs::{fs::UnixPex, RemoteFs, RemoteResult};

#[cfg(feature = "aws-s3")]
use self::aws_s3::AwsS3Args;
Expand Down Expand Up @@ -113,23 +113,180 @@ pub enum RemoteArgs {

impl CliArgs {
/// Create a RemoteFs instance from the CLI arguments
pub fn remote(self) -> Box<dyn RemoteFs> {
pub fn remote(self) -> RemoteFsWrapper {
match self.remote {
#[cfg(feature = "aws-s3")]
RemoteArgs::AwsS3(args) => Box::new(remotefs_aws_s3::AwsS3Fs::from(args)),
RemoteArgs::AwsS3(args) => RemoteFsWrapper::Aws(remotefs_aws_s3::AwsS3Fs::from(args)),
#[cfg(feature = "ftp")]
RemoteArgs::Ftp(args) => Box::new(remotefs_ftp::FtpFs::from(args)),
RemoteArgs::Ftp(args) => RemoteFsWrapper::Ftp(remotefs_ftp::FtpFs::from(args)),
#[cfg(feature = "kube")]
RemoteArgs::Kube(args) => Box::new(remotefs_kube::KubeMultiPodFs::from(args)),
RemoteArgs::Memory(args) => Box::new(remotefs_memory::MemoryFs::from(args)),
RemoteArgs::Kube(args) => {
RemoteFsWrapper::Kube(remotefs_kube::KubeMultiPodFs::from(args))
}
RemoteArgs::Memory(args) => {
RemoteFsWrapper::Memory(remotefs_memory::MemoryFs::from(args))
}
#[cfg(feature = "ssh")]
RemoteArgs::Scp(args) => Box::new(remotefs_ssh::ScpFs::from(args)),
RemoteArgs::Scp(args) => RemoteFsWrapper::Scp(remotefs_ssh::ScpFs::from(args)),
#[cfg(feature = "ssh")]
RemoteArgs::Sftp(args) => Box::new(remotefs_ssh::SftpFs::from(args)),
RemoteArgs::Sftp(args) => RemoteFsWrapper::Sftp(remotefs_ssh::SftpFs::from(args)),
#[cfg(feature = "smb")]
RemoteArgs::Smb(args) => Box::new(remotefs_smb::SmbFs::from(args)),
RemoteArgs::Smb(args) => RemoteFsWrapper::Smb(remotefs_smb::SmbFs::from(args)),
#[cfg(feature = "webdav")]
RemoteArgs::Webdav(args) => Box::new(remotefs_webdav::WebDAVFs::from(args)),
RemoteArgs::Webdav(args) => {
RemoteFsWrapper::Webdav(remotefs_webdav::WebDAVFs::from(args))
}
}
}
}

enum RemoteFsWrapper {
#[cfg(feature = "aws-s3")]
Aws(remotefs_aws_s3::AwsS3Fs),
#[cfg(feature = "ftp")]
Ftp(remotefs_ftp::FtpFs),
#[cfg(feature = "kube")]
Kube(remotefs_kube::KubeMultiPodFs),
Memory(remotefs_memory::MemoryFs),
#[cfg(feature = "ssh")]
Scp(remotefs_ssh::ScpFs),
#[cfg(feature = "ssh")]
Sftp(remotefs_ssh::SftpFs),
#[cfg(feature = "smb")]
Smb(remotefs_smb::SmbFs),
#[cfg(feature = "webdav")]
Webdav(remotefs_webdav::WebDAVFs),
}

impl RemoteFsWrapper {
fn on_remote<F, T>(&mut self, f: F) -> T
where
F: FnOnce(&mut dyn RemoteFs) -> T,
{
match self {
#[cfg(feature = "aws-s3")]
RemoteFsWrapper::Aws(fs) => f(fs),
#[cfg(feature = "ftp")]
RemoteFsWrapper::Ftp(fs) => f(fs),
#[cfg(feature = "kube")]
RemoteFsWrapper::Kube(fs) => f(fs),
RemoteFsWrapper::Memory(fs) => f(fs),
#[cfg(feature = "ssh")]
RemoteFsWrapper::Scp(fs) => f(fs),
#[cfg(feature = "ssh")]
RemoteFsWrapper::Sftp(fs) => f(fs),
#[cfg(feature = "smb")]
RemoteFsWrapper::Smb(fs) => f(fs),
#[cfg(feature = "webdav")]
RemoteFsWrapper::Webdav(fs) => f(fs),
}
}
}

impl RemoteFs for RemoteFsWrapper {
fn append(
&mut self,
path: &std::path::Path,
metadata: &remotefs::fs::Metadata,
) -> RemoteResult<remotefs::fs::WriteStream> {
self.on_remote(|fs| fs.append(path, metadata))
}
fn append_file(
&mut self,
path: &std::path::Path,
metadata: &remotefs::fs::Metadata,
reader: Box<dyn std::io::Read + Send>,
) -> RemoteResult<u64> {
self.on_remote(|fs| fs.append_file(path, metadata, reader))
}
fn create_dir(&mut self, path: &std::path::Path, mode: UnixPex) -> RemoteResult<()> {
self.on_remote(|fs| fs.create_dir(path, mode))
}
fn change_dir(&mut self, dir: &std::path::Path) -> RemoteResult<PathBuf> {
self.on_remote(|fs| fs.change_dir(dir))
}
fn connect(&mut self) -> RemoteResult<remotefs::fs::Welcome> {
self.on_remote(|fs| fs.connect())
}
fn copy(&mut self, src: &std::path::Path, dest: &std::path::Path) -> RemoteResult<()> {
self.on_remote(|fs| fs.copy(src, dest))
}
fn create(
&mut self,
path: &std::path::Path,
metadata: &remotefs::fs::Metadata,
) -> RemoteResult<remotefs::fs::WriteStream> {
self.on_remote(|fs| fs.create(path, metadata))
}
fn create_file(
&mut self,
path: &std::path::Path,
metadata: &remotefs::fs::Metadata,
reader: Box<dyn std::io::Read + Send>,
) -> RemoteResult<u64> {
self.on_remote(|fs| fs.create_file(path, metadata, reader))
}
fn disconnect(&mut self) -> RemoteResult<()> {
self.on_remote(|fs| fs.disconnect())
}
fn exec(&mut self, cmd: &str) -> RemoteResult<(u32, String)> {
self.on_remote(|fs| fs.exec(cmd))
}
fn exists(&mut self, path: &std::path::Path) -> RemoteResult<bool> {
self.on_remote(|fs| fs.exists(path))
}
fn find(&mut self, search: &str) -> RemoteResult<Vec<remotefs::File>> {
self.on_remote(|fs| fs.find(search))
}
fn is_connected(&mut self) -> bool {
self.on_remote(|fs| fs.is_connected())
}

fn list_dir(&mut self, path: &std::path::Path) -> RemoteResult<Vec<remotefs::File>> {
self.on_remote(|fs| fs.list_dir(path))
}
fn mov(&mut self, src: &std::path::Path, dest: &std::path::Path) -> RemoteResult<()> {
self.on_remote(|fs| fs.mov(src, dest))
}
fn on_read(&mut self, readable: remotefs::fs::ReadStream) -> RemoteResult<()> {
self.on_remote(|fs| fs.on_read(readable))
}
fn on_written(&mut self, writable: remotefs::fs::WriteStream) -> RemoteResult<()> {
self.on_remote(|fs| fs.on_written(writable))
}
fn open(&mut self, path: &std::path::Path) -> RemoteResult<remotefs::fs::ReadStream> {
self.on_remote(|fs| fs.open(path))
}
fn open_file(
&mut self,
src: &std::path::Path,
dest: Box<dyn std::io::Write + Send>,
) -> RemoteResult<u64> {
self.on_remote(|fs| fs.open_file(src, dest))
}
fn pwd(&mut self) -> RemoteResult<PathBuf> {
self.on_remote(|fs| fs.pwd())
}
fn remove_dir(&mut self, path: &std::path::Path) -> RemoteResult<()> {
self.on_remote(|fs| fs.remove_dir(path))
}
fn remove_dir_all(&mut self, path: &std::path::Path) -> RemoteResult<()> {
self.on_remote(|fs| fs.remove_dir_all(path))
}
fn remove_file(&mut self, path: &std::path::Path) -> RemoteResult<()> {
self.on_remote(|fs| fs.remove_file(path))
}
fn setstat(
&mut self,
path: &std::path::Path,
metadata: remotefs::fs::Metadata,
) -> RemoteResult<()> {
self.on_remote(|fs| fs.setstat(path, metadata))
}
fn stat(&mut self, path: &std::path::Path) -> RemoteResult<remotefs::File> {
self.on_remote(|fs| fs.stat(path))
}
fn symlink(&mut self, path: &std::path::Path, target: &std::path::Path) -> RemoteResult<()> {
self.on_remote(|fs| fs.symlink(path, target))
}
}
3 changes: 2 additions & 1 deletion remotefs-fuse-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ fn main() -> anyhow::Result<()> {
}

// Mount the remote file system
let mut mount = Mount::mount(args.remote(), &mount_path, &options)?;
let remote = args.remote();
let mut mount = Mount::mount(remote, &mount_path, &options)?;
let mut umount = mount.unmounter();

// setup signal handler
Expand Down
8 changes: 6 additions & 2 deletions remotefs-fuse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ path = "src/lib.rs"
[dependencies]
log = "^0.4"
remotefs = "0.3"
thiserror = "^1"
tempfile = "^3"


[target.'cfg(unix)'.dependencies]
fuser = "0.14"
libc = "^0.2"
nix = { version = "0.29", features = ["fs"] }
seahash = "4"
tempfile = "^3"

[target.'cfg(windows)'.dependencies]
dokan = "0.3.1"
widestring = "0.4.3"

[dev-dependencies]
env_logger = "^0.11"
Expand Down
19 changes: 15 additions & 4 deletions remotefs-fuse/src/driver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#[cfg(unix)]
#[cfg_attr(docsrs, doc(cfg(unix)))]
mod unix;
#[cfg(windows)]
#[cfg_attr(docsrs, doc(cfg(windows)))]
mod windows;

use std::sync::{Arc, Mutex};

use remotefs::RemoteFs;

Expand All @@ -12,7 +17,7 @@ use crate::MountOption;
///
/// The driver will use the [`fuser`](https://crates.io/crates/fuser) crate to mount the filesystem, on Unix systems, while
/// it will use [dokan](https://crates.io/crates/dokan) on Windows.
pub struct Driver {
pub struct Driver<T: RemoteFs> {
/// Inode database
#[cfg(unix)]
database: unix::InodeDb,
Expand All @@ -22,10 +27,13 @@ pub struct Driver {
/// Mount options
pub(crate) options: Vec<MountOption>,
/// [`RemoteFs`] instance
remote: Box<dyn RemoteFs>,
remote: T,
}

impl Driver {
impl<T> Driver<T>
where
T: RemoteFs,
{
/// Create a new instance of the [`Driver`] providing a instance which implements the [`RemoteFs`] trait.
///
/// The [`RemoteFs`] instance must be boxed.
Expand All @@ -34,7 +42,7 @@ impl Driver {
///
/// * `remote` - The instance which implements the [`RemoteFs`] trait.
/// * `options` - The mount options.
pub fn new(remote: Box<dyn RemoteFs>, options: Vec<MountOption>) -> Self {
pub fn new(remote: T, options: Vec<MountOption>) -> Self {
Self {
#[cfg(unix)]
database: unix::InodeDb::load(),
Expand All @@ -46,6 +54,7 @@ impl Driver {
}

/// Get the specified uid from the mount options.
#[cfg(unix)]
fn uid(&self) -> Option<u32> {
self.options.iter().find_map(|opt| match opt {
MountOption::Uid(uid) => Some(*uid),
Expand All @@ -54,6 +63,7 @@ impl Driver {
}

/// Get the specified gid from the mount options.
#[cfg(unix)]
fn gid(&self) -> Option<u32> {
self.options.iter().find_map(|opt| match opt {
MountOption::Gid(gid) => Some(*gid),
Expand All @@ -63,6 +73,7 @@ impl Driver {

/// Get the specified default mode from the mount options.
/// If not set, the default is 0755.
#[cfg(unix)]
fn default_mode(&self) -> u32 {
self.options
.iter()
Expand Down
15 changes: 15 additions & 0 deletions remotefs-fuse/src/driver/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#[cfg(test)]
mod test;

use super::Driver;

use dokan::FileSystemHandler;
use remotefs::{File, RemoteFs};

// For reference <https://github.com/dokan-dev/dokan-rust/blob/master/dokan/examples/memfs/main.rs>
impl<'c, 'h: 'c, T> FileSystemHandler<'c, 'h> for Driver<T>
where
T: RemoteFs + Sync + 'h,
{
type Context = File;
}
1 change: 1 addition & 0 deletions remotefs-fuse/src/driver/windows/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use super::Driver;
Loading

0 comments on commit 8024879

Please sign in to comment.