#cs
IMPORTANT NOTES
===============
CRYPT LIBRARY
-------------
This UDF initializes the Crypt library by calling _Crypt_Startup() in the _LFC_ControlBuffers function.
This is done only once (the ref count is checked), however to optimize performance _Crypt_Shutdown() is
NEVER called. It is advised to call _Crypt_Shutdown() when finished using this UDF.
BUFFERS
-------
Global buffers are created on the first call to any of the functions. These buffers will exist for the life
of the script, unless a function is called with a larger buffer size, in which case the buffers will be
recreated at the larger size. The buffers will never shrink. To reclaim the used memory, call the internal
function _LFC_FreeBuffers(). This will free all the allocated memory and will trigger buffer recreation on
the next call to any of the functions.
One additional 2M static buffer is created for file hash verification. It is created once for the life of
the script, when and only if hash verification is selected, and cannot be freed. See the
_LFC_HashFileInternal function.
SECURITY DESCRIPTORS
--------------------
To properly copy all security descriptors and owner information, the script must have full admin rights and
successfully get the SeSecurityPrivilege right. This means your script must include the #RequireAdmin
directive on Vista+ where UAC is enabled. Access rights are checked and acquired only once.
Only non-inherited descriptors are copied. Setting the owner may fail if the script does not have rights,
ie trying to set the owner to SYSTEM or TrustedInstaller.
#ce
#include-once
#include <Crypt.au3>
#include <File.au3>
#include <Memory.au3>
#include <WinAPI.au3>
#include <_FileEx.au3>
#region FUNCTIONS
; #FUNCTION# ====================================================================================================
; Name...........: _LargeFileCopy
; Description....: Copy large files in such a way as to keep AutoIt GUIs responsive
; Syntax.........: _LargeFileCopy($sSrc, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
; Parameters.....: $sSrc - Source file name
; $sDest - Destination: may be a file name or directory
; $iFlags - [Optional] Combine flags with BitOR
; | 1 - Overwrite existing file
; | 2 - Create destination directory structure
; | 4 - Flush the destination file buffer before returning
; | 8 - Verify source and destination are identical via bit by bit comparison
; | 16 - Verify source and destination are identical via MD5 hash
; | 32 - Verify source and destination file size only
; | 64 - Copy source file attributes (NOT including Compression or Encryption)
; | 128 - Copy source file Creation time
; | 256 - Copy source file Last Accessed time
; | 512 - Copy source file Modified time
; |1024 - Copy source file Security Descriptors and Ownership
; |2048 - Copy source compression state
; |4096 - Copy source encryption state
; + If more than one verify flag is set, the smallest flag will take precedence
; $iToRead - [Optional] Size of the read/write buffer (Default = 2 MB)
; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
; $sFunction - [Optional] Function to be called after each write operation (Default = "")
; + Function will be called with the following parameters:
; | 1 - Total bytes written
; | 2 - Total file size in bytes
; | 3 - Optional user variable
; $vUserVar - [Optional] User variable to pass to function (Default = Default)
;
; Return values..: Success - 1
; Failure - 0 and sets @error
; | 1 - Failed to open source file, or source was a directory
; | 2 - Destination file exists and overwrite flag not set
; | 3 - Failed to create destination file
; | 4 - Read error during copy
; | 5 - Write error during copy
; | 6 - Verify failed
; Author.........: Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _LargeFileCopy($sSrc, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
; check / fix source and dest path syntax
_LFC_FixPathEx($sSrc, $sDest)
; open file for reading, fail if it doesn't exist or directory
Local $hSrc = _FileEx_CreateFile($sSrc, $GENERIC_READ, $FILE_SHARE_READ, $OPEN_EXISTING, 0)
If Not $hSrc Then Return SetError(1, 0, 0)
; set option flags
Local $fOverwrite = (BitAND($iFlags, 1) = 1)
Local $fCreate = (BitAND($iFlags, 2) = 2)
Local $fFlush = (BitAND($iFlags, 4) = 4)
Local $fVerify = 0
If (BitAND($iFlags, 8) = 8) Then
; bit by bit
$fVerify = 1
ElseIf (BitAND($iFlags, 16) = 16) Then
; hash
$fVerify = 2
ElseIf (BitAND($iFlags, 32) = 32) Then
; file size
$fVerify = 3
EndIf
Local $fAttr = (BitAND($iFlags, 64) = 64)
Local $fTimeC = (BitAND($iFlags, 128) = 128)
Local $fTimeA = (BitAND($iFlags, 256) = 256)
Local $fTimeM = (BitAND($iFlags, 512) = 512)
Local $fACL = (BitAND($iFlags, 1024) = 1024)
Local $fCompress = (BitAND($iFlags, 2048) = 2048)
Local $fEncrypt = (BitAND($iFlags, 4096) = 4096)
; check destination (this function will delete the destination file if it exists and $fOverwrite is True)
_LFC_CheckDestination($sSrc, $sDest, $fOverwrite, $fCreate)
If @error Then
_WinAPI_CloseHandle($hSrc)
Return SetError(2, 0, 0)
EndIf
; check source and destination file systems and disable NTFS specific features if $fACL or $fCompress or $fEncrypt is true
If ($fACL Or $fCompress Or $fEncrypt) And _
((DriveGetFileSystem(_FileEx_PathGetRoot($sSrc)) <> "NTFS") Or (DriveGetFileSystem(_FileEx_PathGetRoot($sDest)) <> "NTFS")) Then
$fACL = False
$fCompress = False
$fEncrypt = False
EndIf
; get source attributes only if needed
Local $iAttr = 0
If $fAttr Or $fCompress Or $fEncrypt Then
$iAttr = _FileEx_GetAttributes($sSrc)
EndIf
; ACL operations require full Admin access, ie #RequireAdmin on Vista+
; check for proper elevation and attempt to get the SeSecurityPrivilege right
Local $iSeSecurity
If $fACL Then
$iSeSecurity = _LFC_CheckACLAdmin()
If @error Then $fACL = False
EndIf
; create destination file
; check encryption / compression attributes if NTFS, they are mutually exclusive
Local $hDest
If $fCompress And (BitAND($iAttr, 0x800) = 0x800) Then ; FILE_ATTRIBUTE_COMPRESSED
; compression is not a settable attribute
$hDest = _LFC_CreateCompressedFile($sDest)
ElseIf $fEncrypt And (BitAND($iAttr, 0x4000) = 0x4000) Then ; FILE_ATTRIBUTE_ENCRYPTED
; encryption
$hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0x4000)
Else
; normal file
$hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0)
EndIf
;
If Not $hDest Then
_WinAPI_CloseHandle($hSrc)
Return SetError(3, 0, 0)
EndIf
; check for 0 byte source file
Local $iSize = _WinAPI_GetFileSizeEx($hSrc)
If $iSize = 0 Then
; nothing to copy, close handles
_WinAPI_CloseHandle($hDest)
_WinAPI_CloseHandle($hSrc)
Else
; perform copy
Local $iRead, $iWritten, $bytesRead = 0, $iTotal = 0, $mSrc = 0, $iReadError = 0, $iWriteError = 0, $iVerifyError = 0
; allocate buffers
Local $apBuffers = _LFC_CreateBuffers($iToRead)
; read buffer
Local $pBuffer = $apBuffers[0]
; verify buffer
Local $pvBuffer = $apBuffers[1]
While $bytesRead < $iSize
If $iToRead > ($iSize - $bytesRead) Then $iToRead = $iSize - $bytesRead
If Not _WinAPI_ReadFile($hSrc, $pBuffer, $iToRead, $iRead) Or ($iToRead <> $iRead) Then
$iReadError = 1
ExitLoop
EndIf
If Not _WinAPI_WriteFile($hDest, $pBuffer, $iRead, $iWritten) Or ($iRead <> $iWritten) Then
$iWriteError = 1
ExitLoop
EndIf
If $sFunction Then
$iTotal += $iToRead
Call($sFunction, $iTotal, $iSize, $vUserVar)
EndIf
If $fVerify = 1 Then
; compare data
If Not _LFC_BitCompare($hDest, $pBuffer, $pvBuffer, $iToRead) Then
$iVerifyError = 1
ExitLoop
EndIf
ElseIf $fVerify = 2 Then
; hash source inline
$mSrc = _LFC_ChunkHash($mSrc, $pBuffer, $iToRead, $iAlg)
EndIf
$bytesRead += $iToRead
WEnd
; the FlushFileBuffers command here can take some time: ~1s for a 75MB file, ~4s for a 700MB file
; it's probably safest to enable this if you need to make sure the write buffer is empty before continuing
; the FileCopy function does NOT seem to do this based on execution time
If $fFlush Then _WinAPI_FlushFileBuffers($hDest)
; check file size in verify mode 3 before closing handles
If $fVerify = 3 Then
If Not _LFC_SizeCompare($hSrc, $hDest) Then $iVerifyError = 1
EndIf
; close handles
_WinAPI_CloseHandle($hDest)
_WinAPI_CloseHandle($hSrc)
If $fVerify = 2 Then
; finalize hash
$mSrc = _LFC_ChunkHashFinal($mSrc)
EndIf
If $iReadError Then
Return SetError(4, 0, 0)
ElseIf $iWriteError Then
Return SetError(5, 0, 0)
Else
If ($fVerify = 1) Or ($fVerify = 3) Then
If $iVerifyError Then Return SetError(6, 0, 0)
ElseIf ($fVerify = 2) Then
; hash destination and verify
Local $mDest = _LFC_HashFile($sDest, $iAlg)
If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
EndIf
EndIf
EndIf
; copy security descriptors
If $fACL Then _LFC_CopyPathSD($sSrc, $sDest, $iSeSecurity)
; copy file times
If $fTimeC Or $fTimeA Or $fTimeM Then
Local $tC, $tA, $tM
_FileEx_GetFileTime($sSrc, $tC, $tA, $tM)
If Not $fTimeC Then $tC = 0
If Not $fTimeA Then $tA = 0
If Not $fTimeM Then $tM = 0
_FileEx_SetFileTime($sDest, $tC, $tA, $tM)
EndIf
; copy attributes (does not affect file times)
If $fAttr Then _FileEx_SetAttributes($sDest, $iAttr)
Return 1
EndFunc ;==>_LargeFileCopy
; #FUNCTION# ====================================================================================================
; Name...........: _LargeFileCopyUnbuffered
; Description....: Copy large files in such a way as to keep AutoIt GUIs responsive
; Syntax.........: _LargeFileCopyUnbuffered($sSrc, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
; Parameters.....: $sSrc - Source file name
; $sDest - Destination: may be a file name or directory
; $iFlags - [Optional] Combine flags with BitOR
; | 1 - Overwrite existing file
; | 2 - Create destination directory structure
; | 8 - Verify source and destination are identical via bit by bit comparison
; | 16 - Verify source and destination are identical via MD5 hash
; | 64 - Copy source file attributes (NOT including Compression or Encryption)
; | 128 - Copy source file Creation time
; | 256 - Copy source file Last Accessed time
; | 512 - Copy source file Modified time
; |1024 - Copy source file Security Descriptors and Ownership
; |2048 - Copy source compression state
; |4096 - Copy source encryption state
; + If more than one verify flag is set, the smallest flag will take precedence
; $iToRead - [Optional] Size of the read buffer (Default = 8 MB)
; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
; $sFunction - [Optional] Function to be called after each write operation (Default = "")
; + Function will be called with the following parameters:
; | 1 - Total bytes written
; | 2 - Total file size in bytes
; | 3 - Optional user variable
; $vUserVar - [Optional] User variable to pass to function (Default = Default)
;
; Return values..: Success - 1
; Failure - 0 and sets @error
; | 1 - Failed to open source file, or source was a directory
; | 2 - Destination file exists and overwrite flag not set
; | 3 - Failed to create destination file
; | 4 - Read error during copy
; | 5 - Write error during copy
; | 6 - Verify failed
; | 7 - Failed to set destination file size
; Author.........: Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _LargeFileCopyUnbuffered($sSrc, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
; check / fix source and dest path syntax
_LFC_FixPathEx($sSrc, $sDest)
; open file for reading, fail if it doesn't exist or directory
Local $hSrc = _FileEx_CreateFile($sSrc, $GENERIC_READ, $FILE_SHARE_READ, $OPEN_EXISTING, 0)
If Not $hSrc Then Return SetError(1, 0, 0)
; set option flags
Local $fOverwrite = (BitAND($iFlags, 1) = 1)
Local $fCreate = (BitAND($iFlags, 2) = 2)
Local $fVerify = 0
If (BitAND($iFlags, 8) = 8) Then
; bit by bit
$fVerify = 1
ElseIf (BitAND($iFlags, 16) = 16) Then
; hash
$fVerify = 2
EndIf
Local $fAttr = (BitAND($iFlags, 64) = 64)
Local $fTimeC = (BitAND($iFlags, 128) = 128)
Local $fTimeA = (BitAND($iFlags, 256) = 256)
Local $fTimeM = (BitAND($iFlags, 512) = 512)
Local $fACL = (BitAND($iFlags, 1024) = 1024)
Local $fCompress = (BitAND($iFlags, 2048) = 2048)
Local $fEncrypt = (BitAND($iFlags, 4096) = 4096)
; check destination
_LFC_CheckDestination($sSrc, $sDest, $fOverwrite, $fCreate)
If @error Then
_WinAPI_CloseHandle($hSrc)
Return SetError(2, 0, 0)
EndIf
; check source and destination file systems and disable NTFS specific features if $fACL or $fCompress or $fEncrypt is true
If ($fACL Or $fCompress Or $fEncrypt) And _
((DriveGetFileSystem(_FileEx_PathGetRoot($sSrc)) <> "NTFS") Or (DriveGetFileSystem(_FileEx_PathGetRoot($sDest)) <> "NTFS")) Then
$fACL = False
$fCompress = False
$fEncrypt = False
EndIf
; get source attributes only if needed
Local $iAttr = 0
If $fAttr Or $fCompress Or $fEncrypt Then
$iAttr = _FileEx_GetAttributes($sSrc)
EndIf
; ACL operations require full Admin access, ie #RequireAdmin on Vista+
; check for proper elevation and attempt to get the SeSecurityPrivilege right
Local $iSeSecurity
If $fACL Then
$iSeSecurity = _LFC_CheckACLAdmin()
If @error Then $fACL = False
EndIf
; create destination file
; check encryption / compression attributes if NTFS, they are mutually exclusive
Local $hDest
If $fCompress And (BitAND($iAttr, 0x800) = 0x800) Then ; FILE_ATTRIBUTE_COMPRESSED
; compression is not an attribute
$hDest = _LFC_CreateCompressedFile($sDest, 0xA0000000)
ElseIf $fEncrypt And (BitAND($iAttr, 0x4000) = 0x4000) Then ; FILE_ATTRIBUTE_ENCRYPTED
$hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0xA0004000)
Else
; normal file
; FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
$hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0xA0000000)
EndIf
;
If Not $hDest Then
_WinAPI_CloseHandle($hSrc)
Return SetError(3, 0, 0)
EndIf
; check for 0 byte source file
Local $iSize = _WinAPI_GetFileSizeEx($hSrc)
If $iSize = 0 Then
; nothing to copy, close handles
_WinAPI_CloseHandle($hDest)
_WinAPI_CloseHandle($hSrc)
Else
; get destination disk cluster size for unbuffered i/o
Local $ClusterSize = _FileEx_GetDiskClusterSize($sDest)
; if error, default to 512 and hope for the best, at worst the write operation will fail later on
If @error Then $ClusterSize = 512
; perform copy
Local $iRead, $iWritten, $bytesRead = 0, $iTotal = 0, $mSrc = 0, $iReadError = 0, $iWriteError = 0, $iVerifyError = 0
; create aligned buffer
$iToRead = Floor($iToRead / $ClusterSize) * $ClusterSize
If $iToRead = 0 Then $iToRead = $ClusterSize
Local $apBuffers = _LFC_CreateBuffers($iToRead)
Local $pBuffer = $apBuffers[0]
Local $pvBuffer = $apBuffers[1]
Local $alignedWrite = $iToRead
While $bytesRead < $iSize
If $iToRead > ($iSize - $bytesRead) Then $iToRead = $iSize - $bytesRead
If Not _WinAPI_ReadFile($hSrc, $pBuffer, $iToRead, $iRead) Or ($iToRead <> $iRead) Then
$iReadError = 1
ExitLoop
EndIf
; set aligned write size for final pass
If $iRead < $alignedWrite Then $iRead = Ceiling($iRead / $ClusterSize) * $ClusterSize
If Not _WinAPI_WriteFile($hDest, $pBuffer, $iRead, $iWritten) Or ($iRead <> $iWritten) Then
$iWriteError = 1
ExitLoop
EndIf
If $sFunction Then
$iTotal += $iToRead
Call($sFunction, $iTotal, $iSize, $vUserVar)
EndIf
If $fVerify = 1 Then
; compare data, using $iRead because it must be a cluster sized block of data
If Not _LFC_BitCompare($hDest, $pBuffer, $pvBuffer, $iRead) Then
$iVerifyError = 1
ExitLoop
EndIf
ElseIf $fVerify = 2 Then
; hash source inline
$mSrc = _LFC_ChunkHash($mSrc, $pBuffer, $iToRead, $iAlg)
EndIf
$bytesRead += $iToRead
WEnd
; close handles
_WinAPI_CloseHandle($hSrc)
_WinAPI_CloseHandle($hDest)
If $fVerify = 2 Then
; finalize hash
$mSrc = _LFC_ChunkHashFinal($mSrc)
EndIf
; don't bother if errors above
If (Not $iReadError) And (Not $iWriteError) And (Not $iVerifyError) Then
; set correct destination file size
$hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $OPEN_EXISTING, 0)
If $hDest Then
DllCall("kernel32.dll", "bool", "SetFilePointerEx", "handle", $hDest, "int64", $iSize, "ptr", 0, "dword", 0)
_WinAPI_SetEndOfFile($hDest)
_WinAPI_CloseHandle($hDest)
Else
Return SetError(7, 0, 0)
EndIf
EndIf
; close dest handle
_WinAPI_CloseHandle($hDest)
If $iReadError Then
Return SetError(4, 0, 0)
ElseIf $iWriteError Then
Return SetError(5, 0, 0)
Else
If ($fVerify = 1) Then
If $iVerifyError Then Return SetError(6, 0, 0)
ElseIf ($fVerify = 2) Then
; hash destination and verify
Local $mDest = _LFC_HashFile($sDest, $iAlg)
If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
EndIf
EndIf
EndIf
; copy security descriptors
If $fACL Then _LFC_CopyPathSD($sSrc, $sDest, $iSeSecurity)
; copy file times
If $fTimeC Or $fTimeA Or $fTimeM Then
Local $tC, $tA, $tM
_FileEx_GetFileTime($sSrc, $tC, $tA, $tM)
If Not $fTimeC Then $tC = 0
If Not $fTimeA Then $tA = 0
If Not $fTimeM Then $tM = 0
_FileEx_SetFileTime($sDest, $tC, $tA, $tM)
EndIf
; copy attributes (does not affect file times)
If $fAttr Then _FileEx_SetAttributes($sDest, $iAttr)
Return 1
EndFunc ;==>_LargeFileCopyUnbuffered
; #FUNCTION# ====================================================================================================
; Name...........: _LargeRawCopy
; Description....: Copy large memory blocks to files in such a way as to keep AutoIt GUIs responsive
; Syntax.........: _LargeRawCopy($pSrc, $iSrcSize, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
; Parameters.....: $pSrc - Pointer to source raw data
; $iSrcSize - Size of raw data
; $sDest - Destination file name, must not be an existing directory
; $iFlags - [Optional] Combine flags with BitOR
; | 1 - Overwrite existing file
; | 2 - Create destination directory structure
; | 4 - Flush the destination file buffer before returning
; | 8 - Verify source and destination are identical via bit by bit comparison
; |16 - Verify source and destination are identical via MD5 hash
; |32 - Verify source and destination file size only
; + If more than one verify flag is set, the smallest flag will take precedence
; $iToRead - [Optional] Size of the read buffer (Default = 8 MB)
; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
; $sFunction - [Optional] Function to be called after each write operation (Default = "")
; + Function will be called with the following parameters:
; | 1 - Total bytes written
; | 2 - Total file size in bytes
; | 3 - Optional user variable
; $vUserVar - [Optional] User variable to pass to function (Default = Default)
;
; Return values..: Success - 1
; Failure - 0 and sets @error
; |-1 - $iSrcSize may not be 0
; | 1 - $pSrc and $iSrcSize point to inaccessible memory
; | 2 - Destination is an existing directory
; | 3 - Destination file exists and overwrite flag not set
; | 4 - Failed to create destination file
; | 5 - Write error during copy
; | 6 - Verify failed
; Author.........: Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _LargeRawCopy($pSrc, $iSrcSize, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
; check source size
If $iSrcSize = 0 Then Return SetError(-1, 0, 0)
; check source memory, 0 = success
Local $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pSrc, "uint_ptr", $iSrcSize)
If $ret[0] Then Return SetError(1, 0, 0)
; check / fix dest path syntax
$sDest = StringReplace($sDest, "/", "\")
_LFC_FixPath($sDest)
; set option flags
Local $fOverwrite = (BitAND($iFlags, 1) = 1)
Local $fCreate = (BitAND($iFlags, 2) = 2)
Local $fFlush = (BitAND($iFlags, 4) = 4)
Local $fVerify = 0
If (BitAND($iFlags, 8) = 8) Then
; bit by bit
$fVerify = 1
ElseIf (BitAND($iFlags, 16) = 16) Then
; MD5
$fVerify = 2
ElseIf (BitAND($iFlags, 32) = 32) Then
; file size
$fVerify = 3
EndIf
; check destination
_LFC_CheckDestination("", $sDest, $fOverwrite, $fCreate)
Switch @error
Case 1
; overwrite fail
Return SetError(3, 0, 0)
Case 2
; no file name
Return SetError(2, 0, 0)
EndSwitch
; create new file for writing, overwrite
Local $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0)
If Not $hDest Then Return SetError(4, 0, 0)
; perform copy
If $iToRead > $iSrcSize Then $iToRead = $iSrcSize
Local $pRead = $pSrc
Local $iWritten, $bytesRead = 0, $iTotal = 0, $mSrc = 0, $iWriteError = 0, $iVerifyError = 0
; allocate buffers
Local $apBuffers = _LFC_CreateBuffers($iToRead)
; verify buffer
Local $pvBuffer = $apBuffers[1]
While $bytesRead < $iSrcSize
If $iToRead > ($iSrcSize - $bytesRead) Then $iToRead = $iSrcSize - $bytesRead
If Not _WinAPI_WriteFile($hDest, $pRead, $iToRead, $iWritten) Or ($iToRead <> $iWritten) Then
$iWriteError = 1
ExitLoop
EndIf
If $sFunction Then
$iTotal += $iToRead
Call($sFunction, $iTotal, $iSrcSize, $vUserVar)
EndIf
If $fVerify = 1 Then
; compare data
If Not _LFC_BitCompare($hDest, $pRead, $pvBuffer, $iToRead) Then
$iVerifyError = 1
ExitLoop
EndIf
ElseIf $fVerify = 2 Then
; hash source inline
$mSrc = _LFC_ChunkHash($mSrc, $pRead, $iToRead, $iAlg)
EndIf
; ready next chunk
$pRead += $iToRead
$bytesRead += $iToRead
WEnd
; the FlushFileBuffers command here can take some time: ~1s for a 75MB file, ~4s for a 700MB file
; it's probably safest to enable this if you need to make sure the write buffer is empty before continuing
; the FileCopy function does NOT seem to do this based on execution time
If $fFlush Then _WinAPI_FlushFileBuffers($hDest)
; check file size in verify mode 3 before closing handles
If $fVerify = 3 Then
If Not _LFC_SizeCompare($iSrcSize, $hDest) Then $iVerifyError = 1
EndIf
_WinAPI_CloseHandle($hDest)
If $fVerify = 2 Then
; finalize hash
$mSrc = _LFC_ChunkHashFinal($mSrc)
EndIf
If $iWriteError Then
Return SetError(5, 0, 0)
Else
If ($fVerify = 1) Or ($fVerify = 3) Then
If $iVerifyError Then Return SetError(6, 0, 0)
ElseIf ($fVerify = 2) Then
; hash destination and verify
Local $mDest = _LFC_HashFile($sDest, $iAlg)
If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
EndIf
EndIf
Return 1
EndFunc ;==>_LargeRawCopy
; #FUNCTION# ====================================================================================================
; Name...........: _LargeRawCopyUnbuffered
; Description....: Copy large memory blocks to files in such a way as to keep AutoIt GUIs responsive
; Syntax.........: _LargeRawCopyUnbuffered($pSrc, $iSrcSize, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
; Parameters.....: $pSrc - Pointer to source raw data
; $iSrcSize - Size of raw data
; $sDest - Destination file name, must not be an existing directory
; $iFlags - [Optional] Combine flags with BitOR
; | 1 - Overwrite existing file
; | 2 - Create destination directory structure
; | 8 - Verify source and destination are identical via bit by bit comparison
; |16 - Verify source and destination are identical via MD5 hash
; + If more than one verify flag is set, the smallest flag will take precedence
; $iToRead - [Optional] Size of the read buffer (Default = 8 MB)
; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
; $sFunction - [Optional] Function to be called after each write operation (Default = "")
; + Function will be called with the following parameters:
; | 1 - Total bytes written
; | 2 - Total file size in bytes
; | 3 - Optional user variable
; $vUserVar - [Optional] User variable to pass to function (Default = Default)
;
; Return values..: Success - 1
; Failure - 0 and sets @error
; |-1 - $iSrcSize may not be 0
; | 1 - $pSrc and $iSrcSize point to inaccessible memory
; | 2 - Destination is an existing directory
; | 3 - Destination file exists and overwrite flag not set
; | 4 - Failed to create destination file
; | 5 - Write error during copy
; | 6 - Verify failed
; | 7 - Failed to set destination file size
; Author.........: Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _LargeRawCopyUnbuffered($pSrc, $iSrcSize, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
; check source size
If $iSrcSize = 0 Then Return SetError(-1, 0, 0)
; check source memory, 0 = success
Local $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pSrc, "uint_ptr", $iSrcSize)
If $ret[0] Then Return SetError(1, 0, 0)
; check / fix dest path syntax
$sDest = StringReplace($sDest, "/", "\")
_LFC_FixPath($sDest)
; set option flags
Local $fOverwrite = (BitAND($iFlags, 1) = 1)
Local $fCreate = (BitAND($iFlags, 2) = 2)
Local $fVerify = 0
If (BitAND($iFlags, 8) = 8) Then
; bit by bit
$fVerify = 1
ElseIf (BitAND($iFlags, 16) = 16) Then
; MD5
$fVerify = 2
EndIf
; check destination
_LFC_CheckDestination("", $sDest, $fOverwrite, $fCreate)
Switch @error
Case 1
; overwrite fail
Return SetError(3, 0, 0)
Case 2
; no file name
Return SetError(2, 0, 0)
EndSwitch
; get destination disk cluster size for unbuffered i/o
Local $ClusterSize = _FileEx_GetDiskClusterSize($sDest)
; if error, default to 512 and hope for the best, at worst the write operation will fail later on
If @error Then $ClusterSize = 512
; create new file for writing, overwrite
Local $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0xA0000000) ; FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
If Not $hDest Then Return SetError(4, 0, 0)
; perform copy
; create aligned buffer
$iToRead = Floor($iToRead / $ClusterSize) * $ClusterSize
If $iToRead = 0 Then $iToRead = $ClusterSize
Local $pRead = $pSrc
Local $iWritten, $bytesRead = 0, $iRead = 0, $iTotal = 0, $mSrc = 0, $iWriteError = 0, $iVerifyError = 0
Local $apBuffers = _LFC_CreateBuffers($iToRead)
Local $pBuffer = $apBuffers[0]
Local $pvBuffer = $apBuffers[1]
Local $alignedWrite = $iToRead
While $bytesRead < $iSrcSize
If $iToRead > ($iSrcSize - $bytesRead) Then $iToRead = $iSrcSize - $bytesRead
; copy memory to write buffer
_LFC_RtlMoveMemory($pBuffer, $pRead, $iToRead)
$iRead = $iToRead
; set aligned write size for final pass
If $iRead < $alignedWrite Then $iRead = Ceiling($iRead / $ClusterSize) * $ClusterSize
; write data
If Not _WinAPI_WriteFile($hDest, $pBuffer, $iRead, $iWritten) Or ($iRead <> $iWritten) Then
$iWriteError = 1
ExitLoop
EndIf
If $sFunction Then
$iTotal += $iToRead
Call($sFunction, $iTotal, $iSrcSize, $vUserVar)
EndIf
If $fVerify = 1 Then
; compare data, using $iRead because it must be a cluster sized block of data
If Not _LFC_BitCompare($hDest, $pBuffer, $pvBuffer, $iRead) Then
$iVerifyError = 1
ExitLoop
EndIf
ElseIf $fVerify = 2 Then
; hash source inline
$mSrc = _LFC_ChunkHash($mSrc, $pBuffer, $iToRead, $iAlg)
EndIf
; ready next chunk
$pRead += $iToRead
$bytesRead += $iToRead
WEnd
; cleanup
_WinAPI_CloseHandle($hDest)
If $fVerify = 2 Then
; finalize hash
$mSrc = _LFC_ChunkHashFinal($mSrc)
EndIf
; don't bother if errors above
If (Not $iWriteError) And (Not $iVerifyError) Then
; set correct destination file size
$hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $OPEN_EXISTING, 0)
If $hDest Then
DllCall("kernel32.dll", "bool", "SetFilePointerEx", "handle", $hDest, "int64", $iSrcSize, "ptr", 0, "dword", 0)
_WinAPI_SetEndOfFile($hDest)
_WinAPI_CloseHandle($hDest)
Else
Return SetError(7, 0, 0)
EndIf
EndIf
If $iWriteError Then
Return SetError(5, 0, 0)
Else
If ($fVerify = 1) Then
If $iVerifyError Then Return SetError(6, 0, 0)
ElseIf ($fVerify = 2) Then
; hash destination and verify
Local $mDest = _LFC_HashFile($sDest, $iAlg)
If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
EndIf
EndIf
Return 1
EndFunc ;==>_LargeRawCopyUnbuffered
#endregion FUNCTIONS
#region INTERNAL FUNCTIONS
Func _LFC_AllocBuffers(ByRef $apBuffers, $iBuffSize)
Dim $apBuffers[2] = [ _
_MemVirtualAlloc(0, $iBuffSize, $MEM_COMMIT, $PAGE_READWRITE), _
_MemVirtualAlloc(0, $iBuffSize, $MEM_COMMIT, $PAGE_READWRITE) _
]
EndFunc ;==>_LFC_AllocBuffers
Func _LFC_BitCompare($hDest, $pSrc, $pVerify, $iToVerify)
; if there are any errors at all, FAIL
; check memory ranges
Local $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pSrc, "uint_ptr", $iToVerify)
If @error Or $ret[0] Then Return SetError(1, 0, 0)
$ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pVerify, "uint_ptr", $iToVerify)
If @error Or $ret[0] Then Return SetError(2, 0, 0)
; first move file pointer back by $iToVerify bytes
$ret = DllCall("kernel32.dll", "bool", "SetFilePointerEx", "handle", $hDest, "int64", -$iToVerify, "ptr", 0, "dword", 1) ; FILE_CURRENT
If @error Or (Not $ret[0]) Then Return SetError(3, 0, 0)
; read data just written to destination
Local $iRead
If Not _WinAPI_ReadFile($hDest, $pVerify, $iToVerify, $iRead) Or ($iRead <> $iToVerify) Then Return SetError(4, 0, 0)
; compare data=
If Not _LFC_RtlCompareMemory($pSrc, $pVerify, $iToVerify) Then
Return SetError(5, 0, 0)
Else
Return 1
EndIf
EndFunc ;==>_LFC_BitCompare
Func _LFC_CheckACLAdmin()
Static Local $fChecked = False, $iSeSecurity = 0
; check for admin rights and acquire SeSecurityPrivilege only once
; on successive calls, return previous value of $iSeSecurity or error
If Not $fChecked Then
$fChecked = True
If IsAdmin() Then
If _LFC_GetSESECURITYNAME() Then
; include SACL_SECURITY_INFORMATION
$iSeSecurity = 0xF
Else
$iSeSecurity = 7
EndIf
EndIf
EndIf
If $iSeSecurity Then
Return $iSeSecurity
Else
Return SetError(1)
EndIf
EndFunc ;==>_LFC_CheckACLAdmin
Func _LFC_CheckDestination($sSrc, ByRef $sDest, $fOverwrite, $fCreate)
Local $iAttr = _FileEx_GetAttributes($sDest)
Local $iErr = @error
If ($iErr And (StringRight($sDest, 1) = "\")) Or ((Not $iErr) And (BitAND($iAttr, 0x10) = 0x10)) Then
; destination does not exist and should be a directory
; OR destination does exist and is a directory
If $sSrc = "" Then
; raw copy, must provide a file name
Return SetError(2)
Else
; use source file name
If StringRight($sDest, 1) <> "\" Then $sDest &= "\" ; add trailing \
$sDest &= StringRegExpReplace($sSrc, ".*\\", "")
EndIf
ElseIf $iErr And $fCreate Then
; destination does not exist and should be a file
; create destination *parent directory*
_FileEx_CreateDirectory(StringRegExpReplace($sDest, "^(.*)\\.*?$", "${1}"))
ElseIf Not $iErr Then
; destination exists and is a file
; check overwrite
If $fOverwrite Then
; set FILE_ATTRIBUTE_NORMAL before attempting delete
_FileEx_SetAttributes($sDest, 0x80)
If Not FileDelete($sDest) Then Return SetError(1)
Else
Return SetError(1)
EndIf
EndIf
; else do nothing
; ie, destination is a file that doesn't exist and $fCreate is false
; if parent directory does not exist and is not created, CreateFile will fail
EndFunc ;==>_LFC_CheckDestination
Func _LFC_ChunkHash($hCryptHash, $pSrc, $iSize, $iAlg = $CALG_MD5)
Local $aRet
If $hCryptHash = 0 Then
; Create Hash object
$aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptCreateHash", "handle", __Crypt_Context(), "uint", $iAlg, "ptr", 0, "dword", 0, "handle*", 0)
If @error Or (Not $aRet[0]) Then Return SetError(1, 0, -1)
$hCryptHash = $aRet[5]
ElseIf $hCryptHash = -1 Then
; previous error
Return SetError(3, 0, -1)
EndIf
$aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptHashData", "handle", $hCryptHash, "ptr", $pSrc, "dword", $iSize, "dword", $CRYPT_USERDATA)
If @error Or (Not $aRet[0]) Then
DllCall(__Crypt_DllHandle(), "bool", "CryptDestroyHash", "handle", $hCryptHash)
Return SetError(2, 0, -1)
EndIf
Return $hCryptHash
EndFunc ;==>_LFC_ChunkHash
Func _LFC_ChunkHashFinal($hCryptHash)
Local $iError, $vReturn
If $hCryptHash = -1 Then
; previous error
$iError = 1
$vReturn = ""
$hCryptHash = 0
Else
; get hash size, in $aRet[3]
Local $aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptGetHashParam", "handle", $hCryptHash, "dword", $HP_HASHSIZE, "dword*", 0, "dword*", 4, "dword", 0)
If @error Or (Not $aRet[0]) Then
$iError = 2
$vReturn = ""
Else
; get hash
Local $hBuff = DllStructCreate("byte[" & $aRet[3] & "]")
$aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptGetHashParam", "handle", $hCryptHash, "dword", $HP_HASHVAL, "ptr", DllStructGetPtr($hBuff), "dword*", DllStructGetSize($hBuff), "dword", 0)
If @error Or (Not $aRet[0]) Then
$iError = 3
$vReturn = ""
Else
$iError = 0
$vReturn = DllStructGetData($hBuff, 1)
EndIf
EndIf
EndIf
; Cleanup and return hash
If $hCryptHash <> 0 Then DllCall(__Crypt_DllHandle(), "bool", "CryptDestroyHash", "handle", $hCryptHash)
Return SetError($iError, 0, $vReturn)
EndFunc ;==>_LFC_ChunkHashFinal
Func _LFC_ControlBuffers($iBuffSize, $fCreate = True)
Static Local $iPrevSize = 0, $apBuffers = 0
If $fCreate Then
If (Not IsArray($apBuffers)) Or ($iBuffSize > $iPrevSize) Then
_LFC_FreeBuffers()
$iPrevSize = $iBuffSize
_LFC_AllocBuffers($apBuffers, $iBuffSize)
; init crypt library, only once
If Not __Crypt_RefCount() Then _Crypt_Startup()
EndIf
Return $apBuffers
Else
If IsArray($apBuffers) Then
_MemVirtualFree($apBuffers[0], 0, $MEM_RELEASE)
_MemVirtualFree($apBuffers[1], 0, $MEM_RELEASE)
EndIf
$iPrevSize = 0
$apBuffers = 0
EndIf
EndFunc ;==>_LFC_ControlBuffers
Func _LFC_CopyPathSD($sSrc, $sDest, $iSeSecurity)
Local $pOwner, $pGroup, $pDACL, $pSACL, $pSD, $iProtect
; copy source security info
_LFC_GetPathSD($sSrc, $pOwner, $pGroup, $pDACL, $pSACL, $pSD, $iProtect, $iSeSecurity)
If @error Then Return SetError(1, 0, 0)
; set destination security info
Local $iErr = 0
_LFC_SetPathSD($sDest, $pOwner, $pGroup, $pDACL, $pSACL, $iProtect, $iSeSecurity)
If @error Then $iErr = @error
DllCall("kernel32.dll", "handle", "LocalFree", "handle", $pSD)
Return SetError($iErr, 0, (Not $iErr))
EndFunc ;==>_LFC_CopyPathSD
Func _LFC_CreateBuffers($iBuffSize)
Return _LFC_ControlBuffers($iBuffSize)
EndFunc ;==>_LFC_CreateBuffers
Func _LFC_CreateCompressedFile($sPath, $iFlag = 0)
;Local Const $FSCTL_SET_COMPRESSION = 0x0009C040
;Local Const $FSCTL_GET_COMPRESSION = 0x0009003C
;Local Const $COMPRESSION_FORMAT_NONE = 0
;Local Const $COMPRESSION_FORMAT_DEFAULT = 1
;Local Const $COMPRESSION_FORMAT_LZNT1 = 2
; create 0 byte file
Local $hFile = _FileEx_CreateFile($sPath, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, $iFlag)
If Not $hFile Then Return SetError(1, 0, 0)
; set compression state
Local $aRet = DllCall("kernel32.dll", "bool", "DeviceIoControl", "handle", $hFile, "dword", 0x0009C040, "ushort*", 1, "dword", 2, _
"ptr", 0, "dword", 0, "dword*", 0, "ptr", 0)
If @error Or (Not $aRet[0]) Then
_WinAPI_CloseHandle($hFile)
FileDelete($sPath)
Return SetError(2, 0, 0)
Else
Return $hFile
EndIf
EndFunc ;==>_LFC_CreateCompressedFile
Func _LFC_FixPath(ByRef $sPath)
; check for drive and make sure it ends in \
If StringRight($sPath, 1) = ":" Then
$sPath &= "\"
Else
; expand any relative path components
; _PathFull follows same rules as FileExists
$sPath = _PathFull($sPath)
EndIf
EndFunc ;==>_LFC_FixPath
Func _LFC_FixPathEx(ByRef $sSrc, ByRef $sDest)
; fix possible forward /
$sSrc = StringReplace($sSrc, "/", "\")
$sDest = StringReplace($sDest, "/", "\")
; remove trailing \'s from source only
$sSrc = StringRegExpReplace($sSrc, "\\+$", "")
; convert to full paths
_LFC_FixPath($sSrc)
_LFC_FixPath($sDest)
EndFunc ;==>_LFC_FixPathEx
Func _LFC_FreeBuffers()
_LFC_ControlBuffers(0, False)
EndFunc ;==>_LFC_FreeBuffers
Func _LFC_GetPathSD($sPath, ByRef $pOwner, ByRef $pGroup, ByRef $pDACL, ByRef $pSACL, ByRef $pSD, ByRef $iProtect, $iSeSecurity)
;Local Const $SE_FILE_OBJECT = 1
;Local Const $OWNER_SECURITY_INFORMATION = 1
;Local Const $GROUP_SECURITY_INFORMATION = 2
;Local Const $DACL_SECURITY_INFORMATION = 4
;Local Const $SACL_SECURITY_INFORMATION = 8
;
;Local Const $SE_DACL_PROTECTED = 0x1000
;Local Const $PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
;Local Const $UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
;
;Local Const $SE_SACL_PROTECTED = 0x2000
;Local Const $PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
;Local Const $UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
Local $aRet = DllCall("advapi32.dll", "dword", "GetNamedSecurityInfoW", "wstr", $sPath, "int", 1, "dword", $iSeSecurity, _
"ptr*", 0, "ptr*", 0, "ptr*", 0, "ptr*", 0, "ptr*", 0)
If @error Or $aRet[0] Then Return SetError(1, 0, 0)
$pOwner = $aRet[4]
$pGroup = $aRet[5]
$pDACL = $aRet[6]
$pSACL = $aRet[7]
$pSD = $aRet[8]
$iProtect = 0 ; default no change
; query SACL, DACL protected states and set flags
$aRet = DllCall("advapi32.dll", "bool", "GetSecurityDescriptorControl", "ptr", $pSD, "word*", 0, "dword*", 0)
If Not @error And $aRet[0] Then
If BitAND($aRet[2], 0x1000) Then
; DACL protected
$iProtect = BitOR($iProtect, 0x80000000)
Else
; unprotected
$iProtect = BitOR($iProtect, 0x20000000)
EndIf
If BitAND($aRet[2], 0x2000) Then
; SACL protected
$iProtect = BitOR($iProtect, 0x40000000)
Else
; unprotected
$iProtect = BitOR($iProtect, 0x10000000)
EndIf
EndIf
Return 1
EndFunc ;==>_LFC_GetPathSD
Func _LFC_GetSESECURITYNAME()
Local $return = False
Local $tagLUIDANDATTRIB = "int64 Luid;dword Attributes"
Local $count = 1
Local $tagTOKENPRIVILEGES = "dword PrivilegeCount;byte LUIDandATTRIB[" & $count * 12 & "]" ; count of LUID structs * sizeof LUID struct
Local $TOKEN_ADJUST_PRIVILEGES = 0x20
Local $SE_PRIVILEGE_ENABLED = 0x2
Local $curProc = DllCall("kernel32.dll", "ptr", "GetCurrentProcess")
If @error Then Return False
Local $call = DllCall("advapi32.dll", "int", "OpenProcessToken", "ptr", $curProc[0], "dword", $TOKEN_ADJUST_PRIVILEGES, "ptr*", 0)
If (@error Or (Not $call[0])) Then Return False
Local $hToken = $call[3]
$call = DllCall("advapi32.dll", "int", "LookupPrivilegeValueW", "ptr", 0, "wstr", "SeSecurityPrivilege", "int64*", 0)
If ((Not @error) And $call[0]) Then
Local $iLuid = $call[3]
Local $TP = DllStructCreate($tagTOKENPRIVILEGES)
Local $LUID = DllStructCreate($tagLUIDANDATTRIB, DllStructGetPtr($TP, "LUIDandATTRIB"))
DllStructSetData($TP, "PrivilegeCount", $count)
DllStructSetData($LUID, "Luid", $iLuid)
DllStructSetData($LUID, "Attributes", $SE_PRIVILEGE_ENABLED)
$call = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "ptr", $hToken, "int", 0, "ptr", DllStructGetPtr($TP), "dword", 0, "ptr", 0, "ptr", 0)
If Not @error Then $return = ($call[0] <> 0) ; $call[0] <> 0 is success
EndIf
DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hToken)
Return SetError(Number(Not $return), 0, $return)
EndFunc ;==>_LFC_GetSESECURITYNAME
Func _LFC_HashFile($sFile, $iAlg = $CALG_MD5)
; check target exists and is a file
If Not FileExists($sFile) Or StringInStr(FileGetAttrib($sFile), "D") Then Return SetError(1, 0, "")
Local $sHash = _LFC_HashFileInternal($sFile, $iAlg)
If @error Or ($sHash = "") Then
Return SetError(2, 0, "")
Else
Return $sHash
EndIf
EndFunc ;==>_LFC_HashFile
Func _LFC_HashFileInternal($sFile, $iAlg = $CALG_MD5)
Local $hSrc = _FileEx_CreateFile($sFile, $GENERIC_READ, $FILE_SHARE_READ, $OPEN_EXISTING, 0)
If Not $hSrc Then Return SetError(1, 0, "")
Local $iSize = _WinAPI_GetFileSizeEx($hSrc)
Local $iRead, $iReadError = 0, $sHash = 0, $iToRead = (1024 ^ 2) * 2
; create 2M hashing buffer only once
Static Local $pBuffer = _MemVirtualAlloc(0, $iToRead, $MEM_COMMIT, $PAGE_READWRITE)
Local $bytesRead = 0
While $bytesRead < $iSize
If $iToRead > ($iSize - $bytesRead) Then $iToRead = $iSize - $bytesRead
If Not _WinAPI_ReadFile($hSrc, $pBuffer, $iToRead, $iRead) Then
$iReadError = 1
ExitLoop
EndIf
$sHash = _LFC_ChunkHash($sHash, $pBuffer, $iRead, $iAlg)
If @error Then
$iReadError = 1
ExitLoop
EndIf
$bytesRead += $iRead
WEnd
_WinAPI_CloseHandle($hSrc)
$sHash = _LFC_ChunkHashFinal($sHash)
If $iReadError Then
Return SetError(2, 0, "")
Else
Return $sHash
EndIf
EndFunc ;==>_LFC_HashFileInternal
Func _LFC_RtlCompareMemory($pSrc1, $pSrc2, $iSize)
Local $ret = DllCall("ntdll.dll", "ulong_ptr", "RtlCompareMemory", "ptr", $pSrc1, "ptr", $pSrc2, "ulong_ptr", $iSize)
If @error Or ($ret[0] <> $iSize) Then
Return SetError(1, 0, 0)
Else
Return 1
EndIf
EndFunc ;==>_LFC_RtlCompareMemory
Func _LFC_RtlMoveMemory($pDest, $pSrc, $iSize)
DllCall("ntdll.dll", "none", "RtlMoveMemory", "ptr", $pDest, "ptr", $pSrc, "ulong_ptr", $iSize)
If @error Then
Return SetError(1, 0, 0)
Else
Return 1
EndIf
EndFunc ;==>_LFC_RtlMoveMemory
Func _LFC_SetPathSD($sPath, $pOwner, $pGroup, $pDACL, $pSACL, $iProtect, $iSeSecurity)
Local $aRet = DllCall("advapi32.dll", "dword", "SetNamedSecurityInfoW", "wstr", $sPath, "int", 1, "dword", BitOR($iProtect, $iSeSecurity), _
"ptr", $pOwner, "ptr", $pGroup, "ptr", $pDACL, "ptr", $pSACL)
If @error Or $aRet[0] Then Return SetError(2, 0, 0)
Return 1
EndFunc ;==>_LFC_SetPathSD
Func _LFC_SizeCompare($hFile1, $hFile2)
Local $iSize1
If IsPtr($hFile1) Then
$iSize1 = DllCall("kernel32.dll", "bool", "GetFileSizeEx", "handle", $hFile1, "int64*", 0)
If @error Or (Not $iSize1[0]) Then Return SetError(1, 0, 0)
$iSize1 = $iSize1[2]
Else
; for _LargeRawCopy
$iSize1 = $hFile1
EndIf
Local $iSize2 = DllCall("kernel32.dll", "bool", "GetFileSizeEx", "handle", $hFile2, "int64*", 0)
If @error Or (Not $iSize2[0]) Then Return SetError(2, 0, 0)
; compare size
If $iSize1 = $iSize2[2] Then
Return 1
Else
Return SetError(3, 0, 0)
EndIf
EndFunc ;==>_LFC_SizeCompare
#endregion INTERNAL FUNCTIONS