Search code examples
inno-setuppascalscript

Inno Setup get directory size including subdirectories


I am trying to write a function that returns the size of a directory. I have written the following code, but it is not returning the correct size. For example, when I run it on the {pf} directory it returns 174 bytes, which is clearly wrong as this directory is multiple Gigabytes in size. Here is the code I have:

function GetDirSize(DirName: String): Int64;
var
  FindRec: TFindRec;
begin
  if FindFirst(DirName + '\*', FindRec) then
    begin
      try
        repeat
          Result := Result + (Int64(FindRec.SizeHigh) shl 32 + FindRec.SizeLow);
        until not FindNext(FindRec);
      finally
        FindClose(FindRec);
      end;
    end
  else
    begin
      Result := -1;
    end;
end;

I suspect that the FindFirst function does not include subdirectories, which is why I am not getting the correct result. Therefore, how can I return the correct size of a directory i.e. including all files in all subdirectories, the same as selecting Properties on a Folder in Windows Explorer? I am using FindFirst as the function needs to support directory sizes over 2GB.


Solution

  • The FindFirst does include subdirectories, but it won't get you their sizes.

    You have to recurse into subdirectories and calculate the total size file by file, similarly as to for example Inno Setup: copy folder, subfolders and files recursively in Code section.

    function GetDirSize(Path: String): Int64;
    var
      FindRec: TFindRec;
      FilePath: string;
      Size: Int64;
    begin
      if FindFirst(Path + '\*', FindRec) then
      begin
        Result := 0;
        try
          repeat
            if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
            begin
              FilePath := Path + '\' + FindRec.Name;
              if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
              begin
                Size := GetDirSize(FilePath);
              end
                else
              begin
                Size := Int64(FindRec.SizeHigh) shl 32 + FindRec.SizeLow;
              end;
              Result := Result + Size;
            end;
          until not FindNext(FindRec);
        finally
          FindClose(FindRec);
        end;
      end
        else
      begin
        Log(Format('Failed to list %s', [Path]));
        Result := -1;
      end;
    end;
    

    For Int64, you need Unicode version of Inno Setup, what you should be using in any case. Only if you have a very good reason to stick with Ansi version, you can replace the Int64 with Integer, but than you are limited to 2 GB.