Get size on disk: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
(Size On Disk (SOD) utility to get the space used by directories and files)
(Use ReserveFile /plugin)
 
(15 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{PageAuthor|Bnicer}}
This example code shows you how to get the space used by directories and files.
This example code shows you how to get the space used by directories and files.
<highlight-nsis>
<highlight-nsis>
Line 4: Line 5:
; the uninstaller
; the uninstaller
; nsissize.nsi
; nsissize.nsi
; Compile & run the .exe
; Compile, then run the .exe


Name "SOD Tool"
Name "SOD Tool"
Unicode true
RequestExecutionLevel user
RequestExecutionLevel user
#RequestExecutionLevel admin ; More files may be found in system folders
!define LOCAL "" ; Path where local include files reside
!define LOCAL "" ; Path where local include files reside
OutFile "${LOCAL}nsissize.exe"
OutFile "${LOCAL}nsissize.exe"
!include "${LOCAL}macros.nsh"
!include "${LOCAL}macros.nsh"
ReserveFile "${NSISDIR}\Plugins\Math.dll"
Icon "${LOCAL}arrows.ico"
#Icon "${LOCAL}arrows.ico"
ReserveFile /plugin "Math.dll" ; Doesn't seem to like "!include"
!include "LogicLib.nsh"
ShowInstDetails show
ShowInstDetails show
;--------------------------------


; Variables
; Variables
Var NSIS
Var NSIS
Var ZIP
Var COMPRESSED
Var ZIP_UN
Var COMPRESSED_UN
Var COUNT
Var BLOCK
Var BLOCK
Var FILES
Var FILES
Line 33: Line 38:
Var SOD_UN_K
Var SOD_UN_K


;--------------------------------
; Functions
Function Separator ; comma
Function Separator ; comma
  Exch $R1 ; input string
  Push $R2
  Push $R3
  Push $R4
  Push $R5
   StrCpy $R2 $R1
   StrCpy $R2 $R1
   StrCpy $COUNT "16" ; 1,000,000,000,000,000 limit
   StrCpy $R5 "16" ; 1,000,000,000,000,000 limit
   StrLen $R4 $R1
   StrLen $R4 $R1
  loop:
loop:
   IntCmp $COUNT 3 endloop endloop 0
   IntCmp $R5 3 endloop endloop 0
   IntCmp $R4 $COUNT 0 +7 0
   IntCmp $R4 $R5 0 +7 0
   IntOp $COUNT $COUNT - 1
   IntOp $R5 $R5 - 1
   StrCpy $R2 $R2 -$COUNT
   StrCpy $R2 $R2 -$R5
   StrCpy $R3 $R1 "" -$COUNT
   StrCpy $R3 $R1 "" -$R5
   StrCpy $R2 "$R2,$R3"
   StrCpy $R2 "$R2,$R3"
   IntOp $COUNT $COUNT - 2
   IntOp $R5 $R5 - 2
   Goto loop
   Goto loop
   IntOp $COUNT $COUNT - 3
   IntOp $R5 $R5 - 3
   Goto loop
   Goto loop
  endloop:
endloop:
  Pop $R5
  Pop $R4
  Pop $R3
  Exch $R2
  Pop $R1
  Exch $R1 ; output string
FunctionEnd
FunctionEnd


;--------------------------------
; Main Section (nothing will be installed)
Section
Section
; root
; registry
  ReadRegStr $NSIS HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS Unicode" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
   ReadRegStr $NSIS HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\\
   ReadRegStr $NSIS HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\\
   NSIS Unicode" "InstallLocation"
   NSIS Unicode" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
  ReadRegStr $NSIS HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS ANSI" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
  ReadRegStr $NSIS HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS" "InstallLocation"
   IfErrors 0 begin
   IfErrors 0 begin
   ClearErrors
   ClearErrors
Line 80: Line 90:
   begin:
   begin:
   IfFileExists "$NSIS" 0 done
   IfFileExists "$NSIS" 0 done
   ${GetFileAttributes} "$NSIS" "COMPRESSED" $ZIP
   ${GetClusterSize} $NSIS $BLOCK
  ${GetClusterSize} $BLOCK
; directory
   ${GetSizeOnDisk} "$NSIS" "/S=0B" "" $0 $1 $2
   ${GetSizeOnDisk} "$NSIS" "/S=0B" "" $0 $1 $2 $3
  Math::Script "r3 = ff($0 / 1024 / 1024.0, 16 +2"
   StrCpy $SIZE_B $0
   StrCpy $SIZE_B $0
   StrCpy $FILES $1
   StrCpy $FILES $1
   StrCpy $FOLDERS $2
   StrCpy $FOLDERS $2
   StrCpy $SIZE_M $3
  Math::Script "r4 = ff($0 / 1024 / 1024.0, 16 +2)"
   ${GetSizeOnDisk} "$NSIS" "/S=0B" "$BLOCK" $0 $1 $2
   StrCpy $SIZE_M $4
   ${GetSizeOnDisk} "$NSIS" "/S=0B" "$BLOCK" $0 $1 $2 $3
  StrCpy $SOD_B $0
  StrCpy $COMPRESSED $3
   Math::Script "r4 = ff($0 / 1024.0, 16 +0); r5 = ff(r4 / 1024.0, 16 +2)"
   Math::Script "r4 = ff($0 / 1024.0, 16 +0); r5 = ff(r4 / 1024.0, 16 +2)"
  StrCpy $SOD_B $0
   StrCpy $SOD_K $4
   StrCpy $SOD_K $4
   StrCpy $SOD_M $5
   StrCpy $SOD_M $5
; uninstaller
; uninstaller
   IfFileExists "$NSIS\uninst-nsis.exe" 0 done
   IfFileExists "$NSIS\uninst-nsis.exe" 0 done
  ${GetFileAttributes} "$NSIS\uninst-nsis.exe" "COMPRESSED" $ZIP_UN
   ${GetSizeOnDisk} "$NSIS" "/M=uninst-nsis.exe /S=0B /G=0" "" $0 $1 $2 $3
   ${GetSizeOnDisk} "$NSIS" "/M=uninst-nsis.exe /S=0B" "" $0 $1 $2
  Math::Script "r6 = ff($0 / 1024.0, 16 +1); \
  a = $0; b = $BLOCK; c = a % b; #[c == 0, c = $BLOCK]; r7 = (b - c + a); \
  r8 = ff(r7 / 1024.0, 16 +1)"
   StrCpy $SIZE_UN_B $0
   StrCpy $SIZE_UN_B $0
   StrCpy $SIZE_UN_K $6
  Math::Script "r4 = ff($0 / 1024.0, 16 +1)"
   StrCpy $SOD_UN_B $7
   StrCpy $SIZE_UN_K $4
   StrCpy $SOD_UN_K $8
  ${GetSizeOnDisk} "$NSIS" "/M=uninst-nsis.exe /S=0B /G=0" "$BLOCK" $0 $1 $2 $3
   StrCpy $SOD_UN_B $0
  ${If} $3 > 0
    StrCpy $COMPRESSED_UN " (compressed or sparse)"
  ${Else}
    StrCpy $COMPRESSED_UN ""
  ${EndIf}
  Math::Script "r4 = ff($0 / 1024.0, 16 +1)"
   StrCpy $SOD_UN_K $4
