Резюме: я хочу получить номер поколения (i_generation
) файла в Linux (или хотя бы ext4) из пользовательского пространства. Или, альтернативно, «время рождения» (время создания файла).
Я пытаюсь написать программу двунаправленной синхронизации файлов (она же Unison), но без центральной базы данных (просто, просто храните данные в корнях синхронизации) и сохраняя перемещение файлов (очень, очень сложно сделать правильно, если вы хотите поддерживать все странные случаи, такие как перемещение файла из каталога, который впоследствии удаляется, например ).
Наличие способа уникальной идентификации файлов ОЧЕНЬ облегчило бы задачу. Я знаю, как получить индекс и номер устройства (через stat
), но поскольку индексы можно использовать повторно (я сам это видел), я хочу использовать более стабильную уникальную идентификацию.
Я читал о «номере поколения», который используется NFS для уникальной идентификации файлов. В NFS комбинация (st_ino
, i_generation
) используется для уникальной идентификации дескрипторов файлов при перезагрузках и сбоях сервера (или, по крайней мере, для предотвращения повторного использования одного и того же дескриптора файла, что может привести к повреждению данных).
Но мне так и не удалось получить номер. Эта документация по ext4 предполагает, что число может быть получено из ext4 файловая система, но я не могу получить ее из пользовательского пространства (я не собираюсь запускать эту простую программу в пространстве ядра). См. EXT4_IOC_GETVERSION
. Я не могу найти соответствующий заголовочный файл в своей системе (тестирование LMDE, Debian). Есть два варианта, которые я мог найти:
- Попробуйте использовать тот, что в ядре - не получается сказать, что его нельзя использовать из пользовательского пространства.
- Попробуйте использовать
EXT2_IOC_GETVERSION
в<linux/ext2_fs.h>
— получитсяEBADF
(errno
9). Может быть, потому что я пытаюсь получить информацию EXT2 из файловой системы EXT4? А может я что-то не так делаю сioctl
, первый раз пытаюсь им пользоваться. Файл открывается корректно, так как вызовopen
в моем случае возвращает 3 (что должно быть корректно).
код:
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <linux/ext2_fs.h>
#include <stdio.h>
#include <errno.h>
int main () {
int fileno = open("generation.c", O_RDONLY);
printf("fileno: %d\n", fileno);
int generation = 0;
if (ioctl(EXT2_IOC_GETVERSION, fileno, &generation)) {
printf("errno: %d\n", errno);
}
printf("generation: %d\n", generation);
}
Этот код выдает ошибку (errno=9) в Ubuntu 12.04, в LMDE (Debian Testing) выдает ошибку компилятора (EXT2_IOC_GETVERSION
не найден).
В качестве альтернативы можно было бы получить время создания (crtime
или btime
/ время рождения) файла, но все, что я нашел в Google, это то, что это невозможно получить из пользовательского пространства в Linux (IIRC FreeBSD имеет системный вызов для Это). Я бы предпочел crtime
, потому что crtime
может быть более переносимым (в Windows), чем номер поколения.
Я знаю, что это будет зависеть от системы. Я хочу иметь запасной вариант, когда не может быть найден уникальный индекс (или вообще нет индекса, в случае FAT, который распространен на USB-накопителях).
inotify
не вариант. Это программа для синхронизации файлов после их изменения, как это делает rsync одним из способов. В отличие от того, как Dropbox остается в фоновом режиме и следит за изменениями файлов.
Если нет возможности получить эти числа, я также приму это как ответ (конечно, с надлежащей документацией) :)