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