Skip to content

Commit

Permalink
Make directory processing more permissive
Browse files Browse the repository at this point in the history
  • Loading branch information
shamilsan committed Sep 2, 2024
1 parent 6594a47 commit 7124f4e
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 49 deletions.
108 changes: 67 additions & 41 deletions src/internal/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ impl<F> Directory<F> {
pub fn stream_id_for_name_chain(&self, names: &[&str]) -> Option<u32> {
let mut stream_id = consts::ROOT_STREAM_ID;
for name in names.iter() {
stream_id = self.dir_entry(stream_id).child;
stream_id = self.try_dir_entry(stream_id)?.child;
loop {
if stream_id == consts::NO_STREAM {
return None;
}
let dir_entry = self.dir_entry(stream_id);
let dir_entry = self.try_dir_entry(stream_id)?;
match internal::path::compare_names(name, &dir_entry.name) {
Ordering::Equal => break,
Ordering::Less => stream_id = dir_entry.left_sibling,
Expand All @@ -85,6 +85,10 @@ impl<F> Directory<F> {
self.dir_entry(consts::ROOT_STREAM_ID)
}

pub fn try_dir_entry(&self, stream_id: u32) -> Option<&DirEntry> {
self.dir_entries.get(stream_id as usize)
}

pub fn dir_entry(&self, stream_id: u32) -> &DirEntry {
&self.dir_entries[stream_id as usize]
}
Expand Down Expand Up @@ -138,58 +142,80 @@ impl<F> Directory<F> {
if parent_is_red && node_is_red && validation.is_strict() {
malformed!("RB tree has adjacent red nodes");
}
let left_sibling = dir_entry.left_sibling;
let mut left_sibling = dir_entry.left_sibling;
if left_sibling != consts::NO_STREAM {
if left_sibling as usize >= self.dir_entries.len() {
malformed!(
"left sibling index is {}, but directory entry count \
is {}",
left_sibling,
self.dir_entries.len()
);
if validation.is_strict() {
malformed!(
"left sibling index is {}, but directory entry count \
is {}",
left_sibling,
self.dir_entries.len()
);
} else {
left_sibling = consts::NO_STREAM;
}
}
let entry = &self.dir_entry(left_sibling);
if internal::path::compare_names(&entry.name, &dir_entry.name)
!= Ordering::Less
{
malformed!(
"name ordering, {:?} vs {:?}",
dir_entry.name,
entry.name
);
if left_sibling != consts::NO_STREAM {
let entry = &self.dir_entry(left_sibling);
if internal::path::compare_names(
&entry.name,
&dir_entry.name,
) != Ordering::Less
{
malformed!(
"name ordering, {:?} vs {:?}",
dir_entry.name,
entry.name
);
}
stack.push((left_sibling, node_is_red));
}
stack.push((left_sibling, node_is_red));
}
let right_sibling = dir_entry.right_sibling;
let mut right_sibling = dir_entry.right_sibling;
if right_sibling != consts::NO_STREAM {
if right_sibling as usize >= self.dir_entries.len() {
malformed!(
"right sibling index is {}, but directory entry count \
is {}",
right_sibling, self.dir_entries.len());
if validation.is_strict() {
malformed!(
"right sibling index is {}, but directory entry count \
is {}",
right_sibling, self.dir_entries.len());
} else {
right_sibling = consts::NO_STREAM;
}
}
let entry = &self.dir_entry(right_sibling);
if internal::path::compare_names(&dir_entry.name, &entry.name)
!= Ordering::Less
{
malformed!(
"name ordering, {:?} vs {:?}",
dir_entry.name,
entry.name
);
if right_sibling != consts::NO_STREAM {
let entry = &self.dir_entry(right_sibling);
if internal::path::compare_names(
&dir_entry.name,
&entry.name,
) != Ordering::Less
{
malformed!(
"name ordering, {:?} vs {:?}",
dir_entry.name,
entry.name
);
}
stack.push((right_sibling, node_is_red));
}
stack.push((right_sibling, node_is_red));
}
let child = dir_entry.child;
let mut child = dir_entry.child;
if child != consts::NO_STREAM {
if child as usize >= self.dir_entries.len() {
malformed!(
"child index is {}, but directory entry count is {}",
child,
self.dir_entries.len()
);
if validation.is_strict() {
malformed!(
"child index is {}, but directory entry count is {}",
child,
self.dir_entries.len()
);
} else {
child = consts::NO_STREAM;
}
}
if child != consts::NO_STREAM {
stack.push((child, false));
}
stack.push((child, false));
}
}
Ok(())
Expand Down
8 changes: 6 additions & 2 deletions src/internal/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,12 @@ impl<'a, F> Entries<'a, F> {
fn stack_left_spine(&mut self, parent_path: &Path, mut current_id: u32) {
let minialloc = self.minialloc.read().unwrap();
while current_id != consts::NO_STREAM {
self.stack.push((parent_path.to_path_buf(), current_id, true));
current_id = minialloc.dir_entry(current_id).left_sibling;
if let Some(dir_entry) = minialloc.try_dir_entry(current_id) {
self.stack.push((parent_path.to_path_buf(), current_id, true));
current_id = dir_entry.left_sibling;
} else {
break;
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/internal/minialloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ impl<F> MiniAllocator<F> {
self.directory.root_dir_entry()
}

pub fn try_dir_entry(&self, stream_id: u32) -> Option<&DirEntry> {
self.directory.try_dir_entry(stream_id)
}

pub fn dir_entry(&self, stream_id: u32) -> &DirEntry {
self.directory.dir_entry(stream_id)
}
Expand Down
16 changes: 10 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,12 +511,16 @@ impl<F: Read + Seek> CompoundFile<F> {
current_dir_sector
);
} else if current_dir_sector >= num_sectors {
invalid_data!(
"Directory chain includes sector index {}, but sector \
count is only {}",
current_dir_sector,
num_sectors
);
if validation.is_strict() {
invalid_data!(
"Directory chain includes sector index {}, but sector \
count is only {}",
current_dir_sector,
num_sectors
);
} else {
break;
}
}
if seen_dir_sectors.contains(&current_dir_sector) {
invalid_data!(
Expand Down

0 comments on commit 7124f4e

Please sign in to comment.