1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. 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 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __SCCSID("@(#)opendir.c 8.8 (Berkeley) 5/1/95"); 34 #include "namespace.h" 35 #include <sys/param.h> 36 37 #include <dirent.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include "un-namespace.h" 44 45 #include "gen-private.h" 46 #include "telldir.h" 47 48 static DIR * __opendir_common(int, int, bool); 49 50 /* 51 * Open a directory. 52 */ 53 DIR * 54 opendir(const char *name) 55 { 56 57 return (__opendir2(name, DTF_HIDEW|DTF_NODUP)); 58 } 59 60 /* 61 * Open a directory with existing file descriptor. 62 */ 63 DIR * 64 fdopendir(int fd) 65 { 66 67 if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 68 return (NULL); 69 return (__opendir_common(fd, DTF_HIDEW|DTF_NODUP, true)); 70 } 71 72 DIR * 73 __opendir2(const char *name, int flags) 74 { 75 int fd; 76 DIR *dir; 77 int saved_errno; 78 79 if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0) 80 return (NULL); 81 if ((fd = _open(name, 82 O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1) 83 return (NULL); 84 85 dir = __opendir_common(fd, flags, false); 86 if (dir == NULL) { 87 saved_errno = errno; 88 _close(fd); 89 errno = saved_errno; 90 } 91 return (dir); 92 } 93 94 static int 95 opendir_compar(const void *p1, const void *p2) 96 { 97 98 return (strcmp((*(const struct dirent * const *)p1)->d_name, 99 (*(const struct dirent * const *)p2)->d_name)); 100 } 101 102 /* 103 * For a directory at the top of a unionfs stack, the entire directory's 104 * contents are read and cached locally until the next call to rewinddir(). 105 * For the fdopendir() case, the initial seek position must be preserved. 106 * For rewinddir(), the full directory should always be re-read from the 107 * beginning. 108 * 109 * If an error occurs, the existing buffer and state of 'dirp' is left 110 * unchanged. 111 */ 112 bool 113 _filldir(DIR *dirp, bool use_current_pos) 114 { 115 struct dirent **dpv; 116 char *buf, *ddptr, *ddeptr; 117 off_t pos; 118 int fd2, incr, len, n, saved_errno, space; 119 120 len = 0; 121 space = 0; 122 buf = NULL; 123 ddptr = NULL; 124 125 /* 126 * Use the system page size if that is a multiple of DIRBLKSIZ. 127 * Hopefully this can be a big win someday by allowing page 128 * trades to user space to be done by _getdirentries(). 129 */ 130 incr = getpagesize(); 131 if ((incr % DIRBLKSIZ) != 0) 132 incr = DIRBLKSIZ; 133 134 /* 135 * The strategy here is to read all the directory 136 * entries into a buffer, sort the buffer, and 137 * remove duplicate entries by setting the inode 138 * number to zero. 139 * 140 * We reopen the directory because _getdirentries() 141 * on a MNT_UNION mount modifies the open directory, 142 * making it refer to the lower directory after the 143 * upper directory's entries are exhausted. 144 * This would otherwise break software that uses 145 * the directory descriptor for fchdir or *at 146 * functions, such as fts.c. 147 */ 148 if ((fd2 = _openat(dirp->dd_fd, ".", O_RDONLY | O_CLOEXEC)) == -1) 149 return (false); 150 151 if (use_current_pos) { 152 pos = lseek(dirp->dd_fd, 0, SEEK_CUR); 153 if (pos == -1 || lseek(fd2, pos, SEEK_SET) == -1) { 154 saved_errno = errno; 155 _close(fd2); 156 errno = saved_errno; 157 return (false); 158 } 159 } 160 161 do { 162 /* 163 * Always make at least DIRBLKSIZ bytes 164 * available to _getdirentries 165 */ 166 if (space < DIRBLKSIZ) { 167 space += incr; 168 len += incr; 169 buf = reallocf(buf, len); 170 if (buf == NULL) { 171 saved_errno = errno; 172 _close(fd2); 173 errno = saved_errno; 174 return (false); 175 } 176 ddptr = buf + (len - space); 177 } 178 179 n = _getdirentries(fd2, ddptr, space, &dirp->dd_seek); 180 if (n > 0) { 181 ddptr += n; 182 space -= n; 183 } 184 if (n < 0) { 185 saved_errno = errno; 186 _close(fd2); 187 errno = saved_errno; 188 return (false); 189 } 190 } while (n > 0); 191 _close(fd2); 192 193 ddeptr = ddptr; 194 195 /* 196 * There is now a buffer full of (possibly) duplicate 197 * names. 198 */ 199 dirp->dd_buf = buf; 200 201 /* 202 * Go round this loop twice... 203 * 204 * Scan through the buffer, counting entries. 205 * On the second pass, save pointers to each one. 206 * Then sort the pointers and remove duplicate names. 207 */ 208 for (dpv = NULL;;) { 209 n = 0; 210 ddptr = buf; 211 while (ddptr < ddeptr) { 212 struct dirent *dp; 213 214 dp = (struct dirent *) ddptr; 215 if ((long)dp & 03L) 216 break; 217 if ((dp->d_reclen <= 0) || 218 (dp->d_reclen > (ddeptr + 1 - ddptr))) 219 break; 220 ddptr += dp->d_reclen; 221 if (dp->d_fileno) { 222 if (dpv) 223 dpv[n] = dp; 224 n++; 225 } 226 } 227 228 if (dpv) { 229 struct dirent *xp; 230 231 /* 232 * This sort must be stable. 233 */ 234 mergesort(dpv, n, sizeof(*dpv), opendir_compar); 235 236 dpv[n] = NULL; 237 xp = NULL; 238 239 /* 240 * Scan through the buffer in sort order, 241 * zapping the inode number of any 242 * duplicate names. 243 */ 244 for (n = 0; dpv[n]; n++) { 245 struct dirent *dp = dpv[n]; 246 247 if ((xp == NULL) || 248 strcmp(dp->d_name, xp->d_name)) { 249 xp = dp; 250 } else { 251 dp->d_fileno = 0; 252 } 253 if (dp->d_type == DT_WHT && 254 (dirp->dd_flags & DTF_HIDEW)) 255 dp->d_fileno = 0; 256 } 257 258 free(dpv); 259 break; 260 } else { 261 dpv = malloc((n+1) * sizeof(struct dirent *)); 262 if (dpv == NULL) 263 break; 264 } 265 } 266 267 dirp->dd_len = len; 268 dirp->dd_size = ddptr - dirp->dd_buf; 269 return (true); 270 } 271 272 static bool 273 is_unionstack(int fd) 274 { 275 int unionstack; 276 277 unionstack = _fcntl(fd, F_ISUNIONSTACK, 0); 278 if (unionstack != -1) 279 return (unionstack); 280 281 /* 282 * Should not happen unless running on a kernel without the op, 283 * but no use rendering the system useless in such a case. 284 */ 285 return (0); 286 } 287 288 /* 289 * Common routine for opendir(3), __opendir2(3) and fdopendir(3). 290 */ 291 static DIR * 292 __opendir_common(int fd, int flags, bool use_current_pos) 293 { 294 DIR *dirp; 295 int incr; 296 int saved_errno; 297 bool unionstack; 298 299 if ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL) 300 return (NULL); 301 302 dirp->dd_buf = NULL; 303 dirp->dd_fd = fd; 304 dirp->dd_flags = flags; 305 dirp->dd_loc = 0; 306 dirp->dd_lock = NULL; 307 dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR)); 308 LIST_INIT(&dirp->dd_td->td_locq); 309 dirp->dd_td->td_loccnt = 0; 310 dirp->dd_compat_de = NULL; 311 312 /* 313 * Use the system page size if that is a multiple of DIRBLKSIZ. 314 * Hopefully this can be a big win someday by allowing page 315 * trades to user space to be done by _getdirentries(). 316 */ 317 incr = getpagesize(); 318 if ((incr % DIRBLKSIZ) != 0) 319 incr = DIRBLKSIZ; 320 321 /* 322 * Determine whether this directory is the top of a union stack. 323 */ 324 unionstack = false; 325 if (flags & DTF_NODUP) { 326 unionstack = is_unionstack(fd); 327 } 328 329 if (unionstack) { 330 if (!_filldir(dirp, use_current_pos)) 331 goto fail; 332 dirp->dd_flags |= __DTF_READALL; 333 } else { 334 dirp->dd_len = incr; 335 dirp->dd_buf = malloc(dirp->dd_len); 336 if (dirp->dd_buf == NULL) 337 goto fail; 338 if (use_current_pos) { 339 /* 340 * Read the first batch of directory entries 341 * to prime dd_seek. This also checks if the 342 * fd passed to fdopendir() is a directory. 343 */ 344 dirp->dd_size = _getdirentries(dirp->dd_fd, 345 dirp->dd_buf, dirp->dd_len, &dirp->dd_seek); 346 if (dirp->dd_size < 0) { 347 if (errno == EINVAL) 348 errno = ENOTDIR; 349 goto fail; 350 } 351 dirp->dd_flags |= __DTF_SKIPREAD; 352 } else { 353 dirp->dd_size = 0; 354 dirp->dd_seek = 0; 355 } 356 } 357 358 return (dirp); 359 360 fail: 361 saved_errno = errno; 362 free(dirp->dd_buf); 363 free(dirp); 364 errno = saved_errno; 365 return (NULL); 366 } 367