How to show uncompressed total physical size in bytes of an HFS-compressed file or directory?

Posted on

QUESTION :

Case in point: Apple’s TextEdit at /Applications/TextEdit.app

If you calculate the physical size with echo "$(/usr/bin/du -k -d 0 /Applications/TextEdit.app | /usr/bin/awk '{print $1}') * 1024" | /usr/bin/bc -l you’ll get (in my case on 10.11.6) a size of 4538368 bytes.

However, if you open the Info window in Finder, it’ll tell you that the physical size is way bigger: 8.6 MB on disk, almost double the size.

It’s clear why: Apple used HFS compression on TextEdit. Running the third-party tool afsctool (which you can install with Homebrew) produces this result:

/usr/local/bin/afsctool /Applications/TextEdit.app
/Applications/TextEdit.app:
Number of HFS+ compressed files: 693

Now, macOS obviously seems to know the uncompressed physical size, as evidenced by the size-on-disk value in the Finder’s Info window.

My question is, if there is a command-line read-only way to get that info, i.e. a way to show:

(a) the uncompressed physical size (disk use) of a file that is HFS-compressed, i.e. a file for which /usr/bin/stat -f %f returns “32” (even though it’s “524320” for some reason in TextEdit), and

(b) the uncompressed total physical size (disk use) of a directory or bundle that contains HFS compressed files.

Note: only macOS native commands should be used to calculate the size, while not using Spotlight-dependent data, e.g. from the mdls command, which is buggy and sometimes returns (null) for the kMDItemPhysicalSize key, aside from the fact that some users have disabled Spotlight altogether.

ANSWER :

Use afsctool command with -v flag, for example:

$ afsctool -v README
README:
File is HFS+ compressed.
File size (uncompressed data fork; reported size by Mac OS 10.6+ Finder): 3046 bytes / 3 KB (kilobytes) / 3 KiB (kibibytes)
File size (compressed data fork - decmpfs xattr; reported size by Mac OS 10.0-10.5 Finder): 0 bytes / 0 KB (kilobytes) / 0 KiB (kibibytes)
File size (compressed data fork): 1427 bytes / 1 KB (kilobytes) / 1 KiB (kibibytes)
Compression savings: 53.2%
Number of extended attributes: 0
Total size of extended attribute data: 0 bytes
Approximate overhead of extended attributes: 268 bytes
Approximate total file size (compressed data fork + EA + EA overhead + file overhead): 1943 bytes / 2 KB (kilobytes) / 2 KiB (kibibytes)

Well, afsctool was removed from macOS, and du works on entire directories:

  %  ditto -v --hfsCompression  --arch arm64 /Volumes/Thunderbird/Thunderbird.app 
     /Applications/Thunderbird BETA V.99.ARM64.app
Copying /Volumes/Thunderbird/Thunderbird.app [arm64]

 %  ditto -v --hfsCompression  /Volumes/Thunderbird/Thunderbird.app
    /Applications/Thunderbird BETA V.99.UNIVERSAL.app 
Copying /Volumes/Thunderbird/Thunderbird.app 

  % du -sk /Applications/Thunderbird* /Volumes/Thunderbird/Thunderbird.app                                              
352808  /Applications/Thunderbird BETA V.94.Universal.app
74832   /Applications/Thunderbird BETA V.99.ARM64.app
133152  /Applications/Thunderbird BETA V.99.UNIVERSAL.app
349184  /Applications/Thunderbird.app
349184  /Volumes/Thunderbird/Thunderbird.app

 % du -skA /Applications/Thunderbird BETA V.99.*
207938  /Applications/Thunderbird BETA V.99.ARM64.app
348917  /Applications/Thunderbird BETA V.99.UNIVERSAL.app
 % 

From the documentation :

du: -A Display the apparent size instead of the disk usage. This can be helpful when operating on compressed volumes or
sparse files

(I wonder why and when afsctool was removed from macOS, if it can be copied from an old install, and if it is in Darwin.)

Oh, and as for mdls, this works better with the sleep:

% cat /dev/urandom | head -c 5 > foo; sleep 3; mdls foo | grep ize
kMDItemFSSize                          = 5
kMDItemLogicalSize                     = 5
kMDItemPhysicalSize                    = 4096

vs

% cat /dev/urandom | head -c 2 > foo; mdls foo | grep ize
kMDItemFSSize              = (null)

Also, the output depends on the current directory; it acts differently in /tmp vs ~.