182241ed5SAlan Somers /*-
282241ed5SAlan Somers * SPDX-License-Identifier: BSD-2-Clause
382241ed5SAlan Somers *
482241ed5SAlan Somers * Copyright (c) 2017 Spectra Logic Corporation
582241ed5SAlan Somers * All rights reserved.
682241ed5SAlan Somers *
782241ed5SAlan Somers * Redistribution and use in source and binary forms, with or without
882241ed5SAlan Somers * modification, are permitted provided that the following conditions
982241ed5SAlan Somers * are met:
1082241ed5SAlan Somers * 1. Redistributions of source code must retain the above copyright
1182241ed5SAlan Somers * notice, this list of conditions and the following disclaimer.
1282241ed5SAlan Somers * 2. Redistributions in binary form must reproduce the above copyright
1382241ed5SAlan Somers * notice, this list of conditions and the following disclaimer in the
1482241ed5SAlan Somers * documentation and/or other materials provided with the distribution.
1582241ed5SAlan Somers *
1682241ed5SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1782241ed5SAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1882241ed5SAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1982241ed5SAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2082241ed5SAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2182241ed5SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2282241ed5SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2382241ed5SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2482241ed5SAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2582241ed5SAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2682241ed5SAlan Somers * SUCH DAMAGE.
2782241ed5SAlan Somers */
2882241ed5SAlan Somers
2982241ed5SAlan Somers /*
3082241ed5SAlan Somers * Test cases for operations on DIR objects:
3182241ed5SAlan Somers * opendir, readdir, seekdir, telldir, closedir, etc
3282241ed5SAlan Somers */
3382241ed5SAlan Somers
3482241ed5SAlan Somers #include <dirent.h>
3582241ed5SAlan Somers #include <fcntl.h>
3682241ed5SAlan Somers #include <stdio.h>
3782241ed5SAlan Somers #include <stdlib.h>
3882241ed5SAlan Somers
3982241ed5SAlan Somers #include <atf-c.h>
4082241ed5SAlan Somers
4182241ed5SAlan Somers ATF_TC(telldir_after_seekdir);
ATF_TC_HEAD(telldir_after_seekdir,tc)4282241ed5SAlan Somers ATF_TC_HEAD(telldir_after_seekdir, tc)
4382241ed5SAlan Somers {
4482241ed5SAlan Somers
4582241ed5SAlan Somers atf_tc_set_md_var(tc, "descr", "Calling telldir(3) after seekdir(3) "
4682241ed5SAlan Somers "should return the argument passed to seekdir.");
4782241ed5SAlan Somers }
ATF_TC_BODY(telldir_after_seekdir,tc)4882241ed5SAlan Somers ATF_TC_BODY(telldir_after_seekdir, tc)
4982241ed5SAlan Somers {
5082241ed5SAlan Somers const int NUMFILES = 1000;
5182241ed5SAlan Somers char template[] = "dXXXXXX";
5282241ed5SAlan Somers char *tmpdir;
5382241ed5SAlan Somers int i, dirfd;
5482241ed5SAlan Somers DIR *dirp;
5582241ed5SAlan Somers struct dirent *de;
5682241ed5SAlan Somers long beginning, middle, end, td;
5782241ed5SAlan Somers
5882241ed5SAlan Somers /* Create a temporary directory */
5982241ed5SAlan Somers tmpdir = mkdtemp(template);
6082241ed5SAlan Somers ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp failed");
6182241ed5SAlan Somers dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY);
6282241ed5SAlan Somers ATF_REQUIRE(dirfd > 0);
6382241ed5SAlan Somers
6482241ed5SAlan Somers /*
6582241ed5SAlan Somers * Fill it with files. Must be > 128 to ensure that the directory
6682241ed5SAlan Somers * can't fit within a single page
6782241ed5SAlan Somers */
6882241ed5SAlan Somers for (i = 0; i < NUMFILES; i = i+1) {
6982241ed5SAlan Somers int fd;
7082241ed5SAlan Somers char filename[16];
7182241ed5SAlan Somers
7282241ed5SAlan Somers snprintf(filename, sizeof(filename), "%d", i);
73*f95dfdbeSBrooks Davis fd = openat(dirfd, filename, O_WRONLY | O_CREAT, 0600);
7482241ed5SAlan Somers ATF_REQUIRE(fd > 0);
7582241ed5SAlan Somers close(fd);
7682241ed5SAlan Somers }
7782241ed5SAlan Somers
7882241ed5SAlan Somers /* Get some directory bookmarks in various locations */
7982241ed5SAlan Somers dirp = fdopendir(dirfd);
8082241ed5SAlan Somers ATF_REQUIRE_MSG(dirfd >= 0, "fdopendir failed");
8182241ed5SAlan Somers beginning = telldir(dirp);
8282241ed5SAlan Somers for (i = 0; i < NUMFILES / 2; i = i+1) {
8382241ed5SAlan Somers de = readdir(dirp);
8482241ed5SAlan Somers ATF_REQUIRE_MSG(de != NULL, "readdir failed");
8582241ed5SAlan Somers }
8682241ed5SAlan Somers middle = telldir(dirp);
8782241ed5SAlan Somers for (; i < NUMFILES - 1; i = i+1) {
8882241ed5SAlan Somers de = readdir(dirp);
8982241ed5SAlan Somers ATF_REQUIRE_MSG(de != NULL, "readdir failed");
9082241ed5SAlan Somers }
9182241ed5SAlan Somers end = telldir(dirp);
9282241ed5SAlan Somers
9382241ed5SAlan Somers /*
9482241ed5SAlan Somers * Seekdir to each bookmark, check the telldir after seekdir condition,
9582241ed5SAlan Somers * and check that the bookmark is valid by reading another directory
9682241ed5SAlan Somers * entry.
9782241ed5SAlan Somers */
9882241ed5SAlan Somers
9982241ed5SAlan Somers seekdir(dirp, beginning);
10082241ed5SAlan Somers td = telldir(dirp);
10182241ed5SAlan Somers ATF_CHECK_EQ(beginning, td);
10282241ed5SAlan Somers ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
10382241ed5SAlan Somers
10482241ed5SAlan Somers seekdir(dirp, middle);
10582241ed5SAlan Somers td = telldir(dirp);
10682241ed5SAlan Somers ATF_CHECK_EQ(middle, td);
10782241ed5SAlan Somers ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
10882241ed5SAlan Somers
10982241ed5SAlan Somers seekdir(dirp, end);
11082241ed5SAlan Somers td = telldir(dirp);
11182241ed5SAlan Somers ATF_CHECK_EQ(end, td);
11282241ed5SAlan Somers ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
11382241ed5SAlan Somers
11482241ed5SAlan Somers closedir(dirp);
11582241ed5SAlan Somers }
11682241ed5SAlan Somers
11782241ed5SAlan Somers ATF_TC(telldir_at_end_of_block);
ATF_TC_HEAD(telldir_at_end_of_block,tc)11882241ed5SAlan Somers ATF_TC_HEAD(telldir_at_end_of_block, tc)
11982241ed5SAlan Somers {
12082241ed5SAlan Somers
12182241ed5SAlan 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");
12282241ed5SAlan Somers }
ATF_TC_BODY(telldir_at_end_of_block,tc)12382241ed5SAlan Somers ATF_TC_BODY(telldir_at_end_of_block, tc)
12482241ed5SAlan Somers {
12582241ed5SAlan Somers /* For UFS and ZFS, blocks roll over at 128 directory entries. */
12682241ed5SAlan Somers const int NUMFILES = 129;
12782241ed5SAlan Somers char template[] = "dXXXXXX";
12882241ed5SAlan Somers char *tmpdir;
12982241ed5SAlan Somers int i, dirfd;
13082241ed5SAlan Somers DIR *dirp;
13182241ed5SAlan Somers struct dirent *de;
13282241ed5SAlan Somers long td;
13382241ed5SAlan Somers char last_filename[16];
13482241ed5SAlan Somers
13582241ed5SAlan Somers /* Create a temporary directory */
13682241ed5SAlan Somers tmpdir = mkdtemp(template);
13782241ed5SAlan Somers ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp failed");
13882241ed5SAlan Somers dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY);
13982241ed5SAlan Somers ATF_REQUIRE(dirfd > 0);
14082241ed5SAlan Somers
14182241ed5SAlan Somers /*
14282241ed5SAlan Somers * Fill it with files. Must be > 128 to ensure that the directory
14382241ed5SAlan Somers * can't fit within a single page. The "-2" accounts for "." and ".."
14482241ed5SAlan Somers */
14582241ed5SAlan Somers for (i = 0; i < NUMFILES - 2; i = i+1) {
14682241ed5SAlan Somers int fd;
14782241ed5SAlan Somers char filename[16];
14882241ed5SAlan Somers
14982241ed5SAlan Somers snprintf(filename, sizeof(filename), "%d", i);
150*f95dfdbeSBrooks Davis fd = openat(dirfd, filename, O_WRONLY | O_CREAT, 0600);
15182241ed5SAlan Somers ATF_REQUIRE(fd > 0);
15282241ed5SAlan Somers close(fd);
15382241ed5SAlan Somers }
15482241ed5SAlan Somers
15582241ed5SAlan Somers /* Read all entries within the first page */
15682241ed5SAlan Somers dirp = fdopendir(dirfd);
15782241ed5SAlan Somers ATF_REQUIRE_MSG(dirfd >= 0, "fdopendir failed");
15882241ed5SAlan Somers for (i = 0; i < NUMFILES - 1; i = i + 1)
15982241ed5SAlan Somers ATF_REQUIRE_MSG(readdir(dirp) != NULL, "readdir failed");
16082241ed5SAlan Somers
16182241ed5SAlan Somers /* Call telldir at the end of a page */
16282241ed5SAlan Somers td = telldir(dirp);
16382241ed5SAlan Somers
16482241ed5SAlan Somers /* Read the last entry */
16582241ed5SAlan Somers de = readdir(dirp);
16682241ed5SAlan Somers ATF_REQUIRE_MSG(de != NULL, "readdir failed");
16782241ed5SAlan Somers strlcpy(last_filename, de->d_name, sizeof(last_filename));
16882241ed5SAlan Somers
16982241ed5SAlan Somers /* Seek back to the bookmark. readdir() should return the last entry */
17082241ed5SAlan Somers seekdir(dirp, td);
17182241ed5SAlan Somers de = readdir(dirp);
17282241ed5SAlan Somers ATF_REQUIRE_STREQ_MSG(last_filename, de->d_name,
17382241ed5SAlan Somers "seekdir went to the wrong directory position");
17482241ed5SAlan Somers
17582241ed5SAlan Somers closedir(dirp);
17682241ed5SAlan Somers }
17782241ed5SAlan Somers
17882241ed5SAlan Somers
ATF_TP_ADD_TCS(tp)17982241ed5SAlan Somers ATF_TP_ADD_TCS(tp)
18082241ed5SAlan Somers {
18182241ed5SAlan Somers
18282241ed5SAlan Somers ATF_TP_ADD_TC(tp, telldir_after_seekdir);
18382241ed5SAlan Somers ATF_TP_ADD_TC(tp, telldir_at_end_of_block);
18482241ed5SAlan Somers
18582241ed5SAlan Somers return atf_no_error();
18682241ed5SAlan Somers }
187