@@ -57,6 +57,9 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
5757 StandardInformation , file_reference_to_frs, filetime_to_unix_micros,
5858 } ;
5959
60+ // Check for parity debug logging
61+ let debug_parity = std:: env:: var ( "UFFS_PARITY_DEBUG" ) . is_ok ( ) ;
62+
6063 if data. len ( ) < size_of :: < FileRecordSegmentHeader > ( ) {
6164 return false ;
6265 }
@@ -97,6 +100,7 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
97100 let mut name_parse_counter: u16 = 0 ;
98101 let mut default_size = 0u64 ;
99102 let mut default_allocated = 0u64 ;
103+ let mut found_data_attr = false ;
100104 // User-visible ADS: (stream_name, size, allocated)
101105 let mut additional_streams: SmallVec < [ ( String , u64 , u64 ) ; 4 ] > = SmallVec :: new ( ) ;
102106 // Internal NTFS streams (e.g. $REPARSE, $EA, $OBJECT_ID) — not emitted as
@@ -221,10 +225,23 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
221225 let lowest_vcn = i64:: from_le_bytes (
222226 data[ nr_offset..nr_offset + 8 ] . try_into ( ) . unwrap_or ( [ 0 ; 8 ] ) ,
223227 ) ;
224- lowest_vcn == 0
228+ let is_primary = lowest_vcn == 0 ;
229+ if debug_parity && !is_primary {
230+ eprintln ! (
231+ "[PARITY_DEBUG] FRS={}: $DATA LowestVCN={}, SKIPPED (continuation extent)" ,
232+ frs, lowest_vcn
233+ ) ;
234+ }
235+ is_primary
225236 } else {
226237 // Can't read LowestVCN — assume primary (LowestVCN == 0 is common case)
227238 // This prevents skipping valid $DATA attributes near record boundaries
239+ if debug_parity {
240+ eprintln ! (
241+ "[PARITY_DEBUG] FRS={}: $DATA can't read LowestVCN (nr_offset + 8 > data.len()), assuming primary" ,
242+ frs
243+ ) ;
244+ }
228245 true
229246 }
230247 } ;
@@ -252,6 +269,12 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
252269 . try_into ( )
253270 . unwrap_or ( [ 0 ; 8 ] ) ,
254271 ) ;
272+ if debug_parity && name_len == 0 {
273+ eprintln ! (
274+ "[PARITY_DEBUG] FRS={}: $DATA non-resident, size={}, allocated={}" ,
275+ frs, size, allocated
276+ ) ;
277+ }
255278 ( size, allocated)
256279 } else if alloc_offset + 8 <= data. len ( ) {
257280 // Can read AllocatedSize but not DataSize — use AllocatedSize for both
@@ -261,8 +284,20 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
261284 . try_into ( )
262285 . unwrap_or ( [ 0 ; 8 ] ) ,
263286 ) ;
287+ if debug_parity && name_len == 0 {
288+ eprintln ! (
289+ "[PARITY_DEBUG] FRS={}: $DATA non-resident (truncated), allocated={}" ,
290+ frs, allocated
291+ ) ;
292+ }
264293 ( allocated, allocated)
265294 } else {
295+ if debug_parity && name_len == 0 {
296+ eprintln ! (
297+ "[PARITY_DEBUG] FRS={}: $DATA non-resident, but can't read size/allocated (offset beyond data.len()), size=0" ,
298+ frs
299+ ) ;
300+ }
266301 ( 0 , 0 )
267302 }
268303 } else {
@@ -276,8 +311,17 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
276311 . try_into ( )
277312 . unwrap_or ( [ 0 ; 4 ] ) ,
278313 ) as u64 ;
314+ if debug_parity && name_len == 0 {
315+ eprintln ! ( "[PARITY_DEBUG] FRS={}: $DATA resident, size={}" , frs, len) ;
316+ }
279317 ( len, 0 ) // allocated_size = 0 for resident files
280318 } else {
319+ if debug_parity && name_len == 0 {
320+ eprintln ! (
321+ "[PARITY_DEBUG] FRS={}: $DATA resident, but can't read value_length, size=0" ,
322+ frs
323+ ) ;
324+ }
281325 ( 0 , 0 )
282326 }
283327 } ;
@@ -286,6 +330,13 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
286330 // Default stream
287331 default_size = size;
288332 default_allocated = allocated;
333+ found_data_attr = true ;
334+ if debug_parity && size == 0 {
335+ eprintln ! (
336+ "[PARITY_DEBUG] FRS={}: Default $DATA stream has ZERO size" ,
337+ frs
338+ ) ;
339+ }
289340 } else {
290341 // Alternate Data Stream (ADS)
291342 let name_offset = offset + attr_header. name_offset as usize ;
@@ -554,6 +605,11 @@ pub fn parse_record_to_index(data: &[u8], frs: u64, index: &mut crate::index::Mf
554605 default_size = dir_index_size;
555606 default_allocated = dir_index_allocated;
556607 }
608+ } else if debug_parity && !found_data_attr && default_size == 0 {
609+ eprintln ! (
610+ "[PARITY_DEBUG] FRS={}: Non-directory file has NO $DATA attribute, size will be 0" ,
611+ frs
612+ ) ;
557613 }
558614
559615 // Handle records without a filename in the base record
0 commit comments