Skip to content

Instantly share code, notes, and snippets.

@UserUnknownFactor
Last active March 23, 2023 08:45
Show Gist options
  • Save UserUnknownFactor/96d3d3246ce89e0c54feef3f2ee05243 to your computer and use it in GitHub Desktop.
Save UserUnknownFactor/96d3d3246ce89e0c54feef3f2ee05243 to your computer and use it in GitHub Desktop.
Python Windows utility to check what NTFS files correspond to what bad sectors on disk that showed up as failed in System Log (also corresponds to bad physical sector reads in low-level disk checking tools that use native Windows API).
import win32evtlog # requires pywin32 pre-installed (`pip install pywin32`)
import os, sys, platform, tempfile, subprocess, base64, hashlib
from struct import unpack
import ctypes
from ctypes.wintypes import HANDLE
from ctypes.wintypes import BOOL
from ctypes.wintypes import HWND
from ctypes.wintypes import DWORD
from ctypes.wintypes import ULONG
from ctypes.wintypes import USHORT
from ctypes.wintypes import LPVOID
from ctypes.wintypes import LPWSTR
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
print('This script requires Administrator privileges...')
sys.exit()
NULL = 0
HDEVINFO = ctypes.c_void_p
LPCTSTR = ctypes.c_wchar_p
PCTSTR = ctypes.c_wchar_p
PTSTR = ctypes.c_wchar_p
LPDWORD = PDWORD = ctypes.POINTER(DWORD)
LPBYTE = PBYTE = ctypes.c_void_p
ULONG_PTR = ctypes.POINTER(ULONG)
CHAR = ctypes.c_ubyte
LPOVERLAPPED = LPVOID
LPSECURITY_ATTRIBUTES = LPVOID
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 1
GENERIC_ALL = 0x10000000
OPEN_EXISTING = 3
FILE_ATTRIBUTE_NORMAL = 0x00000080
DIGCF_PRESENT = 2
DIGCF_DEVICEINTERFACE = 0x10
IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x002D1080
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E
INVALID_HANDLE_VALUE = -1
ERROR_PATH_NOT_FOUND = 3
ERROR_INSUFFICIENT_BUFFER = 122
SCSI_OP_IOCTL = 0x0F
class STORAGE_DEVICE_NUMBER(ctypes.Structure):
_fields_ = [
('DeviceType', DWORD),
('DeviceNumber', DWORD),
('PartitionNumber', DWORD)
]
class GUID(ctypes.Structure):
_fields_ = [
("data1", ULONG),
("data2", USHORT),
("data3", USHORT),
("data4", CHAR * 8)
]
def __init__(self, dw=0, w1=0, w2=0, b1=0, b2=0, b3=0, b4=0, b5=0, b6=0,
b7=0, b8=0):
self.data1 = dw
self.data2 = w1
self.data3 = w2
self.data4[0] = b1
self.data4[1] = b2
self.data4[2] = b3
self.data4[3] = b4
self.data4[4] = b5
self.data4[5] = b6
self.data4[6] = b7
self.data4[7] = b8
class SP_DEVICE_INTERFACE_DATA(ctypes.Structure):
_fields_ = [
('cbSize', DWORD),
('InterfaceClassGuid', GUID),
('Flags', DWORD),
('Reserved', ULONG_PTR),
]
def __str__(self):
return "InterfaceClassGuid:%s Flags:%s" % (self.InterfaceClassGuid, self.Flags)
PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p
PSP_DEVICE_INTERFACE_DATA = ctypes.POINTER(SP_DEVICE_INTERFACE_DATA)
class SP_DEVICE_INTERFACE_DETAIL_DATA_W(ctypes.Structure):
_fields_ = [
('cbSize', DWORD),
('DevicePath', CHAR * 2)
]
class SP_DEVINFO_DATA(ctypes.Structure):
_fields_ = [
('cbSize', DWORD),
('ClassGuid', GUID),
('DevInst', DWORD),
('Reserved', ULONG_PTR),
]
def __str__(self):
return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst)
PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA)
def ValidHandle(value, func, arguments):
if value == 0:
raise ctypes.WinError()
return value
GUID_DEVINTERFACE_DISK = GUID(0x53f56307, 0xb6bf, 0x11d0, 0x94, 0xf2,
0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b)
GUID_DEVINTERFACE_VOLUME = GUID(0x53F5630D, 0xB6BF, 0x11D0, 0x94, 0xF2,
0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B)
setupapi = ctypes.windll.LoadLibrary("setupapi")
kernel32 = ctypes.windll.kernel32
SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsW
SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD]
SetupDiGetClassDevs.restype = HDEVINFO
SetupDiGetClassDevs.errcheck = ValidHandle
SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo
SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA]
SetupDiEnumDeviceInfo.restype = BOOL
SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyW
SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD]
SetupDiGetDeviceRegistryProperty.restype = BOOL
SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList
SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO]
SetupDiDestroyDeviceInfoList.restype = BOOL
def _DeviceIoControl(devhandle, ioctl, inbuf, inbufsiz, outbuf, outbufsiz):
DeviceIoControl_Fn = kernel32.DeviceIoControl
DeviceIoControl_Fn.argtypes = [
HANDLE, # _In_ HANDLE hDevice
DWORD, # _In_ DWORD dwIoControlCode
LPVOID, # _In_opt_ LPVOID lpInBuffer
DWORD, # _In_ DWORD nInBufferSize
LPVOID, # _Out_opt_ LPVOID lpOutBuffer
DWORD, # _In_ DWORD nOutBufferSize
LPDWORD, # _Out_opt_ LPDWORD lpBytesReturned
LPOVERLAPPED] # _Inout_opt_ LPOVERLAPPED lpOverlapped
DeviceIoControl_Fn.restype = BOOL
# allocate a DWORD, and take its reference
dwBytesReturned = DWORD(0)
lpBytesReturned = ctypes.byref(dwBytesReturned)
status = DeviceIoControl_Fn(devhandle,
ioctl,
inbuf,
inbufsiz,
outbuf,
outbufsiz,
lpBytesReturned,
None)
return status, dwBytesReturned
def _CreateFile(filename, access, mode, creation, flags):
CreateFile_Fn = kernel32.CreateFileW
CreateFile_Fn.argtypes = [
LPWSTR, # _In_ LPCTSTR lpFileName
DWORD, # _In_ DWORD dwDesiredAccess
DWORD, # _In_ DWORD dwShareMode
LPSECURITY_ATTRIBUTES, # _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
DWORD, # _In_ DWORD dwCreationDisposition
DWORD, # _In_ DWORD dwFlagsAndAttributes
HANDLE] # _In_opt_ HANDLE hTemplateFile
CreateFile_Fn.restype = HANDLE
return HANDLE(CreateFile_Fn(filename, access, mode, NULL, creation, flags, NULL))
class DeviceIoControl(object):
def __init__(self, path):
self.path = path
self._fhandle = None
def _validate_handle(self):
if self._fhandle is None:
raise Exception('No file handle')
if self._fhandle.value == HANDLE(INVALID_HANDLE_VALUE).value:
ecode = kernel32.GetLastError()
if ecode == ERROR_PATH_NOT_FOUND:
ecode = 'ERROR_PATH_NOT_FOUND'
raise Exception(f'Failed to open {self.path}. Error: {ecode}')
def ioctl(self, ctl, inbuf, inbufsiz, outbuf, outbufsiz):
res = (None, None)
self._validate_handle()
res = _DeviceIoControl(self._fhandle, ctl, inbuf, inbufsiz, outbuf, outbufsiz)
return res
def __enter__(self):
self._fhandle = _CreateFile(self.path, FILE_SHARE_READ, 0, OPEN_EXISTING, 0)
self._validate_handle()
return self
def __exit__(self, typ, val, tb):
try:
self._validate_handle()
except Exception:
pass
else:
kernel32.CloseHandle(self._fhandle)
map_disks = dict()
def get_device_for_nfi(winpath):
global map_disks
found = None
if winpath in map_disks:
return map_disks[winpath]
disk_guid = GUID_DEVINTERFACE_DISK
g_hdi = SetupDiGetClassDevs(ctypes.byref(disk_guid), None, None,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)
if g_hdi == INVALID_HANDLE_VALUE:
raise Exception
try:
szHardwareID = ctypes.create_unicode_buffer(1024)
lenHardwareID = ctypes.sizeof(szHardwareID) - 1
devinfo = SP_DEVINFO_DATA()
devinfo.cbSize = ctypes.sizeof(SP_DEVINFO_DATA)
index = 0
while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)):
ret = SetupDiGetDeviceRegistryProperty(
g_hdi,
ctypes.byref(devinfo),
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
None,
ctypes.byref(szHardwareID),
lenHardwareID, None)
if not ret: continue
disk = f'\\Device\\Harddisk{index}\\DR{index}'
sdn = STORAGE_DEVICE_NUMBER()
try:
with DeviceIoControl('\\\\.\\GLOBALROOT' + szHardwareID.value) as dev:
status, _ = dev.ioctl(IOCTL_STORAGE_GET_DEVICE_NUMBER, None, 0,
ctypes.pointer(sdn), ctypes.sizeof(STORAGE_DEVICE_NUMBER))
# not always working?
if status:
disk = f'\\Device\\Harddisk{sdn.DeviceNumber}\\DR{sdn.DeviceNumber}'
except:
print(f'Error detecting harddisk device {szHardwareID.value} number...')
index += 1
if winpath == disk:
found = szHardwareID.value
map_disks[winpath] = found
break
except:
print(f'Error detecting device ID for {winpath}...')
finally:
SetupDiDestroyDeviceInfoList(g_hdi)
return found
def call_with_output(command):
success = False
output = None
try:
output = subprocess.check_output(command).decode()
success = True
except subprocess.CalledProcessError as e:
output = e.output.decode()
except Exception as e:
#output = str(e)
pass
return(success, output)
def get_disk_errors(tolerance=200):
server = platform.node() # name of the current computer to get event logs
logtype = 'System' # 'Application' # 'Security'
hlog = win32evtlog.OpenEventLog(server, logtype)
flags = win32evtlog.EVENTLOG_FORWARDS_READ|win32evtlog.EVENTLOG_SEQUENTIAL_READ
total = win32evtlog.GetNumberOfEventLogRecords(hlog)
error_sectors = []
sector = 0
for i in range(total): #while True:
events = win32evtlog.ReadEventLog(hlog, flags,0)
if events:
for event in events:
if event.SourceName == "disk":
data = event.StringInserts
disk = ''
sector_tmp = ''
nsectors = ''
if (event.Data and len(event.Data) > 139 and event.Data[0] != SCSI_OP_IOCTL):
sector_tmp = unpack('>L', event.Data[130:134])[0] # LBA
nsectors = unpack('>L', event.Data[134:138])[0] # length
if event.EventType == 2: #windows 8
if (len(data > 1)):
sector_tmp = int(data[1], 0)
disk = data[3]
else: # windows 10?
disk = get_device_for_nfi(data[0])
if not disk or not sector_tmp:
#print(f"{disk}/{sector_tmp}/+{nsectors}")
continue
if sector_tmp - sector > tolerance or sector_tmp < sector:
sector = sector_tmp
error_sectors.append((disk, str(sector), str(nsectors)))
win32evtlog.CloseEventLog(hlog)
return error_sectors
# nfi.exe: unofficial Microsoft's NTFS File Sector Information Utility.
nfi_exe = "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ZQAAAHMAZQBjADIAZgBpAGwAZQAuAGUAeABlAAAAAAB0ACgAAQBMAGUAZwBhAGwAQwBvAHAAeQByAGkAZwBoAHQAAABDAG8AcAB5AHIAaQBnAGgAdAAgACgAQwApACAATQBpAGMAcgBvAHMAbwBmAHQAIABDAG8AcgBwAC4AIAAxADkAOQA4AC0AMQA5ADkAOQAAAEIADQABAE8AcgBpAGcAaQBuAGEAbABGAGkAbABlAG4AYQBtAGUAAABzAGUAYwAyAGYAaQBsAGUALgBlAHgAZQAAAAAARAASAAEAUAByAG8AZAB1AGMAdABOAGEAbQBlAAAAAABNAGkAYwByAG8AcwBvAGYAdAAgAFcAaQBuAGQAbwB3AHMAAAA8AAwAAQBQAHIAbwBkAHUAYwB0AFYAZQByAHMAaQBvAG4AAAAzAC4AMAAwAC4AMgAwADkAMwAuADEAAABEAAAAAQBWAGEAcgBGAGkAbABlAEkAbgBmAG8AAAAAACQABAAAAFQAcgBhAG4AcwBsAGEAdABpAG8AbgAAAAAACQSwBAAAAAAFAAAAAQAAAA0AAABAAAAAjAAAAIwAAABsDwAAlQAAAJYAAAA0EAAALAEAAC0BAABUEQAAXAEAAHABAABgEgAA2AABAE4AVABGAFMAIABGAGkAbABlACAAUwBlAGMAdABvAHIAIABJAG4AZgBvAHIAbQBhAHQAaQBvAG4AIABVAHQAaQBsAGkAdAB5AC4ADQAKAEMAbwBwAHkAcgBpAGcAaAB0ACAAKABDACkAIABNAGkAYwByAG8AcwBvAGYAdAAgAEMAbwByAHAAbwByAGEAdABpAG8AbgAgADEAOQA5ADkALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgANAAoADQAKAAAAMAoBAEQAdQBtAHAAcwAgAGkAbgBmAG8AcgBtAGEAdABpAG8AbgAgAGEAYgBvAHUAdAAgAGEAbgAgAE4AVABGAFMAIAB2AG8AbAB1AG0AZQAsACAAYQBuAGQAIABvAHAAdABpAG8AbgBhAGwAbAB5ACAAZABlAHQAZQByAG0AaQBuAGUAcwANAAoAdwBoAGkAYwBoACAAdgBvAGwAdQBtAGUAIABhAG4AZAAgAGYAaQBsAGUAIABjAG8AbgB0AGEAaQBuAHMAIABhACAAcABhAHIAdABpAGMAdQBsAGEAcgAgAHMAZQBjAHQAbwByAC4ADQAKAA0ACgBVAHMAYQBnAGUAOgAgACUAMQAgAGQAcgBpAHYAZQAtAGwAZQB0AHQAZQByACAAWwBsAG8AZwBpAGMAYQBsAC0AcwBlAGMAdABvAHIALQBuAHUAbQBiAGUAcgBdAA0ACgANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAARAByAGkAdgBlAC0AbABlAHQAdABlAHIAIABjAGEAbgAgAGIAZQAgAGEAIABzAGkAbgBnAGwAZQAgAGMAaABhAHIAYQBjAHQAZQByACAAbwByACAAYQAgAGMAaABhAHIAYQBjAHQAZQByACAAZgBvAGwAbABvAHcAZQBkAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIABiAHkAIABhACAAYwBvAGwAbwBuACAAKABpAC4AZQAuACwAIABDACAAbwByACAAQwA6ACAAYQByAGUAIABhAGMAYwBlAHAAdABhAGIAbABlACkALgANAAoADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgAEwAbwBnAGkAYwBhAGwALQBzAGUAYwB0AG8AcgAtAG4AdQBtAGIAZQByACAAaQBzACAAYQAgAGQAZQBjAGkAbQBhAGwAIABvAHIAIAAwAHgALQBwAHIAZQBmAGkAeABlAGQAIABoAGUAeAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAbgB1AG0AYgBlAHIALAAgAHMAcABlAGMAaQBmAHkAaQBuAGcAIABhACAAcwBlAGMAdABvAHIAIABuAHUAbQBiAGUAcgAgAHIAZQBsAGEAdABpAHYAZQAgAHQAbwAgAHQAaABlACAAdgBvAGwAdQBtAGUADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHcAaABvAHMAZQAgAGQAcgBpAHYAZQAgAGwAZQB0AHQAZQByACAAaQBzACAAZwBpAHYAZQBuACAAYgB5ACAAZAByAGkAdgBlAC0AbABlAHQAdABlAHIALgAgAEkAZgAgAG4AbwB0AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIABzAHAAZQBjAGkAZgBpAGUAZAAsACAAdABoAGUAbgAgAGkAbgBmAG8AcgBtAGEAdABpAG8AbgAgAGEAYgBvAHUAdAAgAGUAdgBlAHIAeQAgAGYAaQBsAGUAIABvAG4AIAB0AGgAZQAgAHYAbwBsAHUAbQBlAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIABpAHMAIABkAHUAbQBwAGUAZAAuAA0ACgANAAoAIAAgACAAIAAgACAAIAAlADEAIABOAFQALQBkAGUAdgBpAGMAZQAtAHAAYQB0AGgAIABwAGgAeQBzAGkAYwBhAGwALQBzAGUAYwB0AG8AcgAtAG4AdQBtAGIAZQByAA0ACgANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAARABlAHQAZQByAG0AaQBuAGUAcwAgAHcAaABpAGMAaAAgAHYAbwBsAHUAbQBlACAAYQAgAGcAaQB2AGUAbgAgAHAAaAB5AHMAaQBjAGEAbAAgAHMAZQBjAHQAbwByACAAbwBuACAAYQAgAGQAcgBpAHYAZQAgAGkAcwANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdwBpAHQAaABpAG4ALAAgAGEAbgBkACAAdABoAGUAbgAgAHcAaABpAGMAaAAgAGYAaQBsAGUAIABvAG4AIAB0AGgAZQAgAHYAbwBsAHUAbQBlACAAaQB0ACAAaQBzACAAaQBuAC4ADQAKAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIABOAFQALQBkAGUAdgBpAGMAZQAtAHAAYQB0AGgAIABpAHMAIAB0AGgAZQAgAE4AVAAtAHMAdAB5AGwAZQAgAHAAYQB0AGgAIAB0AG8AIABhACAAcABoAHkAcwBpAGMAYQBsACAAZABlAHYAaQBjAGUALgANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAASQB0ACAAbQB1AHMAdAAgAG4AbwB0ACAAaQBuAGMAbAB1AGQAZQAgAGEAIABwAGEAcgB0AGkAdABpAG8AbgAgAHMAcABlAGMAaQBmAGkAYwBhAHQAaQBvAG4ALgANAAoADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgAFAAaAB5AHMAaQBjAGEAbAAtAHMAZQBjAHQAbwByAC0AbgB1AG0AYgBlAHIAIABpAHMAIABhACAAZABlAGMAaQBtAGEAbAAgAG8AcgAgADAAeAAtAHAAcgBlAGYAaQB4AGUAZAAgAGgAZQB4AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIABuAHUAbQBiAGUAcgAsACAAcwBwAGUAYwBpAGYAeQBpAG4AZwAgAGEAIABzAGUAYwB0AG8AcgAgAG4AdQBtAGIAZQByACAAcgBlAGwAYQB0AGkAdgBlACAAdABvACAAdABoAGUAIABwAGgAeQBzAGkAYwBhAGwADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgAGQAcgBpAHYAZQAgAHcAaABvAHMAZQAgAGQAZQB2AGkAYwBlACAAcABhAHQAaAAgAGkAcwAgAGcAaQB2AGUAbgAgAGIAeQAgAE4AVAAtAGQAZQB2AGkAYwBlAC0AcABhAHQAaAAuAA0ACgANAAoAIAAgACAAIAAgACAAIAAgACUAMQAgAGYAdQBsAGwALQB3AGkAbgAzADIALQBwAGEAdABoAA0ACgANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAARAB1AG0AcABzACAAaQBuAGYAbwByAG0AYQB0AGkAbwBuACAAYQBiAG8AdQB0ACAAYQAgAHAAYQByAHQAaQBjAHUAbABhAHIAIABmAGkAbABlAC4AIABmAHUAbABsAC0AdwBpAG4AMwAyAC0AcABhAHQAaAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAbQB1AHMAdAAgAHMAdABhAHIAdAAgAHcAaQB0AGgAIABhACAAZAByAGkAdgBlACAAbABlAHQAdABlAHIAIABhAG4AZAAgAGEAIABjAG8AbABvAG4ALgANAAoAAAAAAEAAAQBVAG4AYQBiAGwAZQAgAHQAbwAgAG8AcABlAG4AIABkAHIAaQB2AGUAIAAlADEAIQBjACEALgANAAoAAAB4AAEAVQBuAGEAYgBsAGUAIAB0AG8AIAByAGUAdAByAGkAZQB2AGUAIAB2AG8AbAB1AG0AZQAgAGkAbgBmAG8AcgBtAGEAdABpAG8AbgAgAGYAbwByACAAZAByAGkAdgBlACAAJQAxACEAYwAhAC4ADQAKAAAAAACcAAEARAByAGkAdgBlACAAJQAxACEAYwAhACAAaQBzACAAbgBvAHQAIABOAFQARgBTAC4AIABPAG4AbAB5ACAATgBUAEYAUwAgAGQAcgBpAHYAZQBzACAAYQByAGUAIABzAHUAcABwAG8AcgB0AGUAZAAgAGIAeQAgAHQAaABpAHMAIABwAHIAbwBnAHIAYQBtAC4ADQAKAAAAAAB4AAEASQBuAHMAdQBmAGYAaQBjAGkAZQBuAHQAIABtAGUAbQBvAHIAeQAgACgAYQAgAHIAZQBxAHUAZQBzAHQAIABmAG8AcgAgACUAMQAhAHUAIQAgAGIAeQB0AGUAcwAgAGYAYQBpAGwAZQBkACkALgANAAoAAABYAAEAVQBuAGEAYgBsAGUAIAB0AG8AIABzAGUAZQBrACAAdABvACAAcwBlAGMAdABvAHIAIAAwAHgAJQAxACEAeAAhACUAMgAhAHgAIQAuAA0ACgAAAAAAhAABAFUAbgBhAGIAbABlACAAdABvACAAcgBlAGEAZAAgACUAMwAhAHUAIQAgAHMAZQBjAHQAbwByAHMAIABzAHQAYQByAHQAaQBuAGcAIABhAHQAIABzAGUAYwB0AG8AcgAgADAAeAAlADEAIQB4ACEAJQAyACEAeAAhAC4ADQAKAAAADAABAA0ACgAAAAAAFAABACUAMQAlADAADQAKAAAAAAAwAAEAKAB1AG4AawBuAG8AdwBuAC8AdQBuAG4AYQBtAGUAZAApACUAMAANAAoAAABcAAEARgBpAGwAZQAgAG4AbwB0ACAAZgBvAHUAbgBkACAAbwByACAAdQBuAGEAYgBsAGUAIAB0AG8AIABhAGMAYwBlAHMAcwAgAGYAaQBsAGUALgANAAoAAAAAANAAAQAqACoAKgBXAGEAcgBuAGkAbgBnADoAIABWAG8AbAB1AG0AZQBzACAAbwBuACAAZAB5AG4AYQBtAGkAYwAgAGQAaQBzAGsAcwAgACgAbwB0AGgAZQByACAAdABoAGEAbgAgAHMAaQBtAHAAbABlACAAdgBvAGwAdQBtAGUAcwApAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIABhAHIAZQAgAG4AbwB0ACAAcwB1AHAAcABvAHIAdABlAGQALgANAAoADQAKAAAAAADIAAEAKgAqACoAUABoAHkAcwBpAGMAYQBsACAAcwBlAGMAdABvAHIAIAAlADEAIAAoADAAeAAlADIAKQAgAGkAcwAgAG4AbwB0ACAAaQBuACAAYQBuAHkAIABwAGEAcgB0AGkAdABpAG8AbgAgAG8AbgAgACUAMwAsAA0ACgBvAHIAIAAlADMAIABpAHMAIABuAG8AdAAgAGEAIABsAGUAZwBhAGwAIABkAGUAdgBpAGMAZQAgAG4AYQBtAGUALgANAAoAAAAAAJgAAQAqACoAKgBQAGgAeQBzAGkAYwBhAGwAIABzAGUAYwB0AG8AcgAgACUAMQAgACgAMAB4ACUAMgApACAAaQBzACAAaQBuACAAZAByAGkAdgBlACAAJQAzACEAYwAhACAAYgB1AHQAIABpAHMADQAKAG4AbwB0ACAAaQBuACAAYQBuAHkAIABmAGkAbABlAC4ADQAKAAAAiAABACoAKgAqAEwAbwBnAGkAYwBhAGwAIABzAGUAYwB0AG8AcgAgACUAMQAgACgAMAB4ACUAMgApACAAbwBuACAAZAByAGkAdgBlACAAJQAzACEAYwAhACAAaQBzACAAbgBvAHQAIABpAG4AIABhAG4AeQAgAGYAaQBsAGUALgANAAoAAAAAAKgAAQBUAGgAZQAgAG0AYQBzAHQAZQByACAAZgBpAGwAZQAgAHQAYQBiAGwAZQAgAGEAcABwAGUAYQByAHMAIAB0AG8AIABiAGUAIABkAGEAbQBhAGcAZQBkAC4AIABUAGgAZQAgAGQAaQBzAGsAIABtAGEAeQAgAGIAZQANAAoAcwBlAHYAZQByAGUAbAB5ACAAZABhAG0AYQBnAGUAZAAuAA0ACgAAAGQAAQBUAGgAZQAgAE0ARgBUACAAaQBzACAAZABhAG0AYQBnAGUAZAAgAGEAdAAgAGYAaQBsAGUAIAByAGUAYwBvAHIAZAAgAHMAZQBnAG0AZQBuAHQAIAAlADEALgANAAoAAABQAAEAcABoAHkAcwBpAGMAYQBsACAAcwBlAGMAdABvAHIAcwAgACUAMQAtACUAMgAgACgAMAB4ACUAMwAtADAAeAAlADQAKQANAAoAAAAAAIwAAQAqACoAKgBQAGgAeQBzAGkAYwBhAGwAIABzAGUAYwB0AG8AcgAgACUAMQAgACgAMAB4ACUAMgApACAAaQBzACAAaQBuACAAZgBpAGwAZQAgAG4AdQBtAGIAZQByACAAJQAzACAAbwBuACAAZAByAGkAdgBlACAAJQA0ACEAYwAhAC4ADQAKAAAAjAABACoAKgAqAEwAbwBnAGkAYwBhAGwAIABzAGUAYwB0AG8AcgAgACUAMQAgACgAMAB4ACUAMgApACAAbwBuACAAZAByAGkAdgBlACAAJQA0ACEAYwAhACAAaQBzACAAaQBuACAAZgBpAGwAZQAgAG4AdQBtAGIAZQByACAAJQAzAC4ADQAKAAAAAAAYAAEARgBpAGwAZQAgACUAMQANAAoAAAAgAAEAIAAoAHIAZQBzAGkAZABlAG4AdAApAA0ACgAAACgAAQAgACgAbgBvAG4AcgBlAHMAaQBkAGUAbgB0ACkADQAKAAAAAABMAAEAbABvAGcAaQBjAGEAbAAgAHMAZQBjAHQAbwByAHMAIAAlADEALQAlADIAIAAoADAAeAAlADMALQAwAHgAJQA0ACkADQAKAAAAPAABAEEAdAB0AHIAaQBiAHUAdABlACAAVAB5AHAAZQAgADAAeAAlADEAIQB4ACEAJQAwAA0ACgAAAAAAQAABAE0AYQBzAHQAZQByACAARgBpAGwAZQAgAFQAYQBiAGwAZQAgACgAJABNAGYAdAApACUAMAANAAoAAAAAAFQAAQBNAGEAcwB0AGUAcgAgAEYAaQBsAGUAIABUAGEAYgBsAGUAIABNAGkAcgByAG8AcgAgACgAJABNAGYAdABNAGkAcgByACkAJQAwAA0ACgAAADQAAQBMAG8AZwAgAEYAaQBsAGUAIAAoACQATABvAGcARgBpAGwAZQApACUAMAANAAoAAAAsAAEARABBAFMARAAgACgAJABWAG8AbAB1AG0AZQApACUAMAANAAoAAAAAAFgAAQBBAHQAdAByAGkAYgB1AHQAZQAgAEQAZQBmAGkAbgBpAHQAaQBvAG4AIABUAGEAYgBsAGUAIAAoACQAQQB0AHQAcgBEAGUAZgApACUAMAANAAoAAAAsAAEAUgBvAG8AdAAgAEQAaQByAGUAYwB0AG8AcgB5ACUAMAANAAoAAAAAADwAAQBWAG8AbAB1AG0AZQAgAEIAaQB0AG0AYQBwACAAKAAkAEIAaQB0AE0AYQBwACkAJQAwAA0ACgAAADgAAQBCAG8AbwB0ACAAUwBlAGMAdABvAHIAcwAgACgAJABCAG8AbwB0ACkAJQAwAA0ACgAAAAAARAABAEIAYQBkACAAQwBsAHUAcwB0AGUAcgAgAEwAaQBzAHQAIAAoACQAQgBhAGQAQwBsAHUAcwApACUAMAANAAoAAAAsAAEAUQB1AG8AdABhACAAKAAkAFEAdQBvAHQAYQApACUAMAANAAoAAAAAADwAAQBVAHAAYwBhAHMAZQAgAFQAYQBiAGwAZQAgACgAJABVAHAAQwBhAHMAZQApACUAMAANAAoAAAAAADwAAQBFAHgAdABlAG4AZAAgAFQAYQBiAGwAZQAgACgAJABFAHgAdABlAG4AZAApACUAMAANAAoAAAAAADQAAQBTAGUAYwB1AHIAaQB0AHkAIAAoACQAUwBlAGMAdQByAGUAKQAlADAADQAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAQAQAAAAAAAG5maS5kYmcAMzg2XG5maS5leGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBQAAFIAAAAAAAAABQAAAMAUAADcAQAARQAAAAUAABSgFgAAeQMAAL8BAAAFAAAUIBoAAOAAAAATAAAAAwAAAgAbAAAZAQAAGgAAAAMAAAMgHAAAGgAAAAAAAAABAAACQBwAADMGAACRAAAABwAAFIAiAACUAQAANgAAAAUAABQgJAAAWwEAAA4AAAAEAAADgCUAAHwAAAABAAAAAQAAAwAmAABjAAAAAAAAAAEAAANwJgAAeAAAAAIAAAADAAAD8CYAAFwBAACAAAAAAwAAFFAoAACcAQAA8AQAAAQAABTwKQAAtwEAAAAAAAAEAAAAsCsAAKUCAAAAAAAAAQAAAGAuAADaAAAACgQAAAQAAANALwAAiwEAAB0AAAACAAAD0DAAACIAAAAAAAAAAQAAAQAxAAAkAAAAAAAAAAUAAAAwMQAAHwAAAAAAAAAEAAAAUDEAAL8AAAAAAAAAAwAAAxAyAAAfAAAAAQAAAAIAAAAwMgAAMwAAAAEAAAACAAAAcDIAACACAAA2AAAAAgAAFJA0AADqAAAAAAAAAAIAABSANQAAzAAAAAAAAAACAAAU4DcAABMAAAAAAAAAAAAAAAA4AAADAAAAAAAAAAEAAAAQOAAAAQAAAAAAAAAAAAAA"
error_sectors = get_disk_errors()
path = 'nfi.exe'
temp = False
if not os.path.exists(path):
fd, path = tempfile.mkstemp(suffix='_nfi.exe')
code = base64.b64decode(nfi_exe)
os.write(fd, code)
#print(f"nfi.exe temporary written as {path}")
os.close(fd)
temp = True
result = ''
check_duplicates = {}
try:
for disk, sect, _ in error_sectors:
if not sect or not disk:
continue
_, text = call_with_output([path, disk, sect])
if not text or "Usage: nfi drive-letter" in text:
print(f'Something went wrong! Disk: {disk}, sector: {sect}')
break
text = text.replace('\r', '').replace('\n\n', '\n')
lines = text.split("\n")[3:]
lines = [
line[4:] if line[:4] == " " else line for line in lines if (
"$STANDARD_INFORMATION (resident)" not in line and "$FILE_NAME (resident)" not in line)
]
md5 = hashlib.md5(lines[2].encode("utf-8")).hexdigest() #file path should be in lines[2]
if md5 not in check_duplicates:
check_duplicates[md5] = True
text = '\n'.join(lines) + '\n'
result += text
finally:
if temp:
os.remove(path)
if result.strip():
with open("errors.txt", "w") as f: f.write(result)
# or maybe instead
print(result) # to use >errors.txt operator to output into a file
else:
print("No bad sectors reported")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment