Get size on disk: Difference between revisions
(Size On Disk (SOD) utility to get the space used by directories and files) |
(Use ReserveFile /plugin) |
||
(16 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 | ; 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" | ||
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 | Var COMPRESSED | ||
Var | Var COMPRESSED_UN | ||
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 $ | StrCpy $R5 "16" ; 1,000,000,000,000,000 limit | ||
StrLen $R4 $R1 | StrLen $R4 $R1 | ||
loop: | |||
IntCmp $ | IntCmp $R5 3 endloop endloop 0 | ||
IntCmp $R4 $ | IntCmp $R4 $R5 0 +7 0 | ||
IntOp $ | IntOp $R5 $R5 - 1 | ||
StrCpy $R2 $R2 -$ | StrCpy $R2 $R2 -$R5 | ||
StrCpy $R3 $R1 "" -$ | StrCpy $R3 $R1 "" -$R5 | ||
StrCpy $R2 "$R2,$R3" | StrCpy $R2 "$R2,$R3" | ||
IntOp $ | IntOp $R5 $R5 - 2 | ||
Goto loop | Goto loop | ||
IntOp $ | IntOp $R5 $R5 - 3 | ||
Goto loop | Goto loop | ||
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 | ||
; | ; registry | ||
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 | IfErrors 0 begin | ||
ClearErrors | ClearErrors | ||
Line 80: | Line 90: | ||
begin: | begin: | ||
IfFileExists "$NSIS" 0 done | IfFileExists "$NSIS" 0 done | ||
${ | ${GetClusterSize} $NSIS $BLOCK | ||
; directory | |||
${GetSizeOnDisk} "$NSIS" "/S=0B" "" $0 $1 $2 | ${GetSizeOnDisk} "$NSIS" "/S=0B" "" $0 $1 $2 $3 | ||
StrCpy $SIZE_B $0 | StrCpy $SIZE_B $0 | ||
StrCpy $FILES $1 | StrCpy $FILES $1 | ||
StrCpy $FOLDERS $2 | StrCpy $FOLDERS $2 | ||
StrCpy $SIZE_M $ | 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_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 | ||
${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 | |||
StrCpy $SIZE_UN_B $0 | StrCpy $SIZE_UN_B $0 | ||
StrCpy $SIZE_UN_K $ | Math::Script "r4 = ff($0 / 1024.0, 16 +1)" | ||
StrCpy $SOD_UN_B $ | StrCpy $SIZE_UN_K $4 | ||
StrCpy $SOD_UN_K $ | ${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 | Call Separator | ||
Pop $SIZE_B | |||
Push $SOD_B | |||
Call Separator | Call Separator | ||
Pop $SOD_B | |||
Push $SOD_K | |||
Call Separator | Call Separator | ||
Pop $SOD_K | |||
Push $SIZE_UN_B | |||
Call Separator | Call Separator | ||
Pop $SIZE_UN_B | |||
Push $SOD_UN_B | |||
Call Separator | Call Separator | ||
Pop $SOD_UN_B | |||
; output | ; output | ||
DetailPrint "" | DetailPrint "" | ||
DetailPrint "$NSIS" | DetailPrint "$NSIS" | ||
DetailPrint "Size: $SIZE_M MB ($SIZE_B bytes)" | DetailPrint "Size: $SIZE_M MB ($SIZE_B bytes)" | ||
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)" | ||
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: | |||
DetailPrint "File not found." | DetailPrint "File not found." | ||
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 | ; Macros include (TN) | ||
;-------------------------------- | ;-------------------------------- | ||
/* | /* | ||
FileFunction=[GetSizeOnDisk|GetClusterSize | FileFunction=[GetSizeOnDisk|GetClusterSize] | ||
*/ | */ | ||
Line 166: | Line 177: | ||
; | ; | ||
; Example: | ; Example: | ||
; !include " | ; !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} | 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 | ||
; | ; 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)" | |||
; | ; 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_ | !macro GetSizeOnDisk_ | ||
Line 252: | Line 265: | ||
!verbose ${_FILEFUNC_VERBOSE} | !verbose ${_FILEFUNC_VERBOSE} | ||
Exch $2 | |||
Exch $ | |||
Exch 2 | Exch 2 | ||
Exch $0 | Exch $0 | ||
Exch | Exch | ||
Exch $1 | |||
Push $3 | Push $3 | ||
Push $4 | Push $4 | ||
Line 268: | Line 277: | ||
Push $8 | Push $8 | ||
Push $9 | Push $9 | ||
Push $R0 | |||
Push $R1 | |||
Push $R2 | Push $R2 | ||
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 | ||
StrCmp $R1 '' FileFunc_GetSize_file_add | |||
StrCmp $ | 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 | ||
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 | 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 | ||
Pop $R2 | Pop $R2 | ||
Pop $R1 | |||
Pop $R0 | |||
Pop $9 | Pop $9 | ||
Pop $8 | Pop $8 | ||
Line 491: | Line 574: | ||
Pop $5 | Pop $5 | ||
Pop $4 | Pop $4 | ||
Exch $3 | |||
Exch 3 | |||
Exch $2 | Exch $2 | ||
Exch | Exch | ||
Line 502: | Line 586: | ||
; --------------- | ; --------------- | ||
; | ; GetClusterSize | ||
; Allocation unit size on NTFS, exFAT and reFS formatted volumes | |||
; Syntax: ${GetClusterSize} $inputpath $outputvariable | |||
; Result: 512, 1024, ..., 4096, ..., 131072, ... | |||
!macro | !define GetClusterSize `!insertmacro GetClusterSizeCall` | ||
!define un.GetClusterSize `!insertmacro GetClusterSizeCall` | |||
!macro GetClusterSize | |||
!macroend | !macroend | ||
!macro un. | !macro un.GetClusterSize | ||
!macroend | !macroend | ||
!macro | !macro GetClusterSize_ | ||
!verbose push | !verbose push | ||
!verbose ${_FILEFUNC_VERBOSE} | !verbose ${_FILEFUNC_VERBOSE} | ||
Exch $0 | Exch $0 | ||
Push $1 | |||
Push $2 | Push $2 | ||
Push $3 | 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 '' | StrCpy $3 '' | ||
IntOp $ | 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 $3 ' | StrCpy $2 $0 1 -1 | ||
StrCmp $2 '\' 0 Root_end | |||
Root_empty: | |||
StrCpy $0 '' | StrCpy $0 '' | ||
Root_end: | |||
System::Call 'kernel32::GetDiskFreeSpace(t "$0\",*i0r1,*i0r2,,)' | |||
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 | ||
</highlight-nsis> | |||
<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. | |||
<attach>SODTool.zip</attach> | |||
<span style="font-size: 110%"><b>=== Download (utility) ===</b></span> | |||
This is a Modern UI2 version that displays selection windows and goes to an output page. Script file is included. | |||
<attach>SOD II tool.zip</attach> | |||
Both downloads are compiled in unicode, so SOD Tool can read Russian file names. | |||
<span style="font-size: 110%"><b>Errors:</b></span> | |||
On failing to obtain the size of a file <em>GetSizeOnDisk</em> does nothing much. You can edit the line that says, | |||
<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> | |||
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 <b>SOD II tool</b> 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) | |||
[[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)