Files

是否可以在沒有 write_close 和重命名事件的情況下創建非空文件?

  • April 1, 2015

我問的原因是因為我正在使用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 

為了得到它,我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沒有明確重命名或數據副本的情況下使用內容創建?

$ 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如果目標文件存在,它會覆蓋它。

引用自:https://unix.stackexchange.com/questions/193915