Страница 1 из 1

Кластеры файла на диске

Добавлено: Вт май 12, 2026 23:39
Orion9
Кнопка для отображения кластерной цепочки (экстентов) файла.
1. Экстент (Extent)

Это единичный непрерывный блок дискового пространства. Он характеризуется двумя числами: «начальный адрес (LCN)» и «количество кластеров». Например: «Начиная с 500-го кластера, 20 штук подряд». Это один экстент.

2. Цепочка (Cluster Chain)

Это совокупность всех экстентов, принадлежащих одному файлу. Если файл записан идеально (одним куском), то его цепочка состоит из одного экстента. Если файл фрагментирован, то его цепочка состоит из нескольких экстентов, разбросанных по диску.
Реализовано на скриптовом языке плагина Autorun. Информация отображается в окне подсказки и специальном наборе колонок.

[cut="Установка плагина Autorun"]Для работы рекомендуется установить последнюю версию плагина. На данный момент это 2.2.21.3 (15.10.2025)

Инструкция по установке плагина
https://total.darkhost.ru/wiki/doku.php?id=ru:autorun

Особенности последней версии. Для версии 2.2.21.3 нет полного архива с дополнительными модулями (субплагинами) и файлами справки, установку придется проводить в два этапа. Сначала нужно установить версию 2.2.21 от 28.09.2025
https://total.darkhost.ru/files/autorun ... 1_beta.zip
Поверх неё накатить последний модуль от 15.10.2025
https://total.darkhost.ru/files/temp/au ... 251015.zip[/cut]
[cut="Кнопка"]TOTALCMD#BAR#DATA
70401

%COMMANDER_EXE%
Кластеры файла|Ctrl - Меню|Shift - Карта диска|Alt - Скопировать в буфер


-1[/cut]
[cut="Clusters.aucfg"]

Код: Выделить всё

Pragma IncludeOnce

# 70400-70499

RegisterCommand 70400 Clusters
RegisterCommand 70401 ClustersButton

SetHotkeyAction /K:A /K:W /H:F /DM /S ClustersOptions

Global FRAG_INI    = COMMANDER_PATH & "\Ini\" & "Clusters.ini", _
       FRAG_LINES  = 30, _
       FRAG_BUFFER = 2048, _
       FRAG_NUM    = 0, _ 
       FRAG_ENTRY  = 1   
Global FRAG_START1 = 100000000, FRAG_END1 = 110000000, _
       FRAG_START2 = 200000000, FRAG_END2 = 220000000, _
       FRAG_START3 =         0, FRAG_END3 =    100000

Func ReadFragConfig()
    If FileExist(FRAG_INI) Then
       IniRead FRAG_LINES   %FRAG_INI% "Config" "Lines"   %"FRAG_LINES"
       IniRead FRAG_BUFFER  %FRAG_INI% "Config" "Buffer"  %"FRAG_BUFFER"
       IniRead FRAG_NUM     %FRAG_INI% "Config" "Numeric" %"FRAG_NUM"
       IniRead FRAG_ENTRY   %FRAG_INI% "Config" "Entry"   %"FRAG_ENTRY"
       
       IniRead FRAG_START1  %FRAG_INI% "Range" "Start1"  %"FRAG_START1"
       IniRead FRAG_START2  %FRAG_INI% "Range" "Start2"  %"FRAG_START2"
       IniRead FRAG_START3  %FRAG_INI% "Range" "Start3"  %"FRAG_START3"   
       IniRead FRAG_END1    %FRAG_INI% "Range" "End1"    %"FRAG_END1"
       IniRead FRAG_END2    %FRAG_INI% "Range" "End2"    %"FRAG_END2"
       IniRead FRAG_END3    %FRAG_INI% "Range" "End3"    %"FRAG_END3"                           
    EndIf
    
    If (FRAG_END1 - FRAG_START1 < 0) OR (FRAG_END2 - FRAG_START2 < 0) OR (FRAG_END3 - FRAG_START3 < 0) Then
       MsgBox("Отрицательный диапазон значений FRAG_START - FRAG_END", "Clusters")
    Endif
    If FRAG_LINES < 30 Then FRAG_LINES = 30
    If FRAG_BUFFER < 100 Then FRAG_BUFFER = 100    
EndFunc

ReadFragConfig()

