Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/ntfs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Finck <colin@reactos.org>2021-10-05 22:46:30 +0300
committerColin Finck <colin@reactos.org>2021-10-05 22:46:30 +0300
commitdef734b62543c78200ae2070c3be8e49895dbfd4 (patch)
tree380cadf854159223b5406dd170a4cb59222aaff6
parent0542441b532b50cf063cff01030c7e73a3df46af (diff)
Fix a corner case in `NtfsIndexEntries::next` after more testing.
For `following_entries` to work, its length must always be one less than `inner_iterators` length. This broke when I started filtering out the last entry without any information. Now `following_entries` is always incremented together with `inner_iterators`. `None` is used to indicate a last entry without any information. Minimum example where this broke: * Top-level node (0) has a subnode (1) and is not the last entry (= inserts an entry into `following_entries`). * Subnode (1) has a subnode (2) and is the last entry. * Subnode (2) has no subnode and is the last entry. When subnode (2) finished iterating, its iterator is dropped and the iterator of subnode (1) becomes the last one. The next item in `following_entries` must now be `None` to loop one more time. Now we notice that subnode (1) has also been fully iterated, drop its iterator, and let the iterator of top-level node (0) become the last iterator. The entry in `following_entries` is now picked up, associated to the correct iterator (0), and returned.
-rw-r--r--src/index.rs44
1 files changed, 29 insertions, 15 deletions
diff --git a/src/index.rs b/src/index.rs
index 2fd4330..91df495 100644
--- a/src/index.rs
+++ b/src/index.rs
@@ -81,7 +81,7 @@ where
{
index: &'i NtfsIndex<'n, 'f, E>,
inner_iterators: Vec<IndexNodeEntryRanges<E>>,
- following_entries: Vec<IndexEntryRange<E>>,
+ following_entries: Vec<Option<IndexEntryRange<E>>>,
}
impl<'n, 'f, 'i, E> NtfsIndexEntries<'n, 'f, 'i, E>
@@ -128,6 +128,7 @@ where
// Get the next `IndexEntryRange` from it.
if let Some(entry_range) = iter.next() {
let entry_range = iter_try!(entry_range);
+
// Convert that `IndexEntryRange` to a (lifetime-bound) `NtfsIndexEntry`.
let entry = iter_try!(entry_range.to_entry(iter.data()));
let is_last_entry = entry.flags().contains(NtfsIndexEntryFlags::LAST_ENTRY);
@@ -135,6 +136,7 @@ where
// Does this entry have a subnode that needs to be iterated first?
if let Some(subnode_vcn) = entry.subnode_vcn() {
let subnode_vcn = iter_try!(subnode_vcn);
+
// Read the subnode from the filesystem and get an iterator for it.
let index_allocation_item =
iter_try!(self.index.index_allocation_item.as_ref().ok_or_else(|| {
@@ -154,18 +156,21 @@ where
));
let subnode_iter = subnode.into_entry_ranges();
- // Save this subnode's iterator.
- // We'll pick it up through `self.inner_iterators.last_mut()` in the next loop iteration.
- self.inner_iterators.push(subnode_iter);
-
- if !is_last_entry {
- // This is not the empty "last entry", so save it as well.
+ let following_entry = if !is_last_entry {
+ // This entry comes after the subnode lexicographically, so save it.
// We'll pick it up again after the subnode iterator has been fully iterated.
- self.following_entries.push(entry_range);
- }
+ Some(entry_range)
+ } else {
+ None
+ };
+
+ // Save this subnode's iterator and any following entry.
+ // We'll pick up the iterator through `self.inner_iterators.last_mut()` in the next loop iteration.
+ self.inner_iterators.push(subnode_iter);
+ self.following_entries.push(following_entry);
} else if !is_last_entry {
// There is no subnode, and this is not the empty "last entry",
- // so our `entry` comes next lexicographically.
+ // so our entry comes next lexicographically.
break entry_range;
}
} else {
@@ -173,17 +178,26 @@ where
// Drop it.
self.inner_iterators.pop();
- // Return the entry, whose subnode we just iterated and which we saved in `following_entries` above.
- // If we just finished iterating the top-level node, `following_entries` is empty and we are done.
- // Otherwise, we can be sure that `inner_iterators` contains the matching iterator for converting
+ // The entry, whose subnode we just fully iterated, may have been saved in `following_entries`.
+ // This depends on its `is_last_entry` flag:
+ // * If it was not the last entry, it contains an entry that comes next lexicographically,
+ // and has therefore been saved in `following_entries`.
+ // * If it was the last entry, it contains no further information.
+ // `None` has been saved in `following_entries`, so that `following_entries.len()` always
+ // matches `inner_iterators.len() - 1`.
+ //
+ // If we just finished iterating the root-level node, `following_entries` is empty and we are done.
+ // Otherwise, we can be sure that `inner_iterators.last()` is the matching iterator for converting
// `IndexEntryRange` to a (lifetime-bound) `NtfsIndexEntry`.
- let entry_range = self.following_entries.pop()?;
- break entry_range;
+ if let Some(entry_range) = self.following_entries.pop()? {
+ break entry_range;
+ }
}
};
let iter = self.inner_iterators.last().unwrap();
let entry = iter_try!(entry_range.to_entry(iter.data()));
+
Some(Ok(entry))
}
}