Определить, указывают ли два пути к одному и тому же файлу в Linux/C?

В Linux у меня есть два пути к файлам A и B:

const char* A = ...;
const char* B = ...;

Теперь я хочу определить, должен ли я open(2) их обоих...

int fda = open(A, ...);
int fdb = open(B, ...);

... получу ли я два файловых дескриптора, открытых для одного и того же файла в файловой системе?

Чтобы определить это, я подумал о stat(2):

struct stat
{
    dev_t st_dev;
    ino_t st_ino;
    ...
}

Что-то вроде (псевдокод):

bool IsSameFile(const char* sA, const char* sB)
{
    stat A = stat(sA);
    stat B = stat(sB);

    return A.st_dev == B.st_dev && A.st_ino == B.st_ino;
}

Есть ли случаи, когда A и B являются одним и тем же файлом, но IsSameFile возвращает false?

Есть ли случаи, когда A и B являются разными файлами, но IsSameFile возвращает true?

Есть ли лучший способ сделать то, что я пытаюсь сделать?


person Andrew Tomazos    schedule 27.03.2013    source источник
comment
У вас может быть несколько файловых дескрипторов, которые ссылаются на один и тот же файл, да.   -  person teppic    schedule 27.03.2013
comment
@teppic: Да, и у вас также может быть несколько дескрипторов файлов, которые относятся к разным файлам. Мой вопрос заключается в том, как мне определить, в какой из этих двух вселенных я нахожусь (или в которой буду)   -  person Andrew Tomazos    schedule 27.03.2013
comment
Если у вас есть открытые дескрипторы файлов, вы можете просто использовать fstat непосредственно на них - если индексы и номера устройств равны, два пути не могут ссылаться на разные файлы.   -  person teppic    schedule 27.03.2013


Ответы (2)


Ваша программа будет работать нормально во всех случаях, потому что A.st_ino вернет номер inode файлов в вашей системе. Поскольку номер inode уникален, ваша программа правильно определит, являются ли два открытых файла одинаковыми или нет.

Вы также можете проверить значение A.st_mode, чтобы узнать, является ли файл символической ссылкой.

person Deepu    schedule 27.03.2013
comment
Вы можете узнать, что имя является (неработающей) символической ссылкой через stat(), только если это действительно неработающая символическая ссылка. Если она не повреждена, stat() сообщает о файле или устройстве в конце ссылки; lstat() сообщает о (первой) символической ссылке, если имя является символической ссылкой. - person Jonathan Leffler; 27.03.2013

Это зависит от того, почему именно вы хотите избежать повторного открытия одного и того же файла. Ваше решение обычно является правильным, но в некоторых ситуациях файлы следует считать одинаковыми, если они имеют одинаковый абсолютный путь, но не являются ссылками на один и тот же индексный дескриптор. В этом случае вам нужно преобразовать пути в абсолютные пути и сравнить их... см. Получение абсолютный путь к файлу

Вам также необходимо решить, считаете ли вы символическую ссылку на файл эквивалентной файлу или другую символическую ссылку на него. Для эквивалентности inode это определяет, использовать ли stat или lstat. Для эквивалентности пути он определяет, можете ли вы использовать realpath или вам нужно получить абсолютный путь без перехода по символическим ссылкам.

person Jim Balter    schedule 27.03.2013
comment
Используя stat(), код не будет обращать внимания на символические ссылки (кроме, возможно, неработающих). Не могли бы вы уточнить «некоторые ситуации, когда файлы следует считать одинаковыми, если они имеют одинаковый абсолютный путь, но не являются ссылками на один и тот же индексный дескриптор»? - person Jonathan Leffler; 27.03.2013
comment
@JonathanLeffler При использовании stat() код не обращает внимания на символические ссылки, но не использует lstat — это именно то различие, которое я сделал. Уточнение: некоторые схемы резервного копирования требуют, чтобы файлы были скопированы один раз для каждого пути (особенно, если восстановление будет производиться на файловую систему, не поддерживающую жесткие ссылки), в то время как нет смысла сохранять один и тот же путь дважды. Они могут быть другими вариантами использования. Но, как я уже сказал, обычно требуется эквивалентность inode. - person Jim Balter; 27.03.2013
comment
@JonathanLeffler И на самом деле это lstat, который не обращает внимания на символические ссылки, тогда как stat делает с ними эффективное readlink и следует им. На самом деле, реализация lstat — это то же самое, что реализация stat была до того, как появились символические ссылки (например, тогда я писал код ядра UNIX). - person Jim Balter; 27.03.2013