Search code examples
macoscocoaattributessymlinknsfilemanager

Set modification date on symbolic link in Cocoa


In Cocoa, I would like to set the modification date of a symbolic link.

Using the [NSFileManager setAttributes:ofItemAtPath:error:] works well with regular files but not with symbolic links.

How can I achieve that?


Solution

  • There is no way to do it directly with NSFileManager. The setAttributes:ofItemAtPath:error: method wraps up a bunch of BSD path-based functions like utimes, setxattr, chown, etc., all of which follow symlinks instead of operating on them directly.

    One obvious alternative is to drop down to the BSD layer manually. Some of the functions have "don't follow symlinks" versions, like lchown, but not all of them do. In particular, the one that changes the mod time, utimes, does not. So you have to open the file and use the fd-based variant, futimes. Here's what the code would look like:

    int fd = open([NSFileManager fileSystemRepresentationWithPath:path], O_RDONLY | O_SYMLINK);
    futimes(fd, 0);
    close(fd);
    

    If you plan to do a lot of this, you can write your own setAttributes:ofSymlinkAtPath:error: implementation in a category on NSFileManager that wraps up futimes, fchflags, fsetxattr, etc.

    The only real problem with this is that you need to have read access to the symlink itself (as well as whatever access you need to modify the mod time, etc.) for this to work, but that's usually not a problem, and as far as I know OS X has no way around it anyway. (Linux does let you open a file for neither read nor write access, just to do f* calls, but BSD does not.)

    As another alternative, I believe the NSURL file URL APIs do not follow symlinks, which means this should work (but I'm not in front of my Mac right now, so I can't test):

    [[NSURL fileURLWithPath:path isDirectory:NO] setResourceValue:[NSDate date] forKey:NSURLContentModificationDateKey error:nil];