Skip to content

Commit e7b6db0

Browse files
committed
fix: read MFT bitmap with sector-aligned reads
- Fixed volume handle access mode: use FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE instead of incorrect FILE_SHARE_READ | FILE_SHARE_WRITE (matching C++ reference) - Fixed ReadFile with FILE_FLAG_NO_BUFFERING: read full clusters (always aligned), then truncate to actual file size - Added FILE_READ_DATA constant (0x0001) to avoid Win32_System_SystemServices feature dependency Root cause: ReadFile was failing with ERROR_INVALID_PARAMETER (0x80070057) because the read size (582048 bytes) was not sector-aligned. With FILE_FLAG_NO_BUFFERING, reads must be aligned to sector boundaries. The C++ code reads cluster_count × cluster_size bytes (always aligned), then uses only the valid portion.
1 parent c161380 commit e7b6db0

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/uffs-mft/src/platform.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -466,30 +466,37 @@ impl VolumeHandle {
466466
};
467467

468468
// Read the bitmap data from the volume at the physical cluster locations
469+
// With FILE_FLAG_NO_BUFFERING, reads must be sector-aligned.
470+
// The C++ code reads full clusters (cluster_count × cluster_size), then
471+
// truncates.
469472
let bytes_per_cluster = self.volume_data.bytes_per_cluster;
470-
let mut buffer = vec![0u8; file_size as usize];
473+
474+
// Calculate total cluster-aligned size to read
475+
let total_clusters: u64 = extents.iter().map(|e| e.cluster_count).sum();
476+
let aligned_size = (total_clusters * u64::from(bytes_per_cluster)) as usize;
477+
let mut buffer = vec![0u8; aligned_size];
471478
let mut buffer_offset = 0usize;
472479

473480
if verbose {
474481
eprintln!(
475-
"[BITMAP] Reading from volume, bytes_per_cluster={}",
476-
bytes_per_cluster
482+
"[BITMAP] Reading from volume, bytes_per_cluster={}, file_size={}, aligned_size={}",
483+
bytes_per_cluster, file_size, aligned_size
477484
);
478485
}
479486

480487
for (i, extent) in extents.iter().enumerate() {
481488
let byte_offset = extent.lcn * i64::from(bytes_per_cluster);
489+
// Read full clusters (always aligned)
482490
let extent_bytes = (extent.cluster_count * u64::from(bytes_per_cluster)) as usize;
483-
let bytes_to_read = extent_bytes.min(buffer.len() - buffer_offset);
484491

485-
if bytes_to_read == 0 {
486-
break;
492+
if extent_bytes == 0 {
493+
continue;
487494
}
488495

489496
if verbose && i < 3 {
490497
eprintln!(
491-
"[BITMAP] Extent {}: seek to offset {}, read {} bytes",
492-
i, byte_offset, bytes_to_read
498+
"[BITMAP] Extent {}: seek to offset {}, read {} bytes (full clusters)",
499+
i, byte_offset, extent_bytes
493500
);
494501
}
495502

@@ -511,12 +518,12 @@ impl VolumeHandle {
511518
}
512519
}
513520

514-
// Read the extent data from the volume
521+
// Read the extent data from the volume (full clusters)
515522
let mut bytes_read: u32 = 0;
516523
unsafe {
517524
if let Err(e) = ReadFile(
518525
self.handle,
519-
Some(&mut buffer[buffer_offset..buffer_offset + bytes_to_read]),
526+
Some(&mut buffer[buffer_offset..buffer_offset + extent_bytes]),
520527
Some(&mut bytes_read),
521528
None,
522529
) {
@@ -545,13 +552,17 @@ impl VolumeHandle {
545552
}
546553

547554
if verbose {
548-
eprintln!("[BITMAP] Total bytes read: {}", buffer_offset);
549-
let all_ff = buffer.iter().take(buffer_offset).all(|&b| b == 0xFF);
550-
let all_00 = buffer.iter().take(buffer_offset).all(|&b| b == 0x00);
555+
eprintln!(
556+
"[BITMAP] Total bytes read: {}, truncating to file_size: {}",
557+
buffer_offset, file_size
558+
);
559+
let all_ff = buffer.iter().take(file_size as usize).all(|&b| b == 0xFF);
560+
let all_00 = buffer.iter().take(file_size as usize).all(|&b| b == 0x00);
551561
eprintln!("[BITMAP] All 0xFF: {}, All 0x00: {}", all_ff, all_00);
552562
}
553563

554-
buffer.truncate(buffer_offset);
564+
// Truncate to actual file size (discard padding from cluster alignment)
565+
buffer.truncate(file_size as usize);
555566
Ok(MftBitmap::from_bytes(buffer))
556567
}
557568
}

0 commit comments

Comments
 (0)