#define _POSIX_C_SOURCE 200809L #include /* assert */ #include /* mkdirat, openat */ #include /* mkdirat, openat */ #include /* unlinkat, linkat, close, write, … */ #include /* mkdirat, unlinkat, openat, linkat, … */ #include /* strlen */ #include /* bool */ #include #include /* Napište podprogram ‹rcount›, kterému je předán popisovač otevřené * složky, a který spočítá, kolik je v takto zadaném podstromě * složek (včetně té kořenové). Nezáporná návratová hodnota určuje * počet nalezených složek, -1 indikuje systémovou chybu. */ int rcount( int dir_fd ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ následují testy ┄┄┄┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄ */ static void mkdir_or_die( int base_dir, const char *name ) { if ( mkdirat( base_dir, name, 0777 ) == -1 ) err( 2, "creating directory %s", name ); } static int open_or_die( int base_dir, const char *name ) { int fd = openat( base_dir, name, O_RDONLY | O_DIRECTORY ); if ( fd == -1 ) err( 2, "opening directory %s", name ); return fd; } static void unlink_if_exists( int fd, const char *name, bool dir ) { if ( unlinkat( fd, name, 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 void unlink_test_dirs( const char *root ) { int dir = openat( AT_FDCWD, root, O_DIRECTORY ); if ( dir != -1 ) { unlink_if_exists( dir, "a/x", true ); unlink_if_exists( dir, "a/y", true ); unlink_if_exists( dir, "a/loop", false ); unlink_if_exists( dir, "a", true ); unlink_if_exists( dir, "b/x", true ); unlink_if_exists( dir, "b", true ); unlink_if_exists( dir, "c", true ); unlink_if_exists( dir, "d", false ); close_or_warn( dir, root ); } unlink_if_exists( AT_FDCWD, root, true ); } int main( void ) { const char *root_name = "zt.r1_root"; int root_fd, a_fd; unlink_test_dirs( root_name ); mkdir_or_die( AT_FDCWD, root_name ); root_fd = open_or_die( AT_FDCWD, root_name ); mkdir_or_die( root_fd, "a" ); mkdir_or_die( root_fd, "a/x" ); mkdir_or_die( root_fd, "a/y" ); mkdir_or_die( root_fd, "b" ); mkdir_or_die( root_fd, "b/x" ); mkdir_or_die( root_fd, "c" ); a_fd = open_or_die( root_fd, "a" ); assert( rcount( -1 ) == -1 ); assert( rcount( root_fd ) == 7 ); assert( rcount( a_fd ) == 3 ); if ( symlinkat( "b", root_fd, "d" ) == -1 ) err( 2, "creating symlink d" ); assert( rcount( root_fd ) == 7 ); assert( rcount( a_fd ) == 3 ); if ( symlinkat( "..", a_fd, "loop" ) == -1 ) err( 2, "creating symlink a/loop" ); assert( rcount( root_fd ) == 7 ); assert( rcount( a_fd ) == 3 ); close_or_warn( a_fd, "zt.r1_root/a" ); close_or_warn( root_fd, root_name ); unlink_test_dirs( root_name ); return 0; }