#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define OPEN(fd, file, args) \
do{ \
fd = open(file, args); \
if(fd == -1) { \
fprintf(stderr, "Can't open file %s\n", file); \
exit(EXIT_FAILURE); \
} \
}while(0)
#define CLOSE(fd, name) \
do{ \
if(close(fd) == -1) { \
fprintf(stderr, "Cant close file descriptor " name "\n"); \
exit(EXIT_FAILURE); \
} \
}while(0)
#define MMAP(address, length, prot, flags, fd, name) \
do{ \
address = mmap(NULL, length, prot, flags, fd, 0); \
if(address == MAP_FAILED) { \
fprintf(stderr, "Can't do mapping of " name "\n"); \
exit(EXIT_FAILURE); \
} \
}while(0)
#define MUNMAP(start, length, name) \
do{ \
if(munmap(start, length) == -1) { \
fprintf(stderr, "Can't unmap the mapping " name "\n"); \
exit(EXIT_FAILURE); \
} \
}while(0)
#define SIZE stats.st_size
void parseArgs(int, char**);
int main(int argc, char** argv) {
int fd1, fd2;
void *map1, *map2;
struct stat stats;
parseArgs(argc, argv);
OPEN(fd1, argv[1], O_RDONLY);
OPEN(fd2, argv[2], O_RDWR | O_CREAT | O_TRUNC);
if(fstat(fd1, &stats) == -1) {
fprintf(stderr, "Can't stat file %s\n", argv[1]);
exit(EXIT_FAILURE);
}
if(lseek(fd2, SIZE - 1, SEEK_SET) == (off_t)-1) {
fprintf(stderr, "Can't do lseek\n");
exit(EXIT_FAILURE);
}
if(write(fd2, '\0', 1) == -1) {
fprintf(stderr, "Can't write last byte of file %s\n", argv[2]);
switch(errno)
{
case EAGAIN: printf("The file descriptor fd has been marked non-blocking (O_NONBLOCK) and the write would block."); break;
case EBADF: printf("fd is not a valid file descriptor or is not open for writing."); break;
case EFAULT: printf("buf is outside your accessible address space."); break;
case EFBIG: printf("An attempt was made to write a file that exceeds the implementation-defined maximum file size or the process's\
file size limit, or to write at a position past the maximum allowed offset."); break;
case EINTR: printf("The call was interrupted by a signal before any data was written."); break;
case EINVAL: printf("fd is attached to an object which is unsuitable for writing; or the file was opened with the O_DIRECT flag, and\
either the address specified in buf, the value specified in count, or the current file offset is not suitably\
aligned."); break;
case EIO: printf("A low-level I/O error occurred while modifying the inode."); break;
case ENOSPC: printf("The device containing the file referred to by fd has no room for the data."); break;
case EPIPE: printf("fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also\
receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores\
this signal.)"); break;
}
printf("\n");
exit(EXIT_FAILURE);
}
MMAP(map1, SIZE, PROT_READ, MAP_SHARED, fd1, "fd1");
MMAP(map2, SIZE, PROT_WRITE, MAP_SHARED, fd2, "fd2");
memcpy(map2, map1, SIZE);
MUNMAP(map1, SIZE, "map1");
MUNMAP(map2, SIZE, "map2");
CLOSE(fd1, "fd1");
CLOSE(fd2, "fd2");
return EXIT_SUCCESS;
}
void parseArgs(int argc, char** argv) {
if(argc == 3)
return;
printf("Usage: %s SOURCE DEST\n", argv[0]);
exit(EXIT_FAILURE);
}