是否可以在没有 write_close 和 rename 事件的情况下创建非空文件?

zer*_*kms 5 sftp hard-link files inotify

我问的原因是因为我使用iwatch(不要与小工具设备混淆)来监视文件系统事件(在我的情况下 - 文件创建/重命名)。

我无法解释的是这个日志:

/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 
Run Code Online (Sandbox Code Playgroud)

为了得到它,我file.ext使用 WinSCP 从远程机器复制了一个,并打开了临时文件创建选项(这样它要么根本没有文件file.ext,以防传输终止,或者完整的文件在目标中)。

令我感到困惑的是,/path/to/file.ext它仅被创建IN_CREATE并修改了它的属性IN_ATTRIB(虽然不确定是哪些,但我认为这就是所有魔法发生的地方)。

这里最奇怪的是:

  1. 这file.ext不是移动的结果file.ext.filepart- 会有不同的移动事件
  2. 这file.ext不是复制的结果file.ext.filepart- 后面会有一堆写事件IN_CLOSE_WRITE

所以我的问题是 - 引擎盖下发生了什么:如何在file.ext没有显式重命名或数据复制的情况下使用内容创建?

Gil*_*il' 10

$ 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
Run Code Online (Sandbox Code Playgroud)

跑步成绩单

$ echo hello >/tmp/file.ext.filepart
$ ln /tmp/file.ext.filepart /tmp/file.ext         
$ rm /tmp/file.ext.filepart
Run Code Online (Sandbox Code Playgroud)

移动文件会生成move事件,但创建硬链接会生成与create创建新的空文件相同的事件(mkfifo与创建文件的其他方式一样)。

为什么 SCP 或 SFTP 服务器创建硬链接然后删除临时文件而不是将临时文件移动到位?在OpenSSH(便携式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);
    }
}
Run Code Online (Sandbox Code Playgroud)

即:尝试创建从临时文件名到所需文件名的硬链接,然后删除临时文件。如果由于操作系统或文件系统不支持而无法创建硬链接,请回退到另一种方法:测试所需文件是否存在,如果不存在,则重命名临时文件。因此,关键是将临时文件重命名为其最终位置,而不会冒覆盖在复制过程中可能已创建的文件的风险。重命名不起作用,因为rename如果目标文件存在,则会覆盖它。