#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/errno.h>

int main(int argc, char *argv[])
{
    int err;

    if (argc != 3) {
        fprintf(stderr, "usage: %s from_file to_file", argv[0]);
        exit(0);
    }

    /* from */
    int from = open(argv[1], O_RDONLY, 0644);
    assert(from >= 0);

    struct stat st_buf;
    assert(fstat(from, &st_buf) >= 0);
    size_t size = st_buf.st_size;

    void *from_mmap = mmap(NULL, size, PROT_READ, MAP_SHARED, from, 0);
    assert(from_mmap >= 0);

#if USE_MADVISE
    err = madvise(from_mmap, size, MADV_SEQUENTIAL);
    assert(err >= 0);
#endif

    /* to */
    int to = open(argv[2], O_CREAT|O_RDWR, st_buf.st_mode);
    assert(to >= 0);

    int i = 0;
    assert(lseek(to, size - sizeof(int), 0L) >= 0);
    assert(write(to, (&i), sizeof(int)) == sizeof(int));

    errno=0;
    void *to_mmap = mmap(NULL, size, PROT_WRITE, MAP_SHARED, to, 0);
    assert_perror(errno);

#if USE_MADVISE
    errno=0;
    err = madvise(to_mmap, size, MADV_SEQUENTIAL);
    assert_perror(errno);
#endif

    /* copy */
    memcpy(to_mmap, from_mmap, size);

#if WITH_MSYNC
    assert(msync(to_mmap, size, MS_SYNC) >= 0);
#endif
#if WITH_MUNMAP
    assert(munmap(to_mmap, size) >= 0);
#endif

    assert(ftruncate(to, size) >= 0);

    return 0;
}
