@@ -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}
0 commit comments