xref: /freebsd/lib/libc/tests/gen/opendir_test.c (revision b5daf675efc746611c7cfcd1fa474b8905064c4b)
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