Skip to content

Commit 2c44c20

Browse files
authored
Merge pull request #6 from githubrobbi/fix-f-drive-parity
fix(mft): preserve extension first_stream.size and dir_index in LIVE parser
2 parents 65f3314 + e90aade commit 2c44c20

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed

crates/uffs-mft/src/io/parser/index.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,12 +723,20 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
723723
let ext_internal_head = record.first_internal_stream;
724724
let ext_internal_size = record.internal_streams_size;
725725
let ext_internal_alloc = record.internal_streams_allocated;
726+
// Snapshot first_stream.size from extension records (IOCP ordering).
727+
let ext_first_stream_len = record.first_stream.size.length;
728+
let ext_first_stream_alloc = record.first_stream.size.allocated;
726729

727730
record.stdinfo = std_info;
728731
record.first_stream.size = SizeInfo {
729732
length: default_size,
730733
allocated: default_allocated,
731734
};
735+
// Restore extension's default-stream size if base has no $DATA/$I30.
736+
if default_size == 0 && default_allocated == 0 && (ext_first_stream_len > 0 || ext_first_stream_alloc > 0) {
737+
record.first_stream.size.length = ext_first_stream_len;
738+
record.first_stream.size.allocated = ext_first_stream_alloc;
739+
}
732740
// Set type_name_id for first_stream: 0 for directories ($I30), 8 for files
733741
// ($DATA)
734742
record.first_stream.flags = if record.stdinfo.is_directory() {
@@ -919,12 +927,25 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
919927
let ext_internal_head = record.first_internal_stream;
920928
let ext_internal_size = record.internal_streams_size;
921929
let ext_internal_alloc = record.internal_streams_allocated;
930+
// Snapshot first_stream.size — extension records processed before the base
931+
// (due to IOCP out-of-order I/O) may have already set the default $DATA or
932+
// $I30 size. We must preserve it if the base record has no $DATA.
933+
let ext_first_stream_len = record.first_stream.size.length;
934+
let ext_first_stream_alloc = record.first_stream.size.allocated;
922935

923936
record.stdinfo = std_info;
924937
record.first_stream.size = SizeInfo {
925938
length: default_size,
926939
allocated: default_allocated,
927940
};
941+
// If the base record has no $DATA (default_size == 0 and default_allocated
942+
// == 0) but an extension record already populated first_stream.size, restore
943+
// the extension's values. This handles files/dirs whose primary $DATA/$I30
944+
// attribute resides entirely in an extension record.
945+
if default_size == 0 && default_allocated == 0 && (ext_first_stream_len > 0 || ext_first_stream_alloc > 0) {
946+
record.first_stream.size.length = ext_first_stream_len;
947+
record.first_stream.size.allocated = ext_first_stream_alloc;
948+
}
928949
// Set type_name_id for first_stream: 0 for directories ($I30), 8 for files
929950
// ($DATA)
930951
record.first_stream.flags = if record.stdinfo.is_directory() {

crates/uffs-mft/src/io/parser/index_extension.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,12 +458,14 @@ pub(super) fn parse_extension_to_index(
458458
offset += attr_header.length as usize;
459459
}
460460

461-
// If no names, user-visible streams, internal streams, or default data found,
462-
// nothing to do
461+
// If no names, user-visible streams, internal streams, default data, or
462+
// directory index sizes found, nothing to do
463463
if names.is_empty()
464464
&& streams.is_empty()
465465
&& ext_internal_streams.is_empty()
466466
&& !found_default_data
467+
&& dir_index_size == 0
468+
&& dir_index_allocated == 0
467469
{
468470
return false;
469471
}
@@ -784,4 +786,6 @@ pub(super) fn parse_extension_to_index(
784786
|| !streams.is_empty()
785787
|| !ext_internal_streams.is_empty()
786788
|| found_default_data
789+
|| dir_index_size > 0
790+
|| dir_index_allocated > 0
787791
}

crates/uffs-mft/src/parse/direct_index_extension.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,14 @@ pub(super) fn parse_extension_to_index(
530530
offset += attr_header.length as usize;
531531
}
532532

533-
// If no names, streams, or default data found, nothing to do
534-
if names.is_empty() && streams.is_empty() && !found_default_data {
533+
// If no names, streams, default data, or directory index sizes found,
534+
// nothing to do
535+
if names.is_empty()
536+
&& streams.is_empty()
537+
&& !found_default_data
538+
&& dir_index_size == 0
539+
&& dir_index_allocated == 0
540+
{
535541
return false;
536542
}
537543

@@ -788,5 +794,9 @@ pub(super) fn parse_extension_to_index(
788794
}
789795
}
790796

791-
!names.is_empty() || !streams.is_empty() || found_default_data
797+
!names.is_empty()
798+
|| !streams.is_empty()
799+
|| found_default_data
800+
|| dir_index_size > 0
801+
|| dir_index_allocated > 0
792802
}

0 commit comments

Comments
 (0)