From e60d52a13698479279c0d20fb9aaee8b37d55081 Mon Sep 17 00:00:00 2001 From: Falko Galperin Date: Fri, 4 Apr 2025 16:49:02 +0200 Subject: [PATCH] feat: add --follow-symlinks flag to follow links for search/archiving --- src/args.rs | 12 ++++++++++++ src/server.rs | 8 ++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/args.rs b/src/args.rs index 032d383..3cbdfcf 100644 --- a/src/args.rs +++ b/src/args.rs @@ -148,6 +148,14 @@ pub fn build_cli() -> Command { .action(ArgAction::SetTrue) .help("Allow download folders as archive file"), ) + .arg( + Arg::new("follow-symlinks") + .env("DUFS_FOLLOW_SYMLINKS") + .hide_env(true) + .long("follow-symlinks") + .action(ArgAction::SetTrue) + .help("When searching files/folders or when archiving folders, also search/archive symlinked targets"), + ) .arg( Arg::new("enable-cors") .env("DUFS_ENABLE_CORS") @@ -281,6 +289,7 @@ pub struct Args { pub allow_search: bool, pub allow_symlink: bool, pub allow_archive: bool, + pub follow_symlinks: bool, pub render_index: bool, pub render_spa: bool, pub render_try_index: bool, @@ -372,6 +381,9 @@ impl Args { if !args.allow_search { args.allow_search = allow_all || matches.get_flag("allow-search"); } + if !args.follow_symlinks { + args.follow_symlinks = matches.get_flag("follow-symlinks"); + } if !args.allow_symlink { args.allow_symlink = allow_all || matches.get_flag("allow-symlink"); } diff --git a/src/server.rs b/src/server.rs index 8e50bc3..0ab0b39 100644 --- a/src/server.rs +++ b/src/server.rs @@ -594,11 +594,12 @@ impl Server { let hidden = Arc::new(self.args.hidden.to_vec()); let hidden = hidden.clone(); let running = self.running.clone(); + let search_symlinks = self.args.follow_symlinks; let access_paths = access_paths.clone(); let search_paths = tokio::task::spawn_blocking(move || { let mut paths: Vec = vec![]; for dir in access_paths.entry_paths(&path_buf) { - let mut it = WalkDir::new(&dir).into_iter(); + let mut it = WalkDir::new(&dir).follow_links(search_symlinks).into_iter(); it.next(); while let Some(Ok(entry)) = it.next() { if !running.load(atomic::Ordering::SeqCst) { @@ -659,6 +660,7 @@ impl Server { let hidden = self.args.hidden.clone(); let running = self.running.clone(); let compression = self.args.compress.to_compression(); + let follow_symlinks = self.args.follow_symlinks; tokio::spawn(async move { if let Err(e) = zip_dir( &mut writer, @@ -666,6 +668,7 @@ impl Server { access_paths, &hidden, compression, + follow_symlinks, running, ) .await @@ -1639,6 +1642,7 @@ async fn zip_dir( access_paths: AccessPaths, hidden: &[String], compression: Compression, + follow_symlinks: bool, running: Arc, ) -> Result<()> { let mut writer = ZipFileWriter::with_tokio(writer); @@ -1647,7 +1651,7 @@ async fn zip_dir( let zip_paths = tokio::task::spawn_blocking(move || { let mut paths: Vec = vec![]; for dir in access_paths.entry_paths(&dir_clone) { - let mut it = WalkDir::new(&dir).into_iter(); + let mut it = WalkDir::new(&dir).follow_links(follow_symlinks).into_iter(); it.next(); while let Some(Ok(entry)) = it.next() { if !running.load(atomic::Ordering::SeqCst) {