; format
; format
   StrCpy $R1 $SIZE_B
   Push $SIZE_B
   Call Separator
   Call Separator
   StrCpy $SIZE_B $R2
   Pop $SIZE_B


   StrCpy $R1 $SOD_B
   Push $SOD_B
   Call Separator
   Call Separator
   StrCpy $SOD_B $R2
   Pop $SOD_B


   StrCpy $R1 $SOD_K
   Push $SOD_K
   Call Separator
   Call Separator
   StrCpy $SOD_K $R2
   Pop $SOD_K


   StrCpy $R1 $SIZE_UN_B
   Push $SIZE_UN_B
   Call Separator
   Call Separator
   StrCpy $SIZE_UN_B $R2
   Pop $SIZE_UN_B
   StrCpy $R1 $SOD_UN_B
 
   Push $SOD_UN_B
   Call Separator
   Call Separator
   StrCpy $SOD_UN_B $R2
   Pop $SOD_UN_B
; output
; output
  ; note: with compression SOD lines are incorrect
   DetailPrint ""
   DetailPrint ""
   DetailPrint "$NSIS"
   DetailPrint "$NSIS"
   DetailPrint "Size: $SIZE_M MB ($SIZE_B bytes)"
   DetailPrint "Size: $SIZE_M MB ($SIZE_B bytes)"
  StrCmp $ZIP "1" +3
  StrCmp $ZIP_UN "1" +2
   DetailPrint "SOD: $SOD_M MB ($SOD_B bytes)"
   DetailPrint "SOD: $SOD_M MB ($SOD_B bytes)"
   DetailPrint ""
   DetailPrint ""
   DetailPrint "Uninstaller"
   DetailPrint "Uninstaller$COMPRESSED_UN"
   DetailPrint "Size: $SIZE_UN_K KB ($SIZE_UN_B bytes)"
   DetailPrint "Size: $SIZE_UN_K KB ($SIZE_UN_B bytes)"
  StrCmp $ZIP "1" +3
  StrCmp $ZIP_UN "1" +2
   DetailPrint "SOD: $SOD_UN_K KB ($SOD_UN_B bytes)"
   DetailPrint "SOD: $SOD_UN_K KB ($SOD_UN_B bytes)"
   DetailPrint ""
   DetailPrint ""
   DetailPrint "$FILES files $FOLDERS folders $SOD_K Kb"
   DetailPrint "$FILES files | $FOLDERS folders | $SOD_K Kb | $COMPRESSED compressed/sparse file(s)"
   DetailPrint ""
   DetailPrint ""
   Goto completed
   Goto completed
  done:
done:
   DetailPrint "File not found."
   DetailPrint "File not found."
  completed:
completed:
SectionEnd
SectionEnd


Line 151: Line 162:
You should copy the next code into a separate file: <b>macros.nsh</b>.
You should copy the next code into a separate file: <b>macros.nsh</b>.
<highlight-nsis>
<highlight-nsis>
; Macros include file
; Macros include (TN)
;--------------------------------
;--------------------------------
/*
/*


  FileFunction=[GetSizeOnDisk|GetClusterSize|GetFileAttributes]
  FileFunction=[GetSizeOnDisk|GetClusterSize]


*/
*/
Line 166: Line 177:
;
;
; Example:
; Example:
; !include "sizemacros.nsh"
; !include "macros.nsh"
; !insertmacro GetSizeOnDisk
; !insertmacro GetSizeOnDisk
; ${FILEFUNC_VERBOSE} 4  # all verbosity
; ${FILEFUNC_VERBOSE} 4  # all verbosity
Line 191: Line 202:
!macroend
!macroend


!macro GetSizeOnDiskCall _PATH _OPTIONS _FILESYSTEM _RESULT1 _RESULT2 _RESULT3
!macro GetSizeOnDiskCall _PATH _OPTIONS _FILESYSTEM _RESULT1 _RESULT2 _RESULT3 _RESULT4
!verbose push
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
!verbose ${_FILEFUNC_VERBOSE}
Push `${_PATH}`
Push `${_PATH}`
Push `${_OPTIONS}`
Push `${_OPTIONS}`
Push `${_FILESYSTEM}` ; block size
Push `${_FILESYSTEM}` ; volume block size
${CallArtificialFunction} GetSizeOnDisk_
${CallArtificialFunction} GetSizeOnDisk_
Pop ${_RESULT1}
Pop ${_RESULT1}
Pop ${_RESULT2}
Pop ${_RESULT2}
Pop ${_RESULT3}
Pop ${_RESULT3}
Pop ${_RESULT4}
!verbose pop
!verbose pop
!macroend
!macroend


!macro GetClusterSizeCall _RESULT
!macro GetClusterSizeCall _PATH _RESULT
!verbose push
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
!verbose ${_FILEFUNC_VERBOSE}
Push `${_PATH}`
${CallArtificialFunction} GetClusterSize_
${CallArtificialFunction} GetClusterSize_
Pop ${_RESULT}
!verbose pop
!macroend
!macro GetFileAttributesCall _PATH _ATTR _RESULT
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
Push `${_PATH}`
Push `${_ATTR}`
${CallArtificialFunction} GetFileAttributes_
Pop ${_RESULT}
Pop ${_RESULT}
!verbose pop
!verbose pop
Line 237: Line 240:


; For documentation, see the NSIS user manual: E.1.3 GetSize
; For documentation, see the NSIS user manual: E.1.3 GetSize
; Three values are returned
; Four (not three) values are returned


; $var1 ; Result1: Size/Size on disk
; $var1 ; Result1: Size/Size on disk
; $var2 ; Result2: Sum of files
; $var2 ; Result2: Sum of files
; $var3 ; Result3: Sum of directories
; $var3 ; Result3: Sum of directories
; $var4 ; Result4: Sum of compressed/sparse files
; Example: ${GetSizeOnDisk} "$INSTDIR" "/S=0K" "SOD" $0 $1 $2 $3
; DetailPrint "$1 file(s) | $2 folder(s) | $0 Kb | $3 compressed or sparse file(s)"


; Example: ${GetSizeOnDisk} "$INSTDIR" "/S=0K" "4096" $0 $1 $2
; Specifying 'SOD' (e.g. Size On Disk) toggles the $var1 result
; Output is logical size, if used, or physical size, if left empty ""
; The target volume's allocation unit size in bytes, the size of a
; cluster, for example '4096' bytes, if valid, can also be the input
; If neither 'SOD' nor a cluster size is specified, $var4 returns 0
; even where compressed and/or sparse files exist


