概括:我想获取代号(i_generation)来自用户空间的 Linux(或至少 ext4)中的文件。或者,“出生时间”(文件创建时间)。

我正在尝试编写一个双向文件同步程序(又名 齐奏),但没有中央数据库(简单,只需将数据存储在同步根中)并通过保留文件移动(如果您想支持所有奇怪的情况,例如将文件移出随后删除的目录,则非常非常难以正确执行) , 例如)。

拥有一种唯一标识文件的方法将使事情变得容易很多。我知道如何获取索引节点和设备号(通过 stat),但由于 inode 可以重复使用(我自己也见过这个),所以我想使用更稳定的唯一标识。

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

不过我还没成功拿到号码。 这个 ext4 文档 似乎表明可以从 ext4 文件系统获取该数字,但我无法从用户空间获取它(我不会在内核空间中运行这个简单的程序)。看 EXT4_IOC_GETVERSION. 。我在我的系统上找不到合适的头文件(LMDE、Debian 测试)。我可以找到两种选择:

  1. 尝试使用内核中的那个 - 失败说不应该从用户空间使用它。
  2. 尝试使用 EXT2_IOC_GETVERSION<linux/ext2_fs.h> - 给出 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 测试)上给出编译器错误(EXT2_IOC_GETVERSION 未找到)。

另一种方法是获取创建时间(crtime, , 或者 btime / 出生时间)的文件,但我谷歌搜索发现这似乎不可能从 Linux 中的用户空间获取(IIRC FreeBSD 有一个系统调用)。我会比较喜欢 crtime 因为 crtime 可能比一代号更便于移植(对于 Windows)。

我知道这将取决于系统。当找不到唯一的索引节点(或者根本没有索引节点,对于 USB 记忆棒上常见的 FAT 而言)时,我希望有一个后备方案。

inotify 不是一个选择。它是一个在文件修改后同步文件的程序,就像 rsync 一样。不像怎样 Dropbox 留在后台监视文件更改。

如果无法获得这些数字,我也会接受它作为答案(当然有适当的文档):)

有帮助吗?

解决方案

我找到了解决方案。我交换了 filenoioctl call(显然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 和 fusion 都没有列出),因为它们可能不支持代号。

coreutils 中的这个片段(压缩包中的 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
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top