2013-11-18 8 views
3

Реферат: Я хочу получить номер поколения (i_generation) файла в Linux (или, по крайней мере, ext4) из пользовательского пространства. Или, альтернативно, «время рождения» (время создания файла).Как получить номер поколения inode в Linux?

Я пытаюсь написать программу двусторонней синхронизации файлов (aka Unison), но без центральной базы данных (просто, просто сохраняйте данные в корнях синхронизации) и сохраняя перемещения файлов (очень и очень сложно получить право, если вы хотите поддержать все странные случаи, например, перемещение файла из каталога, который впоследствии удаляется).

Имея возможность однозначно идентифицировать файлы, облегчит вещи. Я знаю, как получить индекс inode и устройства (через stat), но поскольку inodes можно повторно использовать (я видел это сам), я хочу использовать более стабильную уникальную идентификацию.

Я прочитал о «номере поколения», который используется NFS для уникальной идентификации файлов. В NFS комбинация (, i_generation) используется для уникальной идентификации дескрипторов файлов при перезагрузках и сбоях сервера (или, по крайней мере, для предотвращения повторного использования одного и того же дескриптора файла, приводящего к возможному повреждению данных).

Мне не удалось получить номер. This ext4 documentation, по-видимому, предполагает, что число может быть получено из файловой системы ext4, но я не могу получить от него руки из пользовательского пространства (я не буду запускать эту простую программу в пространстве ядра). См. EXT4_IOC_GETVERSION. Я не могу найти соответствующий заголовочный файл в моей системе (LMDE, тестирование Debian). Есть два варианта, которые я мог бы найти:

  1. Попытайтесь использовать тот, что в ядре, - не говорит, что он не должен использоваться из пользовательского пространства.
  2. Пользуйтесь 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); 
} 

Этот код выдает ошибку (ошибка = 9) на Ubuntu 12.04, на LMDE (Debian Testing) дает ошибку компилятора (EXT2_IOC_GETVERSION не найден).

Альтернативой было бы получить время создания (crtime или btime/время рождения) файла, но все мои Googling подвернулся, что это, кажется, невозможно получить из пользовательского пространства в Linux (IIRC FreeBSD имеет системный вызов для него). Я предпочел бы crtime, потому что crtime может быть более портативным (для Windows), чем номер поколения.

Я знаю, что это будет зависящим от системы. Я хочу иметь резервную копию, если не найден уникальный уникальный индекс (или вообще не используется inode, в случае FAT, который является общим для USB-накопителей).

inotify не является вариантом. Это программа для синхронизации файлов после их изменения, например, rsync. Не нравится, как Dropbox остается в фоновом режиме, наблюдая за изменениями файлов.

Если нет никакого способа, чтобы получить эти цифры, я также признаю, что в качестве ответа (с соответствующей документацией, конечно) :)

ответ

1

Я нашел решение. Я поменял fileno и вызов ioctl (очевидно, C делает некоторое преобразование автоматического типа там).

Рабочий код выглядит следующим образом:

#include <sys/ioctl.h> 
#include <sys/fcntl.h> 
#include <linux/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(fileno, FS_IOC_GETVERSION, &generation)) { 
     printf("errno: %d\n", errno); 
    } 
    printf("generation: %d\n", generation); 
} 

Использование FS_IOC_GETVERSION делает работу вызова для наиболее распространенных файловых систем в Linux. Это исключает vfat и ntfs (по крайней мере, это похоже на источники ядра, там не указаны ни vfat, ни предохранитель), поскольку они, вероятно, не поддерживают номера поколений.

Этот фрагмент из Coreutils (ЦСИ/copy.c в тарболе) заставил меня задуматься:

/* Perform the O(1) btrfs clone operation, if possible. 
    Upon success, return 0. Otherwise, return -1 and set errno. */ 
static inline int 
clone_file (int dest_fd, int src_fd) 
{ 
#ifdef __linux__ 
# undef BTRFS_IOCTL_MAGIC 
# define BTRFS_IOCTL_MAGIC 0x94 
# undef BTRFS_IOC_CLONE 
# define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int) 
    return ioctl (dest_fd, BTRFS_IOC_CLONE, src_fd); 
#else 
    (void) dest_fd; 
    (void) src_fd; 
    errno = ENOTSUP; 
    return -1; 
#endif 
} 
Смежные вопросы