Skip to main content

ntfs_core/usn/
reason.rs

1use bitflags::bitflags;
2
3bitflags! {
4    /// USN Journal reason flags indicating what operation triggered the journal entry.
5    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6    pub struct UsnReason: u32 {
7        const DATA_OVERWRITE        = 0x0000_0001;
8        const DATA_EXTEND           = 0x0000_0002;
9        const DATA_TRUNCATION       = 0x0000_0004;
10        const NAMED_DATA_OVERWRITE  = 0x0000_0010;
11        const NAMED_DATA_EXTEND     = 0x0000_0020;
12        const NAMED_DATA_TRUNCATION = 0x0000_0040;
13        const FILE_CREATE           = 0x0000_0100;
14        const FILE_DELETE           = 0x0000_0200;
15        const EA_CHANGE             = 0x0000_0400;
16        const SECURITY_CHANGE       = 0x0000_0800;
17        const RENAME_OLD_NAME       = 0x0000_1000;
18        const RENAME_NEW_NAME       = 0x0000_2000;
19        const INDEXABLE_CHANGE      = 0x0000_4000;
20        const BASIC_INFO_CHANGE     = 0x0000_8000;
21        const HARD_LINK_CHANGE      = 0x0001_0000;
22        const COMPRESSION_CHANGE    = 0x0002_0000;
23        const ENCRYPTION_CHANGE     = 0x0004_0000;
24        const OBJECT_ID_CHANGE      = 0x0008_0000;
25        const REPARSE_POINT_CHANGE  = 0x0010_0000;
26        const STREAM_CHANGE         = 0x0020_0000;
27        const TRANSACTED_CHANGE     = 0x0040_0000;
28        const INTEGRITY_CHANGE      = 0x0080_0000;
29        const CLOSE                 = 0x8000_0000;
30    }
31}
32
33impl std::fmt::Display for UsnReason {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        let names: Vec<&str> = self.iter_names().map(|(name, _)| name).collect();
36        if names.is_empty() {
37            write!(f, "0x{:x}", self.bits())
38        } else {
39            write!(f, "{}", names.join("|"))
40        }
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn test_single_reason_display() {
50        assert_eq!(UsnReason::FILE_CREATE.to_string(), "FILE_CREATE");
51    }
52
53    #[test]
54    fn test_multiple_reasons_display() {
55        let r = UsnReason::FILE_CREATE | UsnReason::CLOSE;
56        let s = r.to_string();
57        assert!(s.contains("FILE_CREATE"));
58        assert!(s.contains("CLOSE"));
59    }
60
61    #[test]
62    fn test_unknown_bits_display() {
63        let r = UsnReason::from_bits_retain(0);
64        assert_eq!(r.to_string(), "0x0");
65    }
66
67    #[test]
68    fn test_rename_flags() {
69        let r = UsnReason::RENAME_OLD_NAME | UsnReason::RENAME_NEW_NAME;
70        let s = r.to_string();
71        assert!(s.contains("RENAME_OLD_NAME"));
72        assert!(s.contains("RENAME_NEW_NAME"));
73    }
74}