1 /*- 2 * Copyright (c) 2025 Klara, Inc. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/stat.h> 8 9 #include <dirent.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 15 #include <atf-c.h> 16 17 /* 18 * Create a directory with a single subdirectory. 19 */ 20 static void 21 opendir_prepare(const struct atf_tc *tc) 22 { 23 ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); 24 ATF_REQUIRE_EQ(0, mkdir("dir/subdir", 0755)); 25 } 26 27 /* 28 * Assuming dirp represents the directory created by opendir_prepare(), 29 * verify that readdir() returns what we expected to see there. 30 */ 31 static void 32 opendir_check(const struct atf_tc *tc, DIR *dirp) 33 { 34 struct dirent *ent; 35 36 ATF_REQUIRE((ent = readdir(dirp)) != NULL); 37 ATF_CHECK_EQ(1, ent->d_namlen); 38 ATF_CHECK_STREQ(".", ent->d_name); 39 ATF_CHECK_EQ(DT_DIR, ent->d_type); 40 ATF_REQUIRE((ent = readdir(dirp)) != NULL); 41 ATF_CHECK_EQ(2, ent->d_namlen); 42 ATF_CHECK_STREQ("..", ent->d_name); 43 ATF_CHECK_EQ(DT_DIR, ent->d_type); 44 ATF_REQUIRE((ent = readdir(dirp)) != NULL); 45 ATF_CHECK_EQ(sizeof("subdir") - 1, ent->d_namlen); 46 ATF_CHECK_STREQ("subdir", ent->d_name); 47 ATF_CHECK_EQ(DT_DIR, ent->d_type); 48 ATF_CHECK(readdir(dirp) == NULL); 49 ATF_CHECK(readdir(dirp) == NULL); 50 } 51 52 ATF_TC(opendir_ok); 53 ATF_TC_HEAD(opendir_ok, tc) 54 { 55 atf_tc_set_md_var(tc, "descr", "Open a directory."); 56 } 57 ATF_TC_BODY(opendir_ok, tc) 58 { 59 DIR *dirp; 60 61 opendir_prepare(tc); 62 ATF_REQUIRE((dirp = opendir("dir")) != NULL); 63 opendir_check(tc, dirp); 64 ATF_CHECK_EQ(0, closedir(dirp)); 65 } 66 67 ATF_TC(opendir_fifo); 68 ATF_TC_HEAD(opendir_fifo, tc) 69 { 70 atf_tc_set_md_var(tc, "descr", "Do not hang if given a named pipe."); 71 } 72 ATF_TC_BODY(opendir_fifo, tc) 73 { 74 DIR *dirp; 75 int fd; 76 77 ATF_REQUIRE((fd = mkfifo("fifo", 0644)) >= 0); 78 ATF_REQUIRE_EQ(0, close(fd)); 79 ATF_REQUIRE((dirp = opendir("fifo")) == NULL); 80 ATF_CHECK_EQ(ENOTDIR, errno); 81 } 82 83 ATF_TC(fdopendir_ok); 84 ATF_TC_HEAD(fdopendir_ok, tc) 85 { 86 atf_tc_set_md_var(tc, "descr", 87 "Open a directory from a directory descriptor."); 88 } 89 ATF_TC_BODY(fdopendir_ok, tc) 90 { 91 DIR *dirp; 92 int dd; 93 94 opendir_prepare(tc); 95 ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); 96 ATF_REQUIRE((dirp = fdopendir(dd)) != NULL); 97 opendir_check(tc, dirp); 98 ATF_CHECK_EQ(dd, fdclosedir(dirp)); 99 ATF_CHECK_EQ(0, close(dd)); 100 } 101 102 ATF_TC(fdopendir_ebadf); 103 ATF_TC_HEAD(fdopendir_ebadf, tc) 104 { 105 atf_tc_set_md_var(tc, "descr", 106 "Open a directory from an invalid descriptor."); 107 } 108 ATF_TC_BODY(fdopendir_ebadf, tc) 109 { 110 DIR *dirp; 111 int dd; 112 113 ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); 114 ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); 115 ATF_CHECK_EQ(0, close(dd)); 116 ATF_REQUIRE((dirp = fdopendir(dd)) == NULL); 117 ATF_CHECK_EQ(EBADF, errno); 118 } 119 120 ATF_TC(fdopendir_enotdir); 121 ATF_TC_HEAD(fdopendir_enotdir, tc) 122 { 123 atf_tc_set_md_var(tc, "descr", 124 "Open a directory from a non-directory descriptor."); 125 } 126 ATF_TC_BODY(fdopendir_enotdir, tc) 127 { 128 DIR *dirp; 129 int fd; 130 131 ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0); 132 ATF_REQUIRE((dirp = fdopendir(fd)) == NULL); 133 ATF_CHECK_EQ(ENOTDIR, errno); 134 ATF_CHECK_EQ(0, close(fd)); 135 } 136 137 ATF_TP_ADD_TCS(tp) 138 { 139 ATF_TP_ADD_TC(tp, opendir_ok); 140 ATF_TP_ADD_TC(tp, fdopendir_ok); 141 ATF_TP_ADD_TC(tp, fdopendir_ebadf); 142 ATF_TP_ADD_TC(tp, fdopendir_enotdir); 143 ATF_TP_ADD_TC(tp, opendir_fifo); 144 return (atf_no_error()); 145 } 146