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