|
| 1 | +use std::{fs::Metadata, path::Path}; |
| 2 | + |
| 3 | +#[cfg(unix)] |
| 4 | +use dashmap::DashMap; |
| 5 | +#[cfg(unix)] |
| 6 | +use std::{os::unix::fs::MetadataExt, path::PathBuf}; |
| 7 | + |
| 8 | +/// Hook to run with a [`Path`] and its corresponding [`Metadata`]. |
| 9 | +pub trait Hook { |
| 10 | + fn run_hook(&self, path: &Path, metadata: &Metadata); |
| 11 | +} |
| 12 | + |
| 13 | +/// A [hook](Hook) that does nothing. |
| 14 | +#[derive(Debug, Clone, Copy)] |
| 15 | +pub struct DoNothing; |
| 16 | +impl Hook for DoNothing { |
| 17 | + fn run_hook(&self, _: &Path, _: &Metadata) {} |
| 18 | +} |
| 19 | + |
| 20 | +/// A [hook](Hook) that record files with more than 1 links. |
| 21 | +#[cfg(unix)] // Windows does have `MetadataExt::number_of_links` but it requires Nightly |
| 22 | +#[derive(Debug, Clone, Copy)] |
| 23 | +pub struct RecordHardLink<'a> { |
| 24 | + /// Map an inode number to its detected paths. |
| 25 | + storage: &'a DashMap<u64, Vec<PathBuf>>, // TODO: benchmark against Mutex<HashMap<u64, Vec<PathBuf>>> |
| 26 | +} |
| 27 | + |
| 28 | +#[cfg(unix)] |
| 29 | +impl<'a> RecordHardLink<'a> { |
| 30 | + /// Create a [hook](Hook) to record files with more than 1 links. |
| 31 | + pub fn new(storage: &'a DashMap<u64, Vec<PathBuf>>) -> Self { |
| 32 | + RecordHardLink { storage } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +#[cfg(unix)] |
| 37 | +impl<'a> Hook for RecordHardLink<'a> { |
| 38 | + fn run_hook(&self, path: &Path, metadata: &Metadata) { |
| 39 | + if metadata.is_dir() || metadata.nlink() <= 1 { |
| 40 | + return; |
| 41 | + } |
| 42 | + |
| 43 | + self.storage |
| 44 | + .entry(metadata.ino()) |
| 45 | + .or_default() |
| 46 | + .push(path.to_path_buf()); |
| 47 | + } |
| 48 | +} |
0 commit comments