Verwaltung Hardlinks

    • Offizieller Beitrag

    Hi,
    ich arbeite ganz gern mit Hardlinks. Da ich aber langsam alt und drösig werde :D 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
    [autoit]

    #include<EditConstants.au3>
    #include<GuiListBox.au3>
    #include<GuiListView.au3>
    #include<StructureConstants.au3>
    #include<WindowsConstants.au3>
    #include<GUIConstantsEx.au3>
    #include<ListViewConstants.au3>
    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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")

    [/autoit] [autoit][/autoit] [autoit]

    $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)

    [/autoit] [autoit][/autoit] [autoit]

    $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)

    [/autoit] [autoit][/autoit] [autoit]

    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()

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(100)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    Func openPath()
    GUISetState(@SW_SHOW, $guiPath)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func closePath()
    GUISetState(@SW_HIDE, $guiPath)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    Func mainGUIClose()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func closePopup()
    GUISetState(@SW_HIDE, $GUIhardlink)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
    $hWndListView = $hListView
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

    [/autoit] [autoit][/autoit] [autoit]

    $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

    [/autoit]

    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.

  • Hallo BugFix.

    Hardlinks ?( <---- So darfst Du dir vorstellen, habe ich ausgesehen, als ich das Wort "Hardlinks" gelesen habe.
    Dachte ich doch "Da hat sich der Bug aber mal fix vertan", aber so ist es ja gar nicht gewesen.

    Aber wirklich, das die Teile diesen Namen haben, wußte ich gar nicht. Da gibt es dann ja dieses "Wiki-Sowieso" und da habe ich mich dann mal schlau gemacht.

    Danke, da habe ich doch wieder einmal etwas gelernt. Ich nehme es in meinen Wortschatz der Rubrik "Wörter die die Welt nicht kennt" auf ;)

    LG, Crazy-A.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Hallo BugFix.

    Du hast die Vertikallink vergessen. ;)

    LG, Crazy-A.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

    • Offizieller Beitrag

    Hallo,

    noch ein kleiner Tipp für BugFix, wenn Du dir mal nicht sicher bist ob es ein Hardlink oder eine Datei ist, schau dir das Verzeichnis mit TotalComander an der macht vor Hardlinks ein spezieles Symbol autoit.de/wcf/attachment/2629/.