File: mmap-copy.c

/**
 * duplica un file utilizzando 'mmap' per operare sui file
 */
 
#include "lib-misc.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
 
int main(int argc, char *argv[]) {
    int fdin, fdout;
    char *src, *dst;
    struct stat sb;
 
    if (argc < 3)
        exit_with_err_msg("uso: %s <file-sorgente> <file-destinazione>\n",
                          argv[0]);
 
    // apre il file sorgente in lettura
    if ((fdin = open(argv[1], O_RDONLY)) == -1)
        exit_with_sys_err(argv[1]);
 
    // recupera le informazioni sul file sorgente
    if (fstat(fdin, &sb) < 0)
        exit_with_sys_err(argv[1]);
 
    // apre il file destinazione troncandolo o creandolo
    umask(0);
    if ((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC,
                      (sb.st_mode & 0777))) == -1)
        exit_with_sys_err(argv[2]);
 
    // controlla se il file sorgente è vuoto: creerebbe problemi sia con
    // `lseek` che con mmap
    if (sb.st_size == 0)
        exit(EXIT_FAILURE);
 
    // espande il file destinazione alla dimensione voluta prima di mapparlo:
    // utilizza `ftruncate`
    if (ftruncate(fdout, sb.st_size) == -1)
        exit_with_sys_err("ftruncate");
 
    // mappa il file sorgente
    if ((src = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdin,
                            0)) == MAP_FAILED)
        exit_with_sys_err("mmap");
 
    // mappa il file destinazione
    if ((dst = (char *)mmap(NULL, sb.st_size, PROT_WRITE, MAP_SHARED, fdout,
                            0)) == MAP_FAILED)
        exit_with_sys_err("mmap");
 
    // chiudo i descrittori: non servono più!
    close(fdin);
    close(fdout);
 
    // copia il contenuto della sorgente sulla destinazione: usa 'memcpy' per
    // maggiore efficienza
    memcpy(dst, src, sb.st_size);
 
    // operazione di de-mappatura (non indispensabile)
    munmap(src, sb.st_size);
    munmap(dst, sb.st_size);
 
    exit(EXIT_SUCCESS);
}