Func Clusters(lParam)
    Local bClipBoard = IsPressed(0x12)
    Local sPath = RequestCopyDataInfo("SP")
    Local sName = RequestCopyDataInfo("SN")
    Local sFile = sPath & sName    
    If Not FileExist(sFile) Then
       ShowHint("Файл не существует " & sFile)
       Return 
    Endif
    Local nMode = -1
    If bClipBoard Then nMode -= 1
    RunThread("FileVCN", sFile, nMode, 0)
EndFunc

Func ClustersButton(lParam)
    If IsPressed(0x11) Then
       ClustersOptions()
       Return
    EndIf
    Clusters(0)
EndFunc

Func NumVCN(FileName, FieldIndex, UnitIndex)
     Local nFragNum = FRAG_NUM
     FRAG_NUM = 1
     Local nRet = FileVCN(FileName, FieldIndex, 0)
     FRAG_NUM = nFragNum
     Return nRet
EndFunc

Func EntryVCN(FileName, FieldIndex, UnitIndex)
     Local nFragEntry = FRAG_ENTRY
     FRAG_ENTRY = 3
     Local nRet = FileVCN(FileName, FieldIndex, UnitIndex)
     FRAG_ENTRY = nFragEntry
     Return nRet
EndFunc

Func FileVCN(FileName, FieldIndex, UnitIndex)
    Static GENERIC_ALL     = 0x10000000, _
           GENERIC_EXECUTE = 0x20000000, _
           GENERIC_WRITE   = 0x40000000, _
           GENERIC_READ    = 0x80000000, _
           FSCTL_GET_RETRIEVAL_POINTERS     = 0x90073, _
           FSCTL_GET_RETRIEVAL_POINTER_BASE = 0x90234, _
           IOCTL_DISK_GET_PARTITION_INFO_EX = 0x70048, _ 
           OPEN_EXISTING   = 3, _           
           ERROR_MORE_DATA = 234

    Local bMap = IsPressed(0x10)
    Local bShow = (FieldIndex = -1 ? true : false)
    Local bVirt = 0    
    Local bClipBoard = (FieldIndex = -2 ? true : false)
    If bClipBoard Then bShow = false

    Local Bytes = 0
    Local hFile = 0
    Local fs = FileGetSize(FileName)
    Local sVolume, nCluster, nSector, nFree, nTotal, nRet, nSysErr, Dbg = 0, sDbg
    Static bf1 = Buffer(8)
    bf1.Zero()      
    DllCall("GetVolumePathNameW", "wstr", FileName, "ptr", bf1.ptr, "dword", bf1.size)
    sVolume = bf1.GetStr()
    DllCall("GetDiskFreeSpaceW", "wstr", sVolume, _
                                 "dword*", @nCluster, "dword*", @nSector, _
                                 "dword*", @nFree, "dword*", @nTotal)
    bf1.Zero()
    Static bf2 = Buffer(FRAG_BUFFER)
    If bf2.Size <> FRAG_BUFFER Then bf2.Size = FRAG_BUFFER
    bf2.Zero()
    hFile = DllCall("CreateFileW", "wstr",  FileName, _
                                   "dword", 0, _
                                   "dword", 3, _
                                   "ptr",   0, _
                                   "dword", OPEN_EXISTING, _
                                   "dword", 0x40000000, _
                                   "ptr",   0, "handle")
    If hFile <= 0 Then 
       If bClipBoard Or bShow Then       
          ShowHint("Error opening file " & FileName)
       EndIf   
       Return 0
    EndIf      
    
    Local hVol, nBase, bBase, nPartOffset = 0, nPartLength = 0
    hVol = DllCall("CreateFileW", "wstr", "\\.\" & StrReplace(sVolume, "\", ""), _
                                  "dword", GENERIC_READ, _
                                  "dword", 3, _
                                  "ptr",   0, _
                                  "dword", OPEN_EXISTING, _
                                  "dword", 0, _
                                  "ptr",   0, "handle")    
    If SYSERROR = 0 And hVol > 0 Then 
       nRet = DllCall("DeviceIoControl", "handle", hVol, _
                                  "dword",  FSCTL_GET_RETRIEVAL_POINTER_BASE, _
                                  "ptr",    0, _
                                  "dword",  0, _
                                  "ptr",    bf1.ptr, _
                                  "dword",  bf1.size, _
                                  "dword*", @Bytes, _
                                  'ptr', 0)                                  
       If Bytes > 0 Then
          bBase = true
          nBase = bf1.GetNum(0,"int64") 
       EndIf                   
       nRet = DllCall("DeviceIoControl", "handle", hVol, _
                                  "dword",  IOCTL_DISK_GET_PARTITION_INFO_EX, _
                                  "ptr",    0, _
                                  "dword",  0, _
                                  "ptr",    bf2.ptr, _
                                  "dword",  bf2.size, _
                                  "dword*", @Bytes, _
                                  'ptr', 0)                               
       If Bytes > 0 Then 
          nPartOffset =  bf2.GetNum(8,"int64")
          nPartLength =  bf2.GetNum(16,"int64")
       EndIf       
       DllCall("CloseHandle", "handle", hVol)    
    EndIf
    
    bf1.Zero()
    bf2.Zero()
    
    If nPartLength = 0 Then
       Local sDisk, wq = WMIQuery()
       wq.Query('SELECT * FROM Win32_LogicalDiskToPartition')     
       While wq.Next()
           sDisk = StrReplace(StrPart(wq.GetValue("Dependent"), "=", 2), '"', '')
           If sDisk = StrReplace(sVolume, "\", "") Then
              nPartOffset = wq.GetValue("StartingAddress") 
              nPartLength = wq.GetValue("EndingAddress") - nPartOffset
           EndIf                 
       Wend
       Free(wq)
    EndIf

    Local lines = FRAG_LINES-1 
    If bMap Then lines -= 10

    Local nRange1 = 0, nRange2 = 0, nRange3 = 0
    Local c = 0, contig =  0, num = 1, sOut, last_lcn = 0, last_clus = 0, virt_lcn = 0
    Static aMap = List()
    aMap.Count = 0
    
    While 1
       nRet = DllCall("DeviceIoControl", "handle", hFile, _
                                        "dword",  FSCTL_GET_RETRIEVAL_POINTERS, _
                                        "ptr",    bf1.ptr, _
                                        "dword",  bf1.size, _
                                        "ptr",    bf2.ptr, _
                                        "dword",  bf2.size, _
                                        "dword*", @Bytes, _
                                        'ptr', 0)
       nSysErr = SYSERROR
       
       If nRet = 0 Then      
          If nSysErr <> ERROR_MORE_DATA Then 
             DllCall("CloseHandle", "handle", hFile)
             If bClipBoard Or bShow Then
                ShowHint("Error getting file extents " & FileName)
             EndIf
             Return 0
          EndIf   
       EndIf
       
       Local ext       =  bf2.GetNum(0,"dword"), _
             vcn       =  bf2.GetNum(8,"int64"), _
             lcn       =  bf2.GetNum(24,"int64"), _
             next_vcn  =  0, _
             last_vcn  =  bf2.GetNum((ext-1)*16+16,"int64"), _         
             prev_lcn  =  0, _
             real_lcn  =  last_lcn, _
             prev_clus =  last_clus, _ 
             clus, i   =  0
             
       c += ext
       If lcn <> -1 And (lcn - last_clus = last_lcn) Then contig += 1
                  
       If bClipBoard Or (bShow And num <= lines) Then
          If bVirt And lcn = -1 Then
             sOut &= StrFormat("%3u %8u %12s", num, vcn, "VIRT")
          Else
             sOut &= StrFormat("%3u %8u %12s", num, vcn, SizeFormat(lcn, 0, "B", 0, 2))
          EndIf   
       EndIf
       
       For i = 0 To ext - 1           
           next_vcn   =  bf2.GetNum(i*16+16,"int64")
           prev_lcn   =  lcn           
           
           If lcn <> -1 Then
              real_lcn = lcn
           Else   
              virt_lcn += 1
           EndIf
                
           clus =  next_vcn - vcn
           If prev_lcn <> -1 Then prev_clus = clus           
           
           If i < ext - 1 Then
              lcn  =  bf2.GetNum((i+1)*16+24,"int64")
              If lcn <> -1 And (lcn - prev_clus = real_lcn) Then contig += 1
           EndIf
           
           If (bShow Or bClipBoard) And bMap And prev_lcn <> - 1 Then
              ms = Ceil(prev_lcn/nTotal*1000)
              me = Ceil((clus + prev_lcn)/nTotal*1000)
              For m = ms To me              
                 If aMap.IndexOf(m) = -1 Then aMap.Add(m)                
              Next
           EndIf
           
           If FRAG_ENTRY And prev_lcn <> - 1 Then
              Local lcn_start = prev_lcn, lcn_end = prev_lcn + clus
              If (lcn_start >= FRAG_START1 And lcn_start <= FRAG_END1) Or _
                 (lcn_end >= FRAG_START1 And lcn_end <= FRAG_END1) Then 
                 nRange1 += 1
              ElseIf (lcn_start >= FRAG_START2 And lcn_start <= FRAG_END2) Or _
                     (lcn_end >= FRAG_START2 And lcn_end <= FRAG_END2) Then 
                 nRange2 += 1
              ElseIf (lcn_start >= FRAG_START3 And lcn_start <= FRAG_END3) Or _
                     (lcn_end >= FRAG_START3 And lcn_end <= FRAG_END3) Then 
                 nRange3 += 1
              EndIf
           EndIf
           
           If bClipBoard Or (bShow And (num+i+0) <= lines) Then 
              sOut &= ' ' & StrFormat("%9u %12s", clus, SizeFormat(clus*nCluster*nSector, 1, "G", 2))
           EndIf
           
           vcn = next_vcn
           
           If bClipBoard Or (bShow And (num+i+0) <= lines) Then 
              sOut &= auCRLF & StrFormat("%3u %8u", num+i+1, vcn)
              If i < ext - 1 Then
                 If bVirt And lcn = -1 Then
                    sOut &= StrFormat(" %12s", "VIRT")        
                 Else
                    sOut &= StrFormat(" %12s", SizeFormat(lcn, 0, "B", 0, 2))
                 Endif   
              Endif
           EndIf
       Next
       If nSysErr <> ERROR_MORE_DATA Then Break
       bf1.Zero()
       bf1.SetNum(0, "int64", last_vcn)
       bf2.Zero()
       If bClipBoard Or (bShow And (num+i+1) < lines) Then sOut &= auCRLF
       num += ext
       last_lcn = real_lcn
       last_clus = prev_clus
    Wend
    contig += virt_lcn
    
    DllCall("CloseHandle", "handle", hFile)
    
    If bShow Or bClipBoard Then
       If bMap Then
          sMap = ""
           For i = 0 To 19
              For j = 1 To 50
                sMap &= (aMap.IndexOf(i*50+j) = -1 ? " " : "X")
              Next
              If i < 19 Then sMap &= auCRLF
           Next
       EndIf
       Local sRange
       If bMap Then
          If FRAG_ENTRY Then
             sRange = "Range 1-3 check: " & _
                      nRange1 & "+" & nRange2 & "+" & nRange3 & "=" & _
                      nRange1 + nRange2 + nRange3 & " total fragments"
          Else
             sRange = "Range 1-3 check: disabled"      
          EndIf   
       EndIf
       SetHintParam("ShowHint", "Font", 9, "Consolas")
       SetHintParam("ShowHint", "BackColor", 0x000000)
       SetHintParam("ShowHint", "Text", 0xFFFFFF)
       sPart = " Offset: " & SizeFormat(nPartOffset, 1, "T", 2) & " Size: " & SizeFormat(nPartLength, 1, "T", 2)
       sHeader = "File: " & StrLeft(FileGetName(FileName),40) & auCRLF & _
                 "Volume: " & sVolume & sPart & auCRLF & _
                 "Sector: " & nSector & " bytes " & _                 
                 "Cluster: " & nCluster & " sectors Base: " & (bBase ? nBase : "") & auCRLF & _
                 "Free: " & nFree & " (" & Round(nFree/nTotal*100,0) & "%) " & _
                 "Total: " & SizeFormat(nTotal, 0, "B", 0, 2) & auCRLF & _
                 "Fragments: " & (contig > 0 ? c-contig & "/" : "") & c & _
                 " Clusters: " & (nSysErr = ERROR_MORE_DATA ? ">" : "") & last_vcn & _
                 " Size: " & SizeFormat(fs, 1, "G", 2) & auCRLF & _
                 (bMap ? sRange & auCRLF : "") & _
                 "-------------------------------------------------" & auCRLF & _
                 " N     VCN       LCN       Clusters      Size    " & auCRLF & _
                 "-------------------------------------------------"                 
       sOut = (Dbg ? sDbg : "") & sHeader & auCRLF & sOut
       If bMap Then
          block = Round(nTotal/1000)
          sOut &= auCRLF & "--------------------------------------------------"           
          sOut &= auCRLF & " 1000 blocks, 1 block = " & block & ", size: " & SizeFormat(block*nCluster*nSector, 1, "G", 2) 
          sOut &= auCRLF & "--------------------------------------------------" 
          sOut &= auCRLF & sMap
       EndIf
       If bClipBoard = 1 Then 
          ClipPut(sOut)
          ShowHint(c & " фрагментов скопировано в буфер") 
          Sleep(200)
       Else   
          ShowHint(sOut)
       EndIf   
       Sleep(200)
       SetHintParam("ShowHint", "Reload")
       Return
    EndIf
        
    If FRAG_ENTRY = 3 Then 
       Switch UnitIndex
        Case 0
            Return nRange1
        Case 1
            Return nRange2
        Case 2
            Return nRange3
        Else
            Return -1
       EndSwitch 
    EndIf
    
    If FRAG_NUM Then Return c-contig
    
    Local sEntry
    If FRAG_ENTRY = 1 Then 
       If nRange1 Then 
          sEntry = "1"
       ElseIf nRange2 Then 
          sEntry = "2"
       ElseIf nRange3 Then 
          sEntry = "3"
       EndIf    
    ElseIf FRAG_ENTRY = 2 Then 
       If nRange1 Then sEntry &= "1"
       If nRange2 Then sEntry &= "2"
       If nRange3 Then sEntry &= "3"    
    EndIf   
    Return (nSysErr = ERROR_MORE_DATA ? ">" : "") & _
           (contig > 0 ? c-contig & "/" : "") & c & (sEntry <> "" ? "*" & sEntry : "")
EndFunc

Func ClustersOptions
    ShowPopupMenu /D /F /I:0 "ClustersOptionsMenu"
EndFunc

Func ClustersOptionsMenu()
    Local txt
    txt = txt & 'MENUITEM "Options Menu", em_aucmd /D' & auCRLF
    txt = txt & 'MENUITEM SEPARATOR' & auCRLF
    txt = txt & 'MENUITEM "Use numeric field", em_aucmd ' & (FRAG_NUM ? "/C" : "") & ' -1 ClusterOptionsNum' & auCRLF
    If FRAG_NUM Then  
       txt = txt & 'MENUITEM "Show range number after *", em_aucmd /D' & auCRLF
    Else    
       txt = txt & 'MENUITEM "Show range number after *", em_aucmd ' & (FRAG_ENTRY ? "/C" : "") & ' -1 ClusterOptionsEntry' & auCRLF
    EndIf   
    txt = txt & 'MENUITEM "Lines = ' & FRAG_LINES & '", em_aucmd /D' & auCRLF
    txt = txt & 'MENUITEM "Buffer = ' & FRAG_BUFFER & ' bytes", em_aucmd /D' & auCRLF
    txt = txt & 'MENUITEM SEPARATOR' & auCRLF
    txt = txt & 'MENUITEM "Range 1:  ' & FRAG_START1 & '-' & FRAG_END1 & '", em_aucmd /D' & auCRLF
    txt = txt & 'MENUITEM "Range 2:  ' & FRAG_START2 & '-' & FRAG_END2 & '", em_aucmd /D' & auCRLF
    txt = txt & 'MENUITEM "Range 3:  ' & FRAG_START3 & '-' & FRAG_END3 & '", em_aucmd /D' & auCRLF
    txt = txt & 'MENUITEM SEPARATOR' & auCRLF
    txt = txt & 'MENUITEM "Search Range 1", em_search_frag_range1' & auCRLF
    txt = txt & 'MENUITEM "Search Range 2", em_search_frag_range2' & auCRLF
    txt = txt & 'MENUITEM "Search Range 3", em_search_frag_range3' & auCRLF
    txt = txt & 'MENUITEM "Search Clusters > 500", em_search_frag_clus500' & auCRLF
    txt = txt & 'MENUITEM "Search Clusters > 2000", em_search_frag_clus2000' & auCRLF    
    txt = txt & 'MENUITEM SEPARATOR' & auCRLF
    txt = txt & 'MENUITEM "Settings...", em_aucmd -1 ShellExec "' & FRAG_INI & '"' & auCRLF
    txt = txt & 'MENUITEM "Reread settings", em_aucmd -1 RereadFragConfig' & auCRLF
    txt = txt & 'MENUITEM "Custom View: File clusters", em_aucmd -1 ClusterOptionsCustom' & auCRLF
    Return txt
EndFunc

Func RereadFragConfig()
    ReadFragConfig()
    ShowClusterHint("Reading cluster configuration")     
EndFunc

Func ClusterOptionsNum()
     FRAG_NUM = Not FRAG_NUM
     SaveFragConfig()
     ShowClusterHint("Saving cluster configuration")
     ReadFragConfig()        
EndFunc

Func ClusterOptionsEntry()
     FRAG_ENTRY = Not FRAG_ENTRY
     SaveFragConfig()     
     ShowClusterHint("Saving cluster configuration")
     ReadFragConfig()
EndFunc

Func ClusterOptionsCustom()
     CommandExec em_fields_clusters     
     ShowClusterHint("File clusters custom view")
EndFunc

Func ShowClusterHint(HintText)
    Local d
    IniRead d %COMMANDER_INI% "Configuration" "DarkMode" 0
    SetHintParam("ShowHint", "Font", 13, "Tahoma")
    SetHintParam("ShowHint", "BackColor", 0x0F0F0F)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    SetHintParam("ShowHint", "DarkBackColor", 0xFF0000)
    SetHintParam("ShowHint", "DarkText", 0xFFFFFF)    
    ShowHint(auCRLF & "    " & HintText & "    " & auCRLF, 0, 0, 1000, 1)
    WinAlign(LAST_HINT_WINDOW)
    If d = 0 Then
       WinSetStyle(0x80000, 3, LAST_HINT_WINDOW)
       DllCall("SetLayeredWindowAttributes", "hwnd", LAST_HINT_WINDOW, _ 
                                             "ptr", 0, "byte", 192, "dword", 2)
    EndIf                                         
    Sleep(100)
    SetHintParam("ShowHint", "Reload")
    WinRedraw(1)
    SendCommand(540)     # cm_RereadSource         
EndFunc

Func SaveFragConfig()
    IniWrite %FRAG_INI% "Config" "Numeric" %FRAG_NUM%
    IniWrite %FRAG_INI% "Config" "Entry"   %FRAG_ENTRY%    
EndFunc
[/cut]

Модуль подключается к основной конфигурации как обычно, если не считать объявление дополнительных полей инструкцией Pragma AutorunPluginFields

[cut="autorun.cfg"]

Код: Выделить всё

Pragma AutorunPluginFields "Frag:::FileVCN" "FragNum::ft_numeric_32:NumVCN" "FragEntry:R1|R2|R3:ft_numeric_32:EntryVCN"

Pragma AutorunBlockUnload

LoadLibrary Plugins\Autorun_Tweaks.dll
LoadLibrary Plugins\Autorun_Sysinfo.dll
LoadLibrary Plugins\Autorun_Runtime.dll
LoadLibrary Plugins\Autorun_Process.dll

Pragma Include %COMMANDER_PATH%\wdx\Autorun\Clusters.aucfg

Pragma AutorunFinalizeSection
[/cut]

Если в конфигурации используются несколько модулей, то модуль Clusters.aucfg следует подключать в числе первых, в противном случае часть модуля должна быть перенесена в autorun.cfg. Такое разделение связано с использованием специального набора колонок (дополнительных полей плагина) в целях предотвращения ошибок при старте ТС. Файл основной конфигурации в таком случае должен содержать кастомные поля, глобальные переменные и функцию инициализации ReadFragConfig()

[cut="Альтернативный autorun.cfg"]

Код: Выделить всё

Pragma AutorunPluginFields "Frag:::FileVCN" "FragNum::ft_numeric_32:NumVCN" "FragEntry:R1|R2|R3:ft_numeric_32:EntryVCN"

Pragma AutorunBlockUnload

LoadLibrary Plugins\Autorun_Tweaks.dll
LoadLibrary Plugins\Autorun_Sysinfo.dll
LoadLibrary Plugins\Autorun_Runtime.dll
LoadLibrary Plugins\Autorun_Process.dll

Global FRAG_INI    = COMMANDER_PATH & "\Ini\" & "Clusters.ini", _
       FRAG_LINES  = 30, _
       FRAG_BUFFER = 2048, _
       FRAG_NUM    = 0, _ 
       FRAG_ENTRY  = 1   
Global FRAG_START1 = 100000000, FRAG_END1 = 110000000, _
       FRAG_START2 = 200000000, FRAG_END2 = 220000000, _
       FRAG_START3 =         0, FRAG_END3 =    100000

Func ReadFragConfig()
    If FileExist(FRAG_INI) Then
       IniRead FRAG_LINES   %FRAG_INI% "Config" "Lines"   %"FRAG_LINES"
       IniRead FRAG_BUFFER  %FRAG_INI% "Config" "Buffer"  %"FRAG_BUFFER"
       IniRead FRAG_NUM     %FRAG_INI% "Config" "Numeric" %"FRAG_NUM"
       IniRead FRAG_ENTRY   %FRAG_INI% "Config" "Entry"   %"FRAG_ENTRY"
       
       IniRead FRAG_START1  %FRAG_INI% "Range" "Start1"  %"FRAG_START1"
       IniRead FRAG_START2  %FRAG_INI% "Range" "Start2"  %"FRAG_START2"
       IniRead FRAG_START3  %FRAG_INI% "Range" "Start3"  %"FRAG_START3"   
       IniRead FRAG_END1    %FRAG_INI% "Range" "End1"    %"FRAG_END1"
       IniRead FRAG_END2    %FRAG_INI% "Range" "End2"    %"FRAG_END2"
       IniRead FRAG_END3    %FRAG_INI% "Range" "End3"    %"FRAG_END3"                           
    EndIf
    
    If (FRAG_END1 - FRAG_START1 < 0) OR (FRAG_END2 - FRAG_START2 < 0) OR (FRAG_END3 - FRAG_START3 < 0) Then
       MsgBox("Отрицательный диапазон значений FRAG_START - FRAG_END", "Clusters")
    Endif
    If FRAG_LINES < 30 Then FRAG_LINES = 30
    If FRAG_BUFFER < 100 Then FRAG_BUFFER = 100    
EndFunc

ReadFragConfig()

#Pragma Include %COMMANDER_PATH%\wdx\Autorun\Module1.aucfg
#Pragma Include %COMMANDER_PATH%\wdx\Autorun\Module2.aucfg
#Pragma Include %COMMANDER_PATH%\wdx\Autorun\Module3.aucfg

Pragma Include %COMMANDER_PATH%\wdx\Autorun\Clusters.aucfg

Pragma AutorunFinalizeSection
[/cut]

Глобальные переменные влияют на отображение информации и сохраняются в файле Clusters.ini. Если файл не найден, будут использованы настройки по умолчанию. Путь к Clusters.ini задается в переменной FRAG_INI. Можно использовать готовый файл с комментариями:

[cut="Clusters.ini"]

Код: Выделить всё

[Config]
;  Количество строк в подсказке
;  При отображении карты число уменьшается на 10
Lines=30
;  Буфер для считывания кластерных цепочек
;  Минимальное значение 100 байт, 1024 байт 63 цепочки
Buffer=2048
;  Формат для поля "Frag"
;  Numeric 1 отображать только число
;  Numeric 0 отображать строку в формате "1/3*2", где 
;  1 - число реальных фрагментов, 3 - число записей в MFT, 2 - попадание во второй диапазон
Numeric=1
;  Вхождение в диапазон после звездочки в поле "Frag"
;  Entry 0 не отображать
;  Entry 1 отображать первый по порядку диапазон
;  Entry 2 отображать вхождение во все диапазоны
Entry=1

[Range]
;  Первый диапазон для поиска значений
Start1=100000000
End1=110000000
;  Второй диапазон для поиска значений
Start2=200000000
End2=220000000
;  Третий диапазон для поиска значений
Start3=0
End3=100000
[/cut]

Кнопка на панели вызывает меню, которое можно отобразить комбинацией Alt+Win+F. Данная комбинация прописана в модуль и может быть изменена. Для работы пунктов меню в Wincmd.ini или в секциях редиректа необходимо добавить поисковые шаблоны и поля колонок. Можно также можно использовать em_команду для вызова подсказки, связав ее с горячими клавишами, например: Ctrl+F и Ctrl+Shift+F

[cut="wincmd.ini"]

Код: Выделить всё

[Shortcuts]
C+F=em_file_fragments
CS+F=em_file_fragments
[/cut]
[cut]

Код: Выделить всё

[CustomFields]
Titles=File clusters
Headers1=Размер\nFrag
Contents1=[=tc.size.bkMGT2]\n[=autorun.Frag]
Options1=1179|0|120
Widths1=100,30,-40,-30
[/cut]
[cut]

Код: Выделить всё

[Searches]
FragRange1_SearchFor=
FragRange1_SearchIn=
FragRange1_SearchText=
FragRange1_SearchFlags=0|002002000020|||||||||0000|||
FragRange1_plugin=autorun.FragEntry.R1 > 0
FragRange2_SearchFor=
FragRange2_SearchIn=
FragRange2_SearchText=
FragRange2_SearchFlags=0|002002000020|||||||||0000|||
FragRange2_plugin=autorun.FragEntry.R2 > 0
FragRange3_SearchFor=
FragRange3_SearchIn=
FragRange3_SearchText=
FragRange3_SearchFlags=0|002002000020|||||||||0000|||
FragRange3_plugin=autorun.FragEntry.R3 > 0
FragNum > 500_SearchFor=
FragNum > 500_SearchIn=
FragNum > 500_SearchText=
FragNum > 500_SearchFlags=0|002002000020|||||||||0000|||
FragNum > 500_plugin=autorun.FragNum > 500
FragNum > 2000_SearchFor=
FragNum > 2000_SearchIn=
FragNum > 2000_SearchText=
FragNum > 2000_SearchFlags=0|002002000020|||||||||0000|||
FragNum > 2000_plugin=autorun.FragNum > 2000
[/cut]
В примере выше набор колонок создан как "File clusters", но его можно переименовать и подправить команду em_fields_clusters в usercmd.ini. Остальное содержимое usercmd.ini можно добавить как есть.

[cut="usercmd.ini"]

Код: Выделить всё

[em_file_fragments]
cmd=70400

[em_search_frag_range1]
cmd=LOADSEARCH ="FragRange1"
menu=FragRange1
button=Wcmicons.dll,47

[em_search_frag_range2]
cmd=LOADSEARCH ="FragRange2"
menu=FragRange2
button=Wcmicons.dll,47

[em_search_frag_range3]
cmd=LOADSEARCH ="FragRange3"
menu=FragRange3
button=Wcmicons.dll,47

[em_search_frag_clus500]
cmd=LOADSEARCH ="FragNum > 500"
menu=FragNum > 500
button=Wcmicons.dll,47

[em_search_frag_clus2000]
cmd=LOADSEARCH ="FragNum > 2000"
menu=FragNum > 2000
button=Wcmicons.dll,47

[em_fields_clusters]
cmd=OPENCUSTOMVIEW File clusters
menu=File clusters
button=Wcmicons.dll,52
[/cut]

По большому счету функционал носит информационно-развлекательный характер, но может приносить пользу при работе с такими программами, как BadNTFS для поиска файлов в предварительно указанных диапазонах. Информация в подсказке помогает обойтись без сторонних утилит (DiskView, WinContig, Defraggler и др.) для просмотра сведений о фрагментах файла.

Изображение

[cut]

Код: Выделить всё

File: tcmd1157x32_64.exe
Volume: D:\ Offset: 31,50 Kb Size: 60 Gb
Sector: 512 bytes Cluster: 8 sectors Base: 
Free: 849633 (5%) Total: 15 728 698
Fragments: 13 Clusters: 2743 Size: 10,71 Mb
-------------------------------------------------
 N     VCN       LCN       Clusters      Size    
-------------------------------------------------
  1        0    9 451 783        10        40 Kb
  2       10   12 710 362        14        56 Kb
  3       24    8 262 578        64       256 Kb
  4       88    7 441 290        31       124 Kb
  5      119    8 262 674        38       152 Kb
  6      157    9 451 509       139       556 Kb
  7      296   10 444 047       275      1,07 Mb
  8      571    1 273 916       419      1,63 Mb
  9      990    1 267 559       421      1,64 Mb
 10     1411    5 056 699       421      1,64 Mb
 11     1832    1 481 631       422      1,64 Mb
 12     2254    4 525 528       422      1,64 Mb
 13     2676    1 193 415        67       268 Kb
 14     2743
[/cut]