; Specifying 4096 (logical size) toggles the result
; ${GetSizeOnDisk} can be used with Windows NT and Windows 2000
; Output is size on disk, if used, or size in bytes, if left empty ""
; When the volume is FAT32, FAT16 or an older file system, the result
; in $var1 reverts to physical size, although not incorrect


!macro GetSizeOnDisk_
!macro GetSizeOnDisk_
Line 252: Line 265:
!verbose ${_FILEFUNC_VERBOSE}
!verbose ${_FILEFUNC_VERBOSE}


; replace
Exch $2
Exch $R1
Exch
Exch $1
Exch 2
Exch 2
; end replace
Exch $0
Exch $0
Exch
Exch
Push $2
Exch $1
Push $3
Push $3
Push $4
Push $4
Line 268: Line 277:
Push $8
Push $8
Push $9
Push $9
; insert code
Push $R0
Push $R1
Push $R2
Push $R2
; end insert
StrCpy $R1 $2
Push $R3
Push $R3
Push $R4
Push $R4
Line 280: Line 290:
ClearErrors
ClearErrors


StrCmp $R1 '' FileFunc_GetSize_path
StrCpy $5 $0
StrCpy $2 $0 2
StrCmp $2 '\\' FileFunc_GetSize_Root_UNC
StrCpy $3 $2 1 1
StrCmp $3 ':' 0 FileFunc_GetSize_Root_empty
StrCpy $5 $2
goto FileFunc_GetSize_FileSystem
FileFunc_GetSize_Root_UNC:
StrCpy $3 1
StrCpy $4 ''
FileFunc_GetSize_Root_loop:
IntOp $3 $3 + 1
StrCpy $2 $5 1 $3
StrCmp $2$4 '' FileFunc_GetSize_Root_empty
StrCmp $2 '' +5
StrCmp $2 '\' 0 FileFunc_GetSize_Root_loop
StrCmp $4 '1' +3
StrCpy $4 '1'
goto FileFunc_GetSize_Root_loop
StrCpy $5 $5 $3
StrCpy $3 $5 1 -1
StrCmp $3 '\' 0 FileFunc_GetSize_FileSystem
FileFunc_GetSize_Root_empty:
StrCpy $5 ''
FileFunc_GetSize_FileSystem:
System::Call 'Kernel32::GetVolumeInformation\
(t "$5\",t,i ${NSIS_MAX_STRLEN},*i,*i,*i,t.r2,i ${NSIS_MAX_STRLEN})i.r3'
StrCmp $3 0 FileFunc_GetSize_FileSystem_error
StrCpy $2 $2 3
StrCmp $2 'FAT' FileFunc_GetSize_FileSystem_error
StrCmp $R1 'SOD' 0 FileFunc_GetSize_path
System::Call 'kernel32::GetDiskFreeSpace(t "$5\",*i0r2,*i0r3,,)'
IntOp $R1 $2 * $3
goto FileFunc_GetSize_path
FileFunc_GetSize_FileSystem_error:
StrCpy $R1 ''
FileFunc_GetSize_path:
StrCpy $R9 $0 1 -1
StrCpy $R9 $0 1 -1
StrCmp $R9 '\' 0 +3
StrCmp $R9 '\' 0 +3
Line 286: Line 341:
IfFileExists '$0\*.*' 0 FileFunc_GetSize_error
IfFileExists '$0\*.*' 0 FileFunc_GetSize_error


StrCpy $3 ''
StrCpy $3 0
StrCpy $4 ''
StrCpy $4 ''
StrCpy $5 ''
StrCpy $5 ''
Line 399: Line 454:
IntOp $R4 $R4 + 1
IntOp $R4 $R4 + 1
goto FileFunc_GetSize_findnext
goto FileFunc_GetSize_findnext
StrCmp $R1 '' FileFunc_GetSize_fileopen
StrCpy $R0 0
System::Call 'kernel32::GetFileAttributes(t "$R8\$R7")i .R2'
StrCmp $R2 -1 FileFunc_GetSize_fileopen
IntOp $R0 $R2 & 0x0800 ; compressed
IntCmp $R0 0 0 0 FileFunc_GetSize_GetCompressed
IntOp $R0 $R2 & 0x0200 ; sparse file
IntCmp $R0 0 FileFunc_GetSize_fileopen
FileFunc_GetSize_GetCompressed:
System::Call 'kernel32::GetCompressedFileSize(t "$R8\$R7", i)i .R6'
IntCmp $R6 4096 +2 0 +2
StrCpy $R6 4096
IntOp $3 $3 + 1 ; location contains compressed or sparse files
goto FileFunc_GetSize_fileclose
FileFunc_GetSize_fileopen:
FileOpen $9 '$R8\$R7' r
FileOpen $9 '$R8\$R7' r
IfErrors +3
IfErrors +3
FileSeek $9 0 END $R6
FileSeek $9 0 END $R6
FileClose $9
FileClose $9
FileFunc_GetSize_fileclose:
StrCmp $5 '' +2
StrCmp $5 '' +2
IntCmp $R6 $5 0 FileFunc_GetSize_findnext
IntCmp $R6 $5 0 FileFunc_GetSize_findnext
Line 408: Line 479:
IntCmp $R6 $6 0 0 FileFunc_GetSize_findnext
IntCmp $R6 $6 0 0 FileFunc_GetSize_findnext
IntOp $R4 $R4 + 1
IntOp $R4 $R4 + 1
; insert code
StrCmp $R1 '' FileFunc_GetSize_file_add
StrCmp $R1 "" +10 0
StrCmp $R0 0 0 FileFunc_GetSize_file_add
StrCpy $R0 $R1
StrCpy $R0 $R1
IntOp $R6 $R6 + $R0
IntOp $R6 $R6 + $R0
Line 419: Line 490:
IntOp $R6 $R6 + $R2
IntOp $R6 $R6 + $R2
StrCpy $R1 $R0
StrCpy $R1 $R0
; end insert
FileFunc_GetSize_file_add:
System::Int64Op $R3 + $R6
System::Int64Op $R3 + $R6
Pop $R3
Pop $R3
Line 465: Line 536:
StrCpy $1 $R5
StrCpy $1 $R5
StrCpy $0 $R3
StrCpy $0 $R3
goto FileFunc_GetSize_end
goto FileFunc_GetSize_noerror


FileFunc_GetSize_error:
FileFunc_GetSize_error:
Line 472: Line 543:
StrCpy $1 ''
StrCpy $1 ''
StrCpy $2 ''
StrCpy $2 ''
StrCpy $3 ''
goto FileFunc_GetSize_end
FileFunc_GetSize_noerror:
StrCmp $0 '' 0 +2
StrCpy $0 0
StrCmp $1 '' 0 +2
StrCpy $1 0
StrCmp $2 '' 0 +2
StrCpy $2 0
StrCmp $3 '' 0 +2
StrCpy $3 0


FileFunc_GetSize_end:
FileFunc_GetSize_end:
Line 482: Line 565:
Pop $R4
Pop $R4
Pop $R3
Pop $R3
; insert code
Pop $R2
Pop $R2
; end insert
Pop $R1
Pop $R0
Pop $9
Pop $9
Pop $8
Pop $8
Line 491: Line 574:
Pop $5
Pop $5
Pop $4
Pop $4
Pop $3
Exch $3
Exch 3
Exch $2
Exch $2
Exch
Exch
Line 502: Line 586:


; ---------------
; ---------------
; GetFileAttributes (FileFunc.nsh)
; GetClusterSize


!define GetFileAttributes `!insertmacro GetFileAttributesCall`
; Allocation unit size on NTFS, exFAT and reFS formatted volumes
!define un.GetFileAttributes `!insertmacro GetFileAttributesCall`
; Syntax: ${GetClusterSize} $inputpath $outputvariable
; Result: 512, 1024, ..., 4096, ..., 131072, ...


!macro GetFileAttributes
!define GetClusterSize `!insertmacro GetClusterSizeCall`
!define un.GetClusterSize `!insertmacro GetClusterSizeCall`
 
!macro GetClusterSize
!macroend
!macroend


!macro un.GetFileAttributes
!macro un.GetClusterSize
!macroend
!macroend


!macro GetFileAttributes_
!macro GetClusterSize_
!verbose push
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
!verbose ${_FILEFUNC_VERBOSE}
 
Exch $1
Exch
Exch $0
Exch $0
Exch
Push $1
Push $2
Push $2
Push $3
Push $3
Push $4
Push $5


System::Call 'kernel32::GetFileAttributes(t r0)i .r2'
StrCpy $1 $0 2
StrCmp $2 -1 FileFunc_GetFileAttributes_error
StrCmp $1 '\\' Root_UNC
StrCpy $2 $1 1 1
StrCmp $2 ':' 0 Root_empty
StrCpy $0 $1
goto Root_end
 
Root_UNC:
StrCpy $2 1
StrCpy $3 ''
StrCpy $3 ''


IntOp $0 $2 & 0x4000
Root_loop:
IntCmp $0 0 +2
IntOp $2 $2 + 1
StrCpy $3 'ENCRYPTED|'
StrCpy $1 $0 1 $2
 
StrCmp $1$3 '' Root_empty
IntOp $0 $2 & 0x2000
StrCmp $1 '' +5
IntCmp $0 0 +2
StrCmp $1 '\' 0 Root_loop
StrCpy $3 'NOT_CONTENT_INDEXED|$3'
StrCmp $3 '1' +3
 
StrCpy $3 '1'
IntOp $0 $2 & 0x1000
goto Root_loop
IntCmp $0 0 +2
StrCpy $0 $0 $2
StrCpy $3 'OFFLINE|$3'
StrCpy $2 $0 1 -1
 
StrCmp $2 '\' 0 Root_end
IntOp $0 $2 & 0x0800
IntCmp $0 0 +2
StrCpy $3 'COMPRESSED|$3'


IntOp $0 $2 & 0x0400
Root_empty:
IntCmp $0 0 +2
StrCpy $3 'REPARSE_POINT|$3'
 
IntOp $0 $2 & 0x0200
IntCmp $0 0 +2
StrCpy $3 'SPARSE_FILE|$3'
 
IntOp $0 $2 & 0x0100
IntCmp $0 0 +2
StrCpy $3 'TEMPORARY|$3'
 
IntOp $0 $2 & 0x0080
IntCmp $0 0 +2
StrCpy $3 'NORMAL|$3'
 
IntOp $0 $2 & 0x0040
IntCmp $0 0 +2
StrCpy $3 'DEVICE|$3'
 
IntOp $0 $2 & 0x0020
IntCmp $0 0 +2
StrCpy $3 'ARCHIVE|$3'
 
IntOp $0 $2 & 0x0010
IntCmp $0 0 +2
StrCpy $3 'DIRECTORY|$3'
 
IntOp $0 $2 & 0x0004
IntCmp $0 0 +2
StrCpy $3 'SYSTEM|$3'
 
IntOp $0 $2 & 0x0002
IntCmp $0 0 +2
StrCpy $3 'HIDDEN|$3'
 
IntOp $0 $2 & 0x0001
IntCmp $0 0 +2
StrCpy $3 'READONLY|$3'
 
StrCpy $0 $3 -1
StrCmp $1 '' FileFunc_GetFileAttributes_end
StrCmp $1 'ALL' FileFunc_GetFileAttributes_end
 
FileFunc_GetFileAttributes_attrcmp:
StrCpy $5 0
IntOp $5 $5 + 1
StrCpy $4 $1 1 $5
StrCmp $4 '' +2
StrCmp $4 '|'  0 -3
StrCpy $2 $1 $5
IntOp $5 $5 + 1
StrCpy $1 $1 '' $5
StrLen $3 $2
StrCpy $5 -1
IntOp $5 $5 + 1
StrCpy $4 $0 $3 $5
StrCmp $4 '' FileFunc_GetFileAttributes_notfound
StrCmp $4 $2 0 -3
StrCmp $1 '' 0 FileFunc_GetFileAttributes_attrcmp
StrCpy $0 1
goto FileFunc_GetFileAttributes_end
 
FileFunc_GetFileAttributes_notfound:
StrCpy $0 0
goto FileFunc_GetFileAttributes_end
 
FileFunc_GetFileAttributes_error:
SetErrors
StrCpy $0 ''
StrCpy $0 ''


FileFunc_GetFileAttributes_end:
Root_end:
Pop $5
System::Call 'kernel32::GetDiskFreeSpace(t "$0\",*i0r1,*i0r2,,)'
Pop $4
IntOp $0 $1 * $2
Pop $3
Pop $3
Pop $2
Pop $2
Pop $1
Pop $1
Exch $0
Exch $0
 
!verbose pop
!verbose pop
!macroend
!macroend


!define GetFileVersion `!insertmacro GetFileVersionCall`
</highlight-nsis>
!define un.GetFileVersion `!insertmacro GetFileVersionCall`
<span style="font-size: 110%"><b>Credits:</b></span>
 
<em>GetSizeOnDisk</em> has been altered slightly and renamed. The original macro is called <em>GetSize</em>. You will find it in the Users Manual under E.1.3.
 
<span style="font-size: 110%"><b>=== Download (example) ===</b></span>
 
This is the same as the example code above.


!macro GetFileVersion
<attach>SODTool.zip</attach>
!macroend


!macro un.GetFileVersion
<span style="font-size: 110%"><b>=== Download (utility) ===</b></span>
!macroend


