1 1.39 christos /* $NetBSD: opendir.c,v 1.39 2014/11/26 16:48:43 christos Exp $ */ 2 1.28 christos 3 1.28 christos /* 4 1.28 christos * Copyright (c) 1983, 1993 5 1.28 christos * The Regents of the University of California. All rights reserved. 6 1.28 christos * 7 1.28 christos * Redistribution and use in source and binary forms, with or without 8 1.28 christos * modification, are permitted provided that the following conditions 9 1.28 christos * are met: 10 1.28 christos * 1. Redistributions of source code must retain the above copyright 11 1.28 christos * notice, this list of conditions and the following disclaimer. 12 1.28 christos * 2. Redistributions in binary form must reproduce the above copyright 13 1.28 christos * notice, this list of conditions and the following disclaimer in the 14 1.28 christos * documentation and/or other materials provided with the distribution. 15 1.28 christos * 3. Neither the name of the University nor the names of its contributors 16 1.28 christos * may be used to endorse or promote products derived from this software 17 1.28 christos * without specific prior written permission. 18 1.28 christos * 19 1.28 christos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.28 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.28 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.28 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.28 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.28 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.28 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.28 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.28 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.28 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.28 christos * SUCH DAMAGE. 30 1.28 christos */ 31 1.28 christos 32 1.28 christos #include <sys/cdefs.h> 33 1.28 christos #if defined(LIBC_SCCS) && !defined(lint) 34 1.28 christos #if 0 35 1.28 christos static char sccsid[] = "@(#)opendir.c 8.7 (Berkeley) 12/10/94"; 36 1.28 christos #else 37 1.39 christos __RCSID("$NetBSD: opendir.c,v 1.39 2014/11/26 16:48:43 christos Exp $"); 38 1.28 christos #endif 39 1.28 christos #endif /* LIBC_SCCS and not lint */ 40 1.1 cgd 41 1.14 jtc #include "namespace.h" 42 1.28 christos #include "reentrant.h" 43 1.30 christos #include "extern.h" 44 1.34 ad 45 1.28 christos #include <sys/param.h> 46 1.28 christos #include <sys/mount.h> 47 1.6 mycroft #include <sys/stat.h> 48 1.5 mycroft 49 1.28 christos #include <assert.h> 50 1.28 christos #include <dirent.h> 51 1.28 christos #include <errno.h> 52 1.28 christos #include <fcntl.h> 53 1.28 christos #include <stdlib.h> 54 1.28 christos #include <string.h> 55 1.28 christos #include <unistd.h> 56 1.28 christos 57 1.31 christos #include "dirent_private.h" 58 1.31 christos 59 1.34 ad static DIR *__opendir_common(int, const char *, int); 60 1.34 ad 61 1.34 ad __weak_alias(fdopendir,_fdopendir) 62 1.34 ad 63 1.28 christos /* 64 1.28 christos * Open a directory. 65 1.28 christos */ 66 1.28 christos DIR * 67 1.31 christos opendir(const char *name) 68 1.28 christos { 69 1.28 christos 70 1.28 christos _DIAGASSERT(name != NULL); 71 1.28 christos 72 1.28 christos return (__opendir2(name, DTF_HIDEW|DTF_NODUP)); 73 1.28 christos } 74 1.28 christos 75 1.28 christos DIR * 76 1.31 christos __opendir2(const char *name, int flags) 77 1.28 christos { 78 1.39 christos DIR *dirp; 79 1.34 ad int fd; 80 1.34 ad 81 1.39 christos if ((fd = open(name, O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_CLOEXEC)) == -1) 82 1.34 ad return NULL; 83 1.39 christos 84 1.39 christos dirp = __opendir_common(fd, name, flags); 85 1.39 christos if (dirp == NULL) { 86 1.39 christos int serrno = errno; 87 1.39 christos (void)close(fd); 88 1.39 christos errno = serrno; 89 1.39 christos } 90 1.39 christos return dirp; 91 1.34 ad } 92 1.34 ad 93 1.34 ad #ifndef __LIBC12_SOURCE__ 94 1.34 ad DIR * 95 1.34 ad _fdopendir(int fd) 96 1.34 ad { 97 1.39 christos struct stat sb; 98 1.39 christos 99 1.39 christos if (fstat(fd, &sb) == -1) 100 1.39 christos return NULL; 101 1.39 christos 102 1.39 christos if (!S_ISDIR(sb.st_mode)) { 103 1.39 christos errno = ENOTDIR; 104 1.39 christos return NULL; 105 1.39 christos } 106 1.39 christos 107 1.39 christos /* This is optional according to POSIX, but a good measure */ 108 1.38 christos if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 109 1.38 christos return NULL; 110 1.34 ad 111 1.34 ad return __opendir_common(fd, NULL, DTF_HIDEW|DTF_NODUP); 112 1.34 ad } 113 1.34 ad #endif 114 1.34 ad 115 1.34 ad static DIR * 116 1.34 ad __opendir_common(int fd, const char *name, int flags) 117 1.34 ad { 118 1.39 christos DIR *dirp; 119 1.28 christos int serrno; 120 1.28 christos struct statvfs sfb; 121 1.37 yamt int error; 122 1.28 christos 123 1.38 christos if ((dirp = malloc(sizeof(*dirp))) == NULL) 124 1.28 christos goto error; 125 1.28 christos dirp->dd_buf = NULL; 126 1.37 yamt dirp->dd_internal = NULL; 127 1.37 yamt #ifdef _REENTRANT 128 1.37 yamt if (__isthreaded) { 129 1.37 yamt if ((dirp->dd_lock = malloc(sizeof(mutex_t))) == NULL) 130 1.37 yamt goto error; 131 1.37 yamt mutex_init((mutex_t *)dirp->dd_lock, NULL); 132 1.37 yamt } 133 1.37 yamt #endif 134 1.28 christos 135 1.28 christos /* 136 1.37 yamt * Tweak flags for the underlying filesystem. 137 1.28 christos */ 138 1.28 christos 139 1.28 christos if (fstatvfs1(fd, &sfb, ST_NOWAIT) < 0) 140 1.28 christos goto error; 141 1.37 yamt if ((flags & DTF_NODUP) != 0) { 142 1.37 yamt if (!strncmp(sfb.f_fstypename, MOUNT_UNION, 143 1.37 yamt sizeof(sfb.f_fstypename)) || 144 1.37 yamt (sfb.f_flag & MNT_UNION) != 0) { 145 1.37 yamt flags |= __DTF_READALL; 146 1.37 yamt } else { 147 1.37 yamt flags &= ~DTF_NODUP; 148 1.28 christos } 149 1.37 yamt } 150 1.37 yamt if (!strncmp(sfb.f_fstypename, MOUNT_NFS, sizeof(sfb.f_fstypename))) { 151 1.37 yamt flags |= __DTF_READALL | __DTF_RETRY_ON_BADCOOKIE; 152 1.28 christos } 153 1.28 christos 154 1.28 christos dirp->dd_flags = flags; 155 1.37 yamt error = _initdir(dirp, fd, name); 156 1.37 yamt if (error) { 157 1.37 yamt errno = error; 158 1.37 yamt goto error; 159 1.37 yamt } 160 1.5 mycroft 161 1.28 christos return (dirp); 162 1.28 christos error: 163 1.28 christos serrno = errno; 164 1.37 yamt if (dirp != NULL) { 165 1.37 yamt #ifdef _REENTRANT 166 1.37 yamt if (__isthreaded) { 167 1.37 yamt mutex_destroy((mutex_t *)dirp->dd_lock); 168 1.37 yamt free(dirp->dd_lock); 169 1.37 yamt } 170 1.37 yamt #endif 171 1.28 christos free(dirp->dd_buf); 172 1.37 yamt } 173 1.37 yamt free(dirp); 174 1.28 christos errno = serrno; 175 1.28 christos return NULL; 176 1.28 christos } 177