#define _POSIX_C_SOURCE 200809L #include /* mkdirat, openat */ #include /* unlinkat, close, write */ #include /* mkdirat, unlinkat, openat, linkat */ #include /* strlen */ #include /* free, malloc, calloc */ #include /* strncpy */ #include /* bool */ #include #include #include /* Váš úkol v této přípravě je přímočarý – na vstupu dostanete * popisovač otevřené složky, ze kterého vytvoříte zřetězeny seznam * jmen. Jména budou uložena v dynamicky alokovaných polích vhodné * velikosti. Výsledkem je nulový ukazatel, dojde-li během * zpracování složky k chybě, nebo ukazatel na hlavu sestaveného * seznamu. */ struct name_list { char *name; struct name_list *next; }; struct name_list *list( int real_dir_fd ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ následují testy ┄┄┄┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄ */ static int create_and_open_dir( int base_dir, const char *name ) { if ( mkdirat( base_dir, name, 0777 ) == -1 ) err( 2, "creating directory %s", name ); int fd = openat( base_dir, name, O_RDONLY | O_DIRECTORY, 0777 ); if ( fd == -1 ) err( 2, "opening directory %s", name ); return fd; } static void unlink_if_exists( int fd, const char *name, bool is_dir ) { if ( unlinkat( fd, name, is_dir ? AT_REMOVEDIR : 0 ) == -1 && errno != ENOENT ) err( 2, "unlinking %s", name ); } static void close_or_warn( int fd, const char *name ) { if ( close( fd ) == -1 ) warn( "closing %s", name ); } static int create_file( int dir_fd, const char *name ) { int fd; if ( ( fd = openat( dir_fd, name, O_CREAT | O_TRUNC | O_RDWR, 0666 ) ) == -1 ) err( 2, "creating %s", name ); return fd; } static void write_file( int dir, const char *name, const char *str ) { int fd = create_file( dir, name ); if ( write( fd, str, strlen( str ) ) == -1 ) err( 2, "writing file %s", name ); close_or_warn( fd, name ); } static bool contains( struct name_list *node, const char *name ) { while ( node != NULL ) { if ( strcmp( node->name, name ) == 0 ) return true; node = node->next; } return false; } static void check_content( struct name_list *node, const char **names, int size ) { if ( node == NULL ) { assert( size == 0 ); return; } for ( int i = 0; i < size; ++i ) assert( contains( node, names[ i ] ) ); } static void cleanup( struct name_list *head ) { while ( head != NULL ) { free( head->name ); struct name_list *tmp = head->next; free( head ); head = tmp; } } static void unlink_test_files() { int dir1 = openat( AT_FDCWD, "zt.p3_test_dir1", O_DIRECTORY ); if ( dir1 != -1 ) { const char *names[] = { "zt.p3_a", "zt.p3_b", "zt.p3_c", "zt.p3_d", "zt.p3_e" }; for ( int i = 0; i < 5; ++i ) unlink_if_exists( dir1, names[ i ], false ); close( dir1 ); } unlink_if_exists( AT_FDCWD, "zt.p3_test_dir1", true ); } int main() { unlink_test_files(); assert( list( -1 ) == NULL ); int dir1 = create_and_open_dir( AT_FDCWD, "zt.p3_test_dir1" ); const char *in_empty[] = { ".", ".." }; struct name_list *result = list( dir1 ); check_content( result, in_empty, 2 ); cleanup( result ); const char *names[] = { ".", "..", "zt.p3_a", "zt.p3_b", "zt.p3_c", "zt.p3_d", "zt.p3_e" }; const char *contents[] = { "Nobody said it was easy", "It's such a shame for us to part", "Nobody said it was easy", "No one ever said it would be this hard", "Oh, take me back to the start" }; for ( int i = 2; i < 7; ++i ) write_file( dir1, names[ i ], contents[ i - 2 ] ); result = list( dir1 ); check_content( result, names, 7 ); cleanup( result ); close_or_warn( dir1, "zt.p3_test_dir1" ); unlink_test_files(); return 0; }