Reputation: 855
OSX Yosemite introduced a very handy attribute on NSURL: NSURLDocumentIdentifierKey
.
Quoting from the documentation:
NSURLDocumentIdentifierKey
The document identifier returned as an NSNumber (read-only). The document identifier is a value assigned by the kernel to a file or directory. This value is used to identify the document regardless of where it is moved on a volume. The identifier persists across system restarts. It is not transferred when the file is copied, but it survives "safe save” operations. For example, it remains on the path to which it was assigned, even after calling the replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error: method. Document identifiers are only unique within a single volume. This property is not supported by all volumes.
Available in OS X v10.10 and iOS 8.0.
Unfortunately, the value seems to be mostly nil (except rare examples that seem completely disconnected one to the other).
In particular, this code will throw an exception at the last line (tested on Yosemite 10.10.3):
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *attributesFlags = @[NSURLNameKey, mNSURLDocumentIdentifierKey];
NSDirectoryEnumerator *en = [fileManager enumeratorAtURL:[NSURL URLWithString:NSHomeDirectory()]
includingPropertiesForKeys:attributesFlags
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:^BOOL(NSURL *url, NSError *error) {
NSAssert(NO, @"An error has occured");
return YES;
}];
for(NSURL *URL in en) {
NSNumber *documentID = nil;
NSError *error = nil;
BOOL result = [URL getResourceValue:&documentID forKey:NSURLDocumentIdentifierKey error:&error]; \
NSAssert(result == YES && error==nil, @"Unable to read property. Error: %@", error); \
NSLog(@"Processing file: %@", URL);
// This will break most of the times
NSAssert(documentID != nil, @"Document ID should not be nil!!");
}
Perhaps I misunderstood the documentation but it seems to me NSURLDocumentIdentifierKey
should be available on every file on disk.
Upvotes: 3
Views: 618
Reputation: 12095
This issue still exists in macOS 10.14. It probably won't change.
The work-around is to get the inode from NSFileManager
, like this:
NSFileManager *fmgr = [NSFileManager defaultManager];
NSDictionary *attributes = [fmgr attributesOfItemAtPath:url.path error:nil;
if (attributes != nil) {
NSNumber *inode = [attributes objectForKey:NSFileSystemFileNumber];
...
}
Upvotes: 0
Reputation: 71
I filed a bug with Apple on this issue and got a feedback on my report. As of today, the information on tracking the DocumentIdentifier
is not part of the documentation yet, but the ticket is still open.
The missing information is, that the filesystem does not track the DocumentIdentifier
by default. You'll have to enable the tracking by setting a flag on each file that you want to track using chflags
with the UF_TRACKED
flag.
The following script will print the DocumentIdentifier
for a file:
https://gist.github.com/cmittendorf/fac92272a941a9cc64d5
And this script will enable tracking the DocumentIdentifier
:
https://gist.github.com/cmittendorf/b680d1a03aefa08583d7
Upvotes: 2
Reputation: 855
Apparently Yosemite assigns a DocumentIdentifier to a file only when it knows something is trying to track its identity (like Versions or iCloud).
I don't see any way to talk to the kernel and tell it to start tracking files you're interested on. I hope this changes in future releases, since the API has been made public on OS X 10.10 and it's mostly useless at this point.
Upvotes: 0