Reputation: 396
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
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
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