admin管理员组

文章数量:1302333

It appears that [NSURL fileReferenceURL] returns the same information as calling [NSURL getResourceValue:forKey:error:] for the key NSURLFileResourceIdentifierKey.

Are they indeed functionally the same? (Spoiler: No, they aren't!)

It appears that [NSURL fileReferenceURL] returns the same information as calling [NSURL getResourceValue:forKey:error:] for the key NSURLFileResourceIdentifierKey.

Are they indeed functionally the same? (Spoiler: No, they aren't!)

Share Improve this question asked Feb 10 at 15:38 Thomas TempelmannThomas Tempelmann 12.1k11 gold badges88 silver badges166 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 6

There is a fine but important difference between the two - they behave differently if the item is a hard linked file.

If, especially on a APFS formatted volume, you have multiple hard links for the same file content, then

  • NSURLFileResourceIdentifierKey will return the same value (classic "inode") for all these hard links, whereas
  • fileReferenceURL returns unique "link IDs" that keep the reference for each hard link entry's path.

In depth

APFS manages two "inode" values for hard links:

  1. The classic inode is the one that points to the file content. So, if multiple hard links point to the same content, you get that content's inode number. That's what the stat() function and the stat command line tool will show as well, BTW.

  2. The linkID is another inode, but this time it points to the directory entry (which, for non-hardlinked files is identical to the content inode). This value can be retrieved with the getattrlist() function, using the ATTR_CMNEXT_LINKID key. Additionally, since macOS 10.13, the searchfs() function can also return this value along with the classic inode number.

Resolving an inode or a link ID

Invoke fsgetpath by declaring the following:

#include <sys/syscall.h>
#define fsgetpath(buf, bufsize, fsid, objid)  \
    (ssize_t)syscall(SYS_fsgetpath, buf, (size_t)bufsize, fsid, (uint64_t)objid)

Call it like this:

uint64_t inode = 2;         // set this to the linkID or inode
const char *volPath = "/";  // must be set to the file's volume!

struct statfs fsinfo;
int err = statfs (volPath, &fsinfo);
if (err == 0) {
    char path[MAXPATHLEN+1];
    ssize_t len = fsgetpath (path, sizeof(path)-1, &fsinfo.f_fsid, inode);
    if (len > 0) {
        ... process the path
    }
}

To determine the correct volume, ideally at the time of storing the inode value, you can call stat() and pass the file's full path and then store the returned st_dev value or call statfs() as shown above.

本文标签: macosWhat is the difference between fileReferenceURL and NSURLFileResourceIdentifierKeyStack Overflow