Get partitions of a hard disk drive

Share your advanced PureBasic knowledge/code with the community.
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Get partitions of a hard disk drive

Post by doctorized »

I tried to find a way to get the number of partitions of my hard drives. After a search here, in this forum, I found nothing.
So, gathering many info, I wrote the following code:

Code: Select all

Structure PARTITION_INFORMATION
    StartingOffset.q
    PartitionLength.q
    HiddenSectors.l
    PartitionNumber.l
    PartitionType.b
    BootIndicator.b
    RecognizedPartition.b
    RewritePartition.b
    dummy.l
EndStructure

Structure DRIVE_LAYOUT_INFORMATION 
   PartitionCount.l
   Signature.l
   PartitionEntry.PARTITION_INFORMATION[50]
EndStructure
   
Procedure.s GetPartitionType(type.b)
Select type
	Case 0
		ProcedureReturn "Unused"
	Case 1
		ProcedureReturn "12-bit FAT"
	Case 2, 3
		ProcedureReturn "Xenix"
	Case 4
		ProcedureReturn "16-bit FAT"
	Case 5
		ProcedureReturn "Extended"
	Case 6
		ProcedureReturn "Huge partition MS-DOS V4"
	Case 7
		ProcedureReturn "Installable File System (NTFS/HPFS/FAT64)"
	Case 8
		ProcedureReturn "OS/2 (v1.0-1.3 only)/AIX boot partition/Commodore DOS/SplitDrive/DELL partition spanning multiple drives/QNX 1.x and 2.x (qny)"
	Case 9
		ProcedureReturn "AIX data partition/Coherent filesystem/QNX 1.x and 2.x (qnz)"
	Case $A
		ProcedureReturn "OS/2 Boot Manager/OPUS/Coherent swap"
	Case $B
		ProcedureReturn "FAT32"
	Case $C
		ProcedureReturn "FAT32 using extended int13 services"
	Case $E
		ProcedureReturn "Win95 partition using extended int13 services"
	Case $F
		ProcedureReturn "Extended using extended int13 services"
	Case $41
		ProcedureReturn "PowerPC Reference Platform (PReP) Boot Partition"
	Case $42
		ProcedureReturn "Logical Disk Manager partition"
	Case $63
		ProcedureReturn "Unix"
	Case $C0
		ProcedureReturn "NTFT uses high order bits"
	Case $80
		ProcedureReturn "NTFT"
EndSelect
EndProcedure

IOCTL_DISK_GET_DRIVE_LAYOUT.l = 475148
aa.DRIVE_LAYOUT_INFORMATION
BytesRet.l:tmp.l
For ii=0 To 49
	BytesRet = 0: tmp = 0
	hdh.l = CreateFile_("\\.\PhysicalDrive" + Str(ii),#GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE,0, #OPEN_EXISTING, 0, 0)
	DeviceIoControl_(hdh,IOCTL_DISK_GET_DRIVE_LAYOUT, #Null,0,@aa, SizeOf(DRIVE_LAYOUT_INFORMATION), @BytesRet,0)
	
	If BytesRet > 0
		Debug "disk #" + Str(ii)
		Debug "==============="
		For i=0 To aa\PartitionCount-1
		  If aa\PartitionEntry[i]\RecognizedPartition = 1
		  	 tmp + 1
		    Debug "Partition #" + Str(tmp) + "  :  " + GetPartitionType(aa\PartitionEntry[i]\PartitionType) + "  , length  =  " + Str(aa\PartitionEntry[i]\PartitionLength) + " bytes"
		  EndIf
		Next
		Debug ""
	EndIf
Next
Thorium
Addict
Addict
Posts: 1271
Joined: Sat Aug 15, 2009 6:59 pm

Re: Get partitions of a hard disk drive

Post by Thorium »

Does it need admin privilegs?
Because it don't work on my system: Vista 64

BytesRet = 0
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Get partitions of a hard disk drive

Post by rsts »

same on win 7 64 bit; PB4.4b3

cheers
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get partitions of a hard disk drive

Post by doctorized »

According to Microsoft, the caller must have administrative privileges for CreateFile to succeed on a hard disk drive.
Can anyone find a way to bypass it?
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Get partitions of a hard disk drive

Post by rsts »

Running with admin, I get a command window, which ends too quickly to read, followed by
---------------------------
PureBasic Debugger
---------------------------
The debugged executable quit unexpectedly.
---------------------------
OK
---------------------------
No debug output.

OK - problems debugging - too much output- replaced debug with messagerequester and works fine.

Nice :)

cheers
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get partitions of a hard disk drive

Post by doctorized »

rsts wrote:OK - problems debugging - too much output- replaced debug with messagerequester and works fine.
I suppose you are using console debugger. This one shows nothing. I use the integrated IDE debugger and a debugging window
pops up showing the info. The use of MessageRequester is the only solution for this kind of problems, as we do not use the "Debug"
command in our apps. I used "Debug" beacause I only wanted to show the way to take the data, not to show how to handle them, this
lies on everyone's needs.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Get partitions of a hard disk drive

Post by PB »

> According to Microsoft, the caller must have administrative privileges for CreateFile to succeed on a hard disk drive.

What? No way. None of our apps would work on limited accounts if it did!
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Get partitions of a hard disk drive

Post by rsts »

PB wrote:> According to Microsoft, the caller must have administrative privileges for CreateFile to succeed on a hard disk drive.

What? No way. None of our apps would work on limited accounts if it did!
Appears this use may require admin-

Direct access to the disk or to a volume is restricted. For more information, see "Changes to the file system and to the storage stack to restrict direct disk access and direct volume access in Windows Vista and in Windows Server 2008" in the Help and Support Knowledge Base at http://support.microsoft.com/kb/942448.

http://msdn.microsoft.com/en-us/library ... S.85).aspx

"The following requirements must be met for such a call to succeed:

* The caller must have administrative privileges. For more information, see Running with Special Privileges."

BTW - works fine with admin.

cheers
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Get partitions of a hard disk drive

Post by SFSxOI »

doesn't return correct information for RAID0 configurations
User avatar
flaith
Enthusiast
Enthusiast
Posts: 704
Joined: Mon Apr 25, 2005 9:28 pm
Location: $300:20 58 FC 60 - Rennes
Contact:

Re: Get partitions of a hard disk drive

Post by flaith »

Thanks for the code, i needed it :D

i just modified (and added) the procedure GetPartitionType:

Code: Select all

Procedure.s GetPartitionType(type.b)
  Select type & $ff
    Case 0
        ProcedureReturn "Unused"
    Case 1
        ProcedureReturn "12-bit FAT"
    Case 2, 3
        ProcedureReturn "Xenix"
    Case 4
        ProcedureReturn "16-bit FAT"
    Case 5
        ProcedureReturn "Extended"
    Case 6
        ProcedureReturn "Huge partition MS-DOS V4"
    Case 7
        ProcedureReturn "Installable File System (NTFS/HPFS/FAT64)"
    Case 8
        ProcedureReturn "OS/2 (v1.0-1.3 only)/AIX boot partition/Commodore DOS/SplitDrive/DELL partition spanning multiple drives/QNX 1.x and 2.x (qny)"
    Case 9
        ProcedureReturn "AIX data partition/Coherent filesystem/QNX 1.x and 2.x (qnz)"
    Case $A
        ProcedureReturn "OS/2 Boot Manager/OPUS/Coherent swap"
    Case $B
        ProcedureReturn "FAT32"
    Case $C
        ProcedureReturn "FAT32 using extended int13 services"
    Case $E
        ProcedureReturn "Win95 partition using extended int13 services"
    Case $F
        ProcedureReturn "Extended using extended int13 services"
    Case $41
        ProcedureReturn "PowerPC Reference Platform (PReP) Boot Partition"
    Case $42
        ProcedureReturn "Logical Disk Manager partition"
    Case $63
        ProcedureReturn "Unix"
    Case $C0
        ProcedureReturn "NTFT uses high order bits"
    Case $80
        ProcedureReturn "NTFT"
    Case $82
        ProcedureReturn "Linux Swap"
    Case $83
        ProcedureReturn "Linux native partition"
    Case $85
        ProcedureReturn "Linux extended partition"
    Default
        ProcedureReturn "$"+Hex(type, #PB_Byte)
  EndSelect
EndProcedure
Added Linux cause i have the ext3 drivers for windows installed :wink:
“Fear is a reaction. Courage is a decision.” - WC
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4326
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Re: Get partitions of a hard disk drive

Post by Rook Zimbabwe »

OK so once you have it...

How do you delete a partition? (I plan on making a secure delete application!) :mrgreen:

ALSO: Isn't NTFT supposed to be NTFS????
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get partitions of a hard disk drive

Post by doctorized »

Rook Zimbabwe wrote:Isn't NTFT supposed to be NTFS????
No, "A NTFT Patition is different to NTFS file system", as I saw at:
http://social.msdn.microsoft.com/Forums ... f42cdf09b0

Delete Partition? You gave me idea to search more!! If I find something, I'll tell.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Get partitions of a hard disk drive

Post by SFSxOI »

In Windows a NTFT partition is not really anything, not really a partition. Its just basically a value intended to be OR'ed with other values in the table at > http://msdn.microsoft.com/en-us/library ... S.85).aspx. People try to treat it as a seperate partition in their code, I think because of the way its presented in the MSDN without explaination, but its not really a partition all by its self. I ran into this myself a while back and I asked one of the Microsoft consultants we have here where I work, he chuckled a little and said it wasn't really anything (and then told me the above). It has to be logically OR'd with the other values in the table. PARTITION_NTFT is for non-striped (RAID) drives like IDE or SATA drives for example, VALID_NTFT is for striped (RAID) mirrored drive configurations - Which might explain why the above code presented doesn't get the correct information for RAID0 drives - because the correct value isn't OR'ed maybe (dunno as i haven't played with it yet) ? In the presented code this;

Code: Select all

Case $C0
      ProcedureReturn "NTFT uses high order bits" ; <<<< for striped (RAID) mirrored configurations
   Case $80
      ProcedureReturn "NTFT" ; <<<< for non-striped configurations
WMI returns the correct format without resorting to this or creating files, I posted some code using srods COmate in the tricks and tips previously for computer information, part of that contains getting the drive information which includes parameters of the drive including the file system, if it helps anyone.

One simple way to "secure" delete a partition is to format the partition first then overwrite with random 1's and 0's then delete the mount point with the 'DeleteVolumeMountPoint()' API. This is for general purpose everyday plain old 'secure delete' but its not for really-really-really secure purposes which I won't go into here as there is a thread in the Off Topic that discusses this aspect. There are faster ways, but the general rule of thumb in terms of infosec is the faster a delete is the less secure it is although thats not always true in only about 10% of the cases but it depends on how its done too. (NOTE: I edited this part of this post because I got it backwards, temporary lack of brain power and not enough coffee, if you read it previously what I wrote previously was backwards so do it as written now is correct for the general purpose secure delete.)

Ok, I think i said all this right now. Don't kill me if I didn't :), i'm going off memory as I don't have the information with me right now.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Re: Get partitions of a hard disk drive

Post by Joakim Christiansen »

Sweet! :D

I made some tweaks to it:

In the GetPartitionType procedure I changed Select type to Select type & $FF to make it work with unsigned hex values.
I also added Default: ProcedureReturn "Unknown ($"+byteToHex(type)+")"

Code: Select all

Procedure.s byteToHex(byte.b)
  ProcedureReturn RSet(Hex(PeekB(@byte),#PB_Byte),2,"0")
EndProcedure
I also removed any "write" stuff from the API to open the file:

Code: Select all

hdh = CreateFile_("\\.\PhysicalDrive"+Str(ii),#GENERIC_READ,#FILE_SHARE_READ,0,#OPEN_EXISTING,0,0)
So maybe this helps with the admin privileges issue (haven't tested on Vista yet...). Edit: Nah, didn't help. Seems accessing "PhysicalDrive" always need admin priv.

And in the debug output I also formatted the size into KB, MB and GB...

Code: Select all

Debug "Partition #"+Str(tmp)+" - "+GetPartitionType(aa\PartitionEntry[i]\PartitionType)+" - "+SizeString(aa\PartitionEntry[i]\PartitionLength)

Code: Select all

Procedure.s SizeString(Bytes.q)
  Protected Result$, KB.f = Bytes / 1024, Sign$
  
  If KB < 1
    Result$ = Str(Bytes): Sign$ = " B"
  ElseIf KB < 1000
    Result$ = StrF(KB,1): Sign$ = " KB"
  ElseIf KB < 1000000
    Result$ = StrF(KB/1000,1): Sign$ = " MB"
  Else
    Result$ = StrF(KB/1000000,1): Sign$ = " GB"
  EndIf
  
  If Len(StringField(Result$,1,".")) > 1
    Result$ = StrF(ValF(Result$),0)
  EndIf
  
  ProcedureReturn Result$+Sign$
EndProcedure
For more info on partition ID's I found this site btw:
http://www.win.tue.nl/~aeb/partitions/p ... pes-1.html
But I guess we better use it in combination with the GUIDS (how?).
http://en.wikipedia.org/wiki/GUID_Partition_Table

Code with my changes:

Code: Select all

EnableExplicit

Structure PARTITION_INFORMATION
    StartingOffset.q
    PartitionLength.q
    HiddenSectors.l
    PartitionNumber.l
    PartitionType.b
    BootIndicator.b
    RecognizedPartition.b
    RewritePartition.b
    dummy.l
EndStructure

Structure DRIVE_LAYOUT_INFORMATION
   PartitionCount.l
   Signature.l
   PartitionEntry.PARTITION_INFORMATION[50]
EndStructure

Procedure.s byteToHex(byte.b)
  ProcedureReturn RSet(Hex(PeekB(@byte),#PB_Byte),2,"0")
EndProcedure

Procedure.s GetPartitionType(type.b)
  ;More here: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
  Select type & $FF ;make it unsigned
     Case $0
        ProcedureReturn "Unused"
     Case $01
        ProcedureReturn "12-bit FAT"
     Case $02, $03
        ProcedureReturn "Xenix"
     Case $04
        ProcedureReturn "16-bit FAT"
     Case $05
        ProcedureReturn "Extended"
     Case $06
        ProcedureReturn "Huge partition MS-DOS V4"
     Case $07
        ProcedureReturn "Installable File System (NTFS/HPFS/FAT64)"
     Case $08
        ProcedureReturn "OS/2 (v1.0-1.3 only)/AIX boot partition/Commodore DOS/SplitDrive/DELL partition spanning multiple drives/QNX 1.x and 2.x (qny)"
     Case $09
        ProcedureReturn "AIX data partition/Coherent filesystem/QNX 1.x and 2.x (qnz)"
     Case $0A
        ProcedureReturn "OS/2 Boot Manager/OPUS/Coherent swap"
     Case $0B
        ProcedureReturn "FAT32"
     Case $0C
        ProcedureReturn "FAT32 using extended int13 services"
     Case $0E
        ProcedureReturn "Win95 partition using extended int13 services"
     Case $0F
        ProcedureReturn "Extended using extended int13 services"
     Case $41
        ProcedureReturn "PowerPC Reference Platform (PReP) Boot Partition"
     Case $42
        ProcedureReturn "Logical Disk Manager partition"
     Case $63
        ProcedureReturn "Unix"
     Case $C0
        ProcedureReturn "NTFT uses high order bits"
     Case $80
        ProcedureReturn "NTFT"
     Case $AF
       ProcedureReturn "HFS+ (Mac OS)"
     Case $83
       ProcedureReturn "Linux"
     Case $82
       ProcedureReturn "Linux Swap"
     Default
       ProcedureReturn "Unknown ($"+byteToHex(type)+")"
  EndSelect
EndProcedure

Procedure.s SizeString(Bytes.q)
  Protected Result$, KB.f = Bytes / 1024, Sign$
  
  If KB < 1
    Result$ = Str(Bytes): Sign$ = " B"
  ElseIf KB < 1000
    Result$ = StrF(KB,1): Sign$ = " KB"
  ElseIf KB < 1000000
    Result$ = StrF(KB/1000,1): Sign$ = " MB"
  Else
    Result$ = StrF(KB/1000000,1): Sign$ = " GB"
  EndIf
  
  If Len(StringField(Result$,1,".")) > 1
    Result$ = StrF(ValF(Result$),0)
  EndIf
  
  ProcedureReturn Result$+Sign$
EndProcedure

Define IOCTL_DISK_GET_DRIVE_LAYOUT.l = 475148
Define aa.DRIVE_LAYOUT_INFORMATION
Define BytesRet, tmp
Define ii, i, hdh

For ii=0 To 49
   BytesRet = 0: tmp = 0
   hdh = CreateFile_("\\.\PhysicalDrive" + Str(ii),#GENERIC_READ, #FILE_SHARE_READ ,0, #OPEN_EXISTING, 0, 0)
   DeviceIoControl_(hdh,IOCTL_DISK_GET_DRIVE_LAYOUT, #Null,0,@aa, SizeOf(DRIVE_LAYOUT_INFORMATION), @BytesRet,0)
   
   If BytesRet > 0
      Debug "Disk #" + Str(ii)
      Debug "==============="
      For i=0 To aa\PartitionCount-1
        If aa\PartitionEntry[i]\RecognizedPartition = 1
            tmp + 1
          Debug "Partition #"+Str(tmp)+" - "+GetPartitionType(aa\PartitionEntry[i]\PartitionType)+" - "+SizeString(aa\PartitionEntry[i]\PartitionLength)
        EndIf
      Next
      Debug ""
   EndIf
Next
I like logic, hence I dislike humans but love computers.
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get partitions of a hard disk drive

Post by doctorized »

Joakim Christiansen wrote: But I guess we better use it in combination with the GUIDS (how?).
http://en.wikipedia.org/wiki/GUID_Partition_Table
I use this code to read sectors:

Code: Select all

StartingLogicalSector.l=0; Set the starting sector
NumberOfSectors.l=3; Set the number of sectors to be read.
Dim buffer.b(512*NumberOfSectors)

hdh.l = CreateFile_("\\.\C:",#GENERIC_READ, #FILE_SHARE_READ, 0, #OPEN_EXISTING, 0, 0)
SetFilePointer_(hdh, (StartingLogicalSector*512), #Null, 0); I use 512 because every sector should have 512 bytes. In some cases, like floppy disks, we have 1024bytes/sector.
ReadFile_(hdh, @buffer(), 512*NumberOfSectors, @bytesread.l, #Null)
CloseHandle_(hdh)

CreateFile(0,"c:\sector.txt")
For i=0 To bytesread-1
	WriteByte(0,buffer(i))
Next
CloseFile(0)
Debug "OK"; let us know when you finished.
I did a small check but non of the GUIDs provided by wikipedia is found in the third sector (sector 2 starting from 0) of my partitions.
Post Reply