#define _POSIX_C_SOURCE 200809L #include /* assert */ /* Napište podprogram ‹select_records›, který vykopíruje pevně velké * záznamy ze zadaného souboru, podle zadaného klíče. Vstup je * obyčejný soubor – není-li možné ho namapovat do paměti, můžete to * považovat za fatální chybu. * * Parametry: * * • ‹fd_in› – popisovač souboru, ze kterého budeme vybírat, * • ‹fd_out› – popisovač souboru, do kterého budeme zapisovat, * • ‹len› – velikost záznamu v bajtech, * • ‹key› – zřetězený seznam pozic, které se budou kontrolovat. * * Záznamy kopírujte pouze tehdy, mají-li na každé klíčové pozici * nenulový bajt. Pořadí záznamů ze vstupního souboru zachovejte. * Pozor, ‹fd_out› nemusí být obyčejný soubor. Klíčové pozice jsou * popsané tímto typem: */ struct key_list { int position; struct key_list *next; }; /* Návratová hodnota 0 znamená úspěch, hodnota -1, že při zpracování * souboru nastala systémová chyba. */ int select_records( int fd_in, int fd_out, int len, struct key_list *key ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ následují testy ┄┄┄┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄ */ #include /* err, warn, warnx */ #include /* write, read */ #include /* openat */ #include /* uint8_t */ #include /* errno */ #include /* memcmp */ const char *file_in = "zt.r2_in"; const char *file_out = "zt.r2_out"; static void unlink_if_exists( const char *file ) { if ( unlink( file ) == -1 && errno != ENOENT ) err( 2, "unlink" ); } static void close_or_warn( int fd, const char *name ) { if ( close( fd ) == -1 ) warn( "closing %s", name ); } static int open_or_die( const char *name, int oflag ) { int fd = openat( AT_FDCWD, name, oflag, 0644 ); if ( fd == -1 ) err( 2, "opening %s", name ); return fd; } static int create_file( const char *name ) { unlink_if_exists( name ); int fd; if ( ( fd = openat( AT_FDCWD, name, O_CREAT | O_TRUNC | O_WRONLY, 0666 ) ) == -1 ) err( 2, "creating %s", name ); return fd; } static void write_file( const char *name, const uint8_t *data, int size ) { int fd = create_file( name ); if ( write( fd, data, size ) == -1 ) err( 2, "writing file %s", name ); close_or_warn( fd, name ); } static void close2_or_warn( const int fd1, const char *name1, const int fd2, const char *name2 ) { close_or_warn( fd1, name1 ); close_or_warn( fd2, name2 ); } static int cmp_output( const char *name, const unsigned char *expected, int size ) { char buffer[ 256 ]; int fd = open( name, O_RDONLY ); if ( fd == -1 ) err( 2, "opening %s", name ); int rv = 0; int out_size = 0; while ( ( rv = read( fd, buffer, sizeof( buffer ) ) ) > 0 ) { if ( out_size + rv > size ) { rv = -1; goto end; } if ( memcmp( expected + out_size, buffer, rv ) != 0 ) { rv = -1; goto end; } out_size += rv; } end: close_or_warn( fd, name ); return out_size != size ? -1 : rv; } static void prepare_key( struct key_list *kl, const int *positions, const int size ) { for (int i = 0; i < size; ++i) { kl[ i ].position = positions[ i ]; kl[ i ].next = kl + i + 1; } kl[ size - 1 ].next = NULL; } int main( void ) { unlink_if_exists( file_in ); unlink_if_exists( file_out ); struct key_list kl[ 20 ] = { 0 }; int fd_in, fd_out; uint8_t data_1[] = { 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00 }; int positions_1[] = { 1, 2, 0 }; prepare_key( (void *) &kl, positions_1, 3 ); write_file( file_in, data_1, sizeof( data_1 ) ); fd_in = open_or_die( file_in, O_RDONLY ); fd_out = open_or_die( file_out, O_WRONLY | O_CREAT | O_TRUNC ); assert( select_records( fd_in, fd_out, 4, kl ) == 0 ); close2_or_warn( fd_in, file_in, fd_out, file_out ); assert( cmp_output( file_out, data_1 + 8, 4 ) == 0 ); return 0; }