Error when count raw partitions (unallocated space)

Everything else that doesn't fall into one of the other PB categories.
hdt888
User
User
Posts: 47
Joined: Sun Jul 07, 2024 8:42 am

Error when count raw partitions (unallocated space)

Post by hdt888 »

I'm querying for allocated unallocated partitions, but am having problems with structural errors.
Please help me.
Thank you.

Code: Select all

#IOCTL_DISK_GET_DRIVE_LAYOUT = $7400c    ; HEX
#IOCTL_DISK_GET_DRIVE_LAYOUT_EX = $70050 ; HEX

Procedure.i CountRawPartitionsByIndex(index.i)
  Protected lpFileName.s = "\\.\PhysicalDrive" + Str(index)
  
  Protected hDevice.i
  Protected dwBytesReturned
  Protected.b lpOutBuffer
  Protected PartitionStyle.i

  ; Open the physical drive
  hDevice = CreateFile_(lpFileName, #FILE_READ_ATTRIBUTES, #FILE_SHARE_READ | #FILE_SHARE_WRITE, 0, #OPEN_EXISTING, 0, 0)
  
  If hDevice = #INVALID_HANDLE_VALUE
    Debug "Failed to open device!"
    ProcedureReturn -1
  EndIf
  
  ; Determine partition style (MBR or GPT)
  If DeviceIoControl_(hDevice, #IOCTL_DISK_GET_DRIVE_LAYOUT, 0, 0, @lpOutBuffer, SizeOf(lpOutBuffer), @dwBytesReturned, 0)
    PartitionStyle = 0
  ElseIf DeviceIoControl_(hDevice, #IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 0, 0, @lpOutBuffer, SizeOf(lpOutBuffer), @dwBytesReturned, 0)
    PartitionStyle = 1
  Else
    Debug "Failed to get partition layout!"
    CloseHandle_(hDevice)
    ProcedureReturn -1
  EndIf
  
  ; Extract partition information based on partition style
  If PartitionStyle = 0
    ; MBR partition style
    Define pDriveLayout.p = lpOutBuffer
    Define pPartitionEntry.p = @pDriveLayout\PartitionEntry[0]
    
    ; Count raw partitions (unallocated space)
    Define RawPartitionCount.i = 0
    For i = 0 To 3
      If pPartitionEntry[i]\PartitionType = #PARTITION_ENTRY_UNUSED
        Inc(RawPartitionCount)
      EndIf
    Next
    
  ElseIf PartitionStyle = 1
    ; GPT partition style
    Define pDriveLayoutEx.p = lpOutBuffer
    Define pPartitionEntry.p = @pDriveLayoutEx\PartitionEntry[0]
    
    ; Count raw partitions (unallocated space)
    Define RawPartitionCount.i = 0
    For i = 0 To pDriveLayoutEx\PartitionCount - 1
      If pPartitionEntry[i]\PartitionType = #PARTITION_ENTRY_UNUSED
        Inc(RawPartitionCount)
      EndIf
    Next
    
  EndIf
  
  ; Close the device handle
  CloseHandle_(hDevice)
  
  ProcedureReturn RawPartitionCount
EndProcedure

Debug CountRawPartitionsByIndex(0)
PB 5.x + 6.x + Win10. Feel the ...Pure... Power.
User avatar
idle
Always Here
Always Here
Posts: 5899
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Error when count raw partitions (unallocated space)

Post by idle »

Why do you want to do this programmatically, there are built in OS tools to manage drives, so why not use them?
What will you be asking next, how to create a partition and hide it?
AZJIO
Addict
Addict
Posts: 2191
Joined: Sun May 14, 2017 1:48 am

Re: Error when count raw partitions (unallocated space)

Post by AZJIO »

For Linux I used fdisk

Code: Select all

;-  ● TOP
EnableExplicit

;- # Constants
Enumeration Gadget
	#cnv
	#LV
	#cb
	#Editor
EndEnumeration

Enumeration Menu
	#fsck
	#umount
EndEnumeration


#Window = 0
#Win1 = 1
#Menu = 0

; 	https://www.purebasic.fr/english/viewtopic.php?f=12&t=71693
XIncludeFile "RunAsAdmin.pbi"
If Not RunAsAdmin::Login()
	End
EndIf

Structure Disk2
	name.s
	uuid.s
	mountpoint.s
	fstype.s
	label.s
	size.s
	rota.s
	tran.s
EndStructure

Define tmp$, item


;- ● Global
Global NewList Drive.Disk2()
Global Children

Procedure.s GetField(Value.s)
	Protected tmp, res$
	tmp  = GetJSONMember(Children, Value)
	If tmp
		Select JSONType(tmp)
			Case #PB_JSON_Boolean
				res$ = Str(GetJSONBoolean(tmp))
			Case #PB_JSON_Null
				res$ = "-"
			Case #PB_JSON_String
				res$ = GetJSONString(tmp)
		EndSelect
	EndIf
	ProcedureReturn res$
EndProcedure



Procedure GetDriveInfo()
	Protected res$, tmp
	Protected Blockdevices, ObjectBlockdevices, hJSON, i, j, ObjectChildren, BD1Children, oTran, Tran$
	
	; получить список дисков
	tmp = RunProgram("lsblk", "-J -n -o name,UUID,MOUNTPOINT,FSTYPE,LABEL,SIZE,ROTA,TRAN -I8", "", #PB_Program_Open | #PB_Program_Read)
	res$ = Chr(13)
	If tmp
		While ProgramRunning(tmp)
			If AvailableProgramOutput(tmp)
				res$ + ReadProgramString(tmp) + Chr(13)
			EndIf
		Wend
		CloseProgram(tmp)
	EndIf
	; res$ = ReplaceString(res$, Chr(13) + "sd", Chr(13))
	res$ = Trim(res$, Chr(13))
	
	; 	Анализировать JSON и получить список дисков в Drive()
	hJSON = ParseJSON(#PB_Any, res$)
	If hJSON
		ObjectBlockdevices = GetJSONMember(JSONValue(hJSON), "blockdevices")
		If ObjectBlockdevices
			; Debug GetJSONString(ObjectBlockdevices)
			For j = 0 To JSONArraySize(ObjectBlockdevices) - 1
				Tran$ = ""
				BD1Children  = GetJSONElement(ObjectBlockdevices, j)
				ObjectChildren = GetJSONMember(BD1Children, "children")
				oTran = GetJSONMember(BD1Children, "tran")
				If oTran And JSONType(oTran) = #PB_JSON_String
					Tran$ = GetJSONString(oTran)
				EndIf
				; Debug GetJSONString(BD1Children)
				If ObjectChildren
					For i = 0 To JSONArraySize(ObjectChildren) - 1
						Children  = GetJSONElement(ObjectChildren, i)
						AddElement(Drive())
						Drive()\name = GetField("name")
						Drive()\uuid = GetField("uuid")
						Drive()\mountpoint = GetField("mountpoint")
						Drive()\fstype = GetField("fstype")
						Drive()\label = GetField("label")
						Drive()\size = GetField("size")
						Drive()\rota = GetField("rota")
						If Drive()\rota = "1"
							Drive()\rota = "hdd"
						ElseIf Drive()\rota = "0"
							Drive()\rota = "ssd"
						EndIf
						Drive()\tran = Tran$
						; Trim(Drive(), #LF$)
						; Drive() + #CR$
					Next i
				EndIf
			Next j
		EndIf
	EndIf
EndProcedure

Procedure fsch()
	Protected tmp
	tmp = RunProgram("e2fsck", "-f -y -v -C 0 /dev/" + Drive()\name, "", #PB_Program_Open | #PB_Program_Read)
	If tmp
		While ProgramRunning(tmp)
			If AvailableProgramOutput(tmp)
				AddGadgetItem(#Editor, -1, ReadProgramString(tmp))
; 				WindowEvent()
			EndIf
		Wend
		CloseProgram(tmp)
	EndIf
EndProcedure


Procedure Report()
	Protected hWnd
	DisableWindow(#Window, 1)
	
	OpenWindow(#Win1, 0, 0, 900, 600, "Check Disk", #PB_Window_SystemMenu | #PB_Window_ScreenCentered, WindowID(#Window))
	EditorGadget(#Editor, 0 , 0 , 900, 600)
	fsch()

	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_CloseWindow
				Break
		EndSelect
	ForEver

	DisableWindow(#Window, 0)
	CloseWindow(#Win1)
EndProcedure


Procedure ExeComStr(*Result.string, dev$)
	Protected NewList String$(), Len=0, tmp, *Point
	tmp = RunProgram("fdisk", "-l /dev/" + dev$, "", #PB_Program_Open | #PB_Program_Read)
	If tmp
		While ProgramRunning(tmp)
			If AvailableProgramOutput(tmp)
				; 				res$ + ReadProgramString(tmp) + Chr(10)
				; 				StrFastAdd(FS, ReadProgramString(tmp) + Chr(10))
				If AddElement(String$())
					String$() = ReadProgramString(tmp); + Chr(10)
				EndIf
			EndIf
		Wend
		
		; 		подсчитываем длину данных
		; 	   Count = ListSize(String$())
		ForEach String$()
			Len + Len(String$())
		Next
		Len+ListSize(String$()) ; добавляем число переносов строк #LF$ по количеству данных
		
		*Result\s = Space(Len)
		*Point = @*Result\s
		ForEach String$()
			CopyMemoryString(String$()+#LF$, @*Point)
		Next
		ClearList(String$())
		CloseProgram(tmp)
	EndIf
	
	; 	ProcedureReturn res$
EndProcedure

Global Text.String
GetDriveInfo()
ExeComStr(@Text, "sda")
; Debug Text\s
; MessageRequester("", Text\s)
; SetClipboardText(Text\s)

Structure Disk
	Name.s
	DiskSize.s
	DiskType.i
	DiskStart.q
	DiskEnd.q
	DiskSector.q
EndStructure

Global Size.q
Global WndW
Global SizePx.q
Global NewList Disks.Disk()



Procedure RegExp()
	Protected NbFound
	Protected Dim Result$(0)
	#RegExp = 0
	If CreateRegularExpression(#RegExp, "\A[^\r\n]+?\h\K(\d+)(?=\h[^\d]+\n)", #PB_RegularExpression_DotAll | #PB_RegularExpression_AnyNewLine)
		NbFound = ExtractRegularExpression(0, Text\s, Result$())
		If NbFound
			Size = Val(Result$(0))
		Else
			MessageRequester("", "Unable to determine size")
			ProcedureReturn 0
		EndIf
	EndIf
	FreeRegularExpression(#RegExp)
	
	ClearList(Disks())
	
	; If CreateRegularExpression(#RegExp, "/dev/sd\w(\d+)[\h*]+(\d+)\h+(\d+)\h+(\d+)")
	If CreateRegularExpression(#RegExp, "/dev/(sd\w\d+)[\h*]+(\d+)\h+(\d+)\h+(\d+)\h+([\d,]+[TGMKB])\h+([\da-f]+)")
		If ExamineRegularExpression(#RegExp, Text\s)
			While NextRegularExpressionMatch(#RegExp)
				If AddElement(Disks())
					Disks()\Name = RegularExpressionGroup(#RegExp, 1)
					Disks()\DiskStart = Val(RegularExpressionGroup(#RegExp, 2))
					Disks()\DiskEnd = Val(RegularExpressionGroup(#RegExp, 3))
					Disks()\DiskSector = Val(RegularExpressionGroup(#RegExp, 4))
					Disks()\DiskSize = RegularExpressionGroup(#RegExp, 5)
					Disks()\DiskType= Val(RegularExpressionGroup(#RegExp, 6))
				EndIf
			Wend
		EndIf
	EndIf
	FreeRegularExpression(#RegExp)
	ProcedureReturn 1
EndProcedure

Procedure Draw()
	Protected Found, bgcolor
	SizePx = Size/WndW
	ClearGadgetItems(#LV)
	If StartDrawing(CanvasOutput(#cnv))
		DrawingMode(#PB_2DDrawing_Transparent)
		Box(0, 0, WndW, 88, $3f3f3f)
		ForEach Disks()
			bgcolor = RGB(Random($FF, $99), Random($FF, $99), Random($FF, $99))
			Box(Disks()\DiskStart / SizePx, 0, Disks()\DiskSector / SizePx, 88, bgcolor)
			DrawText(Disks()\DiskStart / SizePx + 5, 30, Disks()\Name + #CRLF$ + Disks()\DiskSize, 0, #PB_2DDrawing_Transparent)
			Found = 0
			ForEach Drive()
				If Disks()\Name = Drive()\name
					Found = 1
					Break
				EndIf
			Next
			If Found
				AddGadgetItem(#LV, -1, Disks()\Name + Chr(10) + Disks()\DiskSize + Chr(10) + Disks()\DiskType +
				                       Chr(10) + Drive()\label + Chr(10) + Drive()\mountpoint + Chr(10) + Drive()\fstype + Chr(10) + Drive()\uuid)
			Else
				AddGadgetItem(#LV, -1, Disks()\Name + Chr(10) + Disks()\DiskSize + Chr(10) + Disks()\DiskType)
			EndIf
		Next
		StopDrawing()
	EndIf
EndProcedure

ExamineDesktops()
WndW = DesktopWidth(0) - 50


;-┌──GUI──┐
If OpenWindow(#Window, 0, 0, WndW + 10, 444, "HDD", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	CanvasGadget(#cnv, 5, 0, WndW, 88, #PB_Canvas_Border)
	ComboBoxGadget(#cb, 5, 400 , 90 , 30)
	AddGadgetItem(#cb, -1, "sda")
	AddGadgetItem(#cb, -1, "sdb")
	AddGadgetItem(#cb, -1, "sdc")
	AddGadgetItem(#cb, -1, "sdd")
	AddGadgetItem(#cb, -1, "sde")
	AddGadgetItem(#cb, -1, "sdf")
	ListIconGadget(#LV, 5 , 93, WndW, 300, "Disks", 50)
	AddGadgetColumn(#LV, 1, "Size", 60)
	AddGadgetColumn(#LV, 2, "Type", 50)
	AddGadgetColumn(#LV, 3, "Mark", 80)
	AddGadgetColumn(#LV, 4, "mounting", 120)
	AddGadgetColumn(#LV, 5, "fs", 50)
	AddGadgetColumn(#LV, 6, "uuid", 150)
	
	If RegExp()
		Draw()
	EndIf
	If CreatePopupMenu(#Menu)
		MenuItem(#umount, "Unmount disk")
		MenuItem(#fsck, "Check Disk")
	EndIf
	

;-┌──Loop──┐
	Repeat
		Select WaitWindowEvent()
;- ├ Gadget
			Case #PB_Event_Gadget
				Select EventGadget()
					Case #LV
						If EventType() = #PB_EventType_RightClick
							item = GetGadgetState(#LV)
							If item <> -1
								DisplayPopupMenu(#Menu, WindowID(#Window))
							EndIf
						EndIf
					Case #cb
						If EventType() = #PB_EventType_Change
							tmp$ = GetGadgetText(#cb)
							ExeComStr(@Text, tmp$)
							If RegExp()
								Draw()
							EndIf
						EndIf
				EndSelect
				
;- ├ Menu
			Case #PB_Event_Menu
				Select EventMenu()
					Case #umount
						item = GetGadgetState(#LV)
						If item <> -1
							tmp$ = GetGadgetItemText(#LV, item, 0)
							ForEach Drive()
								If tmp$ = Drive()\name
									RunProgram("umount", "-l " + Drive()\mountpoint, "")
									Break
								EndIf
							Next
						EndIf
					Case #fsck
						item = GetGadgetState(#LV)
						If item <> -1
							tmp$ = GetGadgetItemText(#LV, item, 0)
							ForEach Drive()
								If tmp$ = Drive()\name
									Report()
; 									RunProgram("e2fsck", "-f -y -v -C 0 /dev/" + Drive()\name, "")
; 									RunProgram("bash", "e2fsck -f -y -v -C 0 /dev/" + Drive()\name, "")
; 									RunProgram("bash", "-c " + #DQUOTE$ + "e2fsck -f -y -v -C 0 /dev/" + Drive()\name + #DQUOTE$, "")
									Break
								EndIf
							Next
						EndIf
				EndSelect
				
			Case #PB_Event_CloseWindow
				CloseWindow(#Window)
				End
		EndSelect
	ForEver
;-└───Loop───┘
EndIf
Post Reply