mod error;
mod header;
mod catalog;
mod store;
mod reader;
pub use error::VssError;
pub use header::VssVolumeHeader;
pub use catalog::{CatalogEntry, StoreMeta, StoreLocation};
pub use store::StoreInfo;
pub use reader::VssStoreReader;
use std::io::{Read, Seek, SeekFrom};
use std::collections::HashMap;
const VSS_HEADER_OFFSET: u64 = 0x1E00;
const CATALOG_BLOCK_SIZE: usize = 0x4000; const BLOCK_SIZE: u64 = 0x4000;
pub struct VssVolume {
pub header: VssVolumeHeader,
pub stores: Vec<(StoreMeta, StoreLocation)>,
}
impl VssVolume {
pub fn new<R: Read + Seek>(reader: &mut R) -> Result<Self, VssError> {
reader.seek(SeekFrom::Start(VSS_HEADER_OFFSET))
.map_err(|e| VssError::Io(e))?;
let header = VssVolumeHeader::parse(reader)?;
if header.catalog_offset == 0 {
return Ok(Self {
header,
stores: Vec::new(),
});
}
let entries = catalog::parse_catalog(reader, header.catalog_offset)?;
let mut meta_map: HashMap<[u8; 16], StoreMeta> = HashMap::new();
let mut loc_map: HashMap<[u8; 16], StoreLocation> = HashMap::new();
for entry in entries {
match entry {
CatalogEntry::Meta(m) => { meta_map.insert(m.store_id, m); }
CatalogEntry::Location(l) => { loc_map.insert(l.store_id, l); }
CatalogEntry::Empty => {}
}
}
let mut stores: Vec<(StoreMeta, StoreLocation)> = Vec::new();
for (guid, meta) in &meta_map {
if let Some(loc) = loc_map.get(guid) {
stores.push((meta.clone(), loc.clone()));
}
}
stores.sort_by_key(|(m, _)| m.creation_time);
let mut hdr = header;
if let Some((meta, _)) = stores.first() {
if meta.volume_size > 0 {
hdr.volume_size = meta.volume_size;
}
}
Ok(Self { header: hdr, stores })
}
pub fn store_count(&self) -> usize {
self.stores.len()
}
pub fn store_info(&self, index: usize) -> Result<StoreInfo, VssError> {
let (meta, loc) = self.stores.get(index)
.ok_or(VssError::InvalidStoreIndex(index))?;
Ok(StoreInfo::from_meta_and_location(meta, loc))
}
pub fn store_delta_size<R: Read + Seek>(
&self,
reader: &mut R,
index: usize,
) -> Result<(usize, u64), VssError> {
let (_, loc) = self.stores.get(index)
.ok_or(VssError::InvalidStoreIndex(index))?;
let block_map = store::parse_block_descriptors(reader, loc.block_list_offset)?;
let count = block_map.len();
let size = count as u64 * BLOCK_SIZE;
Ok((count, size))
}
pub fn store_reader<'a, R: Read + Seek>(
&'a self,
reader: &'a mut R,
index: usize,
) -> Result<VssStoreReader<'a, R>, VssError> {
let (_, loc) = self.stores.get(index)
.ok_or(VssError::InvalidStoreIndex(index))?;
let block_map = store::parse_block_descriptors(reader, loc.block_list_offset)?;
Ok(VssStoreReader::new(reader, block_map, self.header.volume_size))
}
}