gravityfile_scan/
inode.rs1use gravityfile_core::InodeInfo;
4use std::collections::HashSet;
5
6#[derive(Debug, Default)]
11pub struct InodeTracker {
12 seen: HashSet<InodeInfo>,
13 track_single_links: bool,
14}
15
16impl InodeTracker {
17 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub(crate) fn with_alias_tracking() -> Self {
24 Self {
25 track_single_links: true,
26 ..Self::default()
27 }
28 }
29
30 pub fn track(&mut self, info: InodeInfo, nlink: u64) -> bool {
35 if self.track_single_links || nlink > 1 {
36 self.seen.insert(info)
37 } else {
38 !self.seen.contains(&info)
39 }
40 }
41
42 #[doc(hidden)]
44 pub fn pending_count(&self) -> usize {
45 self.seen.len()
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn changing_link_counts_and_extra_aliases_do_not_recount_seen_identity() {
55 let mut tracker = InodeTracker::new();
56 let info = InodeInfo::new(42, 1);
57 assert!(tracker.track(info, 2));
58 for count in [2, 1, 0, 3, 2] {
59 assert!(!tracker.track(info, count));
60 }
61 let mut aliases = InodeTracker::with_alias_tracking();
62 assert!(aliases.track(info, 1));
63 assert!(!aliases.track(info, 1));
64 }
65
66 #[test]
67 fn test_track_new_inode_nlink_1() {
68 let mut tracker = InodeTracker::new();
69 let info = InodeInfo::new(12345, 1);
70 assert!(tracker.track(info, 1));
72 assert!(tracker.track(info, 1));
73 }
74
75 #[test]
76 fn test_track_hardlink_nlink_2() {
77 let mut tracker = InodeTracker::new();
78 let info = InodeInfo::new(12345, 1);
79 assert!(tracker.track(info, 2));
81 assert!(!tracker.track(info, 2));
82 assert_eq!(tracker.pending_count(), 1);
84 }
85
86 #[test]
87 fn test_track_hardlink_nlink_3() {
88 let mut tracker = InodeTracker::new();
89 let info = InodeInfo::new(99, 2);
90 assert!(tracker.track(info, 3));
92 assert!(!tracker.track(info, 3));
93 assert!(!tracker.track(info, 3));
94 assert_eq!(tracker.pending_count(), 1);
95 }
96
97 #[test]
98 fn test_different_devices() {
99 let mut tracker = InodeTracker::new();
100 let info1 = InodeInfo::new(12345, 1);
101 let info2 = InodeInfo::new(12345, 2); assert!(tracker.track(info1, 2));
104 assert!(tracker.track(info2, 2)); }
106}