xref: /freebsd/lib/libc/tests/gen/dir2_test.c (revision 82241ed55ce11de0aaf52d62728f3ef80f814ae7)
1*82241ed5SAlan Somers /*-
2*82241ed5SAlan Somers  * SPDX-License-Identifier: BSD-2-Clause
3*82241ed5SAlan Somers  *
4*82241ed5SAlan Somers  * Copyright (c) 2017 Spectra Logic Corporation
5*82241ed5SAlan Somers  * All rights reserved.
6*82241ed5SAlan Somers  *
7*82241ed5SAlan Somers  * Redistribution and use in source and binary forms, with or without
8*82241ed5SAlan Somers  * modification, are permitted provided that the following conditions
9*82241ed5SAlan Somers  * are met:
10*82241ed5SAlan Somers  * 1. Redistributions of source code must retain the above copyright
11*82241ed5SAlan Somers  *    notice, this list of conditions and the following disclaimer.
12*82241ed5SAlan Somers  * 2. Redistributions in binary form must reproduce the above copyright
13*82241ed5SAlan Somers  *    notice, this list of conditions and the following disclaimer in the
14*82241ed5SAlan Somers  *    documentation and/or other materials provided with the distribution.
15*82241ed5SAlan Somers  *
16*82241ed5SAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*82241ed5SAlan Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*82241ed5SAlan Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*82241ed5SAlan Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*82241ed5SAlan Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*82241ed5SAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*82241ed5SAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*82241ed5SAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*82241ed5SAlan Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*82241ed5SAlan Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*82241ed5SAlan Somers  * SUCH DAMAGE.
27*82241ed5SAlan Somers  */
28*82241ed5SAlan Somers 
29*82241ed5SAlan Somers /*
30*82241ed5SAlan Somers  * Test cases for operations on DIR objects:
31*82241ed5SAlan Somers  * opendir, readdir, seekdir, telldir, closedir, etc
32*82241ed5SAlan Somers  */
33*82241ed5SAlan Somers 
34*82241ed5SAlan Somers #include <sys/cdefs.h>
35*82241ed5SAlan Somers __FBSDID("$FreeBSD$");
36*82241ed5SAlan Somers 
37*82241ed5SAlan Somers #include <dirent.h>
38*82241ed5SAlan Somers #include <fcntl.h>
39*82241ed5SAlan Somers #include <stdio.h>
40*82241ed5SAlan Somers #include <stdlib.h>
41*82241ed5SAlan Somers 
42*82241ed5SAlan Somers #include <atf-c.h>
43*82241ed5SAlan Somers 
44*82241ed5SAlan Somers ATF_TC(telldir_after_seekdir);
45*82241ed5SAlan Somers ATF_TC_HEAD(telldir_after_seekdir, tc)
46*82241ed5SAlan Somers {
47*82241ed5SAlan Somers 
48*82241ed5SAlan Somers 	atf_tc_set_md_var(tc, "descr", "Calling telldir(3) after seekdir(3) "
49*82241ed5SAlan Somers 	    "should return the argument passed to seekdir.");
50*82241ed5SAlan Somers }
51*82241ed5SAlan Somers ATF_TC_BODY(telldir_after_seekdir, tc)
52*82241ed5SAlan Somers {
53*82241ed5SAlan Somers 	const int NUMFILES = 1000;
54*82241ed5SAlan Somers 	char template[] = "dXXXXXX";
55*82241ed5SAlan Somers 	char *tmpdir;
56*82241ed5SAlan Somers 	int i, dirfd;
57*82241ed5SAlan Somers 	DIR *dirp;
58*82241ed5SAlan Somers 	struct dirent *de;
59*82241ed5SAlan Somers 	long beginning, middle, end, td;
60*82241ed5SAlan Somers 
61*82241ed5SAlan Somers 	/* Create a temporary directory */
62*82241ed5SAlan Somers 	tmpdir = mkdtemp(template);
63*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp failed");
64*82241ed5SAlan Somers 	dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY);
65*82241ed5SAlan Somers 	ATF_REQUIRE(dirfd > 0);
66*82241ed5SAlan Somers 
67*82241ed5SAlan Somers 	/*
68*82241ed5SAlan Somers 	 * Fill it with files.  Must be > 128 to ensure that the directory
69*82241ed5SAlan Somers 	 * can't fit within a single page
70*82241ed5SAlan Somers 	 */
71*82241ed5SAlan Somers 	for (i = 0; i < NUMFILES; i = i+1) {
72*82241ed5SAlan Somers 		int fd;
73*82241ed5SAlan Somers 		char filename[16];
74*82241ed5SAlan Somers 
75*82241ed5SAlan Somers 		snprintf(filename, sizeof(filename), "%d", i);
76*82241ed5SAlan Somers 		fd = openat(dirfd, filename, O_WRONLY | O_CREAT);
77*82241ed5SAlan Somers 		ATF_REQUIRE(fd > 0);
78*82241ed5SAlan Somers 		close(fd);
79*82241ed5SAlan Somers 	}
80*82241ed5SAlan Somers 
81*82241ed5SAlan Somers 	/* Get some directory bookmarks in various locations */
82*82241ed5SAlan Somers 	dirp = fdopendir(dirfd);
83*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(dirfd >= 0, "fdopendir failed");
84*82241ed5SAlan Somers 	beginning = telldir(dirp);
85*82241ed5SAlan Somers 	for (i = 0; i < NUMFILES / 2; i = i+1) {
86*82241ed5SAlan Somers 		de = readdir(dirp);
87*82241ed5SAlan Somers 		ATF_REQUIRE_MSG(de != NULL, "readdir failed");
88*82241ed5SAlan Somers 	}
89*82241ed5SAlan Somers 	middle = telldir(dirp);
90*82241ed5SAlan Somers 	for (; i < NUMFILES - 1; i = i+1) {
91*82241ed5SAlan Somers 		de = readdir(dirp);
92*82241ed5SAlan Somers 		ATF_REQUIRE_MSG(de != NULL, "readdir failed");
93*82241ed5SAlan Somers 	}
94*82241ed5SAlan Somers 	end = telldir(dirp);
95*82241ed5SAlan Somers 
96*82241ed5SAlan Somers 	/*
97*82241ed5SAlan Somers 	 * Seekdir to each bookmark, check the telldir after seekdir condition,
98*82241ed5SAlan Somers 	 * and check that the bookmark is valid by reading another directory
99*82241ed5SAlan Somers 	 * entry.
100*82241ed5SAlan Somers 	 */
101*82241ed5SAlan Somers 
102*82241ed5SAlan Somers 	seekdir(dirp, beginning);
103*82241ed5SAlan Somers 	td = telldir(dirp);
104*82241ed5SAlan Somers 	ATF_CHECK_EQ(beginning, td);
105*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
106*82241ed5SAlan Somers 
107*82241ed5SAlan Somers 	seekdir(dirp, middle);
108*82241ed5SAlan Somers 	td = telldir(dirp);
109*82241ed5SAlan Somers 	ATF_CHECK_EQ(middle, td);
110*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
111*82241ed5SAlan Somers 
112*82241ed5SAlan Somers 	seekdir(dirp, end);
113*82241ed5SAlan Somers 	td = telldir(dirp);
114*82241ed5SAlan Somers 	ATF_CHECK_EQ(end, td);
115*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
116*82241ed5SAlan Somers 
117*82241ed5SAlan Somers 	closedir(dirp);
118*82241ed5SAlan Somers }
119*82241ed5SAlan Somers 
120*82241ed5SAlan Somers ATF_TC(telldir_at_end_of_block);
121*82241ed5SAlan Somers ATF_TC_HEAD(telldir_at_end_of_block, tc)
122*82241ed5SAlan Somers {
123*82241ed5SAlan Somers 
124*82241ed5SAlan Somers 	atf_tc_set_md_var(tc, "descr", "Calling telldir(3) after readdir(3) read the last entry in the block should return a valid location");
125*82241ed5SAlan Somers }
126*82241ed5SAlan Somers ATF_TC_BODY(telldir_at_end_of_block, tc)
127*82241ed5SAlan Somers {
128*82241ed5SAlan Somers 	/* For UFS and ZFS, blocks roll over at 128 directory entries.  */
129*82241ed5SAlan Somers 	const int NUMFILES = 129;
130*82241ed5SAlan Somers 	char template[] = "dXXXXXX";
131*82241ed5SAlan Somers 	char *tmpdir;
132*82241ed5SAlan Somers 	int i, dirfd;
133*82241ed5SAlan Somers 	DIR *dirp;
134*82241ed5SAlan Somers 	struct dirent *de;
135*82241ed5SAlan Somers 	long td;
136*82241ed5SAlan Somers 	char last_filename[16];
137*82241ed5SAlan Somers 
138*82241ed5SAlan Somers 	/* Create a temporary directory */
139*82241ed5SAlan Somers 	tmpdir = mkdtemp(template);
140*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp failed");
141*82241ed5SAlan Somers 	dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY);
142*82241ed5SAlan Somers 	ATF_REQUIRE(dirfd > 0);
143*82241ed5SAlan Somers 
144*82241ed5SAlan Somers 	/*
145*82241ed5SAlan Somers 	 * Fill it with files.  Must be > 128 to ensure that the directory
146*82241ed5SAlan Somers 	 * can't fit within a single page.  The "-2" accounts for "." and ".."
147*82241ed5SAlan Somers 	 */
148*82241ed5SAlan Somers 	for (i = 0; i < NUMFILES - 2; i = i+1) {
149*82241ed5SAlan Somers 		int fd;
150*82241ed5SAlan Somers 		char filename[16];
151*82241ed5SAlan Somers 
152*82241ed5SAlan Somers 		snprintf(filename, sizeof(filename), "%d", i);
153*82241ed5SAlan Somers 		fd = openat(dirfd, filename, O_WRONLY | O_CREAT);
154*82241ed5SAlan Somers 		ATF_REQUIRE(fd > 0);
155*82241ed5SAlan Somers 		close(fd);
156*82241ed5SAlan Somers 	}
157*82241ed5SAlan Somers 
158*82241ed5SAlan Somers 	/* Read all entries within the first page */
159*82241ed5SAlan Somers 	dirp = fdopendir(dirfd);
160*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(dirfd >= 0, "fdopendir failed");
161*82241ed5SAlan Somers 	for (i = 0; i < NUMFILES - 1; i = i + 1)
162*82241ed5SAlan Somers 		ATF_REQUIRE_MSG(readdir(dirp) != NULL, "readdir failed");
163*82241ed5SAlan Somers 
164*82241ed5SAlan Somers 	/* Call telldir at the end of a page */
165*82241ed5SAlan Somers 	td = telldir(dirp);
166*82241ed5SAlan Somers 
167*82241ed5SAlan Somers 	/* Read the last entry */
168*82241ed5SAlan Somers 	de = readdir(dirp);
169*82241ed5SAlan Somers 	ATF_REQUIRE_MSG(de != NULL, "readdir failed");
170*82241ed5SAlan Somers 	strlcpy(last_filename, de->d_name, sizeof(last_filename));
171*82241ed5SAlan Somers 
172*82241ed5SAlan Somers 	/* Seek back to the bookmark. readdir() should return the last entry */
173*82241ed5SAlan Somers 	seekdir(dirp, td);
174*82241ed5SAlan Somers 	de = readdir(dirp);
175*82241ed5SAlan Somers 	ATF_REQUIRE_STREQ_MSG(last_filename, de->d_name,
176*82241ed5SAlan Somers 			"seekdir went to the wrong directory position");
177*82241ed5SAlan Somers 
178*82241ed5SAlan Somers 	closedir(dirp);
179*82241ed5SAlan Somers }
180*82241ed5SAlan Somers 
181*82241ed5SAlan Somers 
182*82241ed5SAlan Somers ATF_TP_ADD_TCS(tp)
183*82241ed5SAlan Somers {
184*82241ed5SAlan Somers 
185*82241ed5SAlan Somers 	ATF_TP_ADD_TC(tp, telldir_after_seekdir);
186*82241ed5SAlan Somers 	ATF_TP_ADD_TC(tp, telldir_at_end_of_block);
187*82241ed5SAlan Somers 
188*82241ed5SAlan Somers 	return atf_no_error();
189*82241ed5SAlan Somers }
190