SetNTFSCompressionFlag Function

From NSIS Wiki
Jump to navigationJump to search
Author: Zinthose (talk, contrib)


About

Function to enable or disable NTFS encryption flag on a file or folder. Obviously it requires a system with an NTFS formatted drive to be useful but it has built in checks so it should fail gracefully.

Forum Discussion

Usage

  ${SetNTFSCompressionFlag} PathToFolderOrFile True|False|Yes|No|1|0
  IfErrors ItDidntWork

Example

    InitPluginsDir
 
    ## Our Control Script
        SetOutPath "$PLUGINSDIR\Not Compressed"
        File "${__FILE__}"
 
    ## To ensure we reduce any disk space while installing we will enable the NTFS compressed folder flag for the $PLUGINSDIR
        ${SetNTFSCompressionFlag} "$PLUGINSDIR" True
        IfErrors 0 +2
            Abort "Errors"
 
    ## Now any new files extracted to the folder will be compressed.
        SetOutPath $PLUGINSDIR\Compressed
        File "${__FILE__}"
 
    ## Now Lets Take a Look
        Exec `explorer "$PLUGINSDIR"`

Function

!define SetNTFSCompressionFlag '!insertmacro _SetNTFSCompressionFlag'
!macro _SetNTFSCompressionFlag _PATH _VALUE
    Push `${_VALUE}`
    Push `${_PATH}`
    Call SetNTFSCompressionFlag
!macroend
Function SetNTFSCompressionFlag
    ClearErrors
 
    ; STACK: _PATH _VALUE
    Exch $0 ; r0 _VALUE
    Exch    ; _VALUE r0
    Exch $1 ; r1 r0
    Push $2 ; r2 r1 r0
    Push $3 ; r3 r2 r1 r0
 
    ## File/Folder Exists?
        IfFileExists $0 0 Errors
 
    ## Is Compression Supported?
        System::Call 'Kernel32::GetVolumePathName(t r0,t .r2,i ${NSIS_MAX_STRLEN})i.r3'
        StrCmp $3 0 Errors       ; <-- If Return Code is 0 then ERROR
        System::Call 'Kernel32::GetVolumeInformation(t r2,t,i ${NSIS_MAX_STRLEN},*i,*i,*i.r3,t,i ${NSIS_MAX_STRLEN})i.r2'
        StrCmp $2 0 Errors       ; <-- If Return Code is 0 then ERROR
        IntOp $2 $3 & 0x00000010 ; <-- Dose the specified volume support file-based compression.
        StrCmp $2 0 Errors
 
    ;## Tweak Value
        StrCmp $1 0 ValueSet
        StrCmp $1 True ValueTrue
        StrCmp $1 Yes ValueTrue
        StrCmp $1 T ValueTrue
        StrCmp $1 Y ValueTrue
        StrCpy $1 0x0000
        Goto ValueSet
        ValueTrue:
            StrCpy $1 0x0001
        ValueSet:
 
    ;## Get status of compression 
        System::Call 'kernel32::GetFileAttributes(t r0)i .r2'
        StrCmp $2 -1 Errors       ; <-- If Return Code is -1 then ERROR
        IntOp $2 $2 & 0x0800      ; <-- Determine if the Compressed flag is set
        StrCmp $1 $2 ExitFunction ; <-- No Change Needed as new setting and current = NoCompression
        StrCmp $2 0 DoChange
        StrCmp $1 1 ExitFunction  ; <-- No Change Needed as new setting and current - Compressed
        StrCmp $1 0 DoChange 
 
    ## Change Compression
        DoChange:
        ## Open FileHandle to Directory
            System::Call "kernel32::CreateFile(t r0, i 0x40000000|0x80000000, i 0x00000003, i 0, i 3, i 0x02000000, i 0) i.r2"
            StrCmp $2 -1 Errors  ; <-- InvalidFileHandle!
 
        ## Apply Change
            System::Call "kernel32::DeviceIoControl(i r2,i 0x9C040,*i r1,i 16,i 0,i 0,*i r3r3,i,0)i.r3"
            System::Call "kernel32::CloseHandle(i r2)i.r2"
            StrCmp $2 0 Errors
 
        ## Validate
            System::Call 'kernel32::GetFileAttributes(t r0)i .r2'
            StrCmp $2 -1 Errors       ; <-- If Return Code is -1 then ERROR
            IntOp $2 $2 & 0x0800      ; <-- Determine if the Compressed flag is set
            StrCmp $1 $2 Errors       ; <-- Change Failed!
            StrCmp $2 0 ExitFunction
            StrCmp $1 1 Errors        ; <-- Change Failed!
            StrCmp $1 0 ExitFunction 
 
    Goto ExitFunction
    Errors:
        SetErrors
        Goto ExitFunction
    ExitFunction:
    Pop $3
    Pop $2
    Pop $1
    Pop $0
FunctionEnd