From b7c5119c2e1985e21a625c20710c318c8b1831f4 Mon Sep 17 00:00:00 2001 From: sigoden Date: Sun, 19 Feb 2023 22:03:59 +0800 Subject: [PATCH] feat: hiding only directories instead of files (#175) A `--hidden` pattern with `/` suffix means hiding only directories not files. A `--hidden` pattern without `/` will hide matching files and directories. --- src/server.rs | 48 ++++++++++++++++++++++++++++++++++++----------- tests/fixtures.rs | 1 + tests/hidden.rs | 15 +++++++++++++++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/server.rs b/src/server.rs index 7dae52c..5045d79 100644 --- a/src/server.rs +++ b/src/server.rs @@ -416,7 +416,18 @@ impl Server { let entry_path = entry.path(); let base_name = get_file_name(entry_path); let file_type = entry.file_type(); - if is_hidden(&hidden, base_name) { + let mut is_dir_type: bool = file_type.is_dir(); + if file_type.is_symlink() { + match std::fs::symlink_metadata(entry_path) { + Ok(meta) => { + is_dir_type = meta.is_dir(); + } + Err(_) => { + continue; + } + } + } + if is_hidden(&hidden, base_name, is_dir_type) { if file_type.is_dir() { it.skip_current_dir(); } @@ -425,9 +436,6 @@ impl Server { if !base_name.to_lowercase().contains(&search) { continue; } - if entry.path().symlink_metadata().is_err() { - continue; - } paths.push(entry_path.to_path_buf()); } paths @@ -939,10 +947,10 @@ impl Server { while let Ok(Some(entry)) = rd.next_entry().await { let entry_path = entry.path(); let base_name = get_file_name(&entry_path); - if is_hidden(&self.args.hidden, base_name) { - continue; - } if let Ok(Some(item)) = self.to_pathitem(entry_path.as_path(), base_path).await { + if is_hidden(&self.args.hidden, base_name, item.is_dir()) { + continue; + } paths.push(item); } } @@ -955,7 +963,6 @@ impl Server { base_path: P, ) -> BoxResult> { let path = path.as_ref(); - let rel_path = path.strip_prefix(base_path).unwrap(); let (meta, meta2) = tokio::join!(fs::metadata(&path), fs::symlink_metadata(&path)); let (meta, meta2) = (meta?, meta2?); let is_symlink = meta2.is_symlink(); @@ -974,6 +981,7 @@ impl Server { PathType::Dir | PathType::SymlinkDir => None, PathType::File | PathType::SymlinkFile => Some(meta.len()), }; + let rel_path = path.strip_prefix(base_path).unwrap(); let name = normalize_path(rel_path); Ok(Some(PathItem { path_type, @@ -1142,7 +1150,18 @@ async fn zip_dir( let entry_path = entry.path(); let base_name = get_file_name(entry_path); let file_type = entry.file_type(); - if is_hidden(&hidden, base_name) { + let mut is_dir_type: bool = file_type.is_dir(); + if file_type.is_symlink() { + match std::fs::symlink_metadata(entry_path) { + Ok(meta) => { + is_dir_type = meta.is_dir(); + } + Err(_) => { + continue; + } + } + } + if is_hidden(&hidden, base_name, is_dir_type) { if file_type.is_dir() { it.skip_current_dir(); } @@ -1228,8 +1247,15 @@ fn status_no_content(res: &mut Response) { *res.status_mut() = StatusCode::NO_CONTENT; } -fn is_hidden(hidden: &[String], file_name: &str) -> bool { - hidden.iter().any(|v| glob(v, file_name)) +fn is_hidden(hidden: &[String], file_name: &str, is_dir_type: bool) -> bool { + hidden.iter().any(|v| { + if is_dir_type { + if let Some(x) = v.strip_suffix('/') { + return glob(x, file_name); + } + } + glob(v, file_name) + }) } fn set_webdav_headers(res: &mut Response) { diff --git a/tests/fixtures.rs b/tests/fixtures.rs index 390ead9..02f2182 100644 --- a/tests/fixtures.rs +++ b/tests/fixtures.rs @@ -65,6 +65,7 @@ pub fn tmpdir() -> TempDir { } } } + tmpdir.child("dir4/hidden").touch().unwrap(); tmpdir } diff --git a/tests/hidden.rs b/tests/hidden.rs index 0dc6588..5156f51 100644 --- a/tests/hidden.rs +++ b/tests/hidden.rs @@ -55,3 +55,18 @@ fn hidden_search_dir(#[case] server: TestServer, #[case] exist: bool) -> Result< } Ok(()) } + +#[rstest] +#[case(server(&["--hidden", "hidden/"]), "dir4/", 1)] +#[case(server(&["--hidden", "hidden"]), "dir4/", 0)] +fn hidden_dir_noly( + #[case] server: TestServer, + #[case] dir: &str, + #[case] count: usize, +) -> Result<(), Error> { + let resp = reqwest::blocking::get(format!("{}{}", server.url(), dir))?; + assert_eq!(resp.status(), 200); + let paths = utils::retrieve_index_paths(&resp.text()?); + assert_eq!(paths.len(), count); + Ok(()) +}