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