mjvotaw
mjvotaw

Reputation: 396

How to get full path (including mount directory) for file path?

I'm working on a plugin for Coda, and I'm running into a strange problem when trying to compare file paths to a sqlite row.

Basically, NSOpenPanel returns an NSURL which returns a path like this:

/Users/michael/Documents/xcode stuff/hM github/Plugin/filename

And Coda returns the current file path as this:

/Volumes/Macintosh HD/Users/michael/Documents/xcode stuff/hM github/Plugin/filename

I need to be able to retrieve a sqlite row tied to this file (which was initially created when the user selects a file through NSOpenPanel) given the path from Coda.

Is there a way to get a file's actual full path, including Volume information? Alternatively, is there a better way to store a reference to a file that could be easily retrievable, regardless of the given path?

update

I've realized that Coda modifies saved files in such a way that you cannot rely on a file's inode number to remain consistent, so trojanfoe's answer will not work for me.

Upvotes: 1

Views: 2418

Answers (2)

JeremyP
JeremyP

Reputation: 86651

Looking at the following:

miranda-6:~ jeremyp$ ls -l /Volumes
total 8
drwxr-xr-x   1 jeremyp  staff  8192 23 Oct 06:54 BOOTCAMP
drwxrwxr-x@ 20 jeremyp  staff   748 23 Oct 11:22 G-DRIVE
lrwxr-xr-x   1 root     admin     1 28 Oct 07:25 Macintosh HD -> /
drwxrwxrwx   0 root     wheel     0  1 Nov 16:28 MobileBackups
miranda-6:~ jeremyp$ 

/Volumes/Macintosh HD is a symbolic link to /.

So what you should do (IMO), is iterate through the items in /Volumes until you find the one that is a symbolic link to / Then whenever you get a file path from Coda that starts with /Volumes/<the item linked to / >, you strip that off before doing a search for it in your database.

You can use NSFileManager attributesOfItemAtPath:error: to find out if you have a symlink and NSFileManager -destinationOfSymbolicLinkAtPath:error: to find out where the symlink goes.

Upvotes: 1

trojanfoe
trojanfoe

Reputation: 122381

A better way to uniquely identify a file, regardless of how it's specified (absolute, relative, or including the mount) is to use the file's device and inode number which are unique across the system:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

static void get_file_details(const char *filename) {
    struct stat statbuf;
    if (stat(filename, &statbuf) == 0) {
        printf("%s = %016llx%016llx\n", filename, (uint64_t)statbuf.st_dev, (uint64_t)statbuf.st_ino);
    } else {
        fprintf(stderr, "Failed to stat '%s': %s\n", filename, strerror(errno));
    }
}

int main(int argc, const char **argv) {
    for (int i = 1; i < argc; i++)
        get_file_details(argv[i]);
    return 0;
}

$ clang -o stattest stattest.c
$ ./stattest stat*
stattest = 00000000010000010000000001b1d48a
stattest.c = 00000000010000010000000001b1d43b

You'll need to decide how you format the device/inode combo, but the above format should work fine for most cases.

Upvotes: 1

Related Questions