_LargeFileCopy UDF


SUBMITTED BY: Guest

DATE: May 30, 2013, 7:58 a.m.

FORMAT: Text only

SIZE: 55.2 kB

HITS: 921

  1. #cs
  2. IMPORTANT NOTES
  3. ===============
  4. CRYPT LIBRARY
  5. -------------
  6. This UDF initializes the Crypt library by calling _Crypt_Startup() in the _LFC_ControlBuffers function.
  7. This is done only once (the ref count is checked), however to optimize performance _Crypt_Shutdown() is
  8. NEVER called. It is advised to call _Crypt_Shutdown() when finished using this UDF.
  9. BUFFERS
  10. -------
  11. Global buffers are created on the first call to any of the functions. These buffers will exist for the life
  12. of the script, unless a function is called with a larger buffer size, in which case the buffers will be
  13. recreated at the larger size. The buffers will never shrink. To reclaim the used memory, call the internal
  14. function _LFC_FreeBuffers(). This will free all the allocated memory and will trigger buffer recreation on
  15. the next call to any of the functions.
  16. One additional 2M static buffer is created for file hash verification. It is created once for the life of
  17. the script, when and only if hash verification is selected, and cannot be freed. See the
  18. _LFC_HashFileInternal function.
  19. SECURITY DESCRIPTORS
  20. --------------------
  21. To properly copy all security descriptors and owner information, the script must have full admin rights and
  22. successfully get the SeSecurityPrivilege right. This means your script must include the #RequireAdmin
  23. directive on Vista+ where UAC is enabled. Access rights are checked and acquired only once.
  24. Only non-inherited descriptors are copied. Setting the owner may fail if the script does not have rights,
  25. ie trying to set the owner to SYSTEM or TrustedInstaller.
  26. #ce
  27. #include-once
  28. #include <Crypt.au3>
  29. #include <File.au3>
  30. #include <Memory.au3>
  31. #include <WinAPI.au3>
  32. #include <_FileEx.au3>
  33. #region FUNCTIONS
  34. ; #FUNCTION# ====================================================================================================
  35. ; Name...........: _LargeFileCopy
  36. ; Description....: Copy large files in such a way as to keep AutoIt GUIs responsive
  37. ; Syntax.........: _LargeFileCopy($sSrc, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
  38. ; Parameters.....: $sSrc - Source file name
  39. ; $sDest - Destination: may be a file name or directory
  40. ; $iFlags - [Optional] Combine flags with BitOR
  41. ; | 1 - Overwrite existing file
  42. ; | 2 - Create destination directory structure
  43. ; | 4 - Flush the destination file buffer before returning
  44. ; | 8 - Verify source and destination are identical via bit by bit comparison
  45. ; | 16 - Verify source and destination are identical via MD5 hash
  46. ; | 32 - Verify source and destination file size only
  47. ; | 64 - Copy source file attributes (NOT including Compression or Encryption)
  48. ; | 128 - Copy source file Creation time
  49. ; | 256 - Copy source file Last Accessed time
  50. ; | 512 - Copy source file Modified time
  51. ; |1024 - Copy source file Security Descriptors and Ownership
  52. ; |2048 - Copy source compression state
  53. ; |4096 - Copy source encryption state
  54. ; + If more than one verify flag is set, the smallest flag will take precedence
  55. ; $iToRead - [Optional] Size of the read/write buffer (Default = 2 MB)
  56. ; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
  57. ; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
  58. ; $sFunction - [Optional] Function to be called after each write operation (Default = "")
  59. ; + Function will be called with the following parameters:
  60. ; | 1 - Total bytes written
  61. ; | 2 - Total file size in bytes
  62. ; | 3 - Optional user variable
  63. ; $vUserVar - [Optional] User variable to pass to function (Default = Default)
  64. ;
  65. ; Return values..: Success - 1
  66. ; Failure - 0 and sets @error
  67. ; | 1 - Failed to open source file, or source was a directory
  68. ; | 2 - Destination file exists and overwrite flag not set
  69. ; | 3 - Failed to create destination file
  70. ; | 4 - Read error during copy
  71. ; | 5 - Write error during copy
  72. ; | 6 - Verify failed
  73. ; Author.........: Erik Pilsits
  74. ; Modified.......:
  75. ; Remarks........:
  76. ; Related........:
  77. ; Link...........:
  78. ; Example........:
  79. ; ===============================================================================================================
  80. Func _LargeFileCopy($sSrc, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
  81. ; check / fix source and dest path syntax
  82. _LFC_FixPathEx($sSrc, $sDest)
  83. ; open file for reading, fail if it doesn't exist or directory
  84. Local $hSrc = _FileEx_CreateFile($sSrc, $GENERIC_READ, $FILE_SHARE_READ, $OPEN_EXISTING, 0)
  85. If Not $hSrc Then Return SetError(1, 0, 0)
  86. ; set option flags
  87. Local $fOverwrite = (BitAND($iFlags, 1) = 1)
  88. Local $fCreate = (BitAND($iFlags, 2) = 2)
  89. Local $fFlush = (BitAND($iFlags, 4) = 4)
  90. Local $fVerify = 0
  91. If (BitAND($iFlags, 8) = 8) Then
  92. ; bit by bit
  93. $fVerify = 1
  94. ElseIf (BitAND($iFlags, 16) = 16) Then
  95. ; hash
  96. $fVerify = 2
  97. ElseIf (BitAND($iFlags, 32) = 32) Then
  98. ; file size
  99. $fVerify = 3
  100. EndIf
  101. Local $fAttr = (BitAND($iFlags, 64) = 64)
  102. Local $fTimeC = (BitAND($iFlags, 128) = 128)
  103. Local $fTimeA = (BitAND($iFlags, 256) = 256)
  104. Local $fTimeM = (BitAND($iFlags, 512) = 512)
  105. Local $fACL = (BitAND($iFlags, 1024) = 1024)
  106. Local $fCompress = (BitAND($iFlags, 2048) = 2048)
  107. Local $fEncrypt = (BitAND($iFlags, 4096) = 4096)
  108. ; check destination (this function will delete the destination file if it exists and $fOverwrite is True)
  109. _LFC_CheckDestination($sSrc, $sDest, $fOverwrite, $fCreate)
  110. If @error Then
  111. _WinAPI_CloseHandle($hSrc)
  112. Return SetError(2, 0, 0)
  113. EndIf
  114. ; check source and destination file systems and disable NTFS specific features if $fACL or $fCompress or $fEncrypt is true
  115. If ($fACL Or $fCompress Or $fEncrypt) And _
  116. ((DriveGetFileSystem(_FileEx_PathGetRoot($sSrc)) <> "NTFS") Or (DriveGetFileSystem(_FileEx_PathGetRoot($sDest)) <> "NTFS")) Then
  117. $fACL = False
  118. $fCompress = False
  119. $fEncrypt = False
  120. EndIf
  121. ; get source attributes only if needed
  122. Local $iAttr = 0
  123. If $fAttr Or $fCompress Or $fEncrypt Then
  124. $iAttr = _FileEx_GetAttributes($sSrc)
  125. EndIf
  126. ; ACL operations require full Admin access, ie #RequireAdmin on Vista+
  127. ; check for proper elevation and attempt to get the SeSecurityPrivilege right
  128. Local $iSeSecurity
  129. If $fACL Then
  130. $iSeSecurity = _LFC_CheckACLAdmin()
  131. If @error Then $fACL = False
  132. EndIf
  133. ; create destination file
  134. ; check encryption / compression attributes if NTFS, they are mutually exclusive
  135. Local $hDest
  136. If $fCompress And (BitAND($iAttr, 0x800) = 0x800) Then ; FILE_ATTRIBUTE_COMPRESSED
  137. ; compression is not a settable attribute
  138. $hDest = _LFC_CreateCompressedFile($sDest)
  139. ElseIf $fEncrypt And (BitAND($iAttr, 0x4000) = 0x4000) Then ; FILE_ATTRIBUTE_ENCRYPTED
  140. ; encryption
  141. $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0x4000)
  142. Else
  143. ; normal file
  144. $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0)
  145. EndIf
  146. ;
  147. If Not $hDest Then
  148. _WinAPI_CloseHandle($hSrc)
  149. Return SetError(3, 0, 0)
  150. EndIf
  151. ; check for 0 byte source file
  152. Local $iSize = _WinAPI_GetFileSizeEx($hSrc)
  153. If $iSize = 0 Then
  154. ; nothing to copy, close handles
  155. _WinAPI_CloseHandle($hDest)
  156. _WinAPI_CloseHandle($hSrc)
  157. Else
  158. ; perform copy
  159. Local $iRead, $iWritten, $bytesRead = 0, $iTotal = 0, $mSrc = 0, $iReadError = 0, $iWriteError = 0, $iVerifyError = 0
  160. ; allocate buffers
  161. Local $apBuffers = _LFC_CreateBuffers($iToRead)
  162. ; read buffer
  163. Local $pBuffer = $apBuffers[0]
  164. ; verify buffer
  165. Local $pvBuffer = $apBuffers[1]
  166. While $bytesRead < $iSize
  167. If $iToRead > ($iSize - $bytesRead) Then $iToRead = $iSize - $bytesRead
  168. If Not _WinAPI_ReadFile($hSrc, $pBuffer, $iToRead, $iRead) Or ($iToRead <> $iRead) Then
  169. $iReadError = 1
  170. ExitLoop
  171. EndIf
  172. If Not _WinAPI_WriteFile($hDest, $pBuffer, $iRead, $iWritten) Or ($iRead <> $iWritten) Then
  173. $iWriteError = 1
  174. ExitLoop
  175. EndIf
  176. If $sFunction Then
  177. $iTotal += $iToRead
  178. Call($sFunction, $iTotal, $iSize, $vUserVar)
  179. EndIf
  180. If $fVerify = 1 Then
  181. ; compare data
  182. If Not _LFC_BitCompare($hDest, $pBuffer, $pvBuffer, $iToRead) Then
  183. $iVerifyError = 1
  184. ExitLoop
  185. EndIf
  186. ElseIf $fVerify = 2 Then
  187. ; hash source inline
  188. $mSrc = _LFC_ChunkHash($mSrc, $pBuffer, $iToRead, $iAlg)
  189. EndIf
  190. $bytesRead += $iToRead
  191. WEnd
  192. ; the FlushFileBuffers command here can take some time: ~1s for a 75MB file, ~4s for a 700MB file
  193. ; it's probably safest to enable this if you need to make sure the write buffer is empty before continuing
  194. ; the FileCopy function does NOT seem to do this based on execution time
  195. If $fFlush Then _WinAPI_FlushFileBuffers($hDest)
  196. ; check file size in verify mode 3 before closing handles
  197. If $fVerify = 3 Then
  198. If Not _LFC_SizeCompare($hSrc, $hDest) Then $iVerifyError = 1
  199. EndIf
  200. ; close handles
  201. _WinAPI_CloseHandle($hDest)
  202. _WinAPI_CloseHandle($hSrc)
  203. If $fVerify = 2 Then
  204. ; finalize hash
  205. $mSrc = _LFC_ChunkHashFinal($mSrc)
  206. EndIf
  207. If $iReadError Then
  208. Return SetError(4, 0, 0)
  209. ElseIf $iWriteError Then
  210. Return SetError(5, 0, 0)
  211. Else
  212. If ($fVerify = 1) Or ($fVerify = 3) Then
  213. If $iVerifyError Then Return SetError(6, 0, 0)
  214. ElseIf ($fVerify = 2) Then
  215. ; hash destination and verify
  216. Local $mDest = _LFC_HashFile($sDest, $iAlg)
  217. If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
  218. EndIf
  219. EndIf
  220. EndIf
  221. ; copy security descriptors
  222. If $fACL Then _LFC_CopyPathSD($sSrc, $sDest, $iSeSecurity)
  223. ; copy file times
  224. If $fTimeC Or $fTimeA Or $fTimeM Then
  225. Local $tC, $tA, $tM
  226. _FileEx_GetFileTime($sSrc, $tC, $tA, $tM)
  227. If Not $fTimeC Then $tC = 0
  228. If Not $fTimeA Then $tA = 0
  229. If Not $fTimeM Then $tM = 0
  230. _FileEx_SetFileTime($sDest, $tC, $tA, $tM)
  231. EndIf
  232. ; copy attributes (does not affect file times)
  233. If $fAttr Then _FileEx_SetAttributes($sDest, $iAttr)
  234. Return 1
  235. EndFunc ;==>_LargeFileCopy
  236. ; #FUNCTION# ====================================================================================================
  237. ; Name...........: _LargeFileCopyUnbuffered
  238. ; Description....: Copy large files in such a way as to keep AutoIt GUIs responsive
  239. ; Syntax.........: _LargeFileCopyUnbuffered($sSrc, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
  240. ; Parameters.....: $sSrc - Source file name
  241. ; $sDest - Destination: may be a file name or directory
  242. ; $iFlags - [Optional] Combine flags with BitOR
  243. ; | 1 - Overwrite existing file
  244. ; | 2 - Create destination directory structure
  245. ; | 8 - Verify source and destination are identical via bit by bit comparison
  246. ; | 16 - Verify source and destination are identical via MD5 hash
  247. ; | 64 - Copy source file attributes (NOT including Compression or Encryption)
  248. ; | 128 - Copy source file Creation time
  249. ; | 256 - Copy source file Last Accessed time
  250. ; | 512 - Copy source file Modified time
  251. ; |1024 - Copy source file Security Descriptors and Ownership
  252. ; |2048 - Copy source compression state
  253. ; |4096 - Copy source encryption state
  254. ; + If more than one verify flag is set, the smallest flag will take precedence
  255. ; $iToRead - [Optional] Size of the read buffer (Default = 8 MB)
  256. ; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
  257. ; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
  258. ; $sFunction - [Optional] Function to be called after each write operation (Default = "")
  259. ; + Function will be called with the following parameters:
  260. ; | 1 - Total bytes written
  261. ; | 2 - Total file size in bytes
  262. ; | 3 - Optional user variable
  263. ; $vUserVar - [Optional] User variable to pass to function (Default = Default)
  264. ;
  265. ; Return values..: Success - 1
  266. ; Failure - 0 and sets @error
  267. ; | 1 - Failed to open source file, or source was a directory
  268. ; | 2 - Destination file exists and overwrite flag not set
  269. ; | 3 - Failed to create destination file
  270. ; | 4 - Read error during copy
  271. ; | 5 - Write error during copy
  272. ; | 6 - Verify failed
  273. ; | 7 - Failed to set destination file size
  274. ; Author.........: Erik Pilsits
  275. ; Modified.......:
  276. ; Remarks........:
  277. ; Related........:
  278. ; Link...........:
  279. ; Example........:
  280. ; ===============================================================================================================
  281. Func _LargeFileCopyUnbuffered($sSrc, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
  282. ; check / fix source and dest path syntax
  283. _LFC_FixPathEx($sSrc, $sDest)
  284. ; open file for reading, fail if it doesn't exist or directory
  285. Local $hSrc = _FileEx_CreateFile($sSrc, $GENERIC_READ, $FILE_SHARE_READ, $OPEN_EXISTING, 0)
  286. If Not $hSrc Then Return SetError(1, 0, 0)
  287. ; set option flags
  288. Local $fOverwrite = (BitAND($iFlags, 1) = 1)
  289. Local $fCreate = (BitAND($iFlags, 2) = 2)
  290. Local $fVerify = 0
  291. If (BitAND($iFlags, 8) = 8) Then
  292. ; bit by bit
  293. $fVerify = 1
  294. ElseIf (BitAND($iFlags, 16) = 16) Then
  295. ; hash
  296. $fVerify = 2
  297. EndIf
  298. Local $fAttr = (BitAND($iFlags, 64) = 64)
  299. Local $fTimeC = (BitAND($iFlags, 128) = 128)
  300. Local $fTimeA = (BitAND($iFlags, 256) = 256)
  301. Local $fTimeM = (BitAND($iFlags, 512) = 512)
  302. Local $fACL = (BitAND($iFlags, 1024) = 1024)
  303. Local $fCompress = (BitAND($iFlags, 2048) = 2048)
  304. Local $fEncrypt = (BitAND($iFlags, 4096) = 4096)
  305. ; check destination
  306. _LFC_CheckDestination($sSrc, $sDest, $fOverwrite, $fCreate)
  307. If @error Then
  308. _WinAPI_CloseHandle($hSrc)
  309. Return SetError(2, 0, 0)
  310. EndIf
  311. ; check source and destination file systems and disable NTFS specific features if $fACL or $fCompress or $fEncrypt is true
  312. If ($fACL Or $fCompress Or $fEncrypt) And _
  313. ((DriveGetFileSystem(_FileEx_PathGetRoot($sSrc)) <> "NTFS") Or (DriveGetFileSystem(_FileEx_PathGetRoot($sDest)) <> "NTFS")) Then
  314. $fACL = False
  315. $fCompress = False
  316. $fEncrypt = False
  317. EndIf
  318. ; get source attributes only if needed
  319. Local $iAttr = 0
  320. If $fAttr Or $fCompress Or $fEncrypt Then
  321. $iAttr = _FileEx_GetAttributes($sSrc)
  322. EndIf
  323. ; ACL operations require full Admin access, ie #RequireAdmin on Vista+
  324. ; check for proper elevation and attempt to get the SeSecurityPrivilege right
  325. Local $iSeSecurity
  326. If $fACL Then
  327. $iSeSecurity = _LFC_CheckACLAdmin()
  328. If @error Then $fACL = False
  329. EndIf
  330. ; create destination file
  331. ; check encryption / compression attributes if NTFS, they are mutually exclusive
  332. Local $hDest
  333. If $fCompress And (BitAND($iAttr, 0x800) = 0x800) Then ; FILE_ATTRIBUTE_COMPRESSED
  334. ; compression is not an attribute
  335. $hDest = _LFC_CreateCompressedFile($sDest, 0xA0000000)
  336. ElseIf $fEncrypt And (BitAND($iAttr, 0x4000) = 0x4000) Then ; FILE_ATTRIBUTE_ENCRYPTED
  337. $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0xA0004000)
  338. Else
  339. ; normal file
  340. ; FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
  341. $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0xA0000000)
  342. EndIf
  343. ;
  344. If Not $hDest Then
  345. _WinAPI_CloseHandle($hSrc)
  346. Return SetError(3, 0, 0)
  347. EndIf
  348. ; check for 0 byte source file
  349. Local $iSize = _WinAPI_GetFileSizeEx($hSrc)
  350. If $iSize = 0 Then
  351. ; nothing to copy, close handles
  352. _WinAPI_CloseHandle($hDest)
  353. _WinAPI_CloseHandle($hSrc)
  354. Else
  355. ; get destination disk cluster size for unbuffered i/o
  356. Local $ClusterSize = _FileEx_GetDiskClusterSize($sDest)
  357. ; if error, default to 512 and hope for the best, at worst the write operation will fail later on
  358. If @error Then $ClusterSize = 512
  359. ; perform copy
  360. Local $iRead, $iWritten, $bytesRead = 0, $iTotal = 0, $mSrc = 0, $iReadError = 0, $iWriteError = 0, $iVerifyError = 0
  361. ; create aligned buffer
  362. $iToRead = Floor($iToRead / $ClusterSize) * $ClusterSize
  363. If $iToRead = 0 Then $iToRead = $ClusterSize
  364. Local $apBuffers = _LFC_CreateBuffers($iToRead)
  365. Local $pBuffer = $apBuffers[0]
  366. Local $pvBuffer = $apBuffers[1]
  367. Local $alignedWrite = $iToRead
  368. While $bytesRead < $iSize
  369. If $iToRead > ($iSize - $bytesRead) Then $iToRead = $iSize - $bytesRead
  370. If Not _WinAPI_ReadFile($hSrc, $pBuffer, $iToRead, $iRead) Or ($iToRead <> $iRead) Then
  371. $iReadError = 1
  372. ExitLoop
  373. EndIf
  374. ; set aligned write size for final pass
  375. If $iRead < $alignedWrite Then $iRead = Ceiling($iRead / $ClusterSize) * $ClusterSize
  376. If Not _WinAPI_WriteFile($hDest, $pBuffer, $iRead, $iWritten) Or ($iRead <> $iWritten) Then
  377. $iWriteError = 1
  378. ExitLoop
  379. EndIf
  380. If $sFunction Then
  381. $iTotal += $iToRead
  382. Call($sFunction, $iTotal, $iSize, $vUserVar)
  383. EndIf
  384. If $fVerify = 1 Then
  385. ; compare data, using $iRead because it must be a cluster sized block of data
  386. If Not _LFC_BitCompare($hDest, $pBuffer, $pvBuffer, $iRead) Then
  387. $iVerifyError = 1
  388. ExitLoop
  389. EndIf
  390. ElseIf $fVerify = 2 Then
  391. ; hash source inline
  392. $mSrc = _LFC_ChunkHash($mSrc, $pBuffer, $iToRead, $iAlg)
  393. EndIf
  394. $bytesRead += $iToRead
  395. WEnd
  396. ; close handles
  397. _WinAPI_CloseHandle($hSrc)
  398. _WinAPI_CloseHandle($hDest)
  399. If $fVerify = 2 Then
  400. ; finalize hash
  401. $mSrc = _LFC_ChunkHashFinal($mSrc)
  402. EndIf
  403. ; don't bother if errors above
  404. If (Not $iReadError) And (Not $iWriteError) And (Not $iVerifyError) Then
  405. ; set correct destination file size
  406. $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $OPEN_EXISTING, 0)
  407. If $hDest Then
  408. DllCall("kernel32.dll", "bool", "SetFilePointerEx", "handle", $hDest, "int64", $iSize, "ptr", 0, "dword", 0)
  409. _WinAPI_SetEndOfFile($hDest)
  410. _WinAPI_CloseHandle($hDest)
  411. Else
  412. Return SetError(7, 0, 0)
  413. EndIf
  414. EndIf
  415. ; close dest handle
  416. _WinAPI_CloseHandle($hDest)
  417. If $iReadError Then
  418. Return SetError(4, 0, 0)
  419. ElseIf $iWriteError Then
  420. Return SetError(5, 0, 0)
  421. Else
  422. If ($fVerify = 1) Then
  423. If $iVerifyError Then Return SetError(6, 0, 0)
  424. ElseIf ($fVerify = 2) Then
  425. ; hash destination and verify
  426. Local $mDest = _LFC_HashFile($sDest, $iAlg)
  427. If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
  428. EndIf
  429. EndIf
  430. EndIf
  431. ; copy security descriptors
  432. If $fACL Then _LFC_CopyPathSD($sSrc, $sDest, $iSeSecurity)
  433. ; copy file times
  434. If $fTimeC Or $fTimeA Or $fTimeM Then
  435. Local $tC, $tA, $tM
  436. _FileEx_GetFileTime($sSrc, $tC, $tA, $tM)
  437. If Not $fTimeC Then $tC = 0
  438. If Not $fTimeA Then $tA = 0
  439. If Not $fTimeM Then $tM = 0
  440. _FileEx_SetFileTime($sDest, $tC, $tA, $tM)
  441. EndIf
  442. ; copy attributes (does not affect file times)
  443. If $fAttr Then _FileEx_SetAttributes($sDest, $iAttr)
  444. Return 1
  445. EndFunc ;==>_LargeFileCopyUnbuffered
  446. ; #FUNCTION# ====================================================================================================
  447. ; Name...........: _LargeRawCopy
  448. ; Description....: Copy large memory blocks to files in such a way as to keep AutoIt GUIs responsive
  449. ; Syntax.........: _LargeRawCopy($pSrc, $iSrcSize, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
  450. ; Parameters.....: $pSrc - Pointer to source raw data
  451. ; $iSrcSize - Size of raw data
  452. ; $sDest - Destination file name, must not be an existing directory
  453. ; $iFlags - [Optional] Combine flags with BitOR
  454. ; | 1 - Overwrite existing file
  455. ; | 2 - Create destination directory structure
  456. ; | 4 - Flush the destination file buffer before returning
  457. ; | 8 - Verify source and destination are identical via bit by bit comparison
  458. ; |16 - Verify source and destination are identical via MD5 hash
  459. ; |32 - Verify source and destination file size only
  460. ; + If more than one verify flag is set, the smallest flag will take precedence
  461. ; $iToRead - [Optional] Size of the read buffer (Default = 8 MB)
  462. ; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
  463. ; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
  464. ; $sFunction - [Optional] Function to be called after each write operation (Default = "")
  465. ; + Function will be called with the following parameters:
  466. ; | 1 - Total bytes written
  467. ; | 2 - Total file size in bytes
  468. ; | 3 - Optional user variable
  469. ; $vUserVar - [Optional] User variable to pass to function (Default = Default)
  470. ;
  471. ; Return values..: Success - 1
  472. ; Failure - 0 and sets @error
  473. ; |-1 - $iSrcSize may not be 0
  474. ; | 1 - $pSrc and $iSrcSize point to inaccessible memory
  475. ; | 2 - Destination is an existing directory
  476. ; | 3 - Destination file exists and overwrite flag not set
  477. ; | 4 - Failed to create destination file
  478. ; | 5 - Write error during copy
  479. ; | 6 - Verify failed
  480. ; Author.........: Erik Pilsits
  481. ; Modified.......:
  482. ; Remarks........:
  483. ; Related........:
  484. ; Link...........:
  485. ; Example........:
  486. ; ===============================================================================================================
  487. Func _LargeRawCopy($pSrc, $iSrcSize, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
  488. ; check source size
  489. If $iSrcSize = 0 Then Return SetError(-1, 0, 0)
  490. ; check source memory, 0 = success
  491. Local $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pSrc, "uint_ptr", $iSrcSize)
  492. If $ret[0] Then Return SetError(1, 0, 0)
  493. ; check / fix dest path syntax
  494. $sDest = StringReplace($sDest, "/", "\")
  495. _LFC_FixPath($sDest)
  496. ; set option flags
  497. Local $fOverwrite = (BitAND($iFlags, 1) = 1)
  498. Local $fCreate = (BitAND($iFlags, 2) = 2)
  499. Local $fFlush = (BitAND($iFlags, 4) = 4)
  500. Local $fVerify = 0
  501. If (BitAND($iFlags, 8) = 8) Then
  502. ; bit by bit
  503. $fVerify = 1
  504. ElseIf (BitAND($iFlags, 16) = 16) Then
  505. ; MD5
  506. $fVerify = 2
  507. ElseIf (BitAND($iFlags, 32) = 32) Then
  508. ; file size
  509. $fVerify = 3
  510. EndIf
  511. ; check destination
  512. _LFC_CheckDestination("", $sDest, $fOverwrite, $fCreate)
  513. Switch @error
  514. Case 1
  515. ; overwrite fail
  516. Return SetError(3, 0, 0)
  517. Case 2
  518. ; no file name
  519. Return SetError(2, 0, 0)
  520. EndSwitch
  521. ; create new file for writing, overwrite
  522. Local $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0)
  523. If Not $hDest Then Return SetError(4, 0, 0)
  524. ; perform copy
  525. If $iToRead > $iSrcSize Then $iToRead = $iSrcSize
  526. Local $pRead = $pSrc
  527. Local $iWritten, $bytesRead = 0, $iTotal = 0, $mSrc = 0, $iWriteError = 0, $iVerifyError = 0
  528. ; allocate buffers
  529. Local $apBuffers = _LFC_CreateBuffers($iToRead)
  530. ; verify buffer
  531. Local $pvBuffer = $apBuffers[1]
  532. While $bytesRead < $iSrcSize
  533. If $iToRead > ($iSrcSize - $bytesRead) Then $iToRead = $iSrcSize - $bytesRead
  534. If Not _WinAPI_WriteFile($hDest, $pRead, $iToRead, $iWritten) Or ($iToRead <> $iWritten) Then
  535. $iWriteError = 1
  536. ExitLoop
  537. EndIf
  538. If $sFunction Then
  539. $iTotal += $iToRead
  540. Call($sFunction, $iTotal, $iSrcSize, $vUserVar)
  541. EndIf
  542. If $fVerify = 1 Then
  543. ; compare data
  544. If Not _LFC_BitCompare($hDest, $pRead, $pvBuffer, $iToRead) Then
  545. $iVerifyError = 1
  546. ExitLoop
  547. EndIf
  548. ElseIf $fVerify = 2 Then
  549. ; hash source inline
  550. $mSrc = _LFC_ChunkHash($mSrc, $pRead, $iToRead, $iAlg)
  551. EndIf
  552. ; ready next chunk
  553. $pRead += $iToRead
  554. $bytesRead += $iToRead
  555. WEnd
  556. ; the FlushFileBuffers command here can take some time: ~1s for a 75MB file, ~4s for a 700MB file
  557. ; it's probably safest to enable this if you need to make sure the write buffer is empty before continuing
  558. ; the FileCopy function does NOT seem to do this based on execution time
  559. If $fFlush Then _WinAPI_FlushFileBuffers($hDest)
  560. ; check file size in verify mode 3 before closing handles
  561. If $fVerify = 3 Then
  562. If Not _LFC_SizeCompare($iSrcSize, $hDest) Then $iVerifyError = 1
  563. EndIf
  564. _WinAPI_CloseHandle($hDest)
  565. If $fVerify = 2 Then
  566. ; finalize hash
  567. $mSrc = _LFC_ChunkHashFinal($mSrc)
  568. EndIf
  569. If $iWriteError Then
  570. Return SetError(5, 0, 0)
  571. Else
  572. If ($fVerify = 1) Or ($fVerify = 3) Then
  573. If $iVerifyError Then Return SetError(6, 0, 0)
  574. ElseIf ($fVerify = 2) Then
  575. ; hash destination and verify
  576. Local $mDest = _LFC_HashFile($sDest, $iAlg)
  577. If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
  578. EndIf
  579. EndIf
  580. Return 1
  581. EndFunc ;==>_LargeRawCopy
  582. ; #FUNCTION# ====================================================================================================
  583. ; Name...........: _LargeRawCopyUnbuffered
  584. ; Description....: Copy large memory blocks to files in such a way as to keep AutoIt GUIs responsive
  585. ; Syntax.........: _LargeRawCopyUnbuffered($pSrc, $iSrcSize, $sDest[, $iFlags = 0[, $iToRead = 2097152[, $iAlg = $CALG_MD5[, $sFunction = ""[, $vUserVar = Default]]]]])
  586. ; Parameters.....: $pSrc - Pointer to source raw data
  587. ; $iSrcSize - Size of raw data
  588. ; $sDest - Destination file name, must not be an existing directory
  589. ; $iFlags - [Optional] Combine flags with BitOR
  590. ; | 1 - Overwrite existing file
  591. ; | 2 - Create destination directory structure
  592. ; | 8 - Verify source and destination are identical via bit by bit comparison
  593. ; |16 - Verify source and destination are identical via MD5 hash
  594. ; + If more than one verify flag is set, the smallest flag will take precedence
  595. ; $iToRead - [Optional] Size of the read buffer (Default = 8 MB)
  596. ; $iAlg - [Optional] Algorithm to use for file verification (Default = $CALG_MD5)
  597. ; + Available algorithms: $CALG_MD2, $CALG_MD4, $CALG_MD5, $CALG_SHA1
  598. ; $sFunction - [Optional] Function to be called after each write operation (Default = "")
  599. ; + Function will be called with the following parameters:
  600. ; | 1 - Total bytes written
  601. ; | 2 - Total file size in bytes
  602. ; | 3 - Optional user variable
  603. ; $vUserVar - [Optional] User variable to pass to function (Default = Default)
  604. ;
  605. ; Return values..: Success - 1
  606. ; Failure - 0 and sets @error
  607. ; |-1 - $iSrcSize may not be 0
  608. ; | 1 - $pSrc and $iSrcSize point to inaccessible memory
  609. ; | 2 - Destination is an existing directory
  610. ; | 3 - Destination file exists and overwrite flag not set
  611. ; | 4 - Failed to create destination file
  612. ; | 5 - Write error during copy
  613. ; | 6 - Verify failed
  614. ; | 7 - Failed to set destination file size
  615. ; Author.........: Erik Pilsits
  616. ; Modified.......:
  617. ; Remarks........:
  618. ; Related........:
  619. ; Link...........:
  620. ; Example........:
  621. ; ===============================================================================================================
  622. Func _LargeRawCopyUnbuffered($pSrc, $iSrcSize, $sDest, $iFlags = 0, $iToRead = 2097152, $iAlg = $CALG_MD5, $sFunction = "", $vUserVar = Default)
  623. ; check source size
  624. If $iSrcSize = 0 Then Return SetError(-1, 0, 0)
  625. ; check source memory, 0 = success
  626. Local $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pSrc, "uint_ptr", $iSrcSize)
  627. If $ret[0] Then Return SetError(1, 0, 0)
  628. ; check / fix dest path syntax
  629. $sDest = StringReplace($sDest, "/", "\")
  630. _LFC_FixPath($sDest)
  631. ; set option flags
  632. Local $fOverwrite = (BitAND($iFlags, 1) = 1)
  633. Local $fCreate = (BitAND($iFlags, 2) = 2)
  634. Local $fVerify = 0
  635. If (BitAND($iFlags, 8) = 8) Then
  636. ; bit by bit
  637. $fVerify = 1
  638. ElseIf (BitAND($iFlags, 16) = 16) Then
  639. ; MD5
  640. $fVerify = 2
  641. EndIf
  642. ; check destination
  643. _LFC_CheckDestination("", $sDest, $fOverwrite, $fCreate)
  644. Switch @error
  645. Case 1
  646. ; overwrite fail
  647. Return SetError(3, 0, 0)
  648. Case 2
  649. ; no file name
  650. Return SetError(2, 0, 0)
  651. EndSwitch
  652. ; get destination disk cluster size for unbuffered i/o
  653. Local $ClusterSize = _FileEx_GetDiskClusterSize($sDest)
  654. ; if error, default to 512 and hope for the best, at worst the write operation will fail later on
  655. If @error Then $ClusterSize = 512
  656. ; create new file for writing, overwrite
  657. Local $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, 0xA0000000) ; FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
  658. If Not $hDest Then Return SetError(4, 0, 0)
  659. ; perform copy
  660. ; create aligned buffer
  661. $iToRead = Floor($iToRead / $ClusterSize) * $ClusterSize
  662. If $iToRead = 0 Then $iToRead = $ClusterSize
  663. Local $pRead = $pSrc
  664. Local $iWritten, $bytesRead = 0, $iRead = 0, $iTotal = 0, $mSrc = 0, $iWriteError = 0, $iVerifyError = 0
  665. Local $apBuffers = _LFC_CreateBuffers($iToRead)
  666. Local $pBuffer = $apBuffers[0]
  667. Local $pvBuffer = $apBuffers[1]
  668. Local $alignedWrite = $iToRead
  669. While $bytesRead < $iSrcSize
  670. If $iToRead > ($iSrcSize - $bytesRead) Then $iToRead = $iSrcSize - $bytesRead
  671. ; copy memory to write buffer
  672. _LFC_RtlMoveMemory($pBuffer, $pRead, $iToRead)
  673. $iRead = $iToRead
  674. ; set aligned write size for final pass
  675. If $iRead < $alignedWrite Then $iRead = Ceiling($iRead / $ClusterSize) * $ClusterSize
  676. ; write data
  677. If Not _WinAPI_WriteFile($hDest, $pBuffer, $iRead, $iWritten) Or ($iRead <> $iWritten) Then
  678. $iWriteError = 1
  679. ExitLoop
  680. EndIf
  681. If $sFunction Then
  682. $iTotal += $iToRead
  683. Call($sFunction, $iTotal, $iSrcSize, $vUserVar)
  684. EndIf
  685. If $fVerify = 1 Then
  686. ; compare data, using $iRead because it must be a cluster sized block of data
  687. If Not _LFC_BitCompare($hDest, $pBuffer, $pvBuffer, $iRead) Then
  688. $iVerifyError = 1
  689. ExitLoop
  690. EndIf
  691. ElseIf $fVerify = 2 Then
  692. ; hash source inline
  693. $mSrc = _LFC_ChunkHash($mSrc, $pBuffer, $iToRead, $iAlg)
  694. EndIf
  695. ; ready next chunk
  696. $pRead += $iToRead
  697. $bytesRead += $iToRead
  698. WEnd
  699. ; cleanup
  700. _WinAPI_CloseHandle($hDest)
  701. If $fVerify = 2 Then
  702. ; finalize hash
  703. $mSrc = _LFC_ChunkHashFinal($mSrc)
  704. EndIf
  705. ; don't bother if errors above
  706. If (Not $iWriteError) And (Not $iVerifyError) Then
  707. ; set correct destination file size
  708. $hDest = _FileEx_CreateFile($sDest, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $OPEN_EXISTING, 0)
  709. If $hDest Then
  710. DllCall("kernel32.dll", "bool", "SetFilePointerEx", "handle", $hDest, "int64", $iSrcSize, "ptr", 0, "dword", 0)
  711. _WinAPI_SetEndOfFile($hDest)
  712. _WinAPI_CloseHandle($hDest)
  713. Else
  714. Return SetError(7, 0, 0)
  715. EndIf
  716. EndIf
  717. If $iWriteError Then
  718. Return SetError(5, 0, 0)
  719. Else
  720. If ($fVerify = 1) Then
  721. If $iVerifyError Then Return SetError(6, 0, 0)
  722. ElseIf ($fVerify = 2) Then
  723. ; hash destination and verify
  724. Local $mDest = _LFC_HashFile($sDest, $iAlg)
  725. If ($mSrc = "") Or ($mDest = "") Or ($mSrc <> $mDest) Then Return SetError(6, 0, 0)
  726. EndIf
  727. EndIf
  728. Return 1
  729. EndFunc ;==>_LargeRawCopyUnbuffered
  730. #endregion FUNCTIONS
  731. #region INTERNAL FUNCTIONS
  732. Func _LFC_AllocBuffers(ByRef $apBuffers, $iBuffSize)
  733. Dim $apBuffers[2] = [ _
  734. _MemVirtualAlloc(0, $iBuffSize, $MEM_COMMIT, $PAGE_READWRITE), _
  735. _MemVirtualAlloc(0, $iBuffSize, $MEM_COMMIT, $PAGE_READWRITE) _
  736. ]
  737. EndFunc ;==>_LFC_AllocBuffers
  738. Func _LFC_BitCompare($hDest, $pSrc, $pVerify, $iToVerify)
  739. ; if there are any errors at all, FAIL
  740. ; check memory ranges
  741. Local $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pSrc, "uint_ptr", $iToVerify)
  742. If @error Or $ret[0] Then Return SetError(1, 0, 0)
  743. $ret = DllCall("kernel32.dll", "bool", "IsBadReadPtr", "ptr", $pVerify, "uint_ptr", $iToVerify)
  744. If @error Or $ret[0] Then Return SetError(2, 0, 0)
  745. ; first move file pointer back by $iToVerify bytes
  746. $ret = DllCall("kernel32.dll", "bool", "SetFilePointerEx", "handle", $hDest, "int64", -$iToVerify, "ptr", 0, "dword", 1) ; FILE_CURRENT
  747. If @error Or (Not $ret[0]) Then Return SetError(3, 0, 0)
  748. ; read data just written to destination
  749. Local $iRead
  750. If Not _WinAPI_ReadFile($hDest, $pVerify, $iToVerify, $iRead) Or ($iRead <> $iToVerify) Then Return SetError(4, 0, 0)
  751. ; compare data=
  752. If Not _LFC_RtlCompareMemory($pSrc, $pVerify, $iToVerify) Then
  753. Return SetError(5, 0, 0)
  754. Else
  755. Return 1
  756. EndIf
  757. EndFunc ;==>_LFC_BitCompare
  758. Func _LFC_CheckACLAdmin()
  759. Static Local $fChecked = False, $iSeSecurity = 0
  760. ; check for admin rights and acquire SeSecurityPrivilege only once
  761. ; on successive calls, return previous value of $iSeSecurity or error
  762. If Not $fChecked Then
  763. $fChecked = True
  764. If IsAdmin() Then
  765. If _LFC_GetSESECURITYNAME() Then
  766. ; include SACL_SECURITY_INFORMATION
  767. $iSeSecurity = 0xF
  768. Else
  769. $iSeSecurity = 7
  770. EndIf
  771. EndIf
  772. EndIf
  773. If $iSeSecurity Then
  774. Return $iSeSecurity
  775. Else
  776. Return SetError(1)
  777. EndIf
  778. EndFunc ;==>_LFC_CheckACLAdmin
  779. Func _LFC_CheckDestination($sSrc, ByRef $sDest, $fOverwrite, $fCreate)
  780. Local $iAttr = _FileEx_GetAttributes($sDest)
  781. Local $iErr = @error
  782. If ($iErr And (StringRight($sDest, 1) = "\")) Or ((Not $iErr) And (BitAND($iAttr, 0x10) = 0x10)) Then
  783. ; destination does not exist and should be a directory
  784. ; OR destination does exist and is a directory
  785. If $sSrc = "" Then
  786. ; raw copy, must provide a file name
  787. Return SetError(2)
  788. Else
  789. ; use source file name
  790. If StringRight($sDest, 1) <> "\" Then $sDest &= "\" ; add trailing \
  791. $sDest &= StringRegExpReplace($sSrc, ".*\\", "")
  792. EndIf
  793. ElseIf $iErr And $fCreate Then
  794. ; destination does not exist and should be a file
  795. ; create destination *parent directory*
  796. _FileEx_CreateDirectory(StringRegExpReplace($sDest, "^(.*)\\.*?$", "${1}"))
  797. ElseIf Not $iErr Then
  798. ; destination exists and is a file
  799. ; check overwrite
  800. If $fOverwrite Then
  801. ; set FILE_ATTRIBUTE_NORMAL before attempting delete
  802. _FileEx_SetAttributes($sDest, 0x80)
  803. If Not FileDelete($sDest) Then Return SetError(1)
  804. Else
  805. Return SetError(1)
  806. EndIf
  807. EndIf
  808. ; else do nothing
  809. ; ie, destination is a file that doesn't exist and $fCreate is false
  810. ; if parent directory does not exist and is not created, CreateFile will fail
  811. EndFunc ;==>_LFC_CheckDestination
  812. Func _LFC_ChunkHash($hCryptHash, $pSrc, $iSize, $iAlg = $CALG_MD5)
  813. Local $aRet
  814. If $hCryptHash = 0 Then
  815. ; Create Hash object
  816. $aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptCreateHash", "handle", __Crypt_Context(), "uint", $iAlg, "ptr", 0, "dword", 0, "handle*", 0)
  817. If @error Or (Not $aRet[0]) Then Return SetError(1, 0, -1)
  818. $hCryptHash = $aRet[5]
  819. ElseIf $hCryptHash = -1 Then
  820. ; previous error
  821. Return SetError(3, 0, -1)
  822. EndIf
  823. $aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptHashData", "handle", $hCryptHash, "ptr", $pSrc, "dword", $iSize, "dword", $CRYPT_USERDATA)
  824. If @error Or (Not $aRet[0]) Then
  825. DllCall(__Crypt_DllHandle(), "bool", "CryptDestroyHash", "handle", $hCryptHash)
  826. Return SetError(2, 0, -1)
  827. EndIf
  828. Return $hCryptHash
  829. EndFunc ;==>_LFC_ChunkHash
  830. Func _LFC_ChunkHashFinal($hCryptHash)
  831. Local $iError, $vReturn
  832. If $hCryptHash = -1 Then
  833. ; previous error
  834. $iError = 1
  835. $vReturn = ""
  836. $hCryptHash = 0
  837. Else
  838. ; get hash size, in $aRet[3]
  839. Local $aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptGetHashParam", "handle", $hCryptHash, "dword", $HP_HASHSIZE, "dword*", 0, "dword*", 4, "dword", 0)
  840. If @error Or (Not $aRet[0]) Then
  841. $iError = 2
  842. $vReturn = ""
  843. Else
  844. ; get hash
  845. Local $hBuff = DllStructCreate("byte[" & $aRet[3] & "]")
  846. $aRet = DllCall(__Crypt_DllHandle(), "bool", "CryptGetHashParam", "handle", $hCryptHash, "dword", $HP_HASHVAL, "ptr", DllStructGetPtr($hBuff), "dword*", DllStructGetSize($hBuff), "dword", 0)
  847. If @error Or (Not $aRet[0]) Then
  848. $iError = 3
  849. $vReturn = ""
  850. Else
  851. $iError = 0
  852. $vReturn = DllStructGetData($hBuff, 1)
  853. EndIf
  854. EndIf
  855. EndIf
  856. ; Cleanup and return hash
  857. If $hCryptHash <> 0 Then DllCall(__Crypt_DllHandle(), "bool", "CryptDestroyHash", "handle", $hCryptHash)
  858. Return SetError($iError, 0, $vReturn)
  859. EndFunc ;==>_LFC_ChunkHashFinal
  860. Func _LFC_ControlBuffers($iBuffSize, $fCreate = True)
  861. Static Local $iPrevSize = 0, $apBuffers = 0
  862. If $fCreate Then
  863. If (Not IsArray($apBuffers)) Or ($iBuffSize > $iPrevSize) Then
  864. _LFC_FreeBuffers()
  865. $iPrevSize = $iBuffSize
  866. _LFC_AllocBuffers($apBuffers, $iBuffSize)
  867. ; init crypt library, only once
  868. If Not __Crypt_RefCount() Then _Crypt_Startup()
  869. EndIf
  870. Return $apBuffers
  871. Else
  872. If IsArray($apBuffers) Then
  873. _MemVirtualFree($apBuffers[0], 0, $MEM_RELEASE)
  874. _MemVirtualFree($apBuffers[1], 0, $MEM_RELEASE)
  875. EndIf
  876. $iPrevSize = 0
  877. $apBuffers = 0
  878. EndIf
  879. EndFunc ;==>_LFC_ControlBuffers
  880. Func _LFC_CopyPathSD($sSrc, $sDest, $iSeSecurity)
  881. Local $pOwner, $pGroup, $pDACL, $pSACL, $pSD, $iProtect
  882. ; copy source security info
  883. _LFC_GetPathSD($sSrc, $pOwner, $pGroup, $pDACL, $pSACL, $pSD, $iProtect, $iSeSecurity)
  884. If @error Then Return SetError(1, 0, 0)
  885. ; set destination security info
  886. Local $iErr = 0
  887. _LFC_SetPathSD($sDest, $pOwner, $pGroup, $pDACL, $pSACL, $iProtect, $iSeSecurity)
  888. If @error Then $iErr = @error
  889. DllCall("kernel32.dll", "handle", "LocalFree", "handle", $pSD)
  890. Return SetError($iErr, 0, (Not $iErr))
  891. EndFunc ;==>_LFC_CopyPathSD
  892. Func _LFC_CreateBuffers($iBuffSize)
  893. Return _LFC_ControlBuffers($iBuffSize)
  894. EndFunc ;==>_LFC_CreateBuffers
  895. Func _LFC_CreateCompressedFile($sPath, $iFlag = 0)
  896. ;Local Const $FSCTL_SET_COMPRESSION = 0x0009C040
  897. ;Local Const $FSCTL_GET_COMPRESSION = 0x0009003C
  898. ;Local Const $COMPRESSION_FORMAT_NONE = 0
  899. ;Local Const $COMPRESSION_FORMAT_DEFAULT = 1
  900. ;Local Const $COMPRESSION_FORMAT_LZNT1 = 2
  901. ; create 0 byte file
  902. Local $hFile = _FileEx_CreateFile($sPath, BitOR($GENERIC_READ, $GENERIC_WRITE), 0, $CREATE_ALWAYS, $iFlag)
  903. If Not $hFile Then Return SetError(1, 0, 0)
  904. ; set compression state
  905. Local $aRet = DllCall("kernel32.dll", "bool", "DeviceIoControl", "handle", $hFile, "dword", 0x0009C040, "ushort*", 1, "dword", 2, _
  906. "ptr", 0, "dword", 0, "dword*", 0, "ptr", 0)
  907. If @error Or (Not $aRet[0]) Then
  908. _WinAPI_CloseHandle($hFile)
  909. FileDelete($sPath)
  910. Return SetError(2, 0, 0)
  911. Else
  912. Return $hFile
  913. EndIf
  914. EndFunc ;==>_LFC_CreateCompressedFile
  915. Func _LFC_FixPath(ByRef $sPath)
  916. ; check for drive and make sure it ends in \
  917. If StringRight($sPath, 1) = ":" Then
  918. $sPath &= "\"
  919. Else
  920. ; expand any relative path components
  921. ; _PathFull follows same rules as FileExists
  922. $sPath = _PathFull($sPath)
  923. EndIf
  924. EndFunc ;==>_LFC_FixPath
  925. Func _LFC_FixPathEx(ByRef $sSrc, ByRef $sDest)
  926. ; fix possible forward /
  927. $sSrc = StringReplace($sSrc, "/", "\")
  928. $sDest = StringReplace($sDest, "/", "\")
  929. ; remove trailing \'s from source only
  930. $sSrc = StringRegExpReplace($sSrc, "\\+$", "")
  931. ; convert to full paths
  932. _LFC_FixPath($sSrc)
  933. _LFC_FixPath($sDest)
  934. EndFunc ;==>_LFC_FixPathEx
  935. Func _LFC_FreeBuffers()
  936. _LFC_ControlBuffers(0, False)
  937. EndFunc ;==>_LFC_FreeBuffers
  938. Func _LFC_GetPathSD($sPath, ByRef $pOwner, ByRef $pGroup, ByRef $pDACL, ByRef $pSACL, ByRef $pSD, ByRef $iProtect, $iSeSecurity)
  939. ;Local Const $SE_FILE_OBJECT = 1
  940. ;Local Const $OWNER_SECURITY_INFORMATION = 1
  941. ;Local Const $GROUP_SECURITY_INFORMATION = 2
  942. ;Local Const $DACL_SECURITY_INFORMATION = 4
  943. ;Local Const $SACL_SECURITY_INFORMATION = 8
  944. ;
  945. ;Local Const $SE_DACL_PROTECTED = 0x1000
  946. ;Local Const $PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
  947. ;Local Const $UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
  948. ;
  949. ;Local Const $SE_SACL_PROTECTED = 0x2000
  950. ;Local Const $PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
  951. ;Local Const $UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
  952. Local $aRet = DllCall("advapi32.dll", "dword", "GetNamedSecurityInfoW", "wstr", $sPath, "int", 1, "dword", $iSeSecurity, _
  953. "ptr*", 0, "ptr*", 0, "ptr*", 0, "ptr*", 0, "ptr*", 0)
  954. If @error Or $aRet[0] Then Return SetError(1, 0, 0)
  955. $pOwner = $aRet[4]
  956. $pGroup = $aRet[5]
  957. $pDACL = $aRet[6]
  958. $pSACL = $aRet[7]
  959. $pSD = $aRet[8]
  960. $iProtect = 0 ; default no change
  961. ; query SACL, DACL protected states and set flags
  962. $aRet = DllCall("advapi32.dll", "bool", "GetSecurityDescriptorControl", "ptr", $pSD, "word*", 0, "dword*", 0)
  963. If Not @error And $aRet[0] Then
  964. If BitAND($aRet[2], 0x1000) Then
  965. ; DACL protected
  966. $iProtect = BitOR($iProtect, 0x80000000)
  967. Else
  968. ; unprotected
  969. $iProtect = BitOR($iProtect, 0x20000000)
  970. EndIf
  971. If BitAND($aRet[2], 0x2000) Then
  972. ; SACL protected
  973. $iProtect = BitOR($iProtect, 0x40000000)
  974. Else
  975. ; unprotected
  976. $iProtect = BitOR($iProtect, 0x10000000)
  977. EndIf
  978. EndIf
  979. Return 1
  980. EndFunc ;==>_LFC_GetPathSD
  981. Func _LFC_GetSESECURITYNAME()
  982. Local $return = False
  983. Local $tagLUIDANDATTRIB = "int64 Luid;dword Attributes"
  984. Local $count = 1
  985. Local $tagTOKENPRIVILEGES = "dword PrivilegeCount;byte LUIDandATTRIB[" & $count * 12 & "]" ; count of LUID structs * sizeof LUID struct
  986. Local $TOKEN_ADJUST_PRIVILEGES = 0x20
  987. Local $SE_PRIVILEGE_ENABLED = 0x2
  988. Local $curProc = DllCall("kernel32.dll", "ptr", "GetCurrentProcess")
  989. If @error Then Return False
  990. Local $call = DllCall("advapi32.dll", "int", "OpenProcessToken", "ptr", $curProc[0], "dword", $TOKEN_ADJUST_PRIVILEGES, "ptr*", 0)
  991. If (@error Or (Not $call[0])) Then Return False
  992. Local $hToken = $call[3]
  993. $call = DllCall("advapi32.dll", "int", "LookupPrivilegeValueW", "ptr", 0, "wstr", "SeSecurityPrivilege", "int64*", 0)
  994. If ((Not @error) And $call[0]) Then
  995. Local $iLuid = $call[3]
  996. Local $TP = DllStructCreate($tagTOKENPRIVILEGES)
  997. Local $LUID = DllStructCreate($tagLUIDANDATTRIB, DllStructGetPtr($TP, "LUIDandATTRIB"))
  998. DllStructSetData($TP, "PrivilegeCount", $count)
  999. DllStructSetData($LUID, "Luid", $iLuid)
  1000. DllStructSetData($LUID, "Attributes", $SE_PRIVILEGE_ENABLED)
  1001. $call = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "ptr", $hToken, "int", 0, "ptr", DllStructGetPtr($TP), "dword", 0, "ptr", 0, "ptr", 0)
  1002. If Not @error Then $return = ($call[0] <> 0) ; $call[0] <> 0 is success
  1003. EndIf
  1004. DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hToken)
  1005. Return SetError(Number(Not $return), 0, $return)
  1006. EndFunc ;==>_LFC_GetSESECURITYNAME
  1007. Func _LFC_HashFile($sFile, $iAlg = $CALG_MD5)
  1008. ; check target exists and is a file
  1009. If Not FileExists($sFile) Or StringInStr(FileGetAttrib($sFile), "D") Then Return SetError(1, 0, "")
  1010. Local $sHash = _LFC_HashFileInternal($sFile, $iAlg)
  1011. If @error Or ($sHash = "") Then
  1012. Return SetError(2, 0, "")
  1013. Else
  1014. Return $sHash
  1015. EndIf
  1016. EndFunc ;==>_LFC_HashFile
  1017. Func _LFC_HashFileInternal($sFile, $iAlg = $CALG_MD5)
  1018. Local $hSrc = _FileEx_CreateFile($sFile, $GENERIC_READ, $FILE_SHARE_READ, $OPEN_EXISTING, 0)
  1019. If Not $hSrc Then Return SetError(1, 0, "")
  1020. Local $iSize = _WinAPI_GetFileSizeEx($hSrc)
  1021. Local $iRead, $iReadError = 0, $sHash = 0, $iToRead = (1024 ^ 2) * 2
  1022. ; create 2M hashing buffer only once
  1023. Static Local $pBuffer = _MemVirtualAlloc(0, $iToRead, $MEM_COMMIT, $PAGE_READWRITE)
  1024. Local $bytesRead = 0
  1025. While $bytesRead < $iSize
  1026. If $iToRead > ($iSize - $bytesRead) Then $iToRead = $iSize - $bytesRead
  1027. If Not _WinAPI_ReadFile($hSrc, $pBuffer, $iToRead, $iRead) Then
  1028. $iReadError = 1
  1029. ExitLoop
  1030. EndIf
  1031. $sHash = _LFC_ChunkHash($sHash, $pBuffer, $iRead, $iAlg)
  1032. If @error Then
  1033. $iReadError = 1
  1034. ExitLoop
  1035. EndIf
  1036. $bytesRead += $iRead
  1037. WEnd
  1038. _WinAPI_CloseHandle($hSrc)
  1039. $sHash = _LFC_ChunkHashFinal($sHash)
  1040. If $iReadError Then
  1041. Return SetError(2, 0, "")
  1042. Else
  1043. Return $sHash
  1044. EndIf
  1045. EndFunc ;==>_LFC_HashFileInternal
  1046. Func _LFC_RtlCompareMemory($pSrc1, $pSrc2, $iSize)
  1047. Local $ret = DllCall("ntdll.dll", "ulong_ptr", "RtlCompareMemory", "ptr", $pSrc1, "ptr", $pSrc2, "ulong_ptr", $iSize)
  1048. If @error Or ($ret[0] <> $iSize) Then
  1049. Return SetError(1, 0, 0)
  1050. Else
  1051. Return 1
  1052. EndIf
  1053. EndFunc ;==>_LFC_RtlCompareMemory
  1054. Func _LFC_RtlMoveMemory($pDest, $pSrc, $iSize)
  1055. DllCall("ntdll.dll", "none", "RtlMoveMemory", "ptr", $pDest, "ptr", $pSrc, "ulong_ptr", $iSize)
  1056. If @error Then
  1057. Return SetError(1, 0, 0)
  1058. Else
  1059. Return 1
  1060. EndIf
  1061. EndFunc ;==>_LFC_RtlMoveMemory
  1062. Func _LFC_SetPathSD($sPath, $pOwner, $pGroup, $pDACL, $pSACL, $iProtect, $iSeSecurity)
  1063. Local $aRet = DllCall("advapi32.dll", "dword", "SetNamedSecurityInfoW", "wstr", $sPath, "int", 1, "dword", BitOR($iProtect, $iSeSecurity), _
  1064. "ptr", $pOwner, "ptr", $pGroup, "ptr", $pDACL, "ptr", $pSACL)
  1065. If @error Or $aRet[0] Then Return SetError(2, 0, 0)
  1066. Return 1
  1067. EndFunc ;==>_LFC_SetPathSD
  1068. Func _LFC_SizeCompare($hFile1, $hFile2)
  1069. Local $iSize1
  1070. If IsPtr($hFile1) Then
  1071. $iSize1 = DllCall("kernel32.dll", "bool", "GetFileSizeEx", "handle", $hFile1, "int64*", 0)
  1072. If @error Or (Not $iSize1[0]) Then Return SetError(1, 0, 0)
  1073. $iSize1 = $iSize1[2]
  1074. Else
  1075. ; for _LargeRawCopy
  1076. $iSize1 = $hFile1
  1077. EndIf
  1078. Local $iSize2 = DllCall("kernel32.dll", "bool", "GetFileSizeEx", "handle", $hFile2, "int64*", 0)
  1079. If @error Or (Not $iSize2[0]) Then Return SetError(2, 0, 0)
  1080. ; compare size
  1081. If $iSize1 = $iSize2[2] Then
  1082. Return 1
  1083. Else
  1084. Return SetError(3, 0, 0)
  1085. EndIf
  1086. EndFunc ;==>_LFC_SizeCompare
  1087. #endregion INTERNAL FUNCTIONS

comments powered by Disqus