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