粘贴文件时 nautilus 不调用 write 系统调用

粘贴文件时 nautilus 不调用 write 系统调用

我正在尝试在 Ubuntu 14.04 桌面版本上使用 Linux 内核模块来挂钩一些系统调用。

然而,当我hookwrite(unsigned int fd, const char __user *buf, size_t count)并转为fdfilename时,我发现当我复制/home/user/1.txt粘贴到/home/user/folder/nautilus中时,这个文件夹中没有调用write。但是,如果我使用cp /home/user/1.txt /home/user/folder,我可以注意到write被调用并且文件名正是/home/user/folder/1.txt.

我也尝试过 hook pwrite,但在使用 nautilus 粘贴文件时仍然没有检测到调用它。

write那么,当目的地没有调用系统调用时,nautilus 如何复制文件并粘贴到特定文件夹?

答案1

看起来 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)它允许在fds 之间传输一些数据,而无需在内核和用户空间之间复制数据。因为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()

相关内容