Como posso usar a função Splice () do Linux para copiar um arquivo para outro arquivo?
Pergunta
Aqui está outra pergunta sobre Splice (). Espero usá -lo para copiar arquivos e estou tentando usar duas chamadas de emenda unidas por um tubo, como o exemplo na página da Wikipedia da Splice. Escrevi um caso de teste simples que só tenta ler os primeiros 32k bytes de um arquivo e escrevê -los para outro:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv) {
int pipefd[2];
int result;
FILE *in_file;
FILE *out_file;
result = pipe(pipefd);
in_file = fopen(argv[1], "rb");
out_file = fopen(argv[2], "wb");
result = splice(fileno(in_file), 0, pipefd[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
printf("%d\n", result);
result = splice(pipefd[0], NULL, fileno(out_file), 0, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
printf("%d\n", result);
if (result == -1)
printf("%d - %s\n", errno, strerror(errno));
close(pipefd[0]);
close(pipefd[1]);
fclose(in_file);
fclose(out_file);
return 0;
}
Quando eu executo isso, o arquivo de entrada parece ser lido corretamente, mas a segunda chamada de emenda falha com o EINVAL. Alguém sabe o que estou fazendo de errado aqui?
Obrigado!
Solução
Que tipo de sistema (s) de arquivos você está copiando para/de?
Seu exemplo é executado no meu sistema quando os dois arquivos estão no Ext3, mas falha quando uso uma unidade externa (esqueço de maneira insuficiente se for DOS ou NTFS). Meu palpite é que um ou ambos os seus arquivos estão em um sistema de arquivos que a emenda não suporta.
Outras dicas
EINVAL Target file system doesn't support splicing; target file is
opened in append mode; neither of the descriptors refers to a
pipe; or offset given for non-seekable device.
Sabemos que um dos descritores é um tubo e o arquivo não está aberto no modo Apênd. Também sabemos que nenhum deslocamento é dado (0
é equivalente a NULL
- Você quis passar um ponteiro para um deslocamento zero?), Então esse não é o problema. Portanto, o sistema de arquivos que você está usando não suporta splicing nos arquivos.
o splice(2)
Chamada do sistema é para copiar entre arquivos e tubos e não entre arquivos, portanto, não pode ser usado para copiar entre arquivos, como foi apontado pelas outras respostas.
A partir do Linux 4.5, no entanto, um novo copy_file_range(2)
Chamada do sistema está disponível que pode copiar entre arquivos. No caso do NFS, ele pode até causar cópia do lado do servidor.
A página do Man Linked contém um programa de exemplo completo.