generalized item + name bytes pattern
This commit is contained in:
parent
33852e99b0
commit
fa66bf415e
|
@ -357,7 +357,7 @@ impl<R: VolumeIo> Btrfs<R> {
|
|||
.expect("dir item")
|
||||
.first()
|
||||
.expect("dir item entry")
|
||||
.dir_item
|
||||
.item()
|
||||
.location
|
||||
.id();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![allow(dead_code)]
|
||||
use core::{mem::size_of, ops::Deref};
|
||||
use core::{fmt::Debug, mem::size_of, ops::Deref};
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use derivative::Derivative;
|
||||
|
@ -67,7 +67,7 @@ unsafe impl Zeroable for ObjectId {}
|
|||
//#[rustc_nonnull_optimization_guaranteed]
|
||||
pub enum ObjectType {
|
||||
INodeItem = 0x01,
|
||||
InodeRef = 0x0C,
|
||||
INodeRef = 0x0C,
|
||||
InodeExtref = 0x0D,
|
||||
XattrItem = 0x18,
|
||||
OrphanInode = 0x30,
|
||||
|
@ -215,18 +215,22 @@ macro_rules! impl_try_from_ctx {
|
|||
};
|
||||
}
|
||||
|
||||
pub trait Parseable: Sized {
|
||||
fn parse(bytes: &[u8]) -> Result<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_parse_try_from_ctx {
|
||||
($($ty:ty),*) => {
|
||||
$(impl $ty {
|
||||
pub fn parse(bytes: &[u8]) -> Result<Self> {
|
||||
$(impl Parseable for $ty {
|
||||
fn parse(bytes: &[u8]) -> Result<Self> {
|
||||
Ok(bytes.pread(0)?)
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
impl_parse_try_from_ctx!(Chunk, Header, Key, RootItem);
|
||||
impl_try_from_ctx!(Key, Chunk, Header, Superblock, RootItem);
|
||||
impl_parse_try_from_ctx!(Chunk, Header, Key, RootItem, INodeItem, INodeRef, DirItem);
|
||||
impl_try_from_ctx!(Key, Chunk, Header, Superblock, RootItem, INodeItem, INodeRef, DirItem);
|
||||
|
||||
const MAX_LABEL_SIZE: usize = 0x100;
|
||||
const SYS_CHUNK_ARRAY_SIZE: usize = 0x800;
|
||||
|
@ -312,13 +316,20 @@ pub struct ExtentData2 {
|
|||
}
|
||||
|
||||
#[repr(C, packed(1))]
|
||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||
#[derive(Debug, Clone, Copy, FromBytes, AsBytes)]
|
||||
pub struct INodeRef {
|
||||
index: u64,
|
||||
n: u16,
|
||||
name: [u8; 1],
|
||||
index: U64<LE>,
|
||||
name_len: U16<LE>,
|
||||
}
|
||||
|
||||
impl NameLength for INodeRef {
|
||||
fn name_length(&self) -> usize {
|
||||
self.name_len.get() as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub type INodeRefEntry = ItemWithName<INodeRef>;
|
||||
|
||||
#[repr(C, packed(1))]
|
||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||
pub struct INodeExtRef {
|
||||
|
@ -793,32 +804,29 @@ pub struct DirItem {
|
|||
ty: u8,
|
||||
}
|
||||
|
||||
impl NameLength for DirItem {
|
||||
fn name_length(&self) -> usize {
|
||||
self.name_len.get() as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl DirItem {
|
||||
pub fn ty(&self) -> DirItemType {
|
||||
DirItemType::from_primitive(self.ty)
|
||||
}
|
||||
|
||||
pub fn parse_single(bytes: &[u8]) -> Result<DirItemEntry> {
|
||||
let offset = &mut 0;
|
||||
Self::parse_single_inner(bytes, offset)
|
||||
}
|
||||
|
||||
fn parse_single_inner(bytes: &[u8], offset: &mut usize) -> Result<DirItemEntry> {
|
||||
let dir_item = DirItem::read_from(&bytes[*offset..*offset + size_of::<DirItem>()])
|
||||
.ok_or(Error::ReadFailed)?;
|
||||
*offset += size_of::<DirItem>();
|
||||
let name_len = dir_item.name_len.get() as usize;
|
||||
let name = &bytes[*offset..*offset + name_len];
|
||||
*offset += name_len;
|
||||
|
||||
Ok(DirItemEntry::new(dir_item, name.to_vec()))
|
||||
}
|
||||
|
||||
pub fn parse(bytes: &[u8]) -> Result<Vec<DirItemEntry>> {
|
||||
pub fn parse_all(bytes: &[u8]) -> Result<Vec<DirItemEntry>> {
|
||||
let offset = &mut 0;
|
||||
let entries = core::iter::from_fn(|| {
|
||||
if *offset + size_of::<DirItem>() < bytes.len() {
|
||||
Some(Self::parse_single_inner(&bytes[*offset..], offset))
|
||||
if *offset + size_of::<Self>() < bytes.len() {
|
||||
let item = DirItemEntry::parse(&bytes[*offset..]);
|
||||
*offset += size_of::<Self>()
|
||||
+ item
|
||||
.as_ref()
|
||||
.map(|item| item.item().name_length())
|
||||
.unwrap_or(0);
|
||||
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -829,17 +837,35 @@ impl DirItem {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DirItemEntry {
|
||||
pub dir_item: DirItem,
|
||||
pub name: Vec<u8>,
|
||||
pub trait NameLength {
|
||||
fn name_length(&self) -> usize;
|
||||
}
|
||||
|
||||
impl DirItemEntry {
|
||||
pub fn new(dir_item: DirItem, name: Vec<u8>) -> Self {
|
||||
Self { dir_item, name }
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct ItemWithName<I>
|
||||
where
|
||||
I: NameLength + Parseable,
|
||||
{
|
||||
inner: I,
|
||||
name: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<I> Debug for ItemWithName<I>
|
||||
where
|
||||
I: NameLength + Parseable + Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "({:?}, {:?})", &self.inner, &self.name_as_string_lossy())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ItemWithName<I>
|
||||
where
|
||||
I: NameLength + Parseable,
|
||||
{
|
||||
pub fn item(&self) -> &I {
|
||||
&self.inner
|
||||
}
|
||||
pub fn name_as_str(&self) -> core::result::Result<&str, core::str::Utf8Error> {
|
||||
core::str::from_utf8(&self.name)
|
||||
}
|
||||
|
@ -848,15 +874,19 @@ impl DirItemEntry {
|
|||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for DirItemEntry {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("DirItemEntry")
|
||||
.field("dir_item", &self.dir_item)
|
||||
.field("name", &self.name_as_string_lossy())
|
||||
.finish()
|
||||
impl<I> Parseable for ItemWithName<I>
|
||||
where
|
||||
I: NameLength + Parseable,
|
||||
{
|
||||
fn parse(bytes: &[u8]) -> Result<Self> {
|
||||
let inner = I::parse(bytes)?;
|
||||
let name = bytes[size_of::<I>()..][..inner.name_length()].to_vec();
|
||||
Ok(Self { inner, name })
|
||||
}
|
||||
}
|
||||
|
||||
pub type DirItemEntry = ItemWithName<DirItem>;
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||
pub struct InodeRef {
|
||||
|
@ -906,6 +936,8 @@ pub enum TreeItem {
|
|||
Root(RootItem),
|
||||
DirItem(Vec<DirItemEntry>),
|
||||
DirIndex(DirItemEntry),
|
||||
INodeItem(INodeItem),
|
||||
INodeRef(INodeRefEntry),
|
||||
Unimplemented,
|
||||
}
|
||||
|
||||
|
@ -933,13 +965,27 @@ impl From<DirItemEntry> for TreeItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<INodeItem> for TreeItem {
|
||||
fn from(value: INodeItem) -> Self {
|
||||
Self::INodeItem(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<INodeRefEntry> for TreeItem {
|
||||
fn from(value: INodeRefEntry) -> Self {
|
||||
Self::INodeRef(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeItem {
|
||||
pub fn parse(item: &Item, bytes: &[u8]) -> Result<Self> {
|
||||
Ok(match item.key.ty() {
|
||||
ObjectType::RootItem => RootItem::parse(bytes)?.into(),
|
||||
ObjectType::ChunkItem => Chunk::parse(bytes)?.into(),
|
||||
ObjectType::DirItem => DirItem::parse(bytes)?.into(),
|
||||
ObjectType::DirIndex => DirItem::parse_single(bytes)?.into(),
|
||||
ObjectType::DirItem => DirItem::parse_all(bytes)?.into(),
|
||||
ObjectType::DirIndex => DirItemEntry::parse(bytes)?.into(),
|
||||
ObjectType::INodeItem => INodeItem::parse(bytes)?.into(),
|
||||
ObjectType::INodeRef => INodeRefEntry::parse(bytes)?.into(),
|
||||
_ => TreeItem::Unimplemented,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ use alloc::collections::btree_map::Entry;
|
|||
use alloc::{collections::BTreeMap, rc::Rc, vec, vec::Vec};
|
||||
use scroll::Pread;
|
||||
|
||||
use crate::structs::{Chunk, Key, KeyPtr, KnownObjectId, ObjectType, Stripe, Superblock, TreeItem};
|
||||
use crate::structs::{
|
||||
Chunk, Key, KeyPtr, KnownObjectId, ObjectType, RootItem, Stripe, Superblock, TreeItem,
|
||||
};
|
||||
use crate::{Error, Result};
|
||||
|
||||
use super::tree::Tree;
|
||||
|
@ -326,7 +328,7 @@ impl<R: super::Read> Volume2<R> {
|
|||
.expect("dir item")
|
||||
.first()
|
||||
.expect("dir item entry")
|
||||
.dir_item
|
||||
.item()
|
||||
.location
|
||||
.id();
|
||||
|
||||
|
|
Loading…
Reference in a new issue