在Linux中,我该如何获取一个inode的生成编号?

4
简介:我想从用户空间获取Linux(或至少是ext4)文件的生成编号(i_generation)。或者,作为替代方案,获取“出生时间”(文件创建时间)。
我正在尝试编写一个双向文件同步程序(也称为Unison),但没有中央数据库(很容易,只需在同步根中存储数据)并保留文件移动(如果要支持所有怪异情况(例如将文件移出随后被删除的目录),则非常难以正确处理)。
有一种方法可以唯一地识别文件,这将极大地简化事情。我知道如何通过stat获得inode和设备号,但由于inode可能会被重用(我自己见过这种情况),因此我想使用更稳定的唯一标识。
我已经阅读了有关NFS使用“生成编号”来唯一标识文件的文章。在NFS中,(st_inoi_generation)组合用于唯一标识文件句柄,跨重启和服务器崩溃(或至少防止重复使用相同的文件句柄导致可能的数据损坏)。
我还没有成功地获取到这个数字。这份ext4文档似乎表明可以从一个ext4文件系统中获取这个数字,但是我无法从用户空间获取它(我不会在内核空间运行这个简单的程序)。请参见EXT4_IOC_GETVERSION。我在我的系统(LMDE,Debian测试版)中找不到适当的头文件。我找到了两个选项:
  1. 尝试使用内核中的一个 - 失败并显示不应该从用户空间使用。
  2. 尝试在<linux/ext2_fs.h>中使用EXT2_IOC_GETVERSION - 返回EBADF(errno 9)。也许是因为我正在尝试从EXT4文件系统获取EXT2信息?或者可能是我在使用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);
}

这段代码在Ubuntu 12.04上报错(errno=9),在LMDE(Debian Testing)上编译时会出现编译错误(EXT2_IOC_GETVERSION未找到)。

另一种方法是获取文件的创建时间(crtimebtime/birth time),但我所有的谷歌搜索结果都表明在Linux的用户空间中似乎无法获取此信息(IIRC FreeBSD有一个系统调用可以实现)。我更喜欢使用crtime,因为crtime可能比生成号码更具可移植性(到Windows)。

我知道这将依赖于系统。当找不到唯一的inode(或者在USB闪存上常见的FAT中根本没有inode)时,我希望有一个后备方案。

inotify不是一个选项。它是一个程序,在文件被修改后同步文件,类似于rsync单向同步。而不像Dropbox那样在后台监视文件变化。

如果没有办法获取这些数字,我也会接受这个答案(当然需要适当的文档支持) :)

1个回答

5
我找到了解决方案。我交换了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(至少在内核源代码中看起来是这样,因为它们可能不支持生成编号)。
来自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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接