我问的原因是因为我正在使用我看(不要与小工具设备混淆)监视文件系统事件(在我的例子中 - 文件创建/重命名)。
我无法解释的是这个日志:
/path/to/file.ext.filepart 0 IN_MODIFY
/path/to/file.ext.filepart 0 IN_MODIFY
/path/to/file.ext.filepart 0 IN_MODIFY
/path/to/file.ext.filepart 0 IN_MODIFY
/path/to/file.ext.filepart 0 IN_CLOSE_WRITE
/path/to/file.ext 0 IN_CREATE
/path/to/file.ext.filepart 0 IN_DELETE
/path/to/file.ext 0 IN_ATTRIB
为了获得它,我file.ext
使用 WinSCP 从远程计算机复制了一个文件,并打开了临时文件创建选项(以便它根本没有文件file.ext
,以防传输终止,或者完整的文件位于目标中)。
让我困惑的是,/path/to/file.ext
仅创建了它IN_CREATE
并修改了它的属性IN_ATTRIB
(虽然不确定是哪些,但我认为这就是所有魔法发生的地方)。
这里最奇怪的是:
- 这
file.ext
不是移动的结果file.ext.filepart
- 会有不同的移动事件 - 这
file.ext
不是复制的结果file.ext.filepart
- 后面会有一堆写入事件IN_CLOSE_WRITE
所以我的问题是 - 幕后发生了什么:如何在file.ext
没有显式重命名或数据副本的情况下使用内容创建?
答案1
$ inotifywait -m /tmp
Setting up watches.
Watches established.
/tmp/ CREATE file.ext.filepart
/tmp/ OPEN file.ext.filepart
/tmp/ MODIFY file.ext.filepart
/tmp/ CLOSE_WRITE,CLOSE file.ext.filepart
/tmp/ CREATE file.ext
/tmp/ DELETE file.ext.filepart
跑步记录
$ echo hello >/tmp/file.ext.filepart
$ ln /tmp/file.ext.filepart /tmp/file.ext
$ rm /tmp/file.ext.filepart
移动文件会生成一个move
事件,但创建硬链接会生成create
与创建新的空文件相同的事件(与mkfifo
创建文件的其他方法一样)。
为什么 SCP 或 SFTP 服务器创建硬链接然后删除临时文件而不是将临时文件移动到位?在OpenSSH(portable 6.0)的源代码中,在sftp-server.c
函数中process_rename
,我看到以下代码(重新格式化和简化以说明我想要展示的部分):
if (S_ISREG(sb.st_mode)) {
/* Race-free rename of regular files */
if (link(oldpath, newpath) == -1) {
if (errno == EOPNOTSUPP || errno == ENOSYS) {
/* fs doesn't support links, so fall back to stat+rename. This is racy. */
if (stat(newpath, &st) == -1) {
rename(oldpath, newpath) == -1)
}
}
} else {
unlink(newpath);
}
}
即:尝试创建从临时文件名到所需文件名的硬链接,然后删除临时文件。如果由于操作系统或文件系统不支持而无法创建硬链接,请使用不同的方法:测试所需的文件是否存在,如果不存在,则重命名临时文件。因此,重点是将临时文件重命名为其最终位置,而不必冒覆盖复制过程中可能已创建的文件的风险。重命名不起作用,因为rename
会覆盖目标文件(如果存在)。