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)
(Size On Disk (SOD) utility to get the space used by directories and files)
Line 104: Line 104:
   StrCpy $SOD_UN_B $7
   StrCpy $SOD_UN_B $7
   StrCpy $SOD_UN_K $8
   StrCpy $SOD_UN_K $8
  ; format
; format
   StrCpy $R1 $SIZE_B
   StrCpy $R1 $SIZE_B
   Call Separator
   Call Separator

Revision as of 09:51, 12 February 2013

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 & run the .exe
 
Name "SOD Tool"
RequestExecutionLevel user
!define LOCAL "" ; Path where local include files reside
OutFile "${LOCAL}nsissize.exe"
!include "${LOCAL}macros.nsh"
ReserveFile "${NSISDIR}\Plugins\Math.dll"
#Icon "${LOCAL}arrows.ico"
ShowInstDetails show
 
; Variables
Var NSIS
Var ZIP
Var ZIP_UN
Var COUNT
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
 
Function Separator ; comma
  StrCpy $R2 $R1
  StrCpy $COUNT "16" ; 1,000,000,000,000,000 limit
  StrLen $R4 $R1
  loop:
  IntCmp $COUNT 3 endloop endloop 0
  IntCmp $R4 $COUNT 0 +7 0
  IntOp $COUNT $COUNT - 1
  StrCpy $R2 $R2 -$COUNT
  StrCpy $R3 $R1 "" -$COUNT
  StrCpy $R2 "$R2,$R3"
  IntOp $COUNT $COUNT - 2
  Goto loop
  IntOp $COUNT $COUNT - 3
  Goto loop
  endloop:
FunctionEnd
 
Section
; root
  ReadRegStr $NSIS HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\\
  NSIS Unicode" "InstallLocation"
  IfErrors 0 begin
  ClearErrors
  ReadRegStr $NSIS HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\\
  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
  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
  ${GetFileAttributes} "$NSIS" "COMPRESSED" $ZIP
  ${GetClusterSize} $BLOCK
  ${GetSizeOnDisk} "$NSIS" "/S=0B" "" $0 $1 $2
  Math::Script "r3 = ff($0 / 1024 / 1024.0, 16 +2"
  StrCpy $SIZE_B $0
  StrCpy $FILES $1
  StrCpy $FOLDERS $2
  StrCpy $SIZE_M $3
  ${GetSizeOnDisk} "$NSIS" "/S=0B" "$BLOCK" $0 $1 $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_M $5
