APFS: Extended attributes revisited

Of all the features in APFS, its support for extended attributes (xattrs) is among the least understood. Their origins go back to the Mac’s original file system and its use of forked files.

Resource forks

At that time, in the early 1980s, as now, the great majority of file systems used a single fork: one file with one block of data for the file’s contents. The Mac was going to be different. Each file would thus consist of two forks, one a regular data fork as in normal file systems, the other a structured database of resources, the resource fork, a concept proposed and implemented by Bruce Horn. This enabled an app to keep different localisations of its menus and other text contents in resources. Resource forks were allowed for any file, so an app could store a document’s window settings in each document’s resource fork, as many did.

Resources were used to store a lot of standard structured data, such as the specifications for and contents of alerts and dialogs, menus, collections of text strings, keyboard definitions and layouts, icons, windows, fonts, and executable code run by apps. You could extend the types of resource supported by means of a template, itself stored as a resource, so developers could define new resource types appropriate to their own apps.

Extended attributes

Mac OS X changed all that, almost for the worse. Traditional Unix at that time didn’t have or support resource forks, and it was proposed that they should be done away with on Macs as well. This is reflected today in application bundles: instead of a Classic app consisting of a single file with its rich collection of resources, in Mac OS X this became a hierarchy of folders containing flat files without resources. In other parts of Mac OS X, former resources like keyboard layouts were also flattened into normal data-only files.

Some of Apple’s engineers wanted to be rid of these awkward resource forks and use file bundles instead, but in the end macOS has transformed Bruce Horn’s brilliant concept into extended attributes, introduced in Mac OS X 10.4. These offer as many different ‘forks’ as you want, among which is com.apple.ResourceFork, the reincarnation of this old feature. Even now, in macOS 14 and APFS, you can still access the resource fork of a file using a specialised path extension of /..namedfork/rsrc for any file with a xattr of type com.apple.ResourceFork. Access the file’s data fork in the conventional way:
ls -l 0test1.zip
-rw——-@ 1 hoakley staff 183136 19 Jul 2023 0test1.zip
and its resource fork thus:
ls -l 0test1.zip/..namedfork/rsrc
-rw——- 1 hoakley staff 80059 19 Jul 2023 0test1.zip/..namedfork/rsrc

Metadata

One of the first of these new xattrs, introduced in Mac OS X 10.5, was what’s commonly referred to as the quarantine flag, or the xattr named com.apple.quarantine. It’s so old that the ‘flag’ itself, a hexadecimal number, is encoded as UTF-8 text rather than in hex. Like resource forks before them, xattrs aren’t stored in the file’s data, ensuring that a quarantine flag can be attached to any file without changing that file’s data.

Against all odds, xattrs began to flourish. In the Mac Extended File System HFS+ they’re stored separately from file data, as they are in APFS today. This makes them ideal for storing metadata: rather than having to edit and store metadata embedded within the file’s data, it could be kept apart in xattrs. The snag here, though, is that other file systems aren’t as accommodating as HFS+ or APFS.

Most image formats embed structured metadata in the image data. That isn’t true of some other file formats, particularly if they’re less widely used or app-specific. In the past, a popular format used for ‘comic’ books, Comic Book Archive, has often included extensive metadata about its image archive, which was stored on Macs as a xattr attached to the CBZ file.

These metadata are stored in JSON format, and when in a xattr it’s a custom type named com.bitcartel.comicbooklover.xattr.metadata. The ComicBookLover app has made more extensive use of xattrs too, adding a thumbnail preview in com.apple.ResourceFork, a star rating in com.apple.metadata:kMDItemStarRating (intended for use by Apple apps), another in org.openmetadata.time:kMDItemStarRating, and a third in org.openmetadata:kMDItemStarRating.

Note the size of the com.apple.ResourceFork xattr here, of over 490 KB, although this is taken from HFS+ rather than APFS.

Extended attribute management

In APFS, a file’s xattrs aren’t stored in the file’s inode with its file system attributes, nor with that file’s data, but are kept separately.

For smaller extended attributes up to 3,804 bytes, their data is stored with the xattr in the file system metadata. Larger extended attributes are stored as data streams, with separate records, but still separately from the file data. Apple doesn’t give a limit on the maximum size of xattrs, but they can certainly exceed 200 KB, and each file and folder can have an effectively unlimited number of xattrs.

Behaviour of xattrs with the cloning of files is revealing, if tricky to investigate. It’s comparatively easy to demonstrate that larger xattrs are cloned and not duplicated when the new inode record is created for the clone file, by simply measuring changes in total file size in a volume. To accomplish the same for xattrs of less than 3,804 bytes requires amplification using multiple xattrs.

In this test ten separate xattrs each of 2,733 bytes were attached to a single file containing only 381 bytes of data.

As the Finder information for that file doesn’t take into account size of xattrs, its size is reported as only 381 bytes.

Its true total size, though, is 27,810 bytes, sufficient to be reflected in volume total used space, as given by Disk Utility. Comparison of files with large, small and no xattrs demonstrates that clones don’t duplicate xattrs of any size, but clone them as well.

Thus cloning only duplicates the inode and its attributes (blue and pink), together with their file extent information. You can verify this by inspecting the numbers of those inodes, as they’re different, and information in file system attributes such as the file’s name will also be different. Thus, as far as APFS is concerned, xattrs are part of the file, not attributes owned and maintained by the file system. As most xattrs are created, maintained and used by processes outside the file system, this is a good functional distinction.

File system xattrs

APFS itself relies on xattrs for managing the file system.

Symbolic links (symlinks) are special files in APFS, and the volume superblock maintains a total number of symlinks on that volume. Rather than consisting simply of text data, they consist of at least one xattr named com.apple.fs.symlink containing the path in the link. That xattr is marked as being owned by the file system, although that doesn’t affect the symlink’s permissions.

Firmlinks introduced in macOS 10.15 Catalina to form bidirectional links between locations in the System and Data volumes in a boot volume group, are also distinguished with their own xattr, this time named com.apple.fs.firmlink. Another file system xattr named com.apple.fs.cow-exempt-file-count is used to mark inodes that are exempt from copy-on-write behaviour if they’re part of a snapshot.

Summary

Extended attributes, xattrs, supersede the resource fork of Classic Mac OS as a means of storing additional file information outside a file’s data.
In APFS, xattrs are stored outside the inode and its attributes, and separate from a file’s data.
Data for smaller xattrs of up to 3,804 bytes is stored with the xattr in the file system metadata.
Data for larger xattrs is stored as data streams, with separate records.
Like file data, both smaller and larger xattrs are cloned when APFS creates clone files, and not duplicated.
APFS uses xattrs to distinguish symlinks, firmlinks, and files exempted from copy-on-write.
Xattrs are now widely used, but their size is ignored in most measurements of file size by macOS.

Articles in this series

1. Files and clones
2. Directories and names
3. Containers and volumes
4. Snapshots
5. Encryption and sealing
6. Special file types
7. Command tools
8. Beyond, to vfs and volfs
9. Log entries

Reference

Apple’s APFS Reference (PDF), last revised 22 June 2020.