]>
git.scottworley.com Git - overonion/blob - reverse_lib.c
1 #define _FILE_OFFSET_BITS 64
11 #include <sys/types.h>
15 static off_t
ceil_div(off_t dividend
, off_t divisor
) {
16 return (dividend
- 1) / divisor
+ 1;
19 void reverse_file(const char* input_filename
, FILE* output_stream
) {
20 const off_t mmap_chunk_size
= 512 << 20;
22 int fd
= open(input_filename
, O_RDONLY
);
23 if (fd
== -1) err(EX_NOINPUT
, "Could not open specified file");
26 if (fstat(fd
, &stats
) == -1) err(EX_NOINPUT
, "Could not stat input");
28 long page_size
= sysconf(_SC_PAGE_SIZE
);
29 off_t num_chunks
= ceil_div(stats
.st_size
, mmap_chunk_size
);
30 for (off_t chunk
= num_chunks
- 1; chunk
>= 0; chunk
--) {
31 off_t start_offset
= chunk
* mmap_chunk_size
;
32 off_t end_offset
= (chunk
+ 1) * mmap_chunk_size
;
33 if (end_offset
> stats
.st_size
) {
34 end_offset
= stats
.st_size
;
36 off_t pages
= ceil_div(end_offset
- start_offset
, page_size
);
37 long map_size
= pages
* page_size
;
38 char *m
= mmap(NULL
, map_size
, PROT_READ
, MAP_SHARED
, fd
, start_offset
);
39 if (m
== MAP_FAILED
) err(EX_NOINPUT
, "Could not mmap chunk %lld of %lld", chunk
, num_chunks
);
41 for (off_t p
= (end_offset
- start_offset
) - 1; p
>= 0; p
--) {
42 if (fputc(m
[p
], output_stream
) == EOF
) errx(EX_IOERR
, "Could not write");
45 if (munmap(m
, map_size
) == -1) err(EX_IOERR
, "Could not unmap chunk %lld of %lld", chunk
, num_chunks
);
48 if (close(fd
) == -1) err(EX_IOERR
, "Could not close input");
51 /* Copy data from input to output until EOF is reached. */
52 static void copy(FILE* input
, FILE* output
) {
56 if (ferror(input
)) errx(EX_IOERR
, "Could not read");
57 if (!feof(input
)) errx(EX_IOERR
, "Unexpected end of file");
60 if (fputc(c
, output
) == EOF
) errx(EX_IOERR
, "Could not write");
64 void reverse_stream(FILE* input_stream
, FILE* output_stream
) {
67 make_temporary_file(&temp_filename
, &temp_file
);
69 copy(input_stream
, temp_file
);
70 if (fclose(temp_file
) != 0) err(EX_IOERR
, "Could not close temporary file");
72 reverse_file(temp_filename
, output_stream
);
74 if (unlink(temp_filename
) == -1) err(EX_IOERR
, "Could not remove temporary file");