如何在Linux中获取inode的世代号?

时间:2013-11-18 16:35:43

标签: linux ioctl stat inode

总结:我想从用户空间获取Linux(或至少是ext4)中文件的世代号(i_generation)。或者,也就是“出生时间”(文件创建时间)。

我正在尝试编写双向文件同步程序(又名Unison),但没有中央数据库(简单,只需在同步根中存储数据)并保留文件移动(非常非常难以获得)如果你想支持所有奇怪的情况,例如将文件从之后删除的目录中移出,就行了吧。

有一种唯一识别文件的方法可以减轻很多事情。我知道如何获取inode和设备号(通过stat),但因为inode可以重复使用(我自己也看过),我想使用更稳定的唯一标识。

我已经读过NFS正在使用的'世代号'来唯一标识文件。在NFS中,(st_inoi_generation)组合用于唯一标识重新启动和服务器崩溃时的文件句柄(或者至少防止重复使用相同的文件句柄导致可能的数据损坏)。

但是,我没有成功获得这个数字。 This ext4 documentation似乎表明这个数字可以从ext4文件系统获得,但我无法从用户空间获取它(我不会在内核空间中运行这个简单的程序)。见EXT4_IOC_GETVERSION。我在我的系统上找不到合适的头文件(LMDE,Debian测试)。我可以找到两个选项:

  1. 尝试使用内核中的那个 - 未能说不应该从用户空间使用它。
  2. 尝试使用EXT2_IOC_GETVERSION中的<linux/ext2_fs.h> - 提供EBADFerrno 9)。也许是因为我试图从EXT4文件系统获取EXT2信息?或者我可能在ioctl做错了,这是我第一次尝试使用它。文件正确打开,因为open调用在我的情况下返回3(应该是有效的)。
  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);
    }
    

    此代码在Ubuntu 12.04上给出错误(errno = 9),在LMDE(Debian Testing)上,它给出了编译器错误(EXT2_IOC_GETVERSION未找到)。

    另一种方法是获取文件的创建时间(crtimebtime /出生时间),但我所看到的所有Google搜索都显示无法获得Linux中的用户空间(IIRC FreeBSD有一个系统调用)。我更希望crtime因为crtime可能比一代号更便携(对于Windows)。

    我知道这将取决于系统。我希望在没有唯一的inode(或者根本没有inode,在FAT的情况下,在USB记忆棒上很常见)的情况下有一个后备。

    inotify不是一个选项。这是一个在文件修改后同步文件的程序,比如rsync以一种方式完成。与Dropbox在后台观看文件更改的方式不同。

    如果没有办法获得这些数字,我也会接受这个答案(当然有适当的文件):)

1 个答案:

答案 0 :(得分:2)

我找到了解决方案。我交换了filenoioctl调用(显然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和fuse都没有列在那里),因为它们可能不支持代数。

来自coreutils的这个片段(tarball中的src / 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
}