Jump to content

Copied file check using SetFilePointerEx


rover
 Share

Recommended Posts

an example using SetFilePointerEx to check integrity of large file copies

works on files above 2gig, but not very fast.

tested up to 4.5gig

Move along, nothing else to see here. :mellow:

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
;#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
;#Obfuscator_Parameters=/striponly
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <WinAPI.au3>

Opt('MustDeclareVars', 1)

Global Const $INVALID_HANDLE_VALUE = 0xFFFFFFFF
Global Const $FILE_BEGIN = 0 ; The starting point is zero (0) or the beginning of the file.
Global Const $FILE_CURRENT = 1 ; The starting point is the current value of the file pointer.
Global Const $FILE_END = 2 ; The starting point is the current end-of-file position.

Global $hInFile1, $hInFile2
Global $iDLL = -1, $iPos

Global $sFile_Src = FileOpenDialog("Select source file", @HomeDrive & "\", "All (*.*)", 1 + 2)
Global $sFile_Copy = FileOpenDialog("Select copied file", @HomeDrive & "\", "All (*.*)", 1 + 2)

;If Not $CmdLine[0] = 2 Then Exit
;Global $sFile_Src  = $CmdLine[1]
;Global $sFile_Copy = $CmdLine[2]

Switch _CheckFileIntegrity($sFile_Src, $sFile_Copy, $iPos)
    Case 0
        MsgBox(262144, "File Integrity Check", "File: " & _
                $sFile_Copy & @CRLF & "Byte position: " & $iPos & @CRLF & "FAILED")
    Case 1
        MsgBox(262144, "File Integrity Check", "File: " & _
                $sFile_Copy & @CRLF & "Time: " & @extended & " Seconds" & @CRLF & "PASSED")
    Case - 1
        MsgBox(262144, "File Integrity Check", "Error code: " & _
                @error & @CRLF & "GetLastError [" & _WinAPI_GetLastError() & "] " & _WinAPI_GetLastErrorMessage())
EndSwitch

Func _CheckFileIntegrity($sFileSrc, $sFileCopy, ByRef $iInt64Pos, $iBlockSize = -1)
    ;Author: rover
    ;tested with large files up to 4.5gig
    ;Parameters:
    ;$sFileSrc   - Path/filename to source file
    ;$sFileCopy  - Path/filename to copied file
    ;$iInt64Pos  - ByRef return failed block byte position
    ;$iBlockSize - Block size in bytes to test (Default size 1048576 bytes)
    ;Return
    ; 0 = Fail   - Error in copied file (byte position of fail returned ByRef in $iInt64Pos)
    ; 1 = Pass   - Files identical (ByRef return in $iInt64Pos is 0)
    ;-1 = Error  - Error in parameters - last error set (ByRef return in $iInt64Pos is -1)
    $iInt64Pos = -1
    If (Not FileExists($sFileSrc)) Or (Not FileExists($sFileCopy)) Then
        Return SetError(1, _WinAPI_SetLastError(2), -1)
    EndIf
    If (Not $iBlockSize) Or ($iBlockSize = -1) Then $iBlockSize = 1024 * 1024
    If FileGetSize($sFileSrc) < $iBlockSize Then
        MsgBox(262144, "File Integrity Check - ERROR", _
                "File is smaller than block size" & @CRLF & "Src: " & _
                FileGetSize($sFileSrc) & @CRLF & "Block size: " & $iBlockSize, 5)
        Return SetError(1, _WinAPI_SetLastError(87), -1)
    EndIf
    Local $iFlagError = 0, $iDLL = -1, $iTimer = 0, $iFlagRemain = 0
    Local $tBuffer1, $tBuffer2, $pBuffer1, $pBuffer2
    Local $aResult1, $aResult2, $iLastError, $iError = 6
    Local $iRead1 = 0, $iRead2 = 0, $iFilePos = 0, $iCompared = 1
    Local $iMaxCompare, $iBlockTotal, $iRemainder
    If (Not $iBlockSize) Or ($iBlockSize = -1) Then $iBlockSize = 1024 * 1024
    $iMaxCompare = FileGetSize($sFileSrc)
    $iBlockTotal = Floor($iMaxCompare / $iBlockSize)
    $iRemainder = $iMaxCompare - $iBlockTotal * $iBlockSize
    If $iRemainder Then
        $iBlockTotal += 1
        $iFlagRemain = 1
    EndIf

    If IsDeclared("hInFile1") = 0 Or IsDeclared("hInFile2") = 0 Or IsDeclared("iDLL") = 0 Then
        ConsoleWrite("!Variables used without being declared" & @CRLF)
        _WinAPI_SetLastError(87) ; set last error for missing global scope variables
        Return SetError(2, 0, -1)
    EndIf

    ConsoleWrite("+Filesize           : " & $iMaxCompare & @CRLF)
    ConsoleWrite("+Block size         : " & $iBlockSize & @CRLF)
    ConsoleWrite("+Remainder block    : " & $iRemainder & @CRLF)
    ConsoleWrite("+Number of blocks   : " & $iBlockTotal & @CRLF)
    ConsoleWrite("+Block total        : " & ($iBlockTotal * $iBlockSize) + ($iRemainder - $iBlockSize) & @CRLF)

    $hInFile1 = _WinAPI_CreateFile($sFileSrc, 2, 2, 6)
    If Not $hInFile1 Or $hInFile1 = $INVALID_HANDLE_VALUE Then Return SetError(3, 0, -1)
    $hInFile2 = _WinAPI_CreateFile($sFileCopy, 2, 2, 6)
    If Not $hInFile2 Or $hInFile2 = $INVALID_HANDLE_VALUE Then
        _WinAPI_CloseHandle($hInFile1)
        Return SetError(4, 0, -1)
    EndIf

    $iDLL = DllOpen("Kernel32.dll")
    If $iDLL = -1 Then
        If $hInFile1 And $hInFile1 <> $INVALID_HANDLE_VALUE Then _WinAPI_CloseHandle($hInFile1)
        If $hInFile2 And $hInFile2 <> $INVALID_HANDLE_VALUE Then _WinAPI_CloseHandle($hInFile2)
        $hInFile1 = ""
        $hInFile2 = ""
        _WinAPI_SetLastError(6) ; set last error for invalid handle
        Return SetError(5, 0, -1)
    EndIf

    $iTimer = TimerInit()

    Do
        ;Sleep(10)
        $aResult1 = DllCall($iDLL, "dword", "SetFilePointerEx", "hwnd", _
                $hInFile1, "uint64", $iFilePos, "uint64*", 0, "dword", $FILE_BEGIN)
        If @error Or Not $aResult1[0] Then
            $iError = 6
            If Not _WinAPI_GetLastError() Then _WinAPI_SetLastError(87)
            ExitLoop
        EndIf

        $aResult2 = DllCall($iDLL, "dword", "SetFilePointerEx", "hwnd", _
                $hInFile2, "uint64", $iFilePos, "uint64*", 0, "dword", $FILE_BEGIN)
        If @error Or Not $aResult2[0] Then
            $iError = 7
            If Not _WinAPI_GetLastError() Then _WinAPI_SetLastError(87)
            ExitLoop
        EndIf

        $tBuffer1 = DllStructCreate("ubyte [" & $iBlockSize & "]")
        If @error Or Not IsDllStruct($tBuffer1) Then
            $iError = 8
            If Not _WinAPI_GetLastError() Then _WinAPI_SetLastError(87)
            ExitLoop
        EndIf

        $pBuffer1 = DllStructGetPtr($tBuffer1)
        If Not __WinAPI_ReadFile($hInFile1, $pBuffer1, $iBlockSize, $iRead1, 0, $iDLL) Then
            $iError = 9
            ExitLoop
        EndIf

        $tBuffer2 = DllStructCreate("ubyte [" & $iBlockSize & "]")
        If @error Or Not IsDllStruct($tBuffer2) Then
            $iError = 10
            If Not _WinAPI_GetLastError() Then _WinAPI_SetLastError(87)
            ExitLoop
        EndIf

        $pBuffer2 = DllStructGetPtr($tBuffer2)
        If Not __WinAPI_ReadFile($hInFile2, $pBuffer2, $iBlockSize, $iRead2, 0, $iDLL) Then
            $iError = 11
            ExitLoop
        EndIf

        ;ConsoleWrite("- File1 pointer position: " & $aResult1[3] & @CRLF) ; debug only: consolewrites slow down loop
        ;ConsoleWrite(" [" & $iRead1 & "] file1 bytes read" & @CRLF)

        If $iRead1 <> $iRead2 Or Not $iRead1 Or Not $iRead2 Then ; compare returned size of read data to block size
            _WinAPI_SetLastError(87)
            $iError = 12
            ExitLoop
        EndIf

        If DllStructGetData($tBuffer1, 1) <> DllStructGetData($tBuffer2, 1) Then $iFlagError = 1
        If @error Then
            _WinAPI_SetLastError(87)
            $iError = 13
            ExitLoop
        EndIf

        $tBuffer1 = "" ; clear memory
        $tBuffer2 = ""
        If $iFlagError Then ExitLoop
        $iFilePos += $iRead1
        $iCompared += 1
        If $iCompared = $iBlockTotal And $iFlagRemain Then $iBlockSize = $iRemainder

    Until $iCompared = ($iBlockTotal + 1)

    $iLastError = _WinAPI_GetLastError()
    If $iLastError Then ConsoleWrite("!GetLastError [" & $iLastError & "] " & _WinAPI_GetLastErrorMessage())
    If $iTimer Then ConsoleWrite("-Duration in seconds: " & Round(TimerDiff($iTimer) / 1000) & @CRLF)

    If $iDLL <> -1 Then DllClose($iDLL)
    If $hInFile1 And $hInFile1 <> $INVALID_HANDLE_VALUE Then _WinAPI_CloseHandle($hInFile1)
    If $hInFile2 And $hInFile2 <> $INVALID_HANDLE_VALUE Then _WinAPI_CloseHandle($hInFile2)
    $iDLL = -1
    $hInFile1 = ""
    $hInFile2 = ""

    If $iFlagError Then
        ConsoleWrite("!Error found in file         : " & $sFileCopy & @CRLF)
        ConsoleWrite("!Error found in block number : " & $iCompared & @CRLF)
        ConsoleWrite("!Block start position        : " & $aResult2[3] & @CRLF)
        ConsoleWrite("!Block end position          : " & $aResult2[3] + $iRead1 & @CRLF)
        ConsoleWrite("!Block size                  : " & $iRead1 & @CRLF)
        $iInt64Pos = $aResult2[3]
        Return SetError(6, 0, 0)
    EndIf

    If $iCompared = ($iBlockTotal + 1) Then
        $iInt64Pos = 0
        ConsoleWrite("-No errors found in file: " & $sFileCopy & @CRLF)
        Return SetError(0, Round(TimerDiff($iTimer) / 1000), 1)
    EndIf

    _WinAPI_SetLastError($iLastError)
    Return SetError($iError, 0, -1)
EndFunc   ;==>_CheckFileIntegrity

Func __WinAPI_ReadFile($hFile, $pBuffer, $iToRead, ByRef $iRead, $pOverlapped = 0, $hDLL = -1)
    ; Modified to use dll handle and removed dllstruct code
    Local $aResult
    $iRead = 0
    ; extended not set in SetError()(only to get code on one line)
    If Not $iToRead Then Return SetError(1, _WinAPI_SetLastError(87), False)
    If Not $hDLL Or $hDLL = -1 Then $hDLL = "Kernel32.dll"
    $aResult = DllCall($hDLL, "int", "ReadFile", "hwnd", $hFile, "ptr", _
            $pBuffer, "int", $iToRead, "int*", 0, "ptr", $pOverlapped)
    If @error Or ($iToRead <> $aResult[4]) Then Return SetError(@error, _WinAPI_SetLastError(87), False)
    $iRead = $aResult[4]
    Return SetError(@error, 0, $aResult[0] <> 0)
EndFunc   ;==>__WinAPI_ReadFile

; if exiting while scanning files (tray icon menu exit etc.) this allows for handle closing
Func OnAutoItExit()
    If _WinAPI_GetLastError() Then
        ConsoleWrite("!GetLastError [" & _WinAPI_GetLastError() & "] " & _WinAPI_GetLastErrorMessage())
    EndIf
    If $iDLL <> -1 Then DllClose($iDLL)
    If $hInFile1 And $hInFile1 <> $INVALID_HANDLE_VALUE Then _WinAPI_CloseHandle($hInFile1)
    If $hInFile2 And $hInFile2 <> $INVALID_HANDLE_VALUE Then _WinAPI_CloseHandle($hInFile2)
EndFunc   ;==>OnAutoItExit

I see fascists...

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...