use crate::types::object::{ObjectHeader, ObjectType};
use crate::types::{le_u32, le_u64};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObjectMapBlock {
pub object: ObjectHeader,
pub flags: u32,
pub snapshot_count: u32,
pub tree_type: u32,
pub snapshot_tree_type: u32,
pub tree_oid: u64,
pub snapshot_tree_oid: u64,
pub most_recent_snapshot_identifier: u64,
pub pending_revert_minimum_identifier: u64,
pub pending_revert_maximum_identifier: u64,
}
impl ObjectMapBlock {
pub fn parse(data: &[u8]) -> crate::Result<Self> {
let object = ObjectHeader::parse(data)?;
if object.kind() != ObjectType::ObjectMap as u16 {
return Err(crate::ApfsError::InvalidValue("object map object type"));
}
Ok(Self {
object,
flags: le_u32(data, 32)?,
snapshot_count: le_u32(data, 36)?,
tree_type: le_u32(data, 40)?,
snapshot_tree_type: le_u32(data, 44)?,
tree_oid: le_u64(data, 48)?,
snapshot_tree_oid: le_u64(data, 56)?,
most_recent_snapshot_identifier: le_u64(data, 64)?,
pending_revert_minimum_identifier: le_u64(data, 72)?,
pending_revert_maximum_identifier: le_u64(data, 80)?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ObjectMapKey {
pub oid: u64,
pub xid: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObjectMapValue {
pub flags: u32,
pub size: u32,
pub address: u64,
}
impl ObjectMapValue {
pub fn parse(data: &[u8]) -> crate::Result<Self> {
Ok(Self {
flags: le_u32(data, 0)?,
size: le_u32(data, 4)?,
address: le_u64(data, 8)?,
})
}
}
pub const BTREE_PHYSICAL: u32 = 0x10;
pub const BTREE_HASHED: u32 = 0x80;
pub const OMAP_VAL_ENCRYPTED: u32 = 4;
pub const OMAP_VAL_NOHEADER: u32 = 8;
pub const OMAP_VAL_DELETED: u32 = 1;
#[cfg(any(feature = "alloc", feature = "std"))]
#[derive(Debug, Clone)]
pub struct VirtualObjectMap {
entries: alloc::collections::BTreeMap<u64, (u64, ObjectMapValue)>,
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl VirtualObjectMap {
pub fn new(values: &[(ObjectMapKey, ObjectMapValue)], max_xid: u64) -> Self {
let mut entries = alloc::collections::BTreeMap::new();
for (key, value) in values.iter().filter(|(key, _)| key.xid <= max_xid) {
let newer = entries
.get(&key.oid)
.is_none_or(|(xid, _): &(u64, ObjectMapValue)| key.xid >= *xid);
if newer {
entries.insert(key.oid, (key.xid, *value));
}
}
Self { entries }
}
pub fn resolve(&self, oid: u64) -> Option<ObjectMapValue> {
self.entries
.get(&oid)
.map(|(_, value)| *value)
.filter(|value| value.flags & OMAP_VAL_DELETED == 0)
}
}