!macro GetFileVersion_
This is a Modern UI2 version that displays selection windows and goes to an output page. Script file is included.
!verbose push
!verbose ${_FILEFUNC_VERBOSE}
Exch $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
ClearErrors


GetDllVersion '$0' $1 $2
<attach>SOD II tool.zip</attach>
IfErrors FileFunc_GetFileVersion_error
IntOp $3 $1 >> 16
IntOp $3 $3 & 0x0000FFFF
IntOp $4 $1 & 0x0000FFFF
IntOp $5 $2 >> 16
IntOp $5 $5 & 0x0000FFFF
IntOp $6 $2 & 0x0000FFFF
StrCpy $0 '$3.$4.$5.$6'
goto FileFunc_GetFileVersion_end


FileFunc_GetFileVersion_error:
Both downloads are compiled in unicode, so SOD Tool can read Russian file names.
SetErrors
StrCpy $0 ''


FileFunc_GetFileVersion_end:
<span style="font-size: 110%"><b>Errors:</b></span>
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0


!verbose pop
On failing to obtain the size of a file <em>GetSizeOnDisk</em> does nothing much. You can edit the line that says,
!macroend
<highlight-nsis>
FileOpen $9 '$R8\$R7' r
IfErrors +3
</highlight-nsis>
changing the instruction to,
<highlight-nsis>
FileOpen $9 '$R8\$R7' r
IfErrors FileFunc_GetSize_error
</highlight-nsis>
It sets an error flag and will abort the macro, if an error is encountered opening a file for reading.


; ---------------
<span style="font-size: 110%"><b>History:</b></span>
; GetClusterSize


!define GetClusterSize `!insertmacro GetClusterSizeCall`
Optional parameter for counting compressed/sparse files added. (Feb. 18, 2013)
!define un.GetClusterSize `!insertmacro GetClusterSizeCall`


!macro GetClusterSize
Option to find without subdirectories '/G=0' switch was missing. (Well, not really missing.) Change to details view (string), showing 'compressed/sparse file(s)'. (Feb. 19, 2013)
!macroend


!macro un.GetClusterSize
Change to unicode, because ansi could not read Russian. (Feb. 20, 2013)
!macroend


!macro GetClusterSize_
Stack operations cleaned up. The <b>SOD II tool</b> uploaded. (Feb. 22, 2013)
!verbose push
!verbose ${_FILEFUNC_VERBOSE}


System::Call 'kernel32::GetDiskFreeSpace(i0,*i0r0,*i0r1,*i0r2,*i)'
String formatting improvements, functions simplified (SOD II) and small revisions in macros header made. (Feb. 23, 2013)
IntOp $0 $0 * $1
Push $0


!verbose pop
Macros behavior modified in order to detect the file system to deal with FAT, FAT12, FAT16 and FAT32 volumes.  Also checking root path, possibly Win2K error. (March 8, 2013)
!macroend
</highlight-nsis>
<span style="font-size: 110%"><b>Credits:</b></span>


<em>GetFileAttributes</em> is borrowed from <b>filefunc.nsh</b>. <em>GetSizeOnDisk</em> has been altered slightly and renamed. The original macro is called <em>GetSize</em>. You will find it in the Users Manual under E.1.3.
Re-Compiled with NSIS 3 new release. (May 24, 2013)
[[Category:Code Examples]]
[[Category:Code Examples]]

Latest revision as of 18:32, 24 May 2013

Author: Bnicer (talk, contrib)


This example code shows you how to get the space used by directories and files.

; A utility for computing the NSIS (or NSIS Unicode) install folder size and the size of
; the uninstaller
; nsissize.nsi
; Compile, then run the .exe
 
Name "SOD Tool"
Unicode true
RequestExecutionLevel user
#RequestExecutionLevel admin ; More files may be found in system folders
!define LOCAL "" ; Path where local include files reside
OutFile "${LOCAL}nsissize.exe"
!include "${LOCAL}macros.nsh"
Icon "${LOCAL}arrows.ico"
ReserveFile /plugin "Math.dll" ; Doesn't seem to like "!include"
!include "LogicLib.nsh"
ShowInstDetails show
 
;--------------------------------
 
; Variables
Var NSIS
Var COMPRESSED
Var COMPRESSED_UN
Var BLOCK
Var FILES
Var FOLDERS
Var SIZE_B
Var SIZE_M
Var SOD_B
Var SOD_K
Var SOD_M
Var SIZE_UN_B
Var SIZE_UN_K
Var SOD_UN_B
Var SOD_UN_K
 
;--------------------------------
 
; Functions
Function Separator ; comma
  Exch $R1 ; input string
  Push $R2
  Push $R3
  Push $R4
  Push $R5
  StrCpy $R2 $R1
  StrCpy $R5 "16" ; 1,000,000,000,000,000 limit
  StrLen $R4 $R1
loop:
  IntCmp $R5 3 endloop endloop 0
  IntCmp $R4 $R5 0 +7 0
  IntOp $R5 $R5 - 1
  StrCpy $R2 $R2 -$R5
  StrCpy $R3 $R1 "" -$R5
  StrCpy $R2 "$R2,$R3"
  IntOp $R5 $R5 - 2
  Goto loop
  IntOp $R5 $R5 - 3
  Goto loop
endloop:
  Pop $R5
  Pop $R4
  Pop $R3
  Exch $R2
  Pop $R1
  Exch $R1 ; output string
FunctionEnd
 
;--------------------------------
 
; Main Section (nothing will be installed)
Section
; registry
  ReadRegStr $NSIS HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS Unicode" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
  ReadRegStr $NSIS HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS ANSI" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
  ReadRegStr $NSIS HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
  Goto done
  begin:
  IfFileExists "$NSIS" 0 done
  ${GetClusterSize} $NSIS $BLOCK
; directory
  ${GetSizeOnDisk} "$NSIS" "/S=0B" "" $0 $1 $2 $3
  StrCpy $SIZE_B $0
  StrCpy $FILES $1
  StrCpy $FOLDERS $2
  Math::Script "r4 = ff($0 / 1024 / 1024.0, 16 +2)"
  StrCpy $SIZE_M $4
  ${GetSizeOnDisk} "$NSIS" "/S=0B" "$BLOCK" $0 $1 $2 $3
  StrCpy $SOD_B $0
  StrCpy $COMPRESSED $3
  Math::Script "r4 = ff($0 / 1024.0, 16 +0); r5 = ff(r4 / 1024.0, 16 +2)"
  StrCpy $SOD_K $4
  StrCpy $SOD_M $5
