Parece que o Nautilus usa uma abordagem diferente para fins de otimização.
Digamos que eu tenha um arquivo de teste /ntest/testfile
com 45 bytes dentro:
Lorem ipsum dolor sit amet
Leroooy Jeeenkins
Eu quero movê-lo para o diretório /ntest2
. Para rastrear o que exatamente o Nautilus faz, posso ativá-lo assim (na verdade, fiz vários lançamentos com limitações menos rigorosas, mas isso é um bom começo):
strace -f -P '/ntest/testfile' -P '/ntest2/testfile' -qq nautilus
Essencialmente, o trecho a seguir explica o que acontece (note que pipe2()
call não é capturado pelo comando acima - eu o inseri baseado em outras sessões de rastreamento):
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
O Nautilus usa splice(2)
, que permite transferir alguns dados entre fd
s sem copiá-los entre o kernel e os espaços do usuário. Como man 2 splice
requer que uma das extremidades seja um canal, o Nautilus cria um canal com descritor de arquivo de entrada 38
e descritor de arquivo de saída 37
. Após abrir os arquivos de origem e de destino e criar o canal, o Nautilus usa splice()
para ler dados do arquivo de origem para a entrada do pipe; então o segundo splice()
é usado para gravar dados desse pipe no arquivo de saída. Essa abordagem não envolve transições de dados de kernel para usuário e de usuário para kernel, como seria com a abordagem comum de read()
- write()
.
Note que este comportamento não é específico do Nautilus, mas sim da biblioteca que ele usa (glib). Parece que esta é a chamada splice () que observamos, como o Nautilus usa g_file_copy () da glib que, por sua vez, chama file_copy_fallback () - > splice_stream_with_progress () - > do_splice () .