From 86dc267a3953fd445030e61964558b17d94defe6 Mon Sep 17 00:00:00 2001 From: aawsome <37850842+aawsome@users.noreply.github.com> Date: Sun, 24 Nov 2024 09:49:54 +0100 Subject: [PATCH] refactor: remove webdav feature (#366) No longer needed as `WebDavFs` is implemented now directly in rustic. The implementation anyhow is not correct as blocking methods are called directly in async context. --- Cargo.lock | 98 --------- crates/core/Cargo.toml | 3 - crates/core/src/vfs.rs | 25 --- crates/core/src/vfs/webdavfs.rs | 354 -------------------------------- 4 files changed, 480 deletions(-) delete mode 100644 crates/core/src/vfs/webdavfs.rs diff --git a/Cargo.lock b/Cargo.lock index 50abfeb77..afa6bfef5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1046,35 +1046,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "dav-server" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a9e373ca09a43ad20c0b7805fcb4b489713f049a3ee2750ed61efa72f9cde9" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "htmlescape", - "http", - "http-body", - "http-body-util", - "lazy_static", - "log", - "mime_guess", - "percent-encoding", - "pin-project", - "pin-utils", - "regex", - "time", - "tokio", - "url", - "uuid", - "xml-rs", - "xmltree", -] - [[package]] name = "der" version = "0.7.9" @@ -1636,30 +1607,6 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" -[[package]] -name = "headers" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" -dependencies = [ - "base64 0.21.7", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" -dependencies = [ - "http", -] - [[package]] name = "heck" version = "0.5.0" @@ -1705,12 +1652,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "htmlescape" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" - [[package]] name = "http" version = "1.1.0" @@ -1751,12 +1692,6 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "humantime" version = "2.1.0" @@ -2305,16 +2240,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3608,7 +3533,6 @@ dependencies = [ "clap", "conflate", "crossbeam-channel", - "dav-server", "derive_more", "derive_setters", "dirs", @@ -3621,7 +3545,6 @@ dependencies = [ "expect-test", "filetime", "flate2", - "futures", "gethostname", "globset", "hex", @@ -4605,12 +4528,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "unicase" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" - [[package]] name = "unicode-ident" version = "1.0.13" @@ -5115,21 +5032,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "xml-rs" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" - -[[package]] -name = "xmltree" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" -dependencies = [ - "xml-rs", -] - [[package]] name = "yansi" version = "1.0.1" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 645770ae6..2b2361090 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -33,7 +33,6 @@ default = [] cli = ["merge", "clap"] merge = ["dep:conflate"] clap = ["dep:clap"] -webdav = ["dep:dav-server", "dep:futures"] [package.metadata.docs.rs] all-features = true @@ -90,8 +89,6 @@ clap = { version = "4.5.19", optional = true, features = ["derive", "env", "wrap conflate = { version = "0.3.1", optional = true } # vfs support -dav-server = { version = "0.7.0", default-features = false, optional = true } -futures = { version = "0.3.30", optional = true } runtime-format = "0.1.3" # other dependencies diff --git a/crates/core/src/vfs.rs b/crates/core/src/vfs.rs index 00d35672a..c6a618ab6 100644 --- a/crates/core/src/vfs.rs +++ b/crates/core/src/vfs.rs @@ -1,6 +1,4 @@ mod format; -#[cfg(feature = "webdav")] -mod webdavfs; use std::{ collections::BTreeMap, @@ -12,10 +10,6 @@ use bytes::{Bytes, BytesMut}; use runtime_format::FormatArgs; use strum::EnumString; -#[cfg(feature = "webdav")] -/// A struct which enables `WebDAV` access to a [`Vfs`] using [`dav-server`] -pub use crate::vfs::webdavfs::WebDavFS; - use crate::{ blob::{tree::TreeId, BlobId, DataId}, error::{ErrorKind, RusticError, RusticResult}, @@ -455,25 +449,6 @@ impl Vfs { }; Ok(result) } - - #[cfg(feature = "webdav")] - /// Turn the [`Vfs`] into a [`WebDavFS`] - /// - /// # Arguments - /// - /// * `repo` - The repository to use - /// * `file_policy` - The policy to use for files - /// - /// # Returns - /// - /// The boxed [`WebDavFS`] for the [`Vfs`] - pub fn into_webdav_fs( - self, - repo: Repository, - file_policy: FilePolicy, - ) -> Box> { - Box::new(WebDavFS::new(repo, self, file_policy)) - } } /// `OpenFile` stores all information needed to access the contents of a file node diff --git a/crates/core/src/vfs/webdavfs.rs b/crates/core/src/vfs/webdavfs.rs deleted file mode 100644 index c24011368..000000000 --- a/crates/core/src/vfs/webdavfs.rs +++ /dev/null @@ -1,354 +0,0 @@ -use std::fmt::{Debug, Formatter}; -use std::io::SeekFrom; -#[cfg(not(windows))] -use std::os::unix::ffi::OsStrExt; -use std::sync::{Arc, OnceLock}; -use std::time::SystemTime; - -use crate::repofile::Node; -use crate::repository::{IndexedFull, Repository}; -use bytes::{Buf, Bytes}; -use futures::FutureExt; - -use dav_server::{ - davpath::DavPath, - fs::{ - DavDirEntry, DavFile, DavFileSystem, DavMetaData, FsError, FsFuture, FsResult, FsStream, - OpenOptions, ReadDirMeta, - }, -}; - -use super::{FilePolicy, OpenFile, Vfs}; - -fn now() -> SystemTime { - static NOW: OnceLock = OnceLock::new(); - *NOW.get_or_init(SystemTime::now) -} - -/// The inner state of a [`WebDavFS`] instance. -struct DavFsInner { - /// The [`Repository`] to use - repo: Repository, - - /// The [`Vfs`] to use - vfs: Vfs, - - /// The [`FilePolicy`] to use - file_policy: FilePolicy, -} - -impl Debug for DavFsInner { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "DavFS") - } -} - -/// DAV Filesystem implementation. -/// -/// This is the main entry point for the DAV filesystem. -/// It implements [`DavFileSystem`] and can be used to serve a [`Repository`] via DAV. -#[derive(Debug)] -pub struct WebDavFS { - inner: Arc>, -} - -impl WebDavFS { - /// Create a new [`WebDavFS`] instance. - /// - /// # Arguments - /// - /// * `repo` - The [`Repository`] to use - /// * `vfs` - The [`Vfs`] to use - /// * `file_policy` - The [`FilePolicy`] to use - /// - /// # Returns - /// - /// A new [`WebDavFS`] instance - pub(crate) fn new(repo: Repository, vfs: Vfs, file_policy: FilePolicy) -> Self { - let inner = DavFsInner { - repo, - vfs, - file_policy, - }; - - Self { - inner: Arc::new(inner), - } - } - - /// Get a [`Node`] from the specified [`DavPath`]. - /// - /// # Arguments - /// - /// * `path` - The path to get the [`Tree`] at - /// - /// # Errors - /// - /// * If the [`Tree`] could not be found - /// - /// # Returns - /// - /// The [`Node`] at the specified path - /// - /// [`Tree`]: crate::repofile::Tree - fn node_from_path(&self, path: &DavPath) -> Result { - self.inner - .vfs - .node_from_path(&self.inner.repo, &path.as_pathbuf()) - .map_err(|_| FsError::GeneralFailure) - } - - /// Get a list of [`Node`]s from the specified directory path. - /// - /// # Arguments - /// - /// * `path` - The path to get the [`Tree`] at - /// - /// # Errors - /// - /// * If the [`Tree`] could not be found - /// - /// # Returns - /// - /// The list of [`Node`]s at the specified path - /// - /// [`Tree`]: crate::repofile::Tree - fn dir_entries_from_path(&self, path: &DavPath) -> Result, FsError> { - self.inner - .vfs - .dir_entries_from_path(&self.inner.repo, &path.as_pathbuf()) - .map_err(|_| FsError::GeneralFailure) - } -} - -impl Clone for WebDavFS { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - } - } -} - -impl DavFileSystem - for WebDavFS -{ - fn metadata<'a>(&'a self, davpath: &'a DavPath) -> FsFuture<'_, Box> { - self.symlink_metadata(davpath) - } - - fn symlink_metadata<'a>(&'a self, davpath: &'a DavPath) -> FsFuture<'_, Box> { - async move { - let node = self.node_from_path(davpath)?; - let meta: Box = Box::new(DavFsMetaData(node)); - Ok(meta) - } - .boxed() - } - - fn read_dir<'a>( - &'a self, - davpath: &'a DavPath, - _meta: ReadDirMeta, - ) -> FsFuture<'_, FsStream>> { - async move { - let entries = self.dir_entries_from_path(davpath)?; - let entry_iter = entries.into_iter().map(|e| { - let entry: Box = Box::new(DavFsDirEntry(e)); - Ok(entry) - }); - let strm: FsStream> = Box::pin(futures::stream::iter(entry_iter)); - Ok(strm) - } - .boxed() - } - - fn open<'a>( - &'a self, - path: &'a DavPath, - options: OpenOptions, - ) -> FsFuture<'_, Box> { - async move { - if options.write - || options.append - || options.truncate - || options.create - || options.create_new - { - return Err(FsError::Forbidden); - } - - let node = self.node_from_path(path)?; - if matches!(self.inner.file_policy, FilePolicy::Forbidden) { - return Err(FsError::Forbidden); - } - - let open = self - .inner - .repo - .open_file(&node) - .map_err(|_err| FsError::GeneralFailure)?; - let file: Box = Box::new(DavFsFile { - node, - open, - fs: self.inner.clone(), - seek: 0, - }); - Ok(file) - } - .boxed() - } -} - -/// A [`DavDirEntry`] implementation for [`Node`]s. -#[derive(Clone, Debug)] -struct DavFsDirEntry(Node); - -impl DavDirEntry for DavFsDirEntry { - fn metadata(&self) -> FsFuture<'_, Box> { - async move { - let meta: Box = Box::new(DavFsMetaData(self.0.clone())); - Ok(meta) - } - .boxed() - } - - #[cfg(not(windows))] - fn name(&self) -> Vec { - self.0.name().as_bytes().to_vec() - } - - #[cfg(windows)] - fn name(&self) -> Vec { - self.0 - .name() - .as_os_str() - .to_string_lossy() - .to_string() - .into_bytes() - } -} - -/// A [`DavFile`] implementation for [`Node`]s. -/// -/// This is a read-only file. -struct DavFsFile { - /// The [`Node`] this file is for - node: Node, - - /// The [`OpenFile`] for this file - open: OpenFile, - - /// The [`DavFsInner`] this file belongs to - fs: Arc>, - - /// The current seek position - seek: usize, -} - -impl Debug for DavFsFile { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "DavFile") - } -} - -impl DavFile for DavFsFile { - fn metadata(&mut self) -> FsFuture<'_, Box> { - async move { - let meta: Box = Box::new(DavFsMetaData(self.node.clone())); - Ok(meta) - } - .boxed() - } - - fn write_bytes(&mut self, _buf: Bytes) -> FsFuture<'_, ()> { - async move { Err(FsError::Forbidden) }.boxed() - } - - fn write_buf(&mut self, _buf: Box) -> FsFuture<'_, ()> { - async move { Err(FsError::Forbidden) }.boxed() - } - - fn read_bytes(&mut self, count: usize) -> FsFuture<'_, Bytes> { - async move { - let data = self - .fs - .repo - .read_file_at(&self.open, self.seek, count) - .map_err(|_err| FsError::GeneralFailure)?; - self.seek += data.len(); - Ok(data) - } - .boxed() - } - - fn seek(&mut self, pos: SeekFrom) -> FsFuture<'_, u64> { - async move { - match pos { - SeekFrom::Start(start) => { - self.seek = usize::try_from(start).expect("usize overflow should not happen"); - } - SeekFrom::Current(delta) => { - self.seek = usize::try_from( - i64::try_from(self.seek).expect("i64 wrapped around") + delta, - ) - .expect("usize overflow should not happen"); - } - SeekFrom::End(end) => { - self.seek = usize::try_from( - i64::try_from(self.node.meta.size).expect("i64 wrapped around") + end, - ) - .expect("usize overflow should not happen"); - } - } - - Ok(self.seek as u64) - } - .boxed() - } - - fn flush(&mut self) -> FsFuture<'_, ()> { - async move { Ok(()) }.boxed() - } -} - -/// A [`DavMetaData`] implementation for [`Node`]s. -#[derive(Clone, Debug)] -struct DavFsMetaData(Node); - -impl DavMetaData for DavFsMetaData { - fn len(&self) -> u64 { - self.0.meta.size - } - fn created(&self) -> FsResult { - Ok(now()) - } - fn modified(&self) -> FsResult { - Ok(self.0.meta.mtime.map_or_else(now, SystemTime::from)) - } - fn accessed(&self) -> FsResult { - Ok(self.0.meta.atime.map_or_else(now, SystemTime::from)) - } - - fn status_changed(&self) -> FsResult { - Ok(self.0.meta.ctime.map_or_else(now, SystemTime::from)) - } - - fn is_dir(&self) -> bool { - self.0.is_dir() - } - fn is_file(&self) -> bool { - self.0.is_file() - } - fn is_symlink(&self) -> bool { - self.0.is_symlink() - } - fn executable(&self) -> FsResult { - if self.0.is_file() { - let Some(mode) = self.0.meta.mode else { - return Ok(false); - }; - return Ok((mode & 0o100) > 0); - } - Err(FsError::NotImplemented) - } -}