2009-10-16 13 views
7

aquí hay otra pregunta sobre empalme(). Espero usarlo para copiar archivos, y estoy tratando de usar dos llamadas de empalme unidas por un tubo como el ejemplo en la página de Wikipedia de empalme. Escribí un caso de prueba sencilla que sólo se trata de leer los primeros 32K bytes de un archivo y escribir a otro:¿Cómo puedo usar la función splice() de Linux para copiar un archivo a otro archivo?

#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; 
} 

Cuando ejecuto esto, el archivo de entrada parece ser leído correctamente, pero la segunda llamada de empalme falla con EINVAL. ¿Alguien sabe lo que estoy haciendo mal aquí?

Gracias!

+0

Para cualquiera que lea esto, la segunda llamada 'empalme' solo debería intentar leer el número de bytes de la tubería cuando se devuelve la primera llamada' empalme'. En Linux de hoy, el tamaño de tubería predeterminado es '65535'. – Jite

Respuesta

3

¿Qué tipo de sistema (s) de archivos está copiando a/desde?

Su ejemplo se ejecuta en mi sistema cuando ambos archivos están en ext3 pero falla cuando uso una unidad externa (lo olvido de manera manual si es DOS o NTFS). Supongo que uno o ambos archivos están en un sistema de archivos que el empalme no admite.

+0

NTFS tendría sentido, eso se implementa a través de FUSE, y el controlador real del sistema de archivos se ejecuta como un proceso de espacio de usuario. Con otros sistemas de archivos, otoh, el sistema de archivos puede funcionar con el caché de la página directamente. Es una lástima que 'splice()' no tenga un retorno automático limpio a un ciclo de copia ... – bdonlan

+0

NTFS aunque el empalme tampoco parece funcionar en DOS. De acuerdo sobre la reserva. Estoy tentado de hacer algunos puntos de referencia simples, ya que parece impresionante a simple vista. – Duck

4

Desde el splice manpage:

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 uno de los descriptores es un tubo, y el archivo no está abierto en el modo de anexos. También sabemos que no se proporciona compensación (0 es equivalente a NULL - ¿Quería pasar un puntero a un desplazamiento cero?), Entonces ese no es el problema. Por lo tanto, el sistema de archivos que está utilizando no admite el empalme de archivos.

+0

Ese fue el problema. ¡Gracias! Debería haber leído la página del manual todo el tiempo, y no me había dado cuenta de que el empalme dependía del sistema de archivos. En mi caso, estaba copiando a un archivador de NFS. Estoy tratando de encontrar la forma más rápida de copiar muchos archivos (que promedian alrededor de 10MB) de un sistema de archivos NFS a otro. mmap-ing el archivo fuente y el uso de write() no están funcionando espectacularmente. ¡Gracias por los consejos! –

2

El splice(2) system call es para copiar entre archivos y tuberías y no entre archivos, por lo que no se puede usar para copiar entre archivos, como se ha señalado en las otras respuestas.

A partir de Linux 4.5, sin embargo, está disponible un nuevo copy_file_range(2) system call que puede copiar entre archivos. En el caso de NFS, incluso puede causar copia en el lado del servidor.

La página man vinculada contiene un programa de ejemplo completo.

Cuestiones relacionadas