2

macOS HFS+ supports transparent filesystem-level compression. How can I enable this compression for certain files via a programmatic API? (e.g. Cocoa or C interface)

I'd like to achieve effect of ditto --hfsCompression src dst, but without shelling out.

To clarify: I'm asking how to make uncompressed file compressed. I'm not interested in reading or preserving existing HFS compression state.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Kornel
  • 97,764
  • 37
  • 219
  • 309

3 Answers3

2

The copyfile.c file discloses some of the implementation details.

There's also a compression tool based on that: afsctool.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Kornel
  • 97,764
  • 37
  • 219
  • 309
  • I'd be interested to know if brkirch used that Apple source. How exactly he created afsctool is lost to time. And thanks for accepting my answer! – Matt Sephton Mar 21 '18 at 20:42
2

There's afsctool which is an open source implementation of HFS+ compression. It was originally by hacker brkirch (macrumors forum link, as he still visits there) but has since been expanded and improved a great deal by @rjvb who is doing amazing things with it.

Matt Sephton
  • 3,711
  • 4
  • 35
  • 46
1

I think you're asking two different questions (and might not know it).

If you're asking "How can I make arbitrary file 'A' an HFS compressed file?" the answer is, you can,'t. HFS compressed files are created by the installer and (technically[1]) only Apple can create them.

If you are asking "How can I emulate the --hfsCompression logic in ditto such that I can copy an HFS compressed file from one HFS+ volume to another HFS+ volume and preserve its compression?" the answer to that is pretty straight forward, albeit not well documented.

HFS Compressed files have a special UF_COMPRESSED file flag. If you see that, the data fork of the file is actually an uncompressed image of a hidden resource. The compressed version of the file is stored in a special extended attribute. It's special because it normally doesn't appear in the list of attributes when you request them (so if you just ls -l@ the file, for example, you won't see it). To list and read this special attribute you must pass the XATTR_SHOWCOMPRESSION flag to both the listxattr() and getxattr() functions.

To restore a compressed file, you reverse the process: Write an empty file, then restore all of its extended attributes, specifically the special one. When you're done, set the file's UF_COMPRESSED flag and the uncompressed data will magically appear in its data fork.

[1] Note: It's rumored that the compressed resource of a file is just a ZIPed version of the data, possibly with some wrapper around it. I've never taken the time to experiment, but if you're intent on creating your own compressed files you could take a stab at reverse-engineering the compressed extended attribute.

James Bucanek
  • 3,299
  • 3
  • 14
  • 30
  • Thanks for the answer. I've clarified the question that I'm asking how to make uncompressed files compressed. – Kornel Mar 20 '18 at 14:15
  • if that's the question, then the answer is you can't. Or at least, there's no officially supported method, as I already explained. – James Bucanek Mar 20 '18 at 15:47