Biatu Posted July 2, 2017 Posted July 2, 2017 (edited) So, I thought I'd take a crack at porting wimlib's compact functionality to AutoIt so that I could essentially Compact files like compact.exe does. After parsing the various funcs, the process is as follows... 1. NtCreateFile to open a file and get hFile 2. Create some structs with some flags for the compression type 3. call NtFsControlFile with $FSCTL_SET_EXTERNAL_BACKING command Now, oddly enough everything returns with a success, yet the file remains uncompressed, even from Compact's point of view Any ideas? Chicken Scratch: expandcollapse popup#RequireAdmin #include <Array.au3> #include <WinAPIDiag.au3> #include <WinAPIFiles.au3> Global Const $tagWOF_EXTERNAL_INFO="uint WOFEI_Version;uint WOFEI_Provider" Global Const $tagFILE_PROVIDER_EXTERNAL_INFO="uint FPEI_Version;uint FPEI_CompressionFormat" Global Const $tagIOSTATUSBLOCK = "ptr Status;ptr Information" Global Const $tagOBJECTATTRIBUTES = "ulong Length;handle RootDirectory;ptr ObjectName;ulong Attributes;ptr SecurityDescriptor;ptr SecurityQualityOfService" Global Const $tagUNICODESTRING = "ushort Length;ushort MaximumLength;ptr Buffer" Global Const $FILE_OPEN=0x00000001 Global Const $STATUS_PENDING=0x00000103 Global Const $STATUS_SUCCESS=0x00000000 Global Const $STATUS_ACCESS_DENIED=0xC0000022 Global Const $OBJ_CASE_INSENSITIVE = 0x00000040 Global Const $FILE_SHARE_VALID_FLAGS=0x00000007 Global Const $FILE_OPEN_REPARSE_POINT=0x00200000 Global Const $FSCTL_SET_EXTERNAL_BACKING=0x9030C Global Const $FILE_OPEN_FOR_BACKUP_INTENT=0x00004000 Global Const $STATUS_INVALID_DEVICE_REQUEST=0xC0000010 Global Const $STATUS_COMPRESSION_NOT_BENEFICIAL=0xC000046F Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K=0 Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_LZX=1 Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS8K=2 Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS16K=3 Global Const $FILE_PROVIDER_CURRENT_VERSION=1 Global Const $WOF_CURRENT_VERSION=1 Global Const $WOF_PROVIDER_FILE=2 Global $hDll_NTDLL=DllOpen("ntdll.dll") MsgBox(64,"",FileGetSize("C:\Test.dat")&@CRLF) ConsoleWrite(_WinAPI_SetSystemCompression("C:\Test.dat",$FILE_PROVIDER_COMPRESSION_FORMAT_LZX)&"|"&@Error&"|"&@Extended&@CRLF) MsgBox(64,"",FileGetSize("C:\Test.dat")&@CRLF) ; Try to attach an instance of the Windows Overlay Filesystem filter driver ; to the specified drive (such as C:) Func DriveAttachWOF($sDrive); win32_try_to_attach_wof Local $iRet,$hDll_FltLib $hDll_FltLib=DllOpen("FltLib.dll") If @error Then Return SetError(1,0,0) $aRet=DllCall($hDll_FltLib,"int","FilterAttach","WSTR","wof","wstr",$sDrive,"ptr",0,"int",0,"ptr",0) If @error Or Not $aRet[0] Then $aRet=DllCall($hDll_FltLib,"int","FilterAttach","WSTR","wofadk","wstr",$sDrive,"ptr",0,"int",0,"ptr",0) If @error Or Not $aRet[0] Then Return SetError(@error, @extended, 0) EndIf DllClose($hDll_FltLib) Return SetError(0,0,$aRet[0]) EndFunc Func PathGetDrive($sPath) $sPath=_WinAPI_GetFullPathName($sPath) If @error Or $sPath="" Then Return SetError(1,0,0) $aTest=StringRegExp($sPath,"^([A-Za-z]\:).*$",1) If @error Then Return SetError(1,0,0) Return SetError(0,0,"\\.\"&StringLower($aTest[0])) EndFunc Func _WinAPI_SetSystemCompression($sFilePath,$iFormat=0) Local $isWin10=0,$iCompatFlag=0 If @OSVersion="WIN_10" Then $isWin10=1 ;$sFilePath="\\.\"&_WinAPI_GetFullPathName($sFilePath) (TODO) ;For compatibility with the Windows bootloader (TODO) ;incompatible = match_pattern_list(dentry->d_full_path,&bootloader_patterns); If $iCompatFlag And ($isWin10 Or $iFormat<>0) Then If $isWin10 Then;Win10 only supports XPRESS4K format $iFormat=0 Else;Anything Else cannot handle boot file compression, die Return SetError(1,1,0) EndIf EndIf $tName=DllStructCreate("wchar[260]") $tUName= DllStructCreate($tagUNICODESTRING) $tOA=DllStructCreate($tagOBJECTATTRIBUTES) DllStructSetData($tName,1,$sFilePath) $aRet=DllCall($hDll_NTDLL,"none","RtlInitUnicodeString","ptr",DllStructGetPtr($tUName),"ptr",DllStructGetPtr($tName)) If @error Or Not $aRet[0] Then Return SetError(@Error,@Extended,0) ;MsgBox(64,"RtlInitUnicodeString",_WinAPI_GetLastErrorMessage()) DllStructSetData($tOA,"Length",DllStructGetSize($tOA)) DllStructSetData($tOA,"RootDirectory",0) DllStructSetData($tOA,"ObjectName",DllStructGetPtr($tUName)) DllStructSetData($tOA,"Attributes",$OBJ_CASE_INSENSITIVE) DllStructSetData($tOA,"SecurityDescriptor",0) DllStructSetData($tOA,"SecurityQualityOfService",0) $tIOSB=DllStructCreate($tagIOSTATUSBLOCK) $tFile=DllStructCreate("HWND") $pFile=DllStructGetPtr($tFile) $aRet=DllCall($hDll_NTDLL,"handle","NtCreateFile", _ "handle*",$pFile, _ "ulong",BitOR($GENERIC_READ,$GENERIC_WRITE,20), _ "ptr",DllStructGetPtr($tOA), _ "ptr",DllStructGetPtr($tIOSB), _ "ptr",0, _ "ulong",0, _ "ulong",$FILE_SHARE_VALID_FLAGS, _ "ulong",$FILE_OPEN, _ "ulong",BitOR($FILE_OPEN_FOR_BACKUP_INTENT,$FILE_OPEN_REPARSE_POINT), _ "ptr",0, _ "ulong",0) If @error Or Not $aRet[0] Then Return SetError(@Error,@Extended,0) ;MsgBox(64,"NtCreateFile",_WinAPI_GetLastErrorMessage()) $tInputBuffer=DllStructCreate("STRUCT;"&$tagWOF_EXTERNAL_INFO&";ENDSTRUCT;STRUCT;"&$tagFILE_PROVIDER_EXTERNAL_INFO&";ENDSTRUCT") DllStructSetData($tInputBuffer,"WOFEI_Version",$WOF_CURRENT_VERSION) DllStructSetData($tInputBuffer,"WOFEI_Provider",$WOF_PROVIDER_FILE) DllStructSetData($tInputBuffer,"FPEI_Version",$FILE_PROVIDER_CURRENT_VERSION) DllStructSetData($tInputBuffer,"FPEI_CompressionFormat",$iFormat) $pInputBuffer=DllStructGetPtr($tInputBuffer) $iInputBuffer=DllStructGetSize($tInputBuffer) Local $iTried=0 Do $iRet=_WinAPI_NtFsControlFile(DllStructGetData($tFile,1),$FSCTL_SET_EXTERNAL_BACKING,$pInputBuffer,$iInputBuffer) If @error Then Return SetError(@Error,@Extended,0) ;MsgBox(64,"_WinAPI_NtFsControlFile",_WinAPI_GetLastErrorMessage()) If $iRet=$STATUS_INVALID_DEVICE_REQUEST And Not $iTried Then DriveAttachWOF(PathGetDrive($sFilePath)) $iTried=1 ContinueLoop EndIf $iTried=1 Until $iTried ;_ArrayDisplay($aRet,@error) Return 0;SetError(0,0,$iRet[0]) EndFunc ;typedef uint32_t u32; ;~ /* We intentionally use NtFsControlFile() rather than DeviceIoControl() ;~ * here because the "compressing this object would not save space" ;~ * status code does not map to a valid Win32 error code on older ;~ * versions of Windows (before Windows 10?). This can be a problem if ;~ * the WOFADK driver is being used rather than the regular WOF, since ;~ * WOFADK can be used on older versions of Windows. */ ;~ status = winnt_fsctl(h, $FSCTL_SET_EXTERNAL_BACKING, ;~ &in, sizeof(in), NULL, 0, NULL); ; Synchronously execute a filesystem control method. This is a wrapper around ; NtFsControlFile() that handles STATUS_PENDING. Note that SYNCHRONIZE ; permission is, in general, required on the handle. Func _WinAPI_NtFsControlFile($hFile,$iFsControlCode,$pInputBuffer,$iInputBuffer,$pOutputBuffer=0,$iOutputAvail=0) $tIOSB=DllStructCreate($tagIOSTATUSBLOCK) $pIOSB=DllStructGetPtr($tIOSB) $aRet=DllCall($hDll_NTDLL,"int","NtFsControlFile", _ "HANDLE",$hFile, _ "ptr",0, _ "ptr",0, _ "ptr",0, _ "ptr",$pIOSB, _ "uint",$iFsControlCode, _ "ptr",$pInputBuffer, _ "uint",$iInputBuffer, _ "ptr",$pOutputBuffer, _ "uint",$iOutputAvail) If @Error Or Not $aRet[0] Then Return SetError(@Error,@Extended,0) ;~ MsgBox(64,"NtFsControlFile",_WinAPI_GetLastErrorMessage()) If $aRet[0]=$STATUS_PENDING Then;Rare $iRet=_WinAPI_WaitForSingleObject($hFile) $iError=_WinAPI_GetLastError() If Not $iError Then SetError(1,$iError,0) Return SetError(1,$iRet,0) EndIf Return SetError(0,0,$aRet[0]) EndFunc Edited July 2, 2017 by Biatu What is what? What is what.
Biatu Posted July 2, 2017 Author Posted July 2, 2017 (edited) ...that moment when I realized that I was reinventing the wheel _WinAPI_SetCompression() Edit: Wait FSCTL_SET_COMPRESSION<>$FSCTL_SET_EXTERNAL_BACKING Edited July 2, 2017 by Biatu What is what? What is what.
Biatu Posted July 16, 2017 Author Posted July 16, 2017 (edited) I figured that I'd make a tray application that would periodically compact the system with LZX compression, and display the progress with a toast gui. besides that, imo...having an autoit solution for file system compression would deem useful for the entire community. Edited July 16, 2017 by Biatu What is what? What is what.
Biatu Posted July 16, 2017 Author Posted July 16, 2017 expandcollapse popup#cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.14.2 Author: BiatuAutMiahn[@Outlook.com] Script Function: Set filesystem compression using windows' WOF file backing. Requires Win10 in most cases. Thanks to Danyfirex for making it actually work! #ce ---------------------------------------------------------------------------- #include <WinAPI.au3> #include <WinAPIFiles.au3> Global Const $sTagWOF_EXTERNAL_INFO = "ulong WOFEI_Version;ulong WOFEI_Provider" Global Const $sTagFILE_PROVIDER_EXTERNAL_INFO_V1 = "ulong FPEI_Version;ulong FPEI_CompressionFormat;ulong Flags" Global Const $sTagIOSTATUSBLOCK = "ptr Status;ptr Information" Global Const $sTagOBJECTATTRIBUTES = "ulong Length;handle RootDirectory;ptr ObjectName;ulong Attributes;ptr SecurityDescriptor;ptr SecurityQualityOfService" Global Const $sTagUNICODESTRING = "ushort Length;ushort MaximumLength;ptr Buffer" Global Const $FILE_OPEN = 0x00000001 Global Const $STATUS_PENDING = 0x00000103 Global Const $STATUS_SUCCESS = 0x00000000 Global Const $STATUS_ACCESS_DENIED = 0xC0000022 Global Const $OBJ_CASE_INSENSITIVE = 0x00000040 Global Const $FILE_SHARE_VALID_FLAGS = 0x00000007 Global Const $FILE_OPEN_REPARSE_POINT = 0x00200000 Global Const $FSCTL_SET_EXTERNAL_BACKING = 0x9030C Global Const $FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000 Global Const $STATUS_INVALID_DEVICE_REQUEST = 0xC0000010 Global Const $STATUS_COMPRESSION_NOT_BENEFICIAL = 0xC000046F Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K = 0 Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_LZX = 1 Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS8K = 2 Global Const $FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS16K = 3 Global Const $FILE_PROVIDER_CURRENT_VERSION = 1 Global Const $WOF_CURRENT_VERSION = 1 Global Const $WOF_PROVIDER_FILE = 2 Global $hDll_NTDLL = DllOpen("ntdll.dll") FileCopy("D:\wimlib-1.12.0-BETA1\wimlib-imagex.exe","D:\test.exe",1) Local $sFilePath = "\??\D:\test.exe" MsgBox(64, "", _WinAPI_GetCompressedFileSize($sFilePath) & @CRLF) ConsoleWrite(_WinAPI_WofSetCompression($sFilePath, $FILE_PROVIDER_COMPRESSION_FORMAT_LZX) MsgBox(64, "", _WinAPI_GetCompressedFileSize($sFilePath) & @CRLF) DllClose($hDll_NTDLL) Func _WinAPI_WofSetCompression($sFilePath, $iFormat) ; Local Const $FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 Local $tFilePath=DllStructCreate("wchar[260]") Local $tFilePathW=DllStructCreate($sTagUNICODESTRING) Local $tObjAttr=DllStructCreate($sTagOBJECTATTRIBUTES) DllStructSetData($tFilePath,1,$sFilePath) Local $aRet=DllCall($hDll_NTDLL,"none","RtlInitUnicodeString","ptr",DllStructGetPtr($tFilePathW),"ptr",DllStructGetPtr($tFilePath)) DllStructSetData($tObjAttr,"Length",DllStructGetSize($tObjAttr)) DllStructSetData($tObjAttr,"RootDirectory",0) DllStructSetData($tObjAttr,"ObjectName",DllStructGetPtr($tFilePathW)) DllStructSetData($tObjAttr,"Attributes",$OBJ_CASE_INSENSITIVE) DllStructSetData($tObjAttr,"SecurityDescriptor",0) DllStructSetData($tObjAttr,"SecurityQualityOfService",0) Local $tIOSB=DllStructCreate($sTagIOSTATUSBLOCK) Local $thFile=DllStructCreate("handle") Local $phFile=DllStructGetPtr($thFile) $aRet=DllCall($hDll_NTDLL,"long","NtCreateFile","ptr",$phFile,"ulong",BitOR($GENERIC_READ,$GENERIC_WRITE,0x20),"ptr",DllStructGetPtr($tObjAttr),"ptr",DllStructGetPtr($tIOSB),"int64*",0,"ulong",0,"ulong",$FILE_SHARE_VALID_FLAGS,"ulong",$FILE_OPEN,"ulong",BitOR($FILE_OPEN_FOR_BACKUP_INTENT,$FILE_OPEN_REPARSE_POINT),"ptr",0,"ulong",0) If @error Or $aRet[0]<>$STATUS_SUCCESS Then Return SetError(@error, @extended, 0) Local $hFile=DllStructGetData($thFile,1) Local $tInputBuffer=DllStructCreate("STRUCT;"&$sTagWOF_EXTERNAL_INFO&";ENDSTRUCT;STRUCT;"&$sTagFILE_PROVIDER_EXTERNAL_INFO_V1&";ENDSTRUCT") DllStructSetData($tInputBuffer,"WOFEI_Version",$WOF_CURRENT_VERSION) DllStructSetData($tInputBuffer,"WOFEI_Provider",$WOF_PROVIDER_FILE) DllStructSetData($tInputBuffer,"FPEI_Version",$FILE_PROVIDER_CURRENT_VERSION) DllStructSetData($tInputBuffer,"FPEI_CompressionFormat",$iFormat) Local $pInputBuffer=DllStructGetPtr($tInputBuffer) Local $iInputBuffer=DllStructGetSize($tInputBuffer) Local $iTried=0, $iRet=0 Do $iRet=_WinAPI_NtFsControlFile($hFile,$FSCTL_SET_EXTERNAL_BACKING,$pInputBuffer,$iInputBuffer) If @error Then Return SetError(@error, @extended, 0) If $iRet=$STATUS_INVALID_DEVICE_REQUEST And Not $iTried Then __DriveAttachWOF(__PathGetDrive($sFilePath)) $iTried=1 ContinueLoop EndIf $iTried=1 Until $iTried DllCall($hDll_NTDLL,"long","NtClose","handle",$hFile);close Handle EndFunc ;==>_WinAPI_SetCompression Func _WinAPI_NtFsControlFile($hFile,$iFsControlCode,$pInputBuffer,$iInputBuffer,$pOutputBuffer=0,$iOutputAvail=0) Local $tIOSB=DllStructCreate($sTagIOSTATUSBLOCK) Local $pIOSB=DllStructGetPtr($tIOSB) Local $aRet=DllCall($hDll_NTDLL,"int","NtFsControlFile","HANDLE",$hFile,"ptr",0,"ptr",0,"ptr",0,"ptr",$pIOSB,"uint",$iFsControlCode,"ptr",$pInputBuffer,"uint",$iInputBuffer,"ptr",$pOutputBuffer,"uint",$iOutputAvail) If @error Or Not $aRet[0] Then Return SetError(@error,@extended,0) Local $iRet=0, $iError=0 If $aRet[0]=$STATUS_PENDING Then $iRet=_WinAPI_WaitForSingleObject($hFile) $iError=_WinAPI_GetLastError() If Not $iError Then SetError(1,$iError,0) Return SetError(1,$iRet,0) EndIf Return SetError(0,0,$aRet[0]) EndFunc Func __DriveAttachWOF($sDrive) ; win32_try_to_attach_wof Local $aRet,$hDll_FltLib $hDll_FltLib=DllOpen("FltLib.dll") If @error Then Return SetError(1,0,0) $aRet=DllCall($hDll_FltLib,"int","FilterAttach","WSTR","wof","wstr",$sDrive,"ptr",0,"int",0,"ptr",0) If @error Or Not $aRet[0] Then $aRet=DllCall($hDll_FltLib,"int","FilterAttach","WSTR","wofadk","wstr",$sDrive,"ptr",0,"int",0,"ptr",0) If @error Or Not $aRet[0] Then Return SetError(@error,@extended,0) EndIf DllClose($hDll_FltLib) Return SetError(0,0,$aRet[0]) EndFunc ;==>DriveAttachWOF Func __PathGetDrive($sPath) $sPath=_WinAPI_GetFullPathName($sPath) If @error Or $sPath="" Then Return SetError(1,0,0) Local $aTest=StringRegExp($sPath,"^([A-Za-z]\:).*$",1) If @error Then Return SetError(1,0,0) Return SetError(0, 0,"\\.\" & StringLower($aTest[0])) EndFunc ;==>PathGetDrive What is what? What is what.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now