xref: /freebsd/lib/libc/tests/gen/scandir_blocks_test.c (revision 0a5b763d98b921f921243525ff25a70bbe00cfaa)
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 <fcntl.h>
11 #include <stdlib.h>
12 
13 #include <atf-c.h>
14 
15 static void
scandir_blocks_prepare(const struct atf_tc * tc)16 scandir_blocks_prepare(const struct atf_tc *tc)
17 {
18 	ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
19 	ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755));
20 	ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
21 	ATF_REQUIRE_EQ(0, symlink("file", "dir/link"));
22 	ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755));
23 }
24 
25 static void
scandir_blocks_verify(const struct atf_tc * tc,int n,struct dirent ** namelist)26 scandir_blocks_verify(const struct atf_tc *tc, int n, struct dirent **namelist)
27 {
28 	ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n);
29 	ATF_CHECK_STREQ("link", namelist[0]->d_name);
30 	ATF_CHECK_STREQ("file", namelist[1]->d_name);
31 	ATF_CHECK_STREQ("dir", namelist[2]->d_name);
32 	ATF_CHECK_STREQ("..", namelist[3]->d_name);
33 	ATF_CHECK_STREQ(".", namelist[4]->d_name);
34 }
35 
36 ATF_TC(scandir_b_test);
ATF_TC_HEAD(scandir_b_test,tc)37 ATF_TC_HEAD(scandir_b_test, tc)
38 {
39 	atf_tc_set_md_var(tc, "descr", "Test scandir_b()");
40 }
ATF_TC_BODY(scandir_b_test,tc)41 ATF_TC_BODY(scandir_b_test, tc)
42 {
43 	struct dirent **namelist = NULL;
44 	int i, ret;
45 
46 	scandir_blocks_prepare(tc);
47 	ret = scandir_b("dir", &namelist,
48 	    ^(const struct dirent *ent) {
49 		    return (strcmp(ent->d_name, "skip") != 0);
50 	    },
51 	    ^(const struct dirent **a, const struct dirent **b) {
52 		    return (strcmp((*b)->d_name, (*a)->d_name));
53 	    });
54 	scandir_blocks_verify(tc, ret, namelist);
55 	for (i = 0; i < ret; i++)
56 		free(namelist[i]);
57 	free(namelist);
58 }
59 
60 ATF_TC(fdscandir_b_test);
ATF_TC_HEAD(fdscandir_b_test,tc)61 ATF_TC_HEAD(fdscandir_b_test, tc)
62 {
63 	atf_tc_set_md_var(tc, "descr", "Test fdscandir_b()");
64 }
ATF_TC_BODY(fdscandir_b_test,tc)65 ATF_TC_BODY(fdscandir_b_test, tc)
66 {
67 	struct dirent **namelist = NULL;
68 	int fd, i, ret;
69 
70 	scandir_blocks_prepare(tc);
71 	ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
72 	ret = fdscandir_b(fd, &namelist,
73 	    ^(const struct dirent *ent) {
74 		    return (strcmp(ent->d_name, "skip") != 0);
75 	    },
76 	    ^(const struct dirent **a, const struct dirent **b) {
77 		    return (strcmp((*b)->d_name, (*a)->d_name));
78 	    });
79 	scandir_blocks_verify(tc, ret, namelist);
80 	for (i = 0; i < ret; i++)
81 		free(namelist[i]);
82 	free(namelist);
83 	ATF_REQUIRE_EQ(0, close(fd));
84 }
85 
86 ATF_TC(scandirat_b_test);
ATF_TC_HEAD(scandirat_b_test,tc)87 ATF_TC_HEAD(scandirat_b_test, tc)
88 {
89 	atf_tc_set_md_var(tc, "descr", "Test scandirat_b()");
90 }
ATF_TC_BODY(scandirat_b_test,tc)91 ATF_TC_BODY(scandirat_b_test, tc)
92 {
93 	struct dirent **namelist = NULL;
94 	int fd, i, ret;
95 
96 	scandir_blocks_prepare(tc);
97 	ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0);
98 	ret = scandirat_b(fd, ".", &namelist,
99 	    ^(const struct dirent *ent) {
100 		    return (strcmp(ent->d_name, "skip") != 0);
101 	    },
102 	    ^(const struct dirent **a, const struct dirent **b) {
103 		    return (strcmp((*b)->d_name, (*a)->d_name));
104 	    });
105 	scandir_blocks_verify(tc, ret, namelist);
106 	for (i = 0; i < ret; i++)
107 		free(namelist[i]);
108 	free(namelist);
109 	ATF_REQUIRE_EQ(0, close(fd));
110 }
111 
ATF_TP_ADD_TCS(tp)112 ATF_TP_ADD_TCS(tp)
113 {
114 	ATF_TP_ADD_TC(tp, scandir_b_test);
115 	ATF_TP_ADD_TC(tp, fdscandir_b_test);
116 	ATF_TP_ADD_TC(tp, scandirat_b_test);
117 	return (atf_no_error());
118 }
119