1use crate::bytes::{le_u16, le_u32, le_u64, read_guid, utf16le_string};
9use crate::guid::{format_guid, VSS_IDENTIFIER};
10
11pub const STORE_BLOCK_HEADER_LEN: usize = 128;
13
14pub const STORE_HEADER_RECORD_TYPE: u32 = 0x0004;
16
17pub const MAX_STORE_INFO_LEN: usize = 1 << 20;
19
20#[derive(Debug, Clone)]
22pub struct StoreBlockHeader {
23 pub has_vss_identifier: bool,
25 pub version: u32,
27 pub record_type: u32,
30 pub relative_offset: u64,
32 pub current_offset: u64,
34 pub next_offset: u64,
36 pub store_information_size: u64,
38}
39
40impl StoreBlockHeader {
41 #[must_use]
43 pub fn parse(buf: &[u8]) -> Self {
44 StoreBlockHeader {
45 has_vss_identifier: read_guid(buf, 0) == VSS_IDENTIFIER,
46 version: le_u32(buf, 16),
47 record_type: le_u32(buf, 20),
48 relative_offset: le_u64(buf, 24),
49 current_offset: le_u64(buf, 32),
50 next_offset: le_u64(buf, 40),
51 store_information_size: le_u64(buf, 48),
52 }
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct AttributeFlags(pub u32);
59
60impl AttributeFlags {
61 pub const PERSISTENT: u32 = 0x0000_0001;
63 pub const NO_AUTO_RECOVERY: u32 = 0x0000_0002;
65 pub const CLIENT_ACCESSIBLE: u32 = 0x0000_0004;
67 pub const NO_AUTO_RELEASE: u32 = 0x0000_0008;
69 pub const NO_WRITERS: u32 = 0x0000_0010;
71 pub const TRANSPORTABLE: u32 = 0x0000_0020;
73 pub const NOT_SURFACED: u32 = 0x0000_0040;
75 pub const NOT_TRANSACTED: u32 = 0x0000_0080;
77 pub const DIFFERENTIAL: u32 = 0x0002_0000;
79 pub const PLEX: u32 = 0x0004_0000;
81
82 #[must_use]
84 pub fn bits(self) -> u32 {
85 self.0
86 }
87
88 #[must_use]
90 pub fn contains(self, flag: u32) -> bool {
91 self.0 & flag != 0
92 }
93
94 #[must_use]
96 pub fn is_persistent(self) -> bool {
97 self.contains(Self::PERSISTENT)
98 }
99
100 #[must_use]
102 pub fn is_client_accessible(self) -> bool {
103 self.contains(Self::CLIENT_ACCESSIBLE)
104 }
105
106 #[must_use]
108 pub fn is_differential(self) -> bool {
109 self.contains(Self::DIFFERENTIAL)
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct StoreInfo {
116 pub shadow_copy_id: [u8; 16],
118 pub shadow_copy_set_id: [u8; 16],
120 pub snapshot_context: u32,
122 pub attributes: AttributeFlags,
124 pub operating_machine: String,
126 pub service_machine: String,
128}
129
130impl StoreInfo {
131 #[must_use]
133 pub fn shadow_copy_id_string(&self) -> String {
134 format_guid(&self.shadow_copy_id)
135 }
136
137 #[must_use]
139 pub fn shadow_copy_set_id_string(&self) -> String {
140 format_guid(&self.shadow_copy_set_id)
141 }
142
143 #[must_use]
150 pub fn parse(buf: &[u8]) -> Self {
151 let op_size = le_u16(buf, 64) as usize;
152 let operating_machine = read_string(buf, 66, op_size);
153 let svc_size_off = 66 + op_size;
154 let svc_size = le_u16(buf, svc_size_off) as usize;
155 let service_machine = read_string(buf, svc_size_off + 2, svc_size);
156 StoreInfo {
157 shadow_copy_id: read_guid(buf, 16),
158 shadow_copy_set_id: read_guid(buf, 32),
159 snapshot_context: le_u32(buf, 48),
160 attributes: AttributeFlags(le_u32(buf, 56)),
161 operating_machine,
162 service_machine,
163 }
164 }
165}
166
167fn read_string(buf: &[u8], off: usize, len: usize) -> String {
170 buf.get(off..off + len)
171 .map(utf16le_string)
172 .unwrap_or_default()
173}