use crate::bytes::{le_u16, le_u32, le_u64, read_guid, utf16le_string};
use crate::guid::{format_guid, VSS_IDENTIFIER};
pub const STORE_BLOCK_HEADER_LEN: usize = 128;
pub const STORE_HEADER_RECORD_TYPE: u32 = 0x0004;
pub const MAX_STORE_INFO_LEN: usize = 1 << 20;
#[derive(Debug, Clone)]
pub struct StoreBlockHeader {
pub has_vss_identifier: bool,
pub version: u32,
pub record_type: u32,
pub relative_offset: u64,
pub current_offset: u64,
pub next_offset: u64,
pub store_information_size: u64,
}
impl StoreBlockHeader {
#[must_use]
pub fn parse(buf: &[u8]) -> Self {
StoreBlockHeader {
has_vss_identifier: read_guid(buf, 0) == VSS_IDENTIFIER,
version: le_u32(buf, 16),
record_type: le_u32(buf, 20),
relative_offset: le_u64(buf, 24),
current_offset: le_u64(buf, 32),
next_offset: le_u64(buf, 40),
store_information_size: le_u64(buf, 48),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AttributeFlags(pub u32);
impl AttributeFlags {
pub const PERSISTENT: u32 = 0x0000_0001;
pub const NO_AUTO_RECOVERY: u32 = 0x0000_0002;
pub const CLIENT_ACCESSIBLE: u32 = 0x0000_0004;
pub const NO_AUTO_RELEASE: u32 = 0x0000_0008;
pub const NO_WRITERS: u32 = 0x0000_0010;
pub const TRANSPORTABLE: u32 = 0x0000_0020;
pub const NOT_SURFACED: u32 = 0x0000_0040;
pub const NOT_TRANSACTED: u32 = 0x0000_0080;
pub const DIFFERENTIAL: u32 = 0x0002_0000;
pub const PLEX: u32 = 0x0004_0000;
#[must_use]
pub fn bits(self) -> u32 {
self.0
}
#[must_use]
pub fn contains(self, flag: u32) -> bool {
self.0 & flag != 0
}
#[must_use]
pub fn is_persistent(self) -> bool {
self.contains(Self::PERSISTENT)
}
#[must_use]
pub fn is_client_accessible(self) -> bool {
self.contains(Self::CLIENT_ACCESSIBLE)
}
#[must_use]
pub fn is_differential(self) -> bool {
self.contains(Self::DIFFERENTIAL)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StoreInfo {
pub shadow_copy_id: [u8; 16],
pub shadow_copy_set_id: [u8; 16],
pub snapshot_context: u32,
pub attributes: AttributeFlags,
pub operating_machine: String,
pub service_machine: String,
}
impl StoreInfo {
#[must_use]
pub fn shadow_copy_id_string(&self) -> String {
format_guid(&self.shadow_copy_id)
}
#[must_use]
pub fn shadow_copy_set_id_string(&self) -> String {
format_guid(&self.shadow_copy_set_id)
}
#[must_use]
pub fn parse(buf: &[u8]) -> Self {
let op_size = le_u16(buf, 64) as usize;
let operating_machine = read_string(buf, 66, op_size);
let svc_size_off = 66 + op_size;
let svc_size = le_u16(buf, svc_size_off) as usize;
let service_machine = read_string(buf, svc_size_off + 2, svc_size);
StoreInfo {
shadow_copy_id: read_guid(buf, 16),
shadow_copy_set_id: read_guid(buf, 32),
snapshot_context: le_u32(buf, 48),
attributes: AttributeFlags(le_u32(buf, 56)),
operating_machine,
service_machine,
}
}
}
fn read_string(buf: &[u8], off: usize, len: usize) -> String {
buf.get(off..off + len)
.map(utf16le_string)
.unwrap_or_default()
}