/**
 * Autor: Jorge Pereira 
 * Data: Thu Oct  9 22:47:47 BRT 2008
 * Desc: Exemplo de um codigo para copia de arquivos utilizando mmap()
 * Arquivo: cp-mmap.c
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <err.h>

#define IO_SIZE 4096

int
main(int argc, char *argv[])
{
int32_t fdr, fdw, fdm;
ssize_t reads;
/* repare que ao inves de utilizarmos um buffer auxilia, iremos ter um ponteiro apenas */
void *mem;

if(argc < 3)
{
  printf("Usage: %s  \n", argv[0]);
  exit(EXIT_FAILURE);
}

/* Arquivo de origem */
fdr = open(argv[1], O_RDONLY);
if(fdr < 0)
{
  err(1, "Falha ao abrir (%s)", argv[1]);
  exit(EXIT_FAILURE);
}

/* Arquivo de destino */
fdw = open(argv[2], O_CREAT | O_RDWR, 0644);
if(fdw < 0)
{
  err(1, "Falha ao abrir (%s)", argv[2]);
  exit(EXIT_FAILURE);
}

/* tal device abaixo ira prover caracteres nulos '\0', estaremos apenas fazendo
* o mapeamento do dispositivo para uma regiao de memoria com tamanho definido
* neste caso por "IO_SIZE", com protecao R+W e sendo visivel apenas para o
* processo corrente, sem offsets referente a paginas de memoria.
*
* 1) Abrindo o device /dev/zero
* 2) Fazendo o mapeamento na linha 67
*
* OBS: Na duvida consulte a man do mmap(), e veja um exemplo utilizando mais
* detalhes conforme sua necessidade!
*/
if((fdm = open("/dev/zero", O_RDWR)) < 0)
{
  err(1, "Falha ao abrir (%s)", argv[2]);
  exit(EXIT_FAILURE);
}
mem = mmap(NULL, IO_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fdm, 0);
close(fdm);

/**
* Inicio da copia, repare que estamos lendo do disco e "copiando" para regiao
* de  memoria mapeada, e escrevendo apartir do mesmo mapeamento! funcionando
* como uma variavel temporaria.
*/
while ((reads = read(fdr, mem, IO_SIZE)) > 0)
{
  if(write(fdw, mem, reads) < reads)
  {
    err(1, "Problemas com write()");
    break;
 }
}

munmap(mem, IO_SIZE);

/* fechando os descritores */
close(fdr);
close(fdw);

return EXIT_SUCCESS;
}
