Skip to content

Commit ffbf285

Browse files
committed
chore: development v0.1.33 - comprehensive testing complete [auto-commit]
1 parent 9135acc commit ffbf285

File tree

10 files changed

+82
-32
lines changed

10 files changed

+82
-32
lines changed

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ members = [
3232
# Workspace Package Metadata (inherited by all crates)
3333
# ─────────────────────────────────────────────────────────────────────────────
3434
[workspace.package]
35-
version = "0.1.31"
35+
version = "0.1.33"
3636
edition = "2024"
3737
rust-version = "1.85"
3838
license = "MPL-2.0 OR LicenseRef-UFFS-Commercial"

crates/uffs-mft/src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,10 @@
3535
// These dependencies are used by the uffs-mft library, not this binary.
3636
// Cargo doesn't support per-binary dependencies, so we suppress the warnings
3737
// here.
38-
use std::io::stdout;
39-
use std::path::PathBuf;
40-
4138
#[cfg(not(windows))]
4239
use core::future::Future;
40+
use std::io::stdout;
41+
use std::path::PathBuf;
4342

4443
#[cfg(windows)]
4544
use anyhow::Context;
@@ -1584,8 +1583,10 @@ async fn cmd_bitmap_diag(drive: char, show_samples: bool) -> Result<()> {
15841583
println!(" Total records (from size): {}", total_records_from_size);
15851584
println!();
15861585

1586+
1587+
15871588
// Try to get bitmap
1588-
println!("📋 BITMAP RETRIEVAL");
1589+
println!("📋 BITMAP RETRIEVAL (via get_mft_bitmap)");
15891590
match handle.get_mft_bitmap() {
15901591
Ok(bitmap) => {
15911592
let bitmap_bytes = bitmap.as_bytes().len();

crates/uffs-mft/src/platform.rs

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,11 @@ impl VolumeHandle {
347347
/// Returns an error if the bitmap cannot be read.
348348
#[allow(unsafe_code)] // Required: Windows FFI for CreateFileW, GetFileSizeEx, ReadFile
349349
pub fn get_mft_bitmap(&self) -> Result<MftBitmap> {
350-
// Open the $MFT::$BITMAP stream
350+
use windows::Win32::Storage::FileSystem::{
351+
FILE_BEGIN, GetFileSizeEx, ReadFile, SetFilePointerEx,
352+
};
353+
354+
// Open the $MFT::$BITMAP stream to get retrieval pointers and size
351355
let bitmap_path: Vec<u16> = format!("{}:\\$MFT::$BITMAP", self.volume)
352356
.encode_utf16()
353357
.chain(core::iter::once(0))
@@ -356,11 +360,11 @@ impl VolumeHandle {
356360
let bitmap_handle = unsafe {
357361
CreateFileW(
358362
PCWSTR::from_raw(bitmap_path.as_ptr()),
359-
FILE_READ_ATTRIBUTES.0 | 0x0001, // FILE_READ_DATA
363+
FILE_READ_ATTRIBUTES.0,
360364
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
361365
None,
362366
OPEN_EXISTING,
363-
FILE_FLAG_OPEN_REPARSE_POINT,
367+
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_NO_BUFFERING,
364368
None,
365369
)
366370
};
@@ -381,35 +385,76 @@ impl VolumeHandle {
381385
// Get file size
382386
let mut file_size: i64 = 0;
383387
unsafe {
384-
use windows::Win32::Storage::FileSystem::GetFileSizeEx;
385388
if GetFileSizeEx(bitmap_handle, &mut file_size).is_err() {
386389
return Ok(MftBitmap::new_all_valid(
387390
self.estimated_record_count() as usize
388391
));
389392
}
390393
}
391394

392-
// Read the bitmap
393-
let mut buffer = vec![0u8; file_size as usize];
394-
let mut bytes_read: u32 = 0;
395-
396-
unsafe {
397-
use windows::Win32::Storage::FileSystem::ReadFile;
398-
if ReadFile(
399-
bitmap_handle,
400-
Some(&mut buffer),
401-
Some(&mut bytes_read),
402-
None,
403-
)
404-
.is_err()
405-
{
395+
// Get retrieval pointers for the bitmap file
396+
let extents = match get_retrieval_pointers(bitmap_handle) {
397+
Ok(e) if !e.is_empty() => e,
398+
_ => {
399+
// Can't get extents, fall back to all valid
406400
return Ok(MftBitmap::new_all_valid(
407401
self.estimated_record_count() as usize
408402
));
409403
}
404+
};
405+
406+
// Read the bitmap data from the volume at the physical cluster locations
407+
let bytes_per_cluster = self.volume_data.bytes_per_cluster;
408+
let mut buffer = vec![0u8; file_size as usize];
409+
let mut buffer_offset = 0usize;
410+
411+
for extent in &extents {
412+
let byte_offset = extent.lcn * i64::from(bytes_per_cluster);
413+
let extent_bytes = (extent.cluster_count * u64::from(bytes_per_cluster)) as usize;
414+
let bytes_to_read = extent_bytes.min(buffer.len() - buffer_offset);
415+
416+
if bytes_to_read == 0 {
417+
break;
418+
}
419+
420+
// Seek to the extent's physical location on the volume
421+
let mut new_position = 0_i64;
422+
unsafe {
423+
if SetFilePointerEx(
424+
self.handle,
425+
byte_offset,
426+
Some(&mut new_position),
427+
FILE_BEGIN,
428+
)
429+
.is_err()
430+
{
431+
return Ok(MftBitmap::new_all_valid(
432+
self.estimated_record_count() as usize
433+
));
434+
}
435+
}
436+
437+
// Read the extent data from the volume
438+
let mut bytes_read: u32 = 0;
439+
unsafe {
440+
if ReadFile(
441+
self.handle,
442+
Some(&mut buffer[buffer_offset..buffer_offset + bytes_to_read]),
443+
Some(&mut bytes_read),
444+
None,
445+
)
446+
.is_err()
447+
{
448+
return Ok(MftBitmap::new_all_valid(
449+
self.estimated_record_count() as usize
450+
));
451+
}
452+
}
453+
454+
buffer_offset += bytes_read as usize;
410455
}
411456

412-
buffer.truncate(bytes_read as usize);
457+
buffer.truncate(buffer_offset);
413458
Ok(MftBitmap::from_bytes(buffer))
414459
}
415460
}

dist/latest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.1.31
1+
v0.1.33

0 commit comments

Comments
 (0)