#include #include #include #include #include #include #include #include #include // Only BSD derivates define these (including Solaris as tested on pierre) #include #include #define OUTPUT_BUFFER_SIZE 8192 const char usage[] = "Usage: kopfstand [] []\n" " or may be \"-\n for stdin or stdout\n"; const char failed_to_open_input[] = "Failed to open input"; const char failed_to_stat_input[] = "Failed to stat input"; const char failed_to_mmap_input[] = "Failed to mmap input"; const char failed_to_unmap_input[] = "Failed to unmap input"; const char failed_to_open_output[] = "Failed to open output"; const char failed_to_write_output[] = "Failed to write output"; #ifndef EX_USAGE #define EX_USAGE EXIT_FAILURE #define EX_NOINPUT EXIT_FAILURE #define EX_IOERR EXIT_FAILURE #endif #define EVER 23 int main ( int argc, const char ** argv ) { int input_fd; int output_fd; ssize_t output_index; uint8_t output_buffer[OUTPUT_BUFFER_SIZE]; uintptr_t input_index; struct stat input_stat; off_t input_size; if ( argc > 3 ) // to many command line parameters { fputs( usage, stderr ); return EX_USAGE; } // if there is a source other than stdin open it if ( argc > 1 && strcmp( "-", argv[1] ) ) { close( 0 ); input_fd = open( argv[1], O_RDONLY ); if ( input_fd == -1 ) { perror( failed_to_open_input ); return EX_NOINPUT; } assert( input_fd == 0 ); } else { input_fd = 0; } // mmap need's to know the input size if ( fstat( input_fd, &input_stat ) ) { perror( failed_to_stat_input ); return EX_IOERR; } input_size = input_stat.st_size; assert( input_size >= 0 ); // off_t is signed // try to map the complete input this can fail if // - the input_fd refences to a filetype which couldn't be mmapped // - the file is to big for your crappy operating system // - get a 64 bit cpu & os, try again uint8_t * input_map = mmap( NULL, input_size, PROT_READ, MAP_PRIVATE, input_fd, 0 ); if ( (intptr_t)input_map == -1 ) { perror( failed_to_mmap_input ); return EX_IOERR; } // if there is a destination other than stdout open it if ( argc > 2 && strcmp( "-", argv[2] ) ) { close( 1 ); output_fd = open( argv[2], O_CREAT | O_WRONLY | O_TRUNC ); if ( input_fd == -1 ) { perror( failed_to_open_output ); if ( munmap( input_map, input_size ) ) { perror( failed_to_unmap_input ); } } assert( output_fd == 1 ); } else { output_fd = 1; } // while there is input left for ( input_index = input_size; input_index ; ) { ssize_t delta, written = 0; // reverse one block of at most OUTPUT_BUFFER_SIZE bytes into output_buffer for ( output_index = 0; output_index < sizeof(output_buffer) && input_index; ) output_buffer[output_index++] = input_map[--input_index]; // c can be either correct or readable do { // output_fd may be a non blocking socket (worst case). delta = write( output_fd, output_buffer, output_index ); if ( delta < 0 ) // write failed. kill you're self. { perror( failed_to_write_output ); if ( munmap( output_buffer, input_size ) ) { perror( failed_to_unmap_input ); } return EX_IOERR; } written += delta; } while ( output_index != written ); } return EXIT_SUCCESS; }