- Offizieller Beitrag
Hi,
ich arbeite ganz gern mit Hardlinks. Da ich aber langsam alt und drösig werde habe ich hiermit eine Verwaltung für meine Hardlinks geschrieben, damit ich die Originaldatei von den Hardlinks unterscheiden kann und auch weiß, welche Hardlinks überhaupt angelegt sind.
Bitte beachten, dass Hardlinks nur innerhalb einer Partition erstellt werden können.
Falls ihr es gebrauchen könnt:
Spoiler anzeigen
#include<EditConstants.au3>
#include<GuiListBox.au3>
#include<GuiListView.au3>
#include<StructureConstants.au3>
#include<WindowsConstants.au3>
#include<GUIConstantsEx.au3>
#include<ListViewConstants.au3>
Opt("GUIOnEventMode", 1)
Global $aLink[1][20], $var, $mnuState = $GUI_CHECKED
Global $linkINI = @ScriptDir & '\hardlink.ini'
Global $gold = 0xFFD700, $blau = 0x1f3f80
If Not FileExists($linkINI) Then
IniWriteSection($linkINI, 'settings', 'quellpfad=' & @MyDocumentsDir & @LF & 'zielpfad=' & @MyDocumentsDir & @LF & 'ntfs_check=1')
IniWriteSection($linkINI, 'hardlinked', '')
EndIf
$quelleINI = IniRead($linkINI, 'settings', 'quellpfad', @MyDocumentsDir)
$zielINI = IniRead($linkINI, 'settings', 'zielpfad', @MyDocumentsDir)
Global $aIni, $ntfs = IniRead($linkINI, 'settings', 'ntfs_check', 1)
If $ntfs = 1 Then
If MsgBox(262436,"NTFS-Check","Soll überprüft werden, ob der PC über NTFS-formatierte Laufwerke verfügt?" & @LF & _
"Die Prüfung kann in den Einstellungen deaktiviert werden.") = 6 Then
Global $wbemFlagReturnImmediately = 0x10, $wbemFlagForwardOnly = 0x20, $colItems = "", $strComputer = "localhost"
Global $Output="", $Out2 = ''
$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDisk", "WQL", _
$wbemFlagReturnImmediately + $wbemFlagForwardOnly)
If IsObj($colItems) then
For $objItem In $colItems
If $objItem.Description = 'Lokale Festplatte' Then
If $objItem.FileSystem <> 'NTFS' Then
$Output = $Output & "DeviceID: " & $objItem.DeviceID & @CRLF
$Output = $Output & "FileSystem: " & $objItem.FileSystem & @CRLF & @CRLF
EndIf
EndIf
Next
If $Output <> "" Then
If MsgBox(262436, 'Dateisystem falsch', 'Folgende Festplatte(n) sind nicht im "NTFS-Format"' & @LF & _
'und somit kann kein Hardlink auf ihnen erzeugt werden:' & @LF & @LF & $Output & @LF & @LF & _
'Wenn die für den Hardlink gewünschte Festplatte nicht aufgezählt wurde,' & @LF & _
'können Sie fortsetzen.' & @LF & _
'Möchten Sie fortsetzen?') = 7 Then Exit
Else
MsgBox(262208,"NTFS-Check","Alle verfügbaren Festplatten sind geeignet.")
EndIf
Else
Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_LogicalDisk" )
Exit
Endif
EndIf
EndIf
HotKeySet("{ESC}", "closePopup")
[/autoit] [autoit][/autoit] [autoit]$mainGUI = GUICreate("Administration von Hardlinks", 480, 385, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "mainGUIClose")
$mnu = GUICtrlCreateMenu('Einstellungen')
$mnuNTFS = GUICtrlCreateMenuItem('NTFS-Check', $mnu)
If $ntfs = 1 Then GUICtrlSetState(-1, $GUI_CHECKED)
GUICtrlSetOnEvent(-1, 'ntfs_checked')
GUICtrlCreateMenuItem('Pfade', $mnu)
GUICtrlSetOnEvent(-1, 'openPath')
$mnuHelp = GUICtrlCreateMenu('?')
GUICtrlCreateMenuItem('Hilfe', $mnuHelp)
GUICtrlSetOnEvent(-1, "HelpClick")
$ListView = GUICtrlCreateListView("Originaldateien ( Anzeige der Hardlinks mit Doppelklick )", 14, 4, 450, 345)
$hListView = GUICtrlGetHandle($ListView)
_GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES,$LVS_EX_TRACKSELECT,$LVS_EX_FULLROWSELECT))
_GUICtrlListView_SetColumnWidth($hListView, 0, 800)
$LVmenu = GUICtrlCreateContextMenu($ListView)
GUICtrlCreateMenuItem('Erstellen', $LVmenu)
GUICtrlSetOnEvent(-1, "NewClickSource")
GUICtrlCreateMenuItem('', $LVmenu)
GUICtrlCreateMenuItem('Löschen', $LVmenu)
GUICtrlSetOnEvent(-1, "DeleteClickSource")
$guiPath = GUICreate('Pfadvoreinstellungen', 538, 126, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, 'closePath')
$Group1 = GUICtrlCreateGroup(" Originaldateipfad ", 8, 8, 520, 50)
$InSource = GUICtrlCreateInput("", 16, 26, 470, 21, BitOR($ES_AUTOHSCROLL,$ES_READONLY))
GUICtrlSetBkColor(-1, 0xffffe0)
$bChgSource = GUICtrlCreateButton("...", 496, 26, 21, 21, 0)
GUICtrlSetOnEvent(-1, "bChgSourceClick")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group2 = GUICtrlCreateGroup(" Hardlinkpfad ", 8, 66, 520, 50)
$InTarget = GUICtrlCreateInput("", 16, 84, 470, 21, BitOR($ES_AUTOHSCROLL,$ES_READONLY))
GUICtrlSetBkColor(-1, 0xffffe0)
$bChgTarget = GUICtrlCreateButton("...", 496, 84, 21, 21, 0)
GUICtrlSetOnEvent(-1, "bChgTargetClick")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$GUIhardlink = GUICreate('', 444, 100, -1, -1, $WS_POPUPWINDOW, $WS_EX_TOPMOST)
$ListBox = GUICtrlCreateList('', 0, 0, 444, 110)
GUICtrlSetBkColor(-1, $blau)
GUICtrlSetColor(-1, $gold)
$Listmnu = GUICtrlCreateContextMenu($ListBox)
GUICtrlCreateMenuItem('Neu', $Listmnu)
GUICtrlSetOnEvent(-1, "NewClickLink")
GUICtrlCreateMenuItem('Ändern', $Listmnu)
GUICtrlSetOnEvent(-1, "ChgClickLink")
GUICtrlCreateMenuItem('', $Listmnu)
GUICtrlCreateMenuItem('Löschen', $Listmnu)
GUICtrlSetOnEvent(-1, "DeleteClickLink")
$hListBox = GUICtrlGetHandle($ListBox)
GUISetState(@SW_SHOW, $mainGUI)
[/autoit] [autoit][/autoit] [autoit]GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
[/autoit] [autoit][/autoit] [autoit]GUICtrlSetData($InSource, $quelleINI)
GUICtrlSetData($InTarget, $zielINI)
LoadFromIni()
FillListView()
While 1
Sleep(100)
WEnd
Func ntfs_checked()
If BitAND(GUICtrlRead($mnuNTFS), $GUI_CHECKED) Then
GUICtrlSetState($mnuNTFS, $GUI_UNCHECKED)
IniWrite($linkINI, 'settings', 'ntfs_check', 0)
ElseIf BitAND(GUICtrlRead($mnuNTFS), $GUI_UNCHECKED) Then
GUICtrlSetState($mnuNTFS, $GUI_CHECKED)
IniWrite($linkINI, 'settings', 'ntfs_check', 1)
EndIf
EndFunc
Func openPath()
GUISetState(@SW_SHOW, $guiPath)
EndFunc
Func closePath()
GUISetState(@SW_HIDE, $guiPath)
EndFunc
Func bChgSourceClick()
Local $path = FileSelectFolder('Startpfad für Originaldateien aussuchen', $quelleINI)
If $path = '' Then Return
GUICtrlSetData($InSource, $path)
IniWrite($linkINI, 'settings', 'quellpfad', $path)
$quelleINI = $path
EndFunc
Func bChgTargetClick()
Local $path = FileSelectFolder('Startpfad für Hardlinks aussuchen', $zielINI)
If $path = '' Then Return
GUICtrlSetData($InTarget, $path)
IniWrite($linkINI, 'settings', 'zielpfad', $path)
$zielINI = $path
EndFunc
Func LoadFromIni()
ReDim $aLink[1][20]
For $i = 0 To 19
$aLink[0][$i] = ''
Next
$aIni = IniReadSection($linkINI, 'hardlinked')
If IsArray($aIni) Then
For $i = 1 To UBound($aIni) -1
If $aLink[UBound($aLink)-1][0] <> '' Then ReDim $aLink[UBound($aLink)+1][20]
$var = StringSplit($aIni[$i][1], ';')
$aLink[UBound($aLink)-1][0] = $aIni[$i][0]
If IsArray($var) Then
For $k = 1 To UBound($var) -1
$aLink[UBound($aLink)-1][$k] = $var[$k]
Next
Else
$aLink[UBound($aLink)-1][1] = $aIni[$i][1]
EndIf
Next
EndIf
EndFunc
Func FillListView()
_GUICtrlListView_DeleteAllItems($hListView)
For $i = 0 To UBound($aLink) -1
If $aLink[$i][0] = '' Then ExitLoop
_GUICtrlListView_AddItem($hListView, $aLink[$i][0])
Next
EndFunc
Func DeleteClickSource()
Local $index = _GUICtrlListView_GetSelectedIndices($hListView)
If $index < 0 Then Return
For $i = 1 To UBound($aLink,2) -1
If $aLink[$index][$i] = '' Then ExitLoop
FileDelete($aLink[$index][$i])
Next
IniDelete($linkINI, 'hardlinked', $aLink[$index][0])
LoadFromIni()
FillListView()
EndFunc
Func NewClickSource()
Local $Source = FileOpenDialog("Original-Datei für Hard-Link", $quelleINI, "Alle Dateien (*.*)")
If $Source = '' Then Return MsgBox(262192, 'Auswahlfehler', 'Es wurde keine Datei ausgewählt!')
IniWrite($linkINI, 'settings', 'quellpfad', $Source)
Local $Link = FileSelectFolder('Bitte den Zielordner für den Hardlink auswählen', $zielINI)
If $Link = '' Then Return MsgBox(262192, 'Auswahlfehler', 'Es wurde keine Link-Pfad ausgewählt!')
IniWrite($linkINI, 'settings', 'zielpfad', $Link)
Local $name = InputBox('Hardlink', 'Bitte den Namen für den Hardlink festlegen.')
If $name = '' Then Return MsgBox(262192, 'Auswahlfehler', 'Es wurde keine Link-Name festgelegt!')
CreateHardLink($Source, $Link & '\' & $name)
IniWrite($linkINI, 'hardlinked', $Source, $Link & '\' & $name)
LoadFromIni()
FillListView()
EndFunc
Func HelpClick()
MsgBox(0, 'Hilfe', _
'Mit Doppelklick auf die Originaldatei öffnet sich die Listbox mit den zugehörigen Hardlinks.' & @LF & _
'Die Listbox kann mit <Esc> geschlossen werden.' & @LF & @LF & _
'Kontextmenü Originaldateien:' & @LF & _
@TAB & '< Erstellen >' & @TAB & 'Hinzufügen einer neuen Datei zur Liste und Erstellen eines Hardlinks dafür.' & @LF & _
@TAB & '< Löschen >' & @TAB & 'Löscht alle Hardlinks für diese Datei und entfernt sie von der Liste.' & @LF & @LF & _
'Kontextmenü Hardlinks:' & @LF & _
@TAB & '< Neu >' & @TAB & @TAB & 'Fügt einen neuen Hardlink für die Quelldatei hinzu.' & @LF & _
@TAB & '< Ändern >' & @TAB & 'Ändert den Namen des gewählten Hardlinks.' & @LF & _
@TAB & '< Löschen >' & @TAB & 'Löscht den gewählten Hardlink.')
EndFunc
Func DeleteClickLink()
If _GUICtrlListBox_GetCount($hListBox) = 1 Then
GUISetState(@SW_HIDE, $GUIhardlink)
Return DeleteClickSource()
EndIf
Local $link = _GUICtrlListBox_GetText($hListBox, _GUICtrlListBox_GetCurSel($hListBox))
FileDelete($link)
Local $indexLV = _GUICtrlListView_GetSelectedIndices($hListView)
Local $source = _GUICtrlListView_GetItemText($hListView, $indexLV)
Local $strINI = IniRead($linkINI, 'hardlinked', $source, '')
Local $var = StringSplit($strINI, ';')
If IsArray($var) Then
Local $strWrite = ''
For $i = 1 To UBound($var) -1
If $var[$i] <> $link Then
$strWrite &= $var[$i] & ';'
EndIf
Next
IniWrite($linkINI, 'hardlinked', $source, StringTrimRight($strWrite, 1))
EndIf
LoadFromIni()
FillListView()
GUISetState(@SW_HIDE, $GUIhardlink)
EndFunc
Func ChgClickLink()
Local $source = _GUICtrlListView_GetItemText($hListView, _GUICtrlListView_GetSelectedIndices($hListView))
Local $index = _GUICtrlListBox_GetCurSel($hListBox)
If $index < 0 Then Return
Local $link_alt = _GUICtrlListBox_GetText($hListBox, $index)
GUISetState(@SW_HIDE, $GUIhardlink)
Local $link = InputBox('Hardlink ändern', 'Bitte den Namen ändern', $link_alt)
If $link = '' Then Return MsgBox(262192, 'Fehler', 'Es wurde keine Änderung vorgenommen.')
FileMove($link_alt, $link)
Local $strINI = IniRead($linkINI, 'hardlinked', $source, '')
Local $var = StringSplit($strINI, ';'), $strWrite = ''
If IsArray($var) Then
For $i = 1 To UBound($var) -1
If $var[$i] = $link_alt Then $var[$i] = $link
$strWrite &= $var[$i] & ';'
Next
Else
$strWrite = $link & ';'
EndIf
IniWrite($linkINI, 'hardlinked', $source, StringTrimRight($strWrite, 1))
LoadFromIni()
FillListView()
EndFunc
Func NewClickLink()
Local $source = _GUICtrlListView_GetItemText($hListView, _GUICtrlListView_GetSelectedIndices($hListView))
Local $index = _GUICtrlListBox_GetCurSel($hListBox)
Local $link_alt = _GUICtrlListBox_GetText($hListBox, $index)
Local $link = FileSelectFolder('Weiteren Hardlink festlegen.', $zielINI)
If $link = '' Then Return MsgBox(262192, 'Auswahlfehler', 'Es wurde keine Link-Pfad ausgewählt!')
IniWrite($linkINI, 'settings', 'zielpfad', $link)
GUISetState(@SW_HIDE, $GUIhardlink)
Local $name = InputBox('Hardlink', 'Bitte den Namen für den Hardlink festlegen.')
If $name = '' Then Return MsgBox(262192, 'Auswahlfehler', 'Es wurde keine Link-Name festgelegt!')
CreateHardLink($Source, $link & '\' & $name)
IniWrite($linkINI, 'hardlinked', $source, IniRead($linkINI, 'hardlinked', $source, '') & ';' & $link & '\' & $name)
LoadFromIni()
FillListView()
EndFunc
Func mainGUIClose()
Exit
EndFunc
Func closePopup()
GUISetState(@SW_HIDE, $GUIhardlink)
EndFunc
Func LVDblClick($aInfo)
_GUICtrlListBox_ResetContent($hListBox)
If $aInfo[3] < 0 Then Return
Local $str = ''
For $i = 1 To UBound($aLink,2) -1
If $aLink[$aInfo[3]][$i] = '' Then ExitLoop
_GUICtrlListBox_AddString($hListBox, $aLink[$aInfo[3]][$i])
Next
GUISetState(@SW_SHOW, $GUIhardlink)
EndFunc
Func CreateHardLink($Path, $LinkPath)
If FileCreateNTFSLink($Path, $LinkPath) = 1 Then
MsgBox(262208, '', 'Der Hardlink' & @LF & @LF & $LinkPath & @LF & @LF & 'wurde erfolgreich angelegt.')
Else
MsgBox(262192, '', 'Der Hardlink' & @LF & @LF & $LinkPath & @LF & @LF & 'konnte nicht angelegt werden.')
EndIf
EndFunc
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
$hWndListView = $hListView
If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)
$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Switch $hWndFrom
Case $hWndListView
Switch $iCode
Case $NM_DBLCLK
Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
Local $aInfo[4] = [$hWndFrom, _
$iIDFrom, _
$iCode, _
DllStructGetData($tInfo, "Index")]
LVDblClick($aInfo)
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY
Edit: Für jene, die mitHardlink nichts anfangen können, eine kurze Erklärung.
Jedem bekannt sind Verweise (Softlinks) in Windows. Diese können unabhängig vom Dateisystem (FAT32, NTFS) unter Windows erstellt werden und verweisen auf den Dateipfad der Originaldatei und leiten einen Aufruf an die Originaldatei weiter.
Nachteil: Wird die Originaldatei verschoben oder gelöscht ist auch der Verweis futsch.
Ein Hardlink ist unter Windows nur auf NTFS-Dateisystem und nur innerhalb einer Partition möglich und ist ein Verweis auf die Adresse der Datei in der Mastertable. Unabhängig vom aktuellen Pfad der Originaldatei bleibt diese Beziehung immer bestehen. Wenn ich den Hardlink im Explorer betrachte, ist kein Unterschied zur Originaldatei feststellbar. Der Hardlink kann wie eine selbständige Datei behandelt werden. Es können mehrere Hardlinks auf dieselbe Datei angelegt werden.
Ganz entscheidend:
Wird versehentlich die Originaldatei gelöscht, dann existiert sie (bzw. deren Inhalt) trotzdem unter dem Hardlink weiter!
(Das kann dann zum Bsp. dazu führen, dass die Originaldatei auf C:\ gelöscht wird, der Hardlink auf D:\ den Inhalt weiter darstellt aber physikalischer Speicherplatz für die Datei weiterhin auf C:\ liegt.)
Gelöscht werden können Hardlinks nur, wenn in dem Moment kein Filehandle auf die Originaldatei oder deren Hardlinks besteht.
Hab noch einen kleinen Fehler (Deaktivierung NTFS-Check per INI) beseitigt.