1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * written by Wayne Boyer
5 * Copyright (c) 2013 Markos Chandras
6 * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz>
7 */
8
9 /*\
10 *
11 * [Description]
12 *
13 * Basic getdents() test that checks if directory listing is correct and
14 * complete.
15 *
16 */
17
18 #define _GNU_SOURCE
19
20 #include "tst_test.h"
21 #include "getdents.h"
22
23 #include <stdlib.h>
24
25 static void reset_flags(void);
26 static void check_flags(void);
27 static void set_flag(const char *name);
28
29 static int fd;
30
31 enum entry_type {
32 ENTRY_DIR,
33 ENTRY_FILE,
34 ENTRY_SYMLINK,
35 };
36
37 struct testcase {
38 const char *name;
39 enum entry_type type;
40 int create:1;
41 int found:1;
42 };
43
44 struct testcase testcases[] = {
45 {.name = ".", .create = 0, .type = ENTRY_DIR},
46 {.name = "..", .create = 0, .type = ENTRY_DIR},
47 {.name = "dir", .create = 1, .type = ENTRY_DIR},
48 {.name = "file", .create = 1, .type = ENTRY_FILE},
49 {.name = "symlink", .create = 1, .type = ENTRY_SYMLINK},
50 };
51
52 /*
53 * Big enough for dirp entires + data, the current size returned
54 * by kernel is 128 bytes.
55 */
56 #define BUFSIZE 512
57
58 static void *dirp;
59
run(void)60 static void run(void)
61 {
62 int rval;
63
64 fd = SAFE_OPEN(".", O_RDONLY|O_DIRECTORY);
65
66 rval = tst_getdents(fd, dirp, BUFSIZE);
67
68 if (rval < 0) {
69 if (errno == ENOSYS)
70 tst_brk(TCONF, "syscall not implemented");
71 else {
72 tst_res(TFAIL | TERRNO, "getdents failed unexpectedly");
73 return;
74 }
75 }
76
77 if (rval == 0) {
78 tst_res(TFAIL, "getdents failed - returned end of directory");
79 return;
80 }
81
82 reset_flags();
83
84 void *recp = dirp;
85
86 do {
87 size_t d_reclen = tst_dirp_reclen(recp);
88 const char *d_name = tst_dirp_name(recp);
89
90 set_flag(d_name);
91
92 tst_res(TINFO, "Found '%s'", d_name);
93
94 rval -= d_reclen;
95 recp += d_reclen;
96 } while (rval > 0);
97
98 check_flags();
99
100 SAFE_CLOSE(fd);
101 }
102
reset_flags(void)103 static void reset_flags(void)
104 {
105 size_t i;
106
107 for (i = 0; i < ARRAY_SIZE(testcases); i++)
108 testcases[i].found = 0;
109 }
110
check_flags(void)111 static void check_flags(void)
112 {
113 size_t i;
114 int err = 0;
115
116 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
117 if (!testcases[i].found) {
118 tst_res(TINFO, "Entry '%s' not found", testcases[i].name);
119 err++;
120 }
121 }
122
123 if (err)
124 tst_res(TFAIL, "Some entries not found");
125 else
126 tst_res(TPASS, "All entries found");
127 }
128
set_flag(const char * name)129 static void set_flag(const char *name)
130 {
131 size_t i;
132
133 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
134 if (!strcmp(name, testcases[i].name)) {
135
136 if (testcases[i].found)
137 tst_res(TFAIL, "Duplicate entry %s", name);
138
139 testcases[i].found = 1;
140 return;
141 }
142 }
143
144 tst_res(TFAIL, "Unexpected entry '%s' found", name);
145 }
146
setup(void)147 static void setup(void)
148 {
149 size_t i;
150
151 getdents_info();
152
153 if (!tst_variant) {
154 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
155 if (!testcases[i].create)
156 continue;
157
158 switch (testcases[i].type) {
159 case ENTRY_DIR:
160 SAFE_MKDIR(testcases[i].name, 0777);
161 break;
162 case ENTRY_FILE:
163 SAFE_FILE_PRINTF(testcases[i].name, " ");
164 break;
165 case ENTRY_SYMLINK:
166 SAFE_SYMLINK("nonexistent", testcases[i].name);
167 break;
168 }
169 }
170 }
171 }
172
173 static struct tst_test test = {
174 .needs_tmpdir = 1,
175 .test_all = run,
176 .setup = setup,
177 .bufs = (struct tst_buffers []) {
178 {&dirp, .size = BUFSIZE},
179 {},
180 },
181 .test_variants = TEST_VARIANTS,
182 };
183