About | ACP | Buy | Free | Industry Watch | Learning Curve | News | Search | Test
Home » Learning Curve » Developers Workshop

Oh Where Oh Where Did My Resource Fork Go?

Oh where can my Finder info be?

Get It

Try It

One of the hallmarks of 'MacOS' was the ability of the system to recognise files with no outwardly apparent hints associated with them. This was done through what is known as 'Finder info' which was volume control block data stored on a per item basis.

Another hallmark was the ability to associate arbitrary additional data with any given file or directory for any purpose whatsoever. The data could be used both for beneficial and nefarious purposes. This was done through what is known as a resource fork, an alternate stream in the same file.

Normally both these data blocks were invisible to the user; in practice they were difficult or impossible to control directly, leading Doug McIlroy to make his now famous remark about Linux someday ceasing to be Unix.

Both these data blocks have traditionally been dependent on HFS* file systems. And as no other OS vendors have ever entertained such a scheme it's been nigh on impossible to seamlessly and painlessly transfer files from a 'MacOS' box to an alien system.

The APIs used to access and control Finder info and resource forks are legacy and some parts of these APIs are now officially deprecated. Whilst direct CatalogInfo APIs are not being phased out the ancient Carbon APIs for resource fork management are. But there's a replacement.

Starting with OS X 10.4 Tiger Apple have a new API group documented in <sys/xattr.h>. Other Unix systems also have extended attributes used in at least a remotely similar fashion. And part of the idea with many implementations is to achieve NT style access control lists. OS X 10.4 Tiger is capable of using extended attributes to achieve such access control lists.

The APIs for getting at these extended attributes are eminently straightforward with four groups of functions with two in each group for listing, getting, setting, and removing extended attributes. In each pair of APIs one takes a path and the other takes a file descriptor.

ssize_t listxattr(const char *path, char *namebuff, size_t size, int options);

ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options);

int setxattr(const char *path, const char *name, const void *value, size_t size, u_int32_t position, int options);

int removexattr(const char *path, const char *name, int options);

The counterparts to the above using file descriptors.

ssize_t flistxattr(int fd, char *namebuff, size_t size, int options);

ssize_t fgetxattr(int fd, const char *name, void *value, size_t size, u_int32_t position, int options);

int fsetxattr(int fd, const char *name, const void *value, size_t size, u_int32_t position, int options);

int fremovexattr(int fd, const char *name, int options);

The first argument is always either a path to a file or a file descriptor for it. The list and get APIs can return the length of data to be returned so a buffer of an appropriate size can first be allocated.

The list APIs return a series of zero terminated strings each of at most XATTR_MAXNAMELEN (127) characters in length. Once received the list can be parsed for use in other API calls.

The get APIs can also return the length of data to be returned: here both a path or file descriptor plus an attribute name are given on input.

position refers to an offset within the attribute data and options varies depending on the context.

When invoking the path based calls a value of XATTR_NOFOLLOW (1) indicates symlinks are not to be followed; when setting attributes XATTR_CREATE (2) indicates an attribute is to be created but the call is to fail if it already exists and XATTR_REPLACE (4) indicates an attribute is to be replaced and the call is to fail if it does not already exist.

Two attribute names are predefined.

#define    XATTR_FINDERINFO_NAME        "com.apple.FinderInfo"
#define    XATTR_RESOURCEFORK_NAME      "com.apple.ResourceFork"

No matter where the system actually stores this data starting with 10.4 Tiger it's accessible through ordinary 'Unix' APIs resolved in a vanilla Unix shared library. Constructing an application that searches all files in a given area of a file system for the presence of either of these new attributes is if not trivial then close to it.

Rabbit Hole

But this is where the rabbit hole comes back in. Although HFS* has always been capable of storing more than resource forks this capability has seldom been used before now. The name of the resource fork prior to Tiger was 'RESOURCE_FORK' and the fork was accessible through a variety of now officially deprecated Carbon APIs.

[The name of the data fork was the empty string; Tiger implies a restructuring of file system data management in that both Finder info and resource forks are grouped today in the same category. Ed.]

Now with Tiger it's eminently simple to create extended attributes of one's own - which can be used in any context one likes and which can coexist with other attributes no matter their function.

The author of Oompa Loompa, the 'worm' that surfaced in early February 2006, used these very extended attribute APIs to manage propagation. Any file that had been successfully corrupted was given the extended attribute 'Oompa' with the value 'Loompa'. The worm was thus able to avoid redundancy in its propagation.

BOOL already_corrupted(char *path) {
    char buf[7];

    return (
            getxattr(path, "Oompa", 0, 0, 0, 1) == 7 &&
            getxattr(path, "Oompa", buf, 7, 0, 1) == 7 &&
            !strcmp(buf, "Loompa")

Clearly as black hats are able to use and exploit these extended attributes ordinary users must be given the same abilities so they can defend themselves.

Currently no file system utilities save Xfile so much as flags for their existence; and no utilities save the ACP's coming Xattr allows insight and control over them.

See Also
Xattr: Extended Attributes

About | ACP | Buy | Free | Industry Watch | Learning Curve | News | Search | Substack | Test
Copyright © Rixstep. All rights reserved.