dua/
inodefilter.rs

1use std::collections::HashMap;
2
3#[derive(Debug, Default, Clone)]
4pub struct InodeFilter {
5    inner: HashMap<(u64, u64), u64>,
6}
7
8impl InodeFilter {
9    #[cfg(unix)]
10    pub fn add(&mut self, metadata: &std::fs::Metadata) -> bool {
11        use std::os::unix::fs::MetadataExt;
12
13        self.add_dev_inode((metadata.dev(), metadata.ino()), metadata.nlink())
14    }
15
16    #[cfg(windows)]
17    pub fn add(&mut self, metadata: &std::fs::Metadata) -> bool {
18        use std::os::windows::fs::MetadataExt;
19
20        if let (Some(dev), Some(inode), Some(nlinks)) = (
21            metadata.volume_serial_number(),
22            metadata.file_index(),
23            metadata.number_of_links(),
24        ) {
25            self.add_dev_inode((dev as u64, inode), nlinks as u64)
26        } else {
27            true
28        }
29    }
30
31    #[cfg(not(any(unix, windows)))]
32    pub fn add(&mut self, metadata: &std::fs::Metadata) -> bool {
33        true
34    }
35
36    pub fn add_dev_inode(&mut self, dev_inode: (u64, u64), nlinks: u64) -> bool {
37        if nlinks <= 1 {
38            return true;
39        }
40
41        match self.inner.get_mut(&dev_inode) {
42            Some(1) => {
43                self.inner.remove(&dev_inode);
44                false
45            }
46            Some(count) => {
47                *count -= 1;
48                false
49            }
50            None => {
51                self.inner.insert(dev_inode, nlinks - 1);
52                true
53            }
54        }
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn it_filters_inodes() {
64        let mut inodes = InodeFilter::default();
65
66        assert!(inodes.add_dev_inode((1, 1), 2));
67        assert!(inodes.add_dev_inode((2, 1), 2));
68        assert!(!inodes.add_dev_inode((1, 1), 2));
69        assert!(!inodes.add_dev_inode((2, 1), 2));
70
71        assert!(inodes.add_dev_inode((1, 1), 3));
72        assert!(!inodes.add_dev_inode((1, 1), 3));
73        assert!(!inodes.add_dev_inode((1, 1), 3));
74
75        assert!(inodes.add_dev_inode((1, 1), 1));
76        assert!(inodes.add_dev_inode((1, 1), 1));
77    }
78}