Home | History | Annotate | Download | only in getdents
      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 (at) 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 
     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 
     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 
    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 
    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 
    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 
    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 
    236 static void cleanup(void)
    237 {
    238 	tst_rmdir();
    239 }
    240