; uninstaller
  IfFileExists "$NSIS\uninst-nsis.exe" 0 done
  ${GetSizeOnDisk} "$NSIS" "/M=uninst-nsis.exe /S=0B /G=0" "" $0 $1 $2 $3
  StrCpy $SIZE_UN_B $0
  Math::Script "r4 = ff($0 / 1024.0, 16 +1)"
  StrCpy $SIZE_UN_K $4
  ${GetSizeOnDisk} "$NSIS" "/M=uninst-nsis.exe /S=0B /G=0" "$BLOCK" $0 $1 $2 $3
  StrCpy $SOD_UN_B $0
  ${If} $3 > 0
    StrCpy $COMPRESSED_UN " (compressed or sparse)"
  ${Else}
    StrCpy $COMPRESSED_UN ""
  ${EndIf}
  Math::Script "r4 = ff($0 / 1024.0, 16 +1)"
  StrCpy $SOD_UN_K $4
; format
  Push $SIZE_B
  Call Separator
  Pop $SIZE_B
 
  Push $SOD_B
  Call Separator
  Pop $SOD_B
 
  Push $SOD_K
  Call Separator
  Pop $SOD_K
 
  Push $SIZE_UN_B
  Call Separator
  Pop $SIZE_UN_B
 
  Push $SOD_UN_B
  Call Separator
  Pop $SOD_UN_B
; output
  DetailPrint ""
  DetailPrint "$NSIS"
  DetailPrint "Size: $SIZE_M MB ($SIZE_B bytes)"
  DetailPrint "SOD: $SOD_M MB ($SOD_B bytes)"
  DetailPrint ""
  DetailPrint "Uninstaller$COMPRESSED_UN"
  DetailPrint "Size: $SIZE_UN_K KB ($SIZE_UN_B bytes)"
  DetailPrint "SOD: $SOD_UN_K KB ($SOD_UN_B bytes)"
  DetailPrint ""
  DetailPrint "$FILES files | $FOLDERS folders | $SOD_K Kb | $COMPRESSED compressed/sparse file(s)"
  DetailPrint ""
  Goto completed
done:
  DetailPrint "File not found."
completed:
SectionEnd
 
;--------------------------------
# EOF

You should copy the next code into a separate file: macros.nsh.

; Macros include (TN)
;--------------------------------
/*
 
 FileFunction=[GetSizeOnDisk|GetClusterSize]
 
*/
;_____________________________________________________________________________
;
;                         Macros
;_____________________________________________________________________________
;
; Change log window verbosity (default: 3=no script)
;
; Example:
; !include "macros.nsh"
; !insertmacro GetSizeOnDisk
; ${FILEFUNC_VERBOSE} 4   # all verbosity
; !insertmacro GetClusterSize
; ${FILEFUNC_VERBOSE} 3   # no script
 
!include Util.nsh ; for "CallArtificialFunction"
 
!verbose push
!verbose 3
!ifndef _FILEFUNC_VERBOSE
	!define _FILEFUNC_VERBOSE 3
!endif
!verbose ${_FILEFUNC_VERBOSE}
!define FILEFUNC_VERBOSE `!insertmacro FILEFUNC_VERBOSE`
!verbose pop
 
!macro FILEFUNC_VERBOSE _VERBOSE
	!verbose push
	!verbose 3
	!undef _FILEFUNC_VERBOSE
	!define _FILEFUNC_VERBOSE ${_VERBOSE}
	!verbose pop
!macroend
 
!macro GetSizeOnDiskCall _PATH _OPTIONS _FILESYSTEM _RESULT1 _RESULT2 _RESULT3 _RESULT4
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
	Push `${_PATH}`
	Push `${_OPTIONS}`
	Push `${_FILESYSTEM}` ; volume block size
	${CallArtificialFunction} GetSizeOnDisk_
	Pop ${_RESULT1}
	Pop ${_RESULT2}
	Pop ${_RESULT3}
	Pop ${_RESULT4}
	!verbose pop
!macroend
 
!macro GetClusterSizeCall _PATH _RESULT
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
	Push `${_PATH}` 
	${CallArtificialFunction} GetClusterSize_
	Pop ${_RESULT}
	!verbose pop
!macroend
 
; ---------------
; GetSizeOnDisk (modified "GetSize" - FileFunc.nsh - KiCHiK - Function "FindFiles")
 
!define GetSizeOnDisk `!insertmacro GetSizeOnDiskCall`
!define un.GetSizeOnDisk `!insertmacro GetSizeOnDiskCall`
 
!macro GetSizeOnDisk
!macroend
 
!macro un.GetSizeOnDisk
!macroend
 
; Usage: similar to "GetSize"
 
; For documentation, see the NSIS user manual: E.1.3 GetSize
; Four (not three) values are returned
 
; $var1		; Result1: Size/Size on disk
; $var2		; Result2: Sum of files
; $var3		; Result3: Sum of directories
; $var4		; Result4: Sum of compressed/sparse files
 
; Example: ${GetSizeOnDisk} "$INSTDIR" "/S=0K" "SOD" $0 $1 $2 $3
; DetailPrint "$1 file(s) | $2 folder(s) | $0 Kb | $3 compressed or sparse file(s)"
 
; Specifying 'SOD' (e.g. Size On Disk) toggles the $var1 result
; Output is logical size, if used, or physical size, if left empty ""
; The target volume's allocation unit size in bytes, the size of a
; cluster, for example '4096' bytes, if valid, can also be the input
; If neither 'SOD' nor a cluster size is specified, $var4 returns 0
; even where compressed and/or sparse files exist
 
; ${GetSizeOnDisk} can be used with Windows NT and Windows 2000
; When the volume is FAT32, FAT16 or an older file system, the result
; in $var1 reverts to physical size, although not incorrect
 
