• 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 #define _GNU_SOURCE
23 #include <stdio.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 
29 #include "test.h"
30 #include "safe_macros.h"
31 #include "getdents.h"
32 
33 static void cleanup(void);
34 static void setup(void);
35 
36 static void reset_flags(void);
37 static void check_flags(void);
38 static void set_flag(const char *name);
39 
40 char *TCID = "getdents01";
41 int TST_TOTAL = 1;
42 
43 static int longsyscall;
44 
45 static option_t options[] = {
46 		/* -l long option. Tests getdents64 */
47 		{"l", &longsyscall, NULL},
48 		{NULL, NULL, NULL}
49 };
50 
help(void)51 static void help(void)
52 {
53 	printf("  -l      Test the getdents64 system call\n");
54 }
55 
56 enum entry_type {
57 	ENTRY_DIR,
58 	ENTRY_FILE,
59 	ENTRY_SYMLINK,
60 };
61 
62 struct testcase {
63 	const char *name;
64 	enum entry_type type;
65 	int create:1;
66 	int found:1;
67 };
68 
69 struct testcase testcases[] = {
70 	{.name = ".",       .create = 0, .type = ENTRY_DIR},
71 	{.name = "..",      .create = 0, .type = ENTRY_DIR},
72 	{.name = "dir",     .create = 1, .type = ENTRY_DIR},
73 	{.name = "file",    .create = 1, .type = ENTRY_FILE},
74 	{.name = "symlink", .create = 1, .type = ENTRY_SYMLINK},
75 };
76 
77 /*
78  * Big enough for dirp entires + data, the current size returned
79  * by kernel is 128 bytes.
80  */
81 #define BUFSIZE 512
82 
main(int ac,char ** av)83 int main(int ac, char **av)
84 {
85 	int lc;
86 	int rval, fd;
87 	struct linux_dirent64 *dirp64;
88 	struct linux_dirent *dirp;
89 	void *buf;
90 
91 	tst_parse_opts(ac, av, options, &help);
92 
93 	/* The buffer is allocated to make sure it's suitably aligned */
94 	buf = malloc(BUFSIZE);
95 
96 	if (buf == NULL)
97 		tst_brkm(TBROK, NULL, "malloc failed");
98 
99 	dirp64 = buf;
100 	dirp = buf;
101 
102 	setup();
103 
104 	for (lc = 0; TEST_LOOPING(lc); lc++) {
105 		const char *d_name;
106 
107 		tst_count = 0;
108 
109 		if ((fd = open(".", O_RDONLY)) == -1)
110 			tst_brkm(TBROK, cleanup, "open of directory failed");
111 
112 		if (longsyscall)
113 			rval = getdents64(fd, dirp64, BUFSIZE);
114 		else
115 			rval = getdents(fd, dirp, BUFSIZE);
116 
117 		if (rval < 0) {
118 			if (errno == ENOSYS)
119 				tst_resm(TCONF, "syscall not implemented");
120 			else
121 				tst_resm(TFAIL | TERRNO,
122 				         "getdents failed unexpectedly");
123 			continue;
124 		}
125 
126 		if (rval == 0) {
127 			tst_resm(TFAIL,
128 				 "getdents failed - returned end of directory");
129 			continue;
130 		}
131 
132 		reset_flags();
133 
134 		do {
135 			size_t d_reclen;
136 
137 			if (longsyscall) {
138 				d_reclen = dirp64->d_reclen;
139 				d_name = dirp64->d_name;
140 			} else {
141 				d_reclen = dirp->d_reclen;
142 				d_name = dirp->d_name;
143 			}
144 
145 			set_flag(d_name);
146 
147 			tst_resm(TINFO, "Found '%s'", d_name);
148 
149 			rval -= d_reclen;
150 
151 			if (longsyscall)
152 				dirp64 = (void*)dirp64 + d_reclen;
153 			else
154 				dirp = (void*)dirp + d_reclen;
155 
156 		} while (rval > 0);
157 
158 		SAFE_CLOSE(cleanup, fd);
159 
160 		check_flags();
161 	}
162 
163 	free(buf);
164 
165 	cleanup();
166 	tst_exit();
167 }
168 
reset_flags(void)169 static void reset_flags(void)
170 {
171 	int i;
172 
173 	for (i = 0; i < ARRAY_SIZE(testcases); i++)
174 		testcases[i].found = 0;
175 }
176 
check_flags(void)177 static void check_flags(void)
178 {
179 	int i, err = 0;
180 
181 	for (i = 0; i < ARRAY_SIZE(testcases); i++) {
182 		if (!testcases[i].found) {
183 			tst_resm(TINFO, "Entry '%s' not found", testcases[i].name);
184 			err++;
185 		}
186 	}
187 
188 	if (err)
189 		tst_resm(TFAIL, "Some entires not found");
190 	else
191 		tst_resm(TPASS, "All entires found");
192 }
193 
set_flag(const char * name)194 static void set_flag(const char *name)
195 {
196 	int i;
197 
198 	for (i = 0; i < ARRAY_SIZE(testcases); i++) {
199 		if (!strcmp(name, testcases[i].name)) {
200 			testcases[i].found = 1;
201 			return;
202 		}
203 	}
204 
205 	tst_resm(TFAIL, "Unexpected entry '%s' found", name);
206 }
207 
setup(void)208 static void setup(void)
209 {
210 	int i;
211 
212 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
213 
214 	tst_tmpdir();
215 
216 	for (i = 0; i < ARRAY_SIZE(testcases); i++) {
217 
218 		if (!testcases[i].create)
219 			continue;
220 
221 		switch (testcases[i].type) {
222 		case ENTRY_DIR:
223 			SAFE_MKDIR(cleanup, testcases[i].name, 0777);
224 		break;
225 		case ENTRY_FILE:
226 			SAFE_FILE_PRINTF(cleanup, testcases[i].name, " ");
227 		break;
228 		case ENTRY_SYMLINK:
229 			SAFE_SYMLINK(cleanup, "nonexistent", testcases[i].name);
230 		break;
231 		}
232 	}
233 
234 	TEST_PAUSE;
235 }
236 
cleanup(void)237 static void cleanup(void)
238 {
239 	tst_rmdir();
240 }
241