nautilus 粘貼文件時不呼叫寫入系統呼叫
我正在嘗試在 Ubuntu 14.04 桌面版上使用 linux 核心模組來掛鉤一些系統呼叫。
但是,當我hook
write(unsigned int fd, const char __user *buf, size_t count)
並變成fd
filename時,我發現當我在nautilus中複製/home/user/1.txt
粘貼到/home/user/folder/
時,在這個文件夾中沒有呼叫write。但是,如果我使用cp /home/user/1.txt /home/user/folder
,我可以注意到write
被呼叫並且文件名是/home/user/folder/1.txt
.我也嘗試過鉤子
pwrite
,但在使用 nautilus 粘貼文件時仍然沒有檢測到呼叫它。
write
那麼,當目標上沒有呼叫系統呼叫時,nautilus 如何復製文件並粘貼到特定文件夾?
看起來 Nautilus 使用不同的方法進行優化。
假設我有一個
/ntest/testfile
包含 45 個字節的測試文件:Lorem ipsum dolor sit amet Leroooy Jeeenkins
我想把它移到目錄
/ntest2
中。為了追踪 Nautilus 到底做了什麼,我可以像這樣啟動它(實際上,我做了多次啟動,限制不那麼嚴格,但這是一個好的開始):strace -f -P '/ntest/testfile' -P '/ntest2/testfile' -qq nautilus
從本質上講,以下摘錄解釋了會發生什麼(請注意,
pipe2()
上面的命令沒有擷取呼叫 - 我根據其他跟踪會話插入了它):openat(AT_FDCWD, "/ntest/testfile", O_RDONLY) = 35 openat(AT_FDCWD, "/ntest2/testfile", O_WRONLY|O_CREAT|O_EXCL, 0644) = 36 pipe2([37, 38], O_CLOEXEC) = 0 stat("/ntest2/testfile", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 splice(35, [0], 38, NULL, 1048576, SPLICE_F_MORE) = 45 splice(37, NULL, 36, [0], 45, SPLICE_F_MORE) = 45 close(35) = 0 close(36) = 0
Nautilus 使用
splice(2)
它允許在fd
s 之間傳輸一些數據,而無需在核心和使用者空間之間複製它。因為man 2 splice
要求一端是管道,所以 Nautilus 創建了一個帶有輸入文件描述符38
和輸出文件描述符的管道37
。在打開源文件和目標文件並創建管道後,Nautilus 使用splice()
從源文件讀取數據到管道的輸入;然後第二個splice()
用於將此管道中的數據寫入輸出文件。read()
這種方法不像普通方法那樣涉及核心到使用者和使用者到核心的數據轉換write()
。請注意,此行為並非特定於 Nautilus,而是特定於它使用的庫 (glib)。看起來這是我們觀察到的 splice() 呼叫,因為 Nautilus 使用 glib 的g_file_copy()反過來呼叫file_copy_fallback() -> splice_stream_with_progress() -> do_splice()。