• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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