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