总结:我想从用户空间获取Linux(或至少是ext4)中文件的世代号(i_generation
)。或者,也就是“出生时间”(文件创建时间)。
我正在尝试编写双向文件同步程序(又名Unison),但没有中央数据库(简单,只需在同步根中存储数据)并保留文件移动(非常非常难以获得)如果你想支持所有奇怪的情况,例如将文件从之后删除的目录中移出,就行了吧。
有一种唯一识别文件的方法可以减轻很多事情。我知道如何获取inode和设备号(通过stat
),但因为inode可以重复使用(我自己也看过),我想使用更稳定的唯一标识。
我已经读过NFS正在使用的'世代号'来唯一标识文件。在NFS中,(st_ino
,i_generation
)组合用于唯一标识重新启动和服务器崩溃时的文件句柄(或者至少防止重复使用相同的文件句柄导致可能的数据损坏)。
EXT4_IOC_GETVERSION
。我在我的系统上找不到合适的头文件(LMDE,Debian测试)。我可以找到两个选项:
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 Testing)上,它给出了编译器错误(EXT2_IOC_GETVERSION
未找到)。
另一种方法是获取文件的创建时间(crtime
或btime
/出生时间),但我所看到的所有Google搜索都显示无法获得Linux中的用户空间(IIRC FreeBSD有一个系统调用)。我更希望crtime
因为crtime
可能比一代号更便携(对于Windows)。
我知道这将取决于系统。我希望在没有唯一的inode(或者根本没有inode,在FAT的情况下,在USB记忆棒上很常见)的情况下有一个后备。
inotify
不是一个选项。这是一个在文件修改后同步文件的程序,比如rsync以一种方式完成。与Dropbox在后台观看文件更改的方式不同。
如果没有办法获得这些数字,我也会接受这个答案(当然有适当的文件):)
答案 0 :(得分:2)
我找到了解决方案。我交换了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和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
}