Menu

#1306 Bug in FileSeek or FileFunc.nsh to get file(folder) size ${GetSize}.

3.0 Series
open
nobody
${GetSize} (1)
5
3 days ago
2024-02-22
nttwqz
No

${GetSize} fails to get the correct file size when a single file is large, such as 2.5G, and is also incorrect when there are large files in the folder.

Simple research found that FileFunc.nsh use FileSeek to get the file size bytes, and then related calculations, the problem is, FileSeek in the processing of larger files will be an error, such as 2716863167B (2.5GB) will return a negative number, and thus the calculation is wrong, I hope that the relevant authors can fix the error!

It would be nice to add a built-in function to access the folder size directly.

Here is an example:

Section
    StrCpy $R0 "D:\test.tmp"
    IfFileExists $R0 +2 0
        ExecWait "fsutil file createnew $R0 2716863167"

    SetDetailsPrint none        # 3.09 bug,Not turning it off will accidentally show something that shouldn't be shown at all
    ${GetSize} "D:\" "/M=test.tmp /S=0K" $0 $1 $2
    SetDetailsPrint both
    DetailPrint "$0:$1:$2"

    FileOpen $0 $R0 r
    FileSeek $0 0 END $1
    FileClose $0
    Math::Script "r2 = r1/1024/1024"
    DetailPrint "$1:$2"     # Return error results: $1=-1578104129

    StrCpy $0 "2716863167"
    IntOp $0 $0 + 0         #  Out of calculation range, probably due to this. The numbers that IntOp can calculate are just a little too small for the 21st century.
    DetailPrint "$$0:$0"    # Return error results: -1578104129
SectionEnd

Discussion

  • Jason

    Jason - 2024-02-22

    NSIS internally uses 32 bit integers for script variables, so it's not useful for anything over 2GB. That being said, I think FileSeek is also written the same way at the moment for backwards compatibility (ie Win 9x).

    One workaround is to use the system plugin to call windows API's directly, or write your own plugin that does the same thing.

     
    • nttwqz

      nttwqz - 2024-02-26

      I believe that many of the use of NSIS is not a professional programmer. System plug-ins for the will not be C has a fairly high learning difficulty, have watched tutorials dozens of times, query GetFileSizeEx official documentation, but also did not figure out how to get the correct value from the LARGE_INTEGER union. Relatively speaking, Python in this regard on the simple too much too much, so has been rewritten in Python all.

      import os
      print(os.path.getsize('D:/test.tmp'))
      sum = 0
      for root,dirs,files in os.walk('D:/test'):
          for fn in files:
              sum += os.path.getsize(os.path.join(root, fn))
      print(round(sum/1024/1024, 2), 'MB')
      

      When will NSIS be this easy?

      FileGetSize $0 'D:\test.tmp'
      DetailPrint $0
      DirGetSize $0 'D:\test'
      DetailPrint $0
      
       
      • Anders

        Anders - 3 days ago
        Function GetFileSize64
        Exch $1
        FileOpen $1 $1 r
        StrCmp $1 "" error
            !if "${NSIS_PTR_SIZE}" > 4 ; Change this to "!if 1" if you don't care about systems older than WinXP.
            System::Call 'KERNEL32::GetFileSizeEx(pr1,*l0s)'
            FileClose $1
            !else
            System::Call 'KERNEL32::GetFileSize(pr1,*i0s)i.s'
            FileClose $1
            Pop $1
            IntFmt $1 "0x%x" $1
            Exch $1
            IntFmt $1 "0x%x00000000" $1
            System::Int64Op $1 |
            !endif
            Pop $1
        error:
        Exch $1
        FunctionEnd
        
        Section
        
        Push "favorite_distro.iso"
        Call GetFileSize64
        Pop $1
        
        DetailPrint Bytes=$1
        
        System::Int64Op $1 >> 20
        Pop $1
        DetailPrint MiB=$1
        
        SectionEnd
        
         

        Last edit: Anders 2 days ago

Log in to post a comment.

MongoDB Logo MongoDB