; uninstaller
  IfFileExists "$NSIS\uninst-nsis.exe" 0 done
  ${GetFileAttributes} "$NSIS\uninst-nsis.exe" "COMPRESSED" $ZIP_UN
  ${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_K $6
  StrCpy $SOD_UN_B $7
  StrCpy $SOD_UN_K $8
; format
  StrCpy $R1 $SIZE_B
  Call Separator
  StrCpy $SIZE_B $R2
 
  StrCpy $R1 $SOD_B
  Call Separator
  StrCpy $SOD_B $R2
 
  StrCpy $R1 $SOD_K
  Call Separator
  StrCpy $SOD_K $R2
 
  StrCpy $R1 $SIZE_UN_B
  Call Separator
  StrCpy $SIZE_UN_B $R2
  StrCpy $R1 $SOD_UN_B
  Call Separator
  StrCpy $SOD_UN_B $R2
; output
  ; note: with compression SOD lines are incorrect
  DetailPrint ""
  DetailPrint "$NSIS"
  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 ""
  DetailPrint "Uninstaller"
  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 ""
  DetailPrint "$FILES files $FOLDERS folders $SOD_K Kb"
  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 file
;--------------------------------
/*
 
 FileFunction=[GetSizeOnDisk|GetClusterSize|GetFileAttributes]
 
*/
;_____________________________________________________________________________
;
;                         Macros
;_____________________________________________________________________________
;
; Change log window verbosity (default: 3=no script)
;
; Example:
; !include "sizemacros.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
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
	Push `${_PATH}`
	Push `${_OPTIONS}`
	Push `${_FILESYSTEM}` ; block size
	${CallArtificialFunction} GetSizeOnDisk_
	Pop ${_RESULT1}
	Pop ${_RESULT2}
	Pop ${_RESULT3}
	!verbose pop
!macroend
 
!macro GetClusterSizeCall _RESULT
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
	${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}
	!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
; Three values are returned
 
; $var1		; Result1: Size/Size on disk
; $var2		; Result2: Sum of files
; $var3		; Result3: Sum of directories
 
; Example: ${GetSizeOnDisk} "$INSTDIR" "/S=0K" "4096" $0 $1 $2
 
; Specifying 4096 (logical size) toggles the result
; Output is size on disk, if used, or size in bytes, if left empty ""
 
!macro GetSizeOnDisk_
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
 
	; replace
	Exch $R1
	Exch
	Exch $1
	Exch 2
	; end replace
	Exch $0
	Exch
	Push $2
	Push $3
	Push $4
	Push $5
	Push $6
	Push $7
	Push $8
	Push $9
	; insert code
	Push $R2
	; end insert
	Push $R3
	Push $R4
	Push $R5
	Push $R6
	Push $R7
	Push $R8
	Push $R9
	ClearErrors
 
	StrCpy $R9 $0 1 -1
	StrCmp $R9 '\' 0 +3
	StrCpy $0 $0 -1
	goto -3
	IfFileExists '$0\*.*' 0 FileFunc_GetSize_error
 
	StrCpy $3 ''
	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
	FileOpen $9 '$R8\$R7' r
	IfErrors +3
	FileSeek $9 0 END $R6
	FileClose $9
	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
	; insert code
	StrCmp $R1 "" +10 0
	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
	; end insert
	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_end
 
	FileFunc_GetSize_error:
	SetErrors
	StrCpy $0 ''
	StrCpy $1 ''
	StrCpy $2 ''
 
	FileFunc_GetSize_end:
	SetDetailsPrint both
	Pop $R9
	Pop $R8
	Pop $R7
	Pop $R6
	Pop $R5
	Pop $R4
	Pop $R3
	; insert code
	Pop $R2
	; end insert
	Pop $9
	Pop $8
	Pop $7
	Pop $6
	Pop $5
	Pop $4
	Pop $3
	Exch $2
	Exch
	Exch $1
	Exch 2
	Exch $0
 
	!verbose pop
!macroend
 
; ---------------
; GetFileAttributes (FileFunc.nsh)
 
!define GetFileAttributes `!insertmacro GetFileAttributesCall`
!define un.GetFileAttributes `!insertmacro GetFileAttributesCall`
 
!macro GetFileAttributes
!macroend
 
!macro un.GetFileAttributes
!macroend
 
!macro GetFileAttributes_
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
 
	Exch $1
	Exch
	Exch $0
	Exch
	Push $2
	Push $3
	Push $4
	Push $5
 
	System::Call 'kernel32::GetFileAttributes(t r0)i .r2'
	StrCmp $2 -1 FileFunc_GetFileAttributes_error
	StrCpy $3 ''
 
	IntOp $0 $2 & 0x4000
	IntCmp $0 0 +2
	StrCpy $3 'ENCRYPTED|'
 
	IntOp $0 $2 & 0x2000
	IntCmp $0 0 +2
	StrCpy $3 'NOT_CONTENT_INDEXED|$3'
 
	IntOp $0 $2 & 0x1000
	IntCmp $0 0 +2
	StrCpy $3 'OFFLINE|$3'
 
	IntOp $0 $2 & 0x0800
	IntCmp $0 0 +2
	StrCpy $3 'COMPRESSED|$3'
 
	IntOp $0 $2 & 0x0400
	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 ''
 
	FileFunc_GetFileAttributes_end:
	Pop $5
	Pop $4
	Pop $3
	Pop $2
	Pop $1
	Exch $0
 
	!verbose pop
!macroend
 
!define GetFileVersion `!insertmacro GetFileVersionCall`
!define un.GetFileVersion `!insertmacro GetFileVersionCall`
 
!macro GetFileVersion
!macroend
 
!macro un.GetFileVersion
!macroend
 
!macro GetFileVersion_
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
 
	Exch $0
	Push $1
	Push $2
	Push $3
	Push $4
	Push $5
	Push $6
	ClearErrors
 
	GetDllVersion '$0' $1 $2
	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:
	SetErrors
	StrCpy $0 ''
 
	FileFunc_GetFileVersion_end:
	Pop $6
	Pop $5
	Pop $4
	Pop $3
	Pop $2
	Pop $1
	Exch $0
 
	!verbose pop
!macroend
 
; ---------------
; GetClusterSize
 
!define GetClusterSize `!insertmacro GetClusterSizeCall`
!define un.GetClusterSize `!insertmacro GetClusterSizeCall`
 
!macro GetClusterSize
!macroend
 
!macro un.GetClusterSize
!macroend
 
!macro GetClusterSize_
	!verbose push
	!verbose ${_FILEFUNC_VERBOSE}
 
	System::Call 'kernel32::GetDiskFreeSpace(i0,*i0r0,*i0r1,*i0r2,*i)'
	IntOp $0 $0 * $1
	Push $0
 
	!verbose pop
!macroend

Credits:

GetFileAttributes is borrowed from filefunc.nsh. 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.