!macro GetSizeOnDisk_
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
 
	Exch $2
	Exch 2
	Exch $0
	Exch
	Exch $1
	Push $3
	Push $4
	Push $5
	Push $6
	Push $7
	Push $8
	Push $9
	Push $R0
	Push $R1
	Push $R2
	StrCpy $R1 $2
	Push $R3
	Push $R4
	Push $R5
	Push $R6
	Push $R7
	Push $R8
	Push $R9
	ClearErrors
 
	StrCmp $R1 '' FileFunc_GetSize_path
 
	StrCpy $5 $0
	StrCpy $2 $0 2
	StrCmp $2 '\\' FileFunc_GetSize_Root_UNC
	StrCpy $3 $2 1 1
	StrCmp $3 ':' 0 FileFunc_GetSize_Root_empty
	StrCpy $5 $2
	goto FileFunc_GetSize_FileSystem
 
	FileFunc_GetSize_Root_UNC:
	StrCpy $3 1
	StrCpy $4 ''
 
	FileFunc_GetSize_Root_loop:
	IntOp $3 $3 + 1
	StrCpy $2 $5 1 $3
	StrCmp $2$4 '' FileFunc_GetSize_Root_empty
	StrCmp $2 '' +5
	StrCmp $2 '\' 0 FileFunc_GetSize_Root_loop
	StrCmp $4 '1' +3
	StrCpy $4 '1'
	goto FileFunc_GetSize_Root_loop
	StrCpy $5 $5 $3
	StrCpy $3 $5 1 -1
	StrCmp $3 '\' 0 FileFunc_GetSize_FileSystem
 
	FileFunc_GetSize_Root_empty:
	StrCpy $5 ''
 
	FileFunc_GetSize_FileSystem:
	System::Call 'Kernel32::GetVolumeInformation\
	(t "$5\",t,i ${NSIS_MAX_STRLEN},*i,*i,*i,t.r2,i ${NSIS_MAX_STRLEN})i.r3'
	StrCmp $3 0 FileFunc_GetSize_FileSystem_error
	StrCpy $2 $2 3
	StrCmp $2 'FAT' FileFunc_GetSize_FileSystem_error
	StrCmp $R1 'SOD' 0 FileFunc_GetSize_path
	System::Call 'kernel32::GetDiskFreeSpace(t "$5\",*i0r2,*i0r3,,)'
	IntOp $R1 $2 * $3
	goto FileFunc_GetSize_path
 
	FileFunc_GetSize_FileSystem_error:
	StrCpy $R1 ''
 
	FileFunc_GetSize_path:
	StrCpy $R9 $0 1 -1
	StrCmp $R9 '\' 0 +3
	StrCpy $0 $0 -1
	goto -3
	IfFileExists '$0\*.*' 0 FileFunc_GetSize_error
 
	StrCpy $3 0
	StrCpy $4 ''
	StrCpy $5 ''
	StrCpy $6 ''
	StrCpy $8 0
	StrCpy $R3 ''
	StrCpy $R4 ''
	StrCpy $R5 ''
 
	FileFunc_GetSize_option:
	StrCpy $R9 $1 1
	StrCpy $1 $1 '' 1
	StrCmp $R9 ' ' -2
	StrCmp $R9 '' FileFunc_GetSize_sizeset
	StrCmp $R9 '/' 0 -4
 
	StrCpy $9 -1
	IntOp $9 $9 + 1
	StrCpy $R9 $1 1 $9
	StrCmp $R9 '' +2
	StrCmp $R9 '/' 0 -3
	StrCpy $8 $1 $9
	StrCpy $8 $8 '' 2
	StrCpy $R9 $8 '' -1
	StrCmp $R9 ' ' 0 +3
	StrCpy $8 $8 -1
	goto -3
	StrCpy $R9 $1 2
	StrCpy $1 $1 '' $9
 
	StrCmp $R9 'M=' 0 FileFunc_GetSize_size
	StrCpy $4 $8
	goto FileFunc_GetSize_option
 
	FileFunc_GetSize_size:
	StrCmp $R9 'S=' 0 FileFunc_GetSize_gotosubdir
	StrCpy $6 $8
	goto FileFunc_GetSize_option
 
	FileFunc_GetSize_gotosubdir:
	StrCmp $R9 'G=' 0 FileFunc_GetSize_error
	StrCpy $7 $8
	StrCmp $7 '' +3
	StrCmp $7 '1' +2
	StrCmp $7 '0' 0 FileFunc_GetSize_error
	goto FileFunc_GetSize_option
 
	FileFunc_GetSize_sizeset:
	StrCmp $6 '' FileFunc_GetSize_default
	StrCpy $9 0
	StrCpy $R9 $6 1 $9
	StrCmp $R9 '' +4
	StrCmp $R9 ':' +3
	IntOp $9 $9 + 1
	goto -4
	StrCpy $5 $6 $9
	IntOp $9 $9 + 1
	StrCpy $1 $6 1 -1
	StrCpy $6 $6 -1 $9
	StrCmp $5 '' +2
	IntOp $5 $5 + 0
	StrCmp $6 '' +2
	IntOp $6 $6 + 0
 
	StrCmp $1 'B' 0 +4
	StrCpy $1 1
	StrCpy $2 bytes
	goto FileFunc_GetSize_default
	StrCmp $1 'K' 0 +4
	StrCpy $1 1024
	StrCpy $2 Kb
	goto FileFunc_GetSize_default
	StrCmp $1 'M' 0 +4
	StrCpy $1 1048576
	StrCpy $2 Mb
	goto FileFunc_GetSize_default
	StrCmp $1 'G' 0 FileFunc_GetSize_error
	StrCpy $1 1073741824
	StrCpy $2 Gb
 
	FileFunc_GetSize_default:
	StrCmp $4 '' 0 +2
	StrCpy $4 '*.*'
	StrCmp $7 '' 0 +2
	StrCpy $7 '1'
 
	StrCpy $8 1
	Push $0
	SetDetailsPrint textonly
 
	FileFunc_GetSize_nextdir:
	IntOp $8 $8 - 1
	Pop $R8
	FindFirst $0 $R7 '$R8\$4'
	IfErrors FileFunc_GetSize_show
	StrCmp $R7 '.' 0 FileFunc_GetSize_dir
	FindNext $0 $R7
	StrCmp $R7 '..' 0 FileFunc_GetSize_dir
	FindNext $0 $R7
	IfErrors 0 FileFunc_GetSize_dir
	FindClose $0
	goto FileFunc_GetSize_show
 
	FileFunc_GetSize_dir:
	IfFileExists '$R8\$R7\*.*' 0 FileFunc_GetSize_file
	IntOp $R5 $R5 + 1
	goto FileFunc_GetSize_findnext
 
	FileFunc_GetSize_file:
	StrCpy $R6 0
	StrCmp $5$6 '' 0 +3
	IntOp $R4 $R4 + 1
	goto FileFunc_GetSize_findnext
	StrCmp $R1 '' FileFunc_GetSize_fileopen
	StrCpy $R0 0
	System::Call 'kernel32::GetFileAttributes(t "$R8\$R7")i .R2'
	StrCmp $R2 -1 FileFunc_GetSize_fileopen
	IntOp $R0 $R2 & 0x0800 ; compressed
	IntCmp $R0 0 0 0 FileFunc_GetSize_GetCompressed
	IntOp $R0 $R2 & 0x0200 ; sparse file
	IntCmp $R0 0 FileFunc_GetSize_fileopen
	FileFunc_GetSize_GetCompressed:
	System::Call 'kernel32::GetCompressedFileSize(t "$R8\$R7", i)i .R6'
	IntCmp $R6 4096 +2 0 +2
	StrCpy $R6 4096
	IntOp $3 $3 + 1 ; location contains compressed or sparse files
	goto FileFunc_GetSize_fileclose
	FileFunc_GetSize_fileopen:
	FileOpen $9 '$R8\$R7' r
	IfErrors +3
	FileSeek $9 0 END $R6
	FileClose $9
	FileFunc_GetSize_fileclose:
	StrCmp $5 '' +2
	IntCmp $R6 $5 0 FileFunc_GetSize_findnext
	StrCmp $6 '' +2
	IntCmp $R6 $6 0 0 FileFunc_GetSize_findnext
	IntOp $R4 $R4 + 1
	StrCmp $R1 '' FileFunc_GetSize_file_add
	StrCmp $R0 0 0 FileFunc_GetSize_file_add
	StrCpy $R0 $R1
	IntOp $R6 $R6 + $R0
	IntOp $R1 $R6 % $R0
	StrCmp $R1 0 0 +2
	StrCpy $R1 $R0
	IntOp $R2 $R0 - $R1
	IntOp $R6 $R6 - $R0
	IntOp $R6 $R6 + $R2
	StrCpy $R1 $R0
	FileFunc_GetSize_file_add:
	System::Int64Op $R3 + $R6
	Pop $R3
 
	FileFunc_GetSize_findnext:
	FindNext $0 $R7
	IfErrors 0 FileFunc_GetSize_dir
	FindClose $0
 
	FileFunc_GetSize_show:
	StrCmp $5$6 '' FileFunc_GetSize_nosize
	System::Int64Op $R3 / $1
	Pop $9
	DetailPrint 'Size:$9 $2  Files:$R4  Folders:$R5'
	goto FileFunc_GetSize_subdir
	FileFunc_GetSize_nosize:
	DetailPrint 'Files:$R4  Folders:$R5'
 
	FileFunc_GetSize_subdir:
	StrCmp $7 0 FileFunc_GetSize_preend
	FindFirst $0 $R7 '$R8\*.*'
	StrCmp $R7 '.' 0 FileFunc_GetSize_pushdir
	FindNext $0 $R7
	StrCmp $R7 '..' 0 FileFunc_GetSize_pushdir
	FindNext $0 $R7
	IfErrors 0 FileFunc_GetSize_pushdir
	FindClose $0
	StrCmp $8 0 FileFunc_GetSize_preend FileFunc_GetSize_nextdir
 
	FileFunc_GetSize_pushdir:
	IfFileExists '$R8\$R7\*.*' 0 +3
	Push '$R8\$R7'
	IntOp $8 $8 + 1
	FindNext $0 $R7
	IfErrors 0 FileFunc_GetSize_pushdir
	FindClose $0
	StrCmp $8 0 FileFunc_GetSize_preend FileFunc_GetSize_nextdir
 
	FileFunc_GetSize_preend:
	StrCmp $R3 '' FileFunc_GetSize_nosizeend
	System::Int64Op $R3 / $1
	Pop $R3
	FileFunc_GetSize_nosizeend:
	StrCpy $2 $R4
	StrCpy $1 $R5
	StrCpy $0 $R3
	goto FileFunc_GetSize_noerror
 
	FileFunc_GetSize_error:
	SetErrors
	StrCpy $0 ''
	StrCpy $1 ''
	StrCpy $2 ''
	StrCpy $3 ''
	goto FileFunc_GetSize_end
 
	FileFunc_GetSize_noerror:
	StrCmp $0 '' 0 +2
	StrCpy $0 0
	StrCmp $1 '' 0 +2
	StrCpy $1 0
	StrCmp $2 '' 0 +2
	StrCpy $2 0
	StrCmp $3 '' 0 +2
	StrCpy $3 0
 
	FileFunc_GetSize_end:
	SetDetailsPrint both
	Pop $R9
	Pop $R8
	Pop $R7
	Pop $R6
	Pop $R5
	Pop $R4
	Pop $R3
	Pop $R2
	Pop $R1
	Pop $R0
	Pop $9
	Pop $8
	Pop $7
	Pop $6
	Pop $5
	Pop $4
	Exch $3
	Exch 3
	Exch $2
	Exch
	Exch $1
	Exch 2
	Exch $0
 
	!verbose pop
