Page 1 of 1
DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sat Sep 17, 2022 9:55 pm
by firace
Would anyone have an example of how to call the DeviceIoControl Windows API with FSCTL_GET_VOLUME_BITMAP?
Ref:
https://docs.microsoft.com/fr-fr/window ... ume_bitmap
Thanks!
(example code in C - see my next post)
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sat Sep 17, 2022 11:33 pm
by Olli
Hello, here :
Code: Select all
hDevice = CreateFile_ ("\\.\PhysicalDrive0", 0, #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, 0, #Null)
I think you have to replace 0 with #Generic_Read (1 << 31).
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 8:54 am
by firace
Hi, I've removed the code in the OP as it is not so relevant to the topic.
More info about the cluster map (volume bitmap):
https://redcircle.blog/2008/11/26/cluster-map/
https://codeistry.wordpress.com/2015/01 ... fs-volume/
This is what I would like to write in PB:
Code: Select all
const int bitmapSize = 65536;
byte bitmapBuffer[bitmapSize + sizeof (VOLUME_BITMAP_BUFFER)];
VOLUME_BITMAP_BUFFER *bitmap = (VOLUME_BITMAP_BUFFER *) bitmapBuffer;
startLcn.q = 0;
DWORD bytesReturned;
DeviceIoControl (volumeHandle, FSCTL_GET_VOLUME_BITMAP, &startLcn, sizeof (startLcn), &bitmapBuffer, sizeof (bitmapBuffer), &bytesReturned, NULL)
My main obstacle is the VOLUME_BITMAP_BUFFER type I guess.
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 9:37 am
by infratec
You need 'Administrator mode' in compiler options.
Else LastError is 6 (0x6): The handle is invalid.
If LastError is 234 (0xEA): More data is available.
then the buffer is to small,
And you can not open a 'physical drive', you need to open a Volume.
In my case, this works:
(222GB Volume returns 7288861 bytes -> clustersize is 32768)
Code: Select all
EnableExplicit
#FSCTL_GET_VOLUME_BITMAP = $0009006F
Define.i hVolume, Result, LastError
Define.q startLcn, bytesReturned
Define *bitmapBuffer
hVolume = CreateFile_ ("\\.\c:", #GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, 0, #Null)
If hVolume
*bitmapBuffer = AllocateMemory($800000)
If *bitmapBuffer
Result = DeviceIoControl_(hVolume, #FSCTL_GET_VOLUME_BITMAP, @startLcn, SizeOf(startLcn), *bitmapBuffer, MemorySize(*bitmapBuffer), @bytesReturned, #Null)
LastError = GetLastError_()
If LastError
MessageRequester("Last Error", Str(LastError) + " (" + Hex(LastError) + ") " + Str(bytesReturned))
Else
MessageRequester("Info", "Bytes returned: " + Str(bytesReturned))
EndIf
FreeMemory(*bitmapBuffer)
EndIf
CloseHandle_(hVolume)
EndIf
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 10:27 am
by firace
Thanks a lot infratec, great answer as usual!
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 3:37 pm
by infratec
A bit more extended:
Code: Select all
EnableExplicit
#IOCTL_STORAGE_READ_CAPACITY = $2D5140
#FSCTL_GET_VOLUME_BITMAP = $0009006F
Structure STORAGE_READ_CAPACITY Align #PB_Structure_AlignC
Version.l
Size.l
BlockLength.l
NumberOfBlocks.LARGE_INTEGER
DiskLength.LARGE_INTEGER
EndStructure
Structure STARTING_VCN_INPUT_BUFFER Align #PB_Structure_AlignC
StartingVcn.LARGE_INTEGER
EndStructure
Structure VOLUME_BITMAP_BUFFER Align #PB_Structure_AlignC
StartingLcn.LARGE_INTEGER
BitmapSize.LARGE_INTEGER
Buffer.a[0]
EndStructure
Define.i hVolume, Result, LastError
Define.q startLcn, bytesReturned
Define *bitmapBuffer.VOLUME_BITMAP_BUFFER
Define StorageReadCapacity.STORAGE_READ_CAPACITY
Define Msg$
hVolume = CreateFile_ ("\\.\c:", #GENERIC_READ, #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, 0, #Null)
If hVolume
Result = DeviceIoControl_(hVolume, #IOCTL_STORAGE_READ_CAPACITY, #Null, 0, @StorageReadCapacity, SizeOf(STORAGE_READ_CAPACITY), @bytesReturned, #Null)
LastError = GetLastError_()
If LastError
MessageRequester("Last Error", Str(LastError) + " (" + Hex(LastError) + ") " + Str(bytesReturned))
Else
Msg$ = "Bytes returned: " + Str(bytesReturned) + #LF$
Msg$ + "Size: " + Str(StorageReadCapacity\Size) + #LF$
Msg$ + "BlockLength: " + Str(StorageReadCapacity\BlockLength) + #LF$
Msg$ + "NumberOfBlocks: " + Str(StorageReadCapacity\NumberOfBlocks\QuadPart) + #LF$
Msg$ + "DiskLength: " + Str(StorageReadCapacity\DiskLength\QuadPart)
MessageRequester("Info", Msg$)
EndIf
*bitmapBuffer = AllocateMemory(StorageReadCapacity\DiskLength\QuadPart / 4096 / 8)
If *bitmapBuffer
Result = DeviceIoControl_(hVolume, #FSCTL_GET_VOLUME_BITMAP, @startLcn, SizeOf(startLcn), *bitmapBuffer, MemorySize(*bitmapBuffer), @bytesReturned, #Null)
LastError = GetLastError_()
If LastError
MessageRequester("Last Error", Str(LastError) + " (" + Hex(LastError) + ") " + Str(bytesReturned))
Else
Msg$ = "Bytes returned: " + Str(bytesReturned) + #LF$
Msg$ + "StartingLcn: " + Str(*bitmapBuffer\StartingLcn\QuadPart) + #LF$
Msg$ + "BitMapSize: " + Str(*bitmapBuffer\BitmapSize\QuadPart)
MessageRequester("Info", Msg$)
EndIf
FreeMemory(*bitmapBuffer)
EndIf
CloseHandle_(hVolume)
EndIf
In front of the real data is the Starting LCN and the BitMap size.
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 4:41 pm
by Olli
Very good subject, very good questions, and very good answers.
Thanks to you two,
firace and
infratec. I cannot test it actually, but just the name of "cluster" makes me remember the hundreds hours I spent more than twenty years ago, to format and repair freely harddisks. Imagine the start of this very strange session, as the children of my time were playing "PSX" or football outdoor : a message I discovered on a stick on a side of a harddisk in a garbage, just this << 11 megabytes Execute C800:0005 >> !
When I had only 3 floppy disks of 1.44MB, 11 megabytes was the paradise ! I did not remember if it was a seagate (ST), but I read the "cluster" word, for the first time on its stick.
It was noisy like a vacuum cleaner, took about twenty seconds to initialize in a din, and was so bulky, but I loved this first hard drive! Thank you so, just to read a so interesting subject !
Without computer, I cannot give a lot, to complete your work, certainly less than you already know :
Code: Select all
Structure bit32
i.L[0]
EndStructure
Structure bit64
i.q[0]
EndStructure
Procedure bit32GetBit(*this.bit32, i)
ProcedureReturn *this\i[i >> 5] >> (i & 31) & 1
EndProcedure
Procedure bit64GetBit(*this.bit64, i)
ProcedureReturn *this\i[i >> 6] >> (i & 63) & 1
EndProcedure
Here, is a linear bit reader (from long or from quad). But I am even not sure it is okay, depending of the endianness of the API...
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 5:44 pm
by firace
Thanks again!

Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 9:23 pm
by tester
infratec wrote: Sun Sep 18, 2022 3:37 pm
A bit more extended:
Code: Select all
EnableExplicit
#IOCTL_STORAGE_READ_CAPACITY = $2D5140
#FSCTL_GET_VOLUME_BITMAP = $0009006F
Structure STORAGE_READ_CAPACITY Align #PB_Structure_AlignC
Version.l
Size.l
BlockLength.l
NumberOfBlocks.LARGE_INTEGER
DiskLength.LARGE_INTEGER
EndStructure
Structure STARTING_VCN_INPUT_BUFFER Align #PB_Structure_AlignC
StartingVcn.LARGE_INTEGER
EndStructure
Structure VOLUME_BITMAP_BUFFER Align #PB_Structure_AlignC
StartingLcn.LARGE_INTEGER
BitmapSize.LARGE_INTEGER
Buffer.a[0]
EndStructure
Define.i hVolume, Result, LastError
Define.q startLcn, bytesReturned
Define *bitmapBuffer.VOLUME_BITMAP_BUFFER
Define StorageReadCapacity.STORAGE_READ_CAPACITY
Define Msg$
hVolume = CreateFile_ ("\\.\c:", #GENERIC_READ, #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, 0, #Null)
If hVolume
Result = DeviceIoControl_(hVolume, #IOCTL_STORAGE_READ_CAPACITY, #Null, 0, @StorageReadCapacity, SizeOf(STORAGE_READ_CAPACITY), @bytesReturned, #Null)
LastError = GetLastError_()
If LastError
MessageRequester("Last Error", Str(LastError) + " (" + Hex(LastError) + ") " + Str(bytesReturned))
Else
Msg$ = "Bytes returned: " + Str(bytesReturned) + #LF$
Msg$ + "Size: " + Str(StorageReadCapacity\Size) + #LF$
Msg$ + "BlockLength: " + Str(StorageReadCapacity\BlockLength) + #LF$
Msg$ + "NumberOfBlocks: " + Str(StorageReadCapacity\NumberOfBlocks\QuadPart) + #LF$
Msg$ + "DiskLength: " + Str(StorageReadCapacity\DiskLength\QuadPart)
MessageRequester("Info", Msg$)
EndIf
*bitmapBuffer = AllocateMemory(StorageReadCapacity\DiskLength\QuadPart / 4096 / 8)
If *bitmapBuffer
Result = DeviceIoControl_(hVolume, #FSCTL_GET_VOLUME_BITMAP, @startLcn, SizeOf(startLcn), *bitmapBuffer, MemorySize(*bitmapBuffer), @bytesReturned, #Null)
LastError = GetLastError_()
If LastError
MessageRequester("Last Error", Str(LastError) + " (" + Hex(LastError) + ") " + Str(bytesReturned))
Else
Msg$ = "Bytes returned: " + Str(bytesReturned) + #LF$
Msg$ + "StartingLcn: " + Str(*bitmapBuffer\StartingLcn\QuadPart) + #LF$
Msg$ + "BitMapSize: " + Str(*bitmapBuffer\BitmapSize\QuadPart)
MessageRequester("Info", Msg$)
EndIf
FreeMemory(*bitmapBuffer)
EndIf
CloseHandle_(hVolume)
EndIf
In front of the real data is the Starting LCN and the BitMap size.
; PB 6.0 LTS (x86) & (x64) ASM Backend
; OK
; PB 6.0 LTS (x86) & (x64) C Backend:
; Error: Negative DiskLength (and the NumberOfBlocks also not correct)
The disk length is determined correctly if I change the structure.:
Code: Select all
Structure STORAGE_READ_CAPACITY Align #PB_Structure_AlignC
Version.l
Size.l
BlockLength.l
NumberOfBlocks.q
DiskLength.q
EndStructure
The size of the disk being checked is 1000204886016 bytes.
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Sun Sep 18, 2022 11:42 pm
by Olli
My apologize, it was a Western Digital... 0.000011 terabytes. And it is Microsoft DBLSPACE which has killed my vacuum cleaner... I had been too greedy... It had fins like moped engines...
Re: DeviceIoControl API call with FSCTL_GET_VOLUME_BITMAP
Posted: Mon Sep 19, 2022 2:55 pm
by Olli
I was typing the extended version of infratec, when I stopped on front of "4096"...
On one level we have 512, and on a second level we habe 4096 : does this mean, there are two allocating table ?