Files
是否可以在沒有 write_close 和重命名事件的情況下創建非空文件?
我問的原因是因為我正在使用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
(雖然不確定是哪些,但我認為這就是所有魔法發生的地方)。這裡最奇怪的是:
- 這
file.ext
不是移動的結果file.ext.filepart
- 會有不同的移動事件- 這
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
如果目標文件存在,它會覆蓋它。