!macroend
 
; ---------------
; GetClusterSize
 
; Allocation unit size on NTFS, exFAT and reFS formatted volumes
; Syntax: ${GetClusterSize} $inputpath $outputvariable
; Result: 512, 1024, ..., 4096, ..., 131072, ...
 
!define GetClusterSize `!insertmacro GetClusterSizeCall`
!define un.GetClusterSize `!insertmacro GetClusterSizeCall`
 
!macro GetClusterSize
!macroend
 
!macro un.GetClusterSize
!macroend
 
!macro GetClusterSize_
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
 
	Exch $0
	Push $1
	Push $2
	Push $3
 
	StrCpy $1 $0 2
	StrCmp $1 '\\' Root_UNC
	StrCpy $2 $1 1 1
	StrCmp $2 ':' 0 Root_empty
	StrCpy $0 $1
	goto Root_end
 
	Root_UNC:
	StrCpy $2 1
	StrCpy $3 ''
 
	Root_loop:
	IntOp $2 $2 + 1
	StrCpy $1 $0 1 $2
	StrCmp $1$3 '' Root_empty
	StrCmp $1 '' +5
	StrCmp $1 '\' 0 Root_loop
	StrCmp $3 '1' +3
	StrCpy $3 '1'
	goto Root_loop
	StrCpy $0 $0 $2
	StrCpy $2 $0 1 -1
	StrCmp $2 '\' 0 Root_end
 
	Root_empty:
	StrCpy $0 ''
 
	Root_end:
	System::Call 'kernel32::GetDiskFreeSpace(t "$0\",*i0r1,*i0r2,,)'
	IntOp $0 $1 * $2
	Pop $3
	Pop $2
	Pop $1
	Exch $0
 
	!verbose pop
!macroend

Credits:

GetSizeOnDisk has been altered slightly and renamed. The original macro is called GetSize. You will find it in the Users Manual under E.1.3.

=== Download (example) ===

This is the same as the example code above.

SODTool.zip (68 KB)

=== Download (utility) ===

This is a Modern UI2 version that displays selection windows and goes to an output page. Script file is included.

SOD II tool.zip (76 KB)

Both downloads are compiled in unicode, so SOD Tool can read Russian file names.

Errors:

On failing to obtain the size of a file GetSizeOnDisk does nothing much. You can edit the line that says,

FileOpen $9 '$R8\$R7' r
IfErrors +3

changing the instruction to,

FileOpen $9 '$R8\$R7' r
IfErrors FileFunc_GetSize_error

It sets an error flag and will abort the macro, if an error is encountered opening a file for reading.

History:

Optional parameter for counting compressed/sparse files added. (Feb. 18, 2013)

Option to find without subdirectories '/G=0' switch was missing. (Well, not really missing.) Change to details view (string), showing 'compressed/sparse file(s)'. (Feb. 19, 2013)

Change to unicode, because ansi could not read Russian. (Feb. 20, 2013)

Stack operations cleaned up. The SOD II tool uploaded. (Feb. 22, 2013)

String formatting improvements, functions simplified (SOD II) and small revisions in macros header made. (Feb. 23, 2013)

Macros behavior modified in order to detect the file system to deal with FAT, FAT12, FAT16 and FAT32 volumes. Also checking root path, possibly Win2K error. (March 8, 2013)

Re-Compiled with NSIS 3 new release. (May 24, 2013)