Skip to content

Commit 0ecaa07

Browse files
Add tag iter
1 parent 406e18c commit 0ecaa07

File tree

3 files changed

+58
-39
lines changed

3 files changed

+58
-39
lines changed

src/error.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,6 @@ pub(crate) enum CorruptKind {
250250
/// Journal descriptor tag checksum is invalid.
251251
JournalDescriptorTagChecksum,
252252

253-
/// Not enough bytes to read a journal descriptor tag.
254-
JournalDescriptorTagTruncated,
255-
256253
/// Journal has a descriptor block that contains no tag with the last-tag flag set.
257254
JournalDescriptorBlockMissingLastTag,
258255

@@ -359,9 +356,6 @@ impl Display for CorruptKind {
359356
Self::JournalDescriptorTagChecksum => {
360357
write!(f, "journal descriptor tag checksum is invalid")
361358
}
362-
Self::JournalDescriptorTagTruncated => {
363-
write!(f, "journal descriptor tag truncated")
364-
}
365359
Self::JournalDescriptorBlockMissingLastTag => write!(
366360
f,
367361
"a journal descriptor block has no tag with the last-tag flag set"

src/journal.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use alloc::collections::BTreeMap;
2020
use alloc::vec;
2121
use block_header::{JournalBlockHeader, JournalBlockType};
2222
use descriptor_block::{
23-
is_descriptor_block_checksum_valid, DescriptorBlockTag,
23+
is_descriptor_block_checksum_valid, DescriptorBlockTagIter,
2424
};
2525
use superblock::JournalSuperblock;
2626

@@ -91,6 +91,7 @@ fn load_block_map(
9191
// journal when bad data is encountered.
9292

9393
let mut block = vec![0; fs.0.superblock.block_size.to_usize()];
94+
let mut data_block = vec![0; fs.0.superblock.block_size.to_usize()];
9495
let mut block_map = BTreeMap::new();
9596
let mut uncommitted_block_map = BTreeMap::new();
9697
let mut sequence = superblock.sequence;
@@ -114,19 +115,21 @@ fn load_block_map(
114115
return Err(CorruptKind::JournalDescriptorBlockChecksum.into());
115116
}
116117

117-
let tags =
118-
DescriptorBlockTag::read_bytes_to_vec(&block[12..]).unwrap();
118+
let tags = DescriptorBlockTagIter::new(&block[12..]);
119+
120+
for tag in tags {
121+
let tag = tag?;
119122

120-
for tag in &tags {
121123
let block_index = journal_block_iter
122124
.next()
123125
.ok_or(CorruptKind::JournalTruncated)??;
124126

127+
// Check the data block checksum.
125128
let mut checksum = Checksum::new();
126129
checksum.update(superblock.uuid.as_bytes());
127130
checksum.update_u32_be(sequence);
128-
fs.read_from_block(block_index, 0, &mut block)?;
129-
checksum.update(&block);
131+
fs.read_from_block(block_index, 0, &mut data_block)?;
132+
checksum.update(&data_block);
130133
if checksum.finalize() != tag.checksum {
131134
return Err(
132135
CorruptKind::JournalDescriptorTagChecksum.into()

src/journal/descriptor_block.rs

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::checksum::Checksum;
1010
use crate::error::{CorruptKind, Ext4Error};
1111
use crate::journal::superblock::JournalSuperblock;
1212
use crate::util::{read_u32be, u64_from_hilo};
13-
use alloc::vec::Vec;
1413
use bitflags::bitflags;
1514

1615
pub(super) fn is_descriptor_block_checksum_valid(
@@ -54,14 +53,14 @@ impl DescriptorBlockTag {
5453
}
5554
}
5655

57-
pub(super) fn read_bytes(bytes: &[u8]) -> Result<Self, Ext4Error> {
56+
pub(super) fn read_bytes(bytes: &[u8]) -> Option<Self> {
5857
// Note: the tag format depends on feature flags in the journal
5958
// superblock. The code in this function is only correct if the
6059
// `CHECKSUM_V3` feature is enabled (this is checked when
6160
// loading the superblock).
6261

6362
if bytes.len() < Self::SIZE_WITHOUT_UUID {
64-
return Err(CorruptKind::JournalDescriptorTagTruncated.into());
63+
return None;
6564
}
6665

6766
let t_blocknr = read_u32be(bytes, 0);
@@ -74,42 +73,67 @@ impl DescriptorBlockTag {
7473
if !flags.contains(DescriptorBlockTagFlags::UUID_OMITTED)
7574
&& bytes.len() < Self::SIZE_WITH_UUID
7675
{
77-
return Err(CorruptKind::JournalDescriptorTagTruncated.into());
76+
return None;
7877
}
7978

80-
Ok(Self {
79+
Some(Self {
8180
block_number: u64_from_hilo(t_blocknr_high, t_blocknr),
8281
flags,
8382
checksum: t_checksum,
8483
})
8584
}
85+
}
86+
87+
pub(super) struct DescriptorBlockTagIter<'a> {
88+
bytes: &'a [u8],
89+
is_done: bool,
90+
}
8691

87-
// TODO: this could be an iterator instead of allocating.
88-
pub(super) fn read_bytes_to_vec(
89-
mut bytes: &[u8],
90-
) -> Result<Vec<Self>, Ext4Error> {
91-
let mut v = Vec::new();
92+
impl<'a> DescriptorBlockTagIter<'a> {
93+
pub(super) fn new(bytes: &'a [u8]) -> Self {
94+
Self {
95+
bytes,
96+
is_done: false,
97+
}
98+
}
99+
}
92100

93-
while !bytes.is_empty() {
94-
let tag = Self::read_bytes(bytes)?;
95-
let is_end = tag.flags.contains(DescriptorBlockTagFlags::LAST_TAG);
96-
let size = tag.encoded_size();
97-
v.push(tag);
101+
impl Iterator for DescriptorBlockTagIter<'_> {
102+
type Item = Result<DescriptorBlockTag, Ext4Error>;
98103

99-
if is_end {
100-
return Ok(v);
101-
}
104+
fn next(&mut self) -> Option<Self::Item> {
105+
if self.is_done {
106+
return None;
107+
}
102108

103-
bytes = &bytes[size..];
109+
let tag = if let Some(tag) = DescriptorBlockTag::read_bytes(self.bytes)
110+
{
111+
tag
112+
} else {
113+
// If there were not enough bytes left to read the next tag,
114+
// then the expected tag with the LAST_TAG flag set is missing.
115+
self.is_done = true;
116+
return Some(Err(
117+
CorruptKind::JournalDescriptorBlockMissingLastTag.into(),
118+
));
119+
};
120+
121+
if tag.flags.contains(DescriptorBlockTagFlags::LAST_TAG) {
122+
// Last tag reached, nothing more to read.
123+
self.is_done = true;
124+
return Some(Ok(tag));
104125
}
105126

106-
Err(CorruptKind::JournalDescriptorBlockMissingLastTag.into())
127+
// Update the remaining bytes.
128+
self.bytes = &self.bytes[tag.encoded_size()..];
129+
130+
Some(Ok(tag))
107131
}
108132
}
109133

110134
bitflags! {
111135
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
112-
pub struct DescriptorBlockTagFlags: u32 {
136+
pub(crate) struct DescriptorBlockTagFlags: u32 {
113137
const ESCAPED = 0x1;
114138
const UUID_OMITTED = 0x2;
115139
const DELETED = 0x4;
@@ -128,10 +152,6 @@ mod tests {
128152
#[test]
129153
fn test_journal_descriptor_block_tags() {
130154
let mut bytes = vec![];
131-
assert_eq!(
132-
DescriptorBlockTag::read_bytes_to_vec(&bytes).unwrap_err(),
133-
CorruptKind::JournalDescriptorBlockMissingLastTag
134-
);
135155

136156
// Block number low.
137157
push_u32be(&mut bytes, 0x1000);
@@ -154,8 +174,10 @@ mod tests {
154174
bytes.extend([0; 16]);
155175

156176
assert_eq!(
157-
DescriptorBlockTag::read_bytes_to_vec(&bytes).unwrap(),
158-
vec![
177+
DescriptorBlockTagIter::new(&bytes)
178+
.map(Result::unwrap)
179+
.collect::<Vec<_>>(),
180+
[
159181
DescriptorBlockTag {
160182
block_number: 0xa000_0000_1000,
161183
flags: DescriptorBlockTagFlags::UUID_OMITTED,

0 commit comments

Comments
 (0)