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.pull/176/head
parent
0000bd27f5
commit
b7c5119c2e
|
@ -416,7 +416,18 @@ impl Server {
|
||||||
let entry_path = entry.path();
|
let entry_path = entry.path();
|
||||||
let base_name = get_file_name(entry_path);
|
let base_name = get_file_name(entry_path);
|
||||||
let file_type = entry.file_type();
|
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() {
|
if file_type.is_dir() {
|
||||||
it.skip_current_dir();
|
it.skip_current_dir();
|
||||||
}
|
}
|
||||||
|
@ -425,9 +436,6 @@ impl Server {
|
||||||
if !base_name.to_lowercase().contains(&search) {
|
if !base_name.to_lowercase().contains(&search) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if entry.path().symlink_metadata().is_err() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
paths.push(entry_path.to_path_buf());
|
paths.push(entry_path.to_path_buf());
|
||||||
}
|
}
|
||||||
paths
|
paths
|
||||||
|
@ -939,10 +947,10 @@ impl Server {
|
||||||
while let Ok(Some(entry)) = rd.next_entry().await {
|
while let Ok(Some(entry)) = rd.next_entry().await {
|
||||||
let entry_path = entry.path();
|
let entry_path = entry.path();
|
||||||
let base_name = get_file_name(&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 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);
|
paths.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -955,7 +963,6 @@ impl Server {
|
||||||
base_path: P,
|
base_path: P,
|
||||||
) -> BoxResult<Option<PathItem>> {
|
) -> BoxResult<Option<PathItem>> {
|
||||||
let path = path.as_ref();
|
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) = tokio::join!(fs::metadata(&path), fs::symlink_metadata(&path));
|
||||||
let (meta, meta2) = (meta?, meta2?);
|
let (meta, meta2) = (meta?, meta2?);
|
||||||
let is_symlink = meta2.is_symlink();
|
let is_symlink = meta2.is_symlink();
|
||||||
|
@ -974,6 +981,7 @@ impl Server {
|
||||||
PathType::Dir | PathType::SymlinkDir => None,
|
PathType::Dir | PathType::SymlinkDir => None,
|
||||||
PathType::File | PathType::SymlinkFile => Some(meta.len()),
|
PathType::File | PathType::SymlinkFile => Some(meta.len()),
|
||||||
};
|
};
|
||||||
|
let rel_path = path.strip_prefix(base_path).unwrap();
|
||||||
let name = normalize_path(rel_path);
|
let name = normalize_path(rel_path);
|
||||||
Ok(Some(PathItem {
|
Ok(Some(PathItem {
|
||||||
path_type,
|
path_type,
|
||||||
|
@ -1142,7 +1150,18 @@ async fn zip_dir<W: AsyncWrite + Unpin>(
|
||||||
let entry_path = entry.path();
|
let entry_path = entry.path();
|
||||||
let base_name = get_file_name(entry_path);
|
let base_name = get_file_name(entry_path);
|
||||||
let file_type = entry.file_type();
|
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() {
|
if file_type.is_dir() {
|
||||||
it.skip_current_dir();
|
it.skip_current_dir();
|
||||||
}
|
}
|
||||||
|
@ -1228,8 +1247,15 @@ fn status_no_content(res: &mut Response) {
|
||||||
*res.status_mut() = StatusCode::NO_CONTENT;
|
*res.status_mut() = StatusCode::NO_CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_hidden(hidden: &[String], file_name: &str) -> bool {
|
fn is_hidden(hidden: &[String], file_name: &str, is_dir_type: bool) -> bool {
|
||||||
hidden.iter().any(|v| glob(v, file_name))
|
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) {
|
fn set_webdav_headers(res: &mut Response) {
|
||||||
|
|
|
@ -65,6 +65,7 @@ pub fn tmpdir() -> TempDir {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tmpdir.child("dir4/hidden").touch().unwrap();
|
||||||
|
|
||||||
tmpdir
|
tmpdir
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,3 +55,18 @@ fn hidden_search_dir(#[case] server: TestServer, #[case] exist: bool) -> Result<
|
||||||
}
|
}
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue