Page 1 of 2

Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 1:39 pm
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

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 1:56 pm
by Thorium
Does it need admin privilegs?
Because it don't work on my system: Vista 64

BytesRet = 0

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 2:03 pm
by rsts
same on win 7 64 bit; PB4.4b3

cheers

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 2:19 pm
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?

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 2:32 pm
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

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 2:47 pm
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.

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 2:57 pm
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!

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 3:10 pm
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

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 5:14 pm
by SFSxOI
doesn't return correct information for RAID0 configurations

Re: Get partitions of a hard disk drive

Posted: Sun Sep 20, 2009 6:44 pm
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:

Re: Get partitions of a hard disk drive

Posted: Mon Sep 21, 2009 2:31 am
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????

Re: Get partitions of a hard disk drive

Posted: Mon Sep 21, 2009 9:20 am
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.

Re: Get partitions of a hard disk drive

Posted: Mon Sep 21, 2009 12:13 pm
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.

Re: Get partitions of a hard disk drive

Posted: Wed Sep 23, 2009 10:13 am
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

Re: Get partitions of a hard disk drive

Posted: Wed Sep 23, 2009 2:39 pm
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.