Merge PR #1077
This commit is contained in:
commit
8a640dc70b
|
|
@ -57,6 +57,8 @@ pub fn files_in(root: &Path, skip: Option<&Path>, limits: Limits, mut keep: impl
|
|||
if let Ok(c) = std::fs::canonicalize(root) {
|
||||
linked.insert(c);
|
||||
}
|
||||
// Include aliases to the library in the exclusion, not just its lexical path.
|
||||
let skip_canonical = skip.and_then(|p| std::fs::canonicalize(p).ok());
|
||||
// (path, depth of the folder it is in, is a folder); popped in path order
|
||||
let mut stack: Vec<(PathBuf, usize, bool)> = vec![(root.to_path_buf(), 0, true)];
|
||||
while let Some((path, depth, is_dir)) = stack.pop() {
|
||||
|
|
@ -66,7 +68,9 @@ pub fn files_in(root: &Path, skip: Option<&Path>, limits: Limits, mut keep: impl
|
|||
}
|
||||
continue;
|
||||
}
|
||||
if skip.is_some_and(|s| path == s) {
|
||||
if skip.is_some_and(|s| path == s)
|
||||
|| skip_canonical.as_ref().is_some_and(|s| std::fs::canonicalize(&path).is_ok_and(|p| p.starts_with(s)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if depth >= limits.max_depth {
|
||||
|
|
@ -165,6 +169,31 @@ mod tests {
|
|||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
|
||||
/// Folder imports must not revisit the user's own library through symlinks
|
||||
/// or through an alias to the library's parent.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn skipped_library_stays_skipped_through_symlinks_and_ancestors() {
|
||||
let d = tmp("skip-alias");
|
||||
let root = d.join("incoming");
|
||||
let library = d.join("library");
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
std::fs::create_dir_all(library.join("Originals")).unwrap();
|
||||
std::fs::write(root.join("ordinary.jpg"), b"photo").unwrap();
|
||||
std::fs::write(library.join("Originals").join("library-only.jpg"), b"original").unwrap();
|
||||
std::os::unix::fs::symlink(&library, root.join("library-link")).unwrap();
|
||||
std::os::unix::fs::symlink(&d, root.join("parent-link")).unwrap();
|
||||
|
||||
let photos = files_in(&root, Some(&library), Limits::default(), |p| p.extension().is_some_and(|e| e == "jpg"));
|
||||
assert!(photos.files.contains(&root.join("ordinary.jpg")));
|
||||
assert!(!photos.files.iter().any(|p| p.ends_with("library-only.jpg")), "{photos:?}");
|
||||
|
||||
// Scanning a subfolder already inside the excluded library is also forbidden.
|
||||
let inside = files_in(&library.join("Originals"), Some(&library), Limits::default(), |_| true);
|
||||
assert!(inside.files.is_empty(), "{inside:?}");
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
|
||||
/// A link back up the tree (a loop) is followed at most once: the walk ends.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in New Issue