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

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

我问的原因是因为我正在使用我看(不要与小工具设备混淆)监视文件系统事件(在我的例子中 - 文件创建/重命名)。

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

/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(虽然不确定是哪些,但我认为这就是所有魔法发生的地方)。

这里最奇怪的是:

  1. file.ext不是移动的结果file.ext.filepart- 会有不同的移动事件
  2. 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会覆盖目标文件(如果存在)。

相关内容