简体   繁体   English

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

[英]How do I get the generation number of an inode in Linux?

Summary: I want to get the generation number ( i_generation ) of a file in Linux (or at least ext4) from userspace.摘要:我想从用户空间获取 Linux(或至少 ext4)中文件的代号 ( i_generation )。 Or, alternatively, the 'birth time' (file creation time).或者,“出生时间”(文件创建时间)。

I am trying to write a bidirectional file synchronisation program (aka Unison ), but without a central database (easy, just store data in the synchronisation roots) and by preserving file moves (very, very hard to get right if you want to support all weird cases like moving a file out of a directory that's deleted afterwards, for example).我正在尝试编写一个双向文件同步程序(又名Unison ),但没有中央数据库(简单,只需将数据存储在同步根中)并通过保留文件移动(如果你想支持所有奇怪的情况,例如将文件移出之后删除的目录)。

Having a way to uniquely identify files would ease things A LOT.拥有一种唯一标识文件的方法会减轻很多事情。 I know how to get the inode and device number (via stat ), but as inodes can be re-used (I've seen this myself), I want to use a more stable unique identification.我知道如何获取 inode 和设备号(通过stat ),但由于 inode 可以重复使用(我自己见过),我想使用更稳定的唯一标识。

I have read about the 'generation number' that is being used by NFS to uniquely identify files.我已经阅读了有关 NFS 用于唯一标识文件的“生成编号”的信息。 In NFS, the ( st_ino , i_generation ) combination is used to uniquely identify file handles across reboots and server crashes (or at least to prevent re-using the same file handle leading to possible data corruption).在 NFS 中, ( st_ino , i_generation ) 组合用于在重新启动和服务器崩溃时唯一标识文件句柄(或至少防止重复使用相同的文件句柄导致可能的数据损坏)。

I haven't succeeded in getting the number, though.不过,我还没有成功获得号码。 This ext4 documentation seems to suggest the number can be obtained from an ext4 filesystem, but I cannot get my hands on it from userspace (I'm not going to run this simple program in kernel space). 这个 ext4 文档似乎暗示可以从 ext4 文件系统获得该数字,但我无法从用户空间获得它(我不会在内核空间中运行这个简单的程序)。 SeeEXT4_IOC_GETVERSION .请参阅EXT4_IOC_GETVERSION I cannot find the appropriate header file on my system (LMDE, Debian testing).我在我的系统上找不到合适的头文件(LMDE,Debian 测试)。 There are two options I could find:我可以找到两个选项:

  1. Try to use the one in the kernel - fails saying that it should not be used from userspace.尝试使用内核中的那个 - 失败说它不应该从用户空间使用。
  2. Try using EXT2_IOC_GETVERSION in <linux/ext2_fs.h> - gives EBADF ( errno 9).尝试在<linux/ext2_fs.h>使用EXT2_IOC_GETVERSION - 给出EBADF ( errno 9)。 Maybe because I am trying to get EXT2 information from an EXT4 filesystem?也许是因为我试图从 EXT4 文件系统获取 EXT2 信息? Or maybe I'm doing something wrong with ioctl , this is the first time I'm trying to use it.或者也许我在使用ioctl做错了,这是我第一次尝试使用它。 The file is opened correctly, because the open call returns 3 in my case (which should be valid).该文件已正确打开,因为在我的情况下open调用返回 3 (这应该是有效的)。

the code:代码:

#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);
}

This code gives an error (errno=9) on Ubuntu 12.04, on LMDE (Debian Testing) it gives a compiler error ( EXT2_IOC_GETVERSION not found).此代码在 Ubuntu 12.04 上给出错误 (errno=9),在 LMDE(Debian 测试)上给出编译器错误( EXT2_IOC_GETVERSION )。

An alternative would be to get the creation time ( crtime , or btime / birth time) of the file, but all my Googling has turned up is that this appears to be impossible to get from userspace in Linux (IIRC FreeBSD has a system call for it).另一种方法是获取文件的创建时间( crtime ,或btime / 出生时间),但我所有的谷歌搜索结果都是这似乎不可能从 Linux 中的用户空间获取(IIRC FreeBSD 有一个系统调用它)。 I would prefer crtime because crtime may be more portable (to Windows) than a generation number.我更喜欢crtime因为crtime可能比crtime更便携(到 Windows)。

I know this is going to be system-dependent.我知道这将取决于系统。 I want to have a fallback when no unique inode (or no inode at all, in the case of FAT which is common on USB sticks) can be found.当找不到唯一的 inode(或根本没有 inode,在 USB 记忆棒上常见的 FAT 的情况下)时,我想有一个后备。

inotify is not an option. inotify不是一个选项。 It's a program to synchronize files after they have been modified, like rsync does in one way.它是一个在文件被修改后同步文件的程序,就像 rsync 以一种方式所做的那样。 Not like how Dropbox stays in the background watching for file changes.不像Dropbox在后台监视文件更改的方式。

If there is no way to get these numbers, I will also accept that as an answer (with proper documentation of course) :)如果无法获得这些数字,我也会接受它作为答案(当然还有适当的文档):)

I found the solution.我找到了解决方案。 I swapped the fileno and the ioctl call (apparently C does some automatic type conversion there).我交换了filenoioctl调用(显然 C 在那里做了一些自动类型转换)。

The working code looks like this:工作代码如下所示:

#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);
}

Using FS_IOC_GETVERSION makes the call work for most common file systems in Linux.使用FS_IOC_GETVERSION使该调用适用于 Linux 中最常见的文件系统。 This excludes vfat and ntfs (at least it looks like it in the kernel sources, neither vfat nor fuse are listed there), as they probably don't support generation numbers.这不包括 vfat 和 ntfs(至少它在内核源代码中看起来像,那里没有列出 vfat 和 fuse),因为它们可能不支持代号。

This fragment from coreutils (src/copy.c in the tarball) got me thinking:来自 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM