1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * written by Wayne Boyer
4 * Copyright (c) 2013 Markos Chandras
5 * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <stdio.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #include "test.h"
29 #include "safe_macros.h"
30 #include "getdents.h"
31
32 static void cleanup(void);
33 static void setup(void);
34
35 static void reset_flags(void);
36 static void check_flags(void);
37 static void set_flag(const char *name);
38
39 char *TCID = "getdents01";
40 int TST_TOTAL = 1;
41
42 static int longsyscall;
43
44 static option_t options[] = {
45 /* -l long option. Tests getdents64 */
46 {"l", &longsyscall, NULL},
47 {NULL, NULL, NULL}
48 };
49
help(void)50 static void help(void)
51 {
52 printf(" -l Test the getdents64 system call\n");
53 }
54
55 enum entry_type {
56 ENTRY_DIR,
57 ENTRY_FILE,
58 ENTRY_SYMLINK,
59 };
60
61 struct testcase {
62 const char *name;
63 enum entry_type type;
64 int create:1;
65 int found:1;
66 };
67
68 struct testcase testcases[] = {
69 {.name = ".", .create = 0, .type = ENTRY_DIR},
70 {.name = "..", .create = 0, .type = ENTRY_DIR},
71 {.name = "dir", .create = 1, .type = ENTRY_DIR},
72 {.name = "file", .create = 1, .type = ENTRY_FILE},
73 {.name = "symlink", .create = 1, .type = ENTRY_SYMLINK},
74 };
75
76 /*
77 * Big enough for dirp entires + data, the current size returned
78 * by kernel is 128 bytes.
79 */
80 #define BUFSIZE 512
81
main(int ac,char ** av)82 int main(int ac, char **av)
83 {
84 int lc;
85 int rval, fd;
86 struct linux_dirent64 *dirp64;
87 struct linux_dirent *dirp;
88 void *buf;
89
90 tst_parse_opts(ac, av, options, &help);
91
92 /* The buffer is allocated to make sure it's suitably aligned */
93 buf = malloc(BUFSIZE);
94
95 if (buf == NULL)
96 tst_brkm(TBROK, NULL, "malloc failed");
97
98 dirp64 = buf;
99 dirp = buf;
100
101 setup();
102
103 for (lc = 0; TEST_LOOPING(lc); lc++) {
104 const char *d_name;
105
106 tst_count = 0;
107
108 if ((fd = open(".", O_RDONLY)) == -1)
109 tst_brkm(TBROK, cleanup, "open of directory failed");
110
111 if (longsyscall)
112 rval = getdents64(fd, dirp64, BUFSIZE);
113 else
114 rval = getdents(fd, dirp, BUFSIZE);
115
116 if (rval < 0) {
117 if (errno == ENOSYS)
118 tst_resm(TCONF, "syscall not implemented");
119 else
120 tst_resm(TFAIL | TERRNO,
121 "getdents failed unexpectedly");
122 continue;
123 }
124
125 if (rval == 0) {
126 tst_resm(TFAIL,
127 "getdents failed - returned end of directory");
128 continue;
129 }
130
131 reset_flags();
132
133 do {
134 size_t d_reclen;
135
136 if (longsyscall) {
137 d_reclen = dirp64->d_reclen;
138 d_name = dirp64->d_name;
139 } else {
140 d_reclen = dirp->d_reclen;
141 d_name = dirp->d_name;
142 }
143
144 set_flag(d_name);
145
146 tst_resm(TINFO, "Found '%s'", d_name);
147
148 rval -= d_reclen;
149
150 if (longsyscall)
151 dirp64 = (void*)dirp64 + d_reclen;
152 else
153 dirp = (void*)dirp + d_reclen;
154
155 } while (rval > 0);
156
157 SAFE_CLOSE(cleanup, fd);
158
159 check_flags();
160 }
161
162 free(buf);
163
164 cleanup();
165 tst_exit();
166 }
167
reset_flags(void)168 static void reset_flags(void)
169 {
170 int i;
171
172 for (i = 0; i < ARRAY_SIZE(testcases); i++)
173 testcases[i].found = 0;
174 }
175
check_flags(void)176 static void check_flags(void)
177 {
178 int i, err = 0;
179
180 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
181 if (!testcases[i].found) {
182 tst_resm(TINFO, "Entry '%s' not found", testcases[i].name);
183 err++;
184 }
185 }
186
187 if (err)
188 tst_resm(TFAIL, "Some entires not found");
189 else
190 tst_resm(TPASS, "All entires found");
191 }
192
set_flag(const char * name)193 static void set_flag(const char *name)
194 {
195 int i;
196
197 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
198 if (!strcmp(name, testcases[i].name)) {
199 testcases[i].found = 1;
200 return;
201 }
202 }
203
204 tst_resm(TFAIL, "Unexpected entry '%s' found", name);
205 }
206
setup(void)207 static void setup(void)
208 {
209 int i;
210
211 tst_sig(NOFORK, DEF_HANDLER, cleanup);
212
213 tst_tmpdir();
214
215 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
216
217 if (!testcases[i].create)
218 continue;
219
220 switch (testcases[i].type) {
221 case ENTRY_DIR:
222 SAFE_MKDIR(cleanup, testcases[i].name, 0777);
223 break;
224 case ENTRY_FILE:
225 SAFE_FILE_PRINTF(cleanup, testcases[i].name, " ");
226 break;
227 case ENTRY_SYMLINK:
228 SAFE_SYMLINK(cleanup, "nonexistent", testcases[i].name);
229 break;
230 }
231 }
232
233 TEST_PAUSE;
234 }
235
cleanup(void)236 static void cleanup(void)
237 {
238 tst_rmdir();
239 }
240