Back to index

glibc  2.9
opendir.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991-1996,98,2000-2003,2005,2007
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <limits.h>
00022 #include <stddef.h>
00023 #include <stdlib.h>
00024 #include <dirent.h>
00025 #include <fcntl.h>
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #include <unistd.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 
00032 #include <dirstream.h>
00033 #include <not-cancel.h>
00034 #include <kernel-features.h>
00035 
00036 
00037 /* opendir() must not accidentally open something other than a directory.
00038    Some OS's have kernel support for that, some don't.  In the worst
00039    case we have to stat() before the open() AND fstat() after.
00040 
00041    We have to test at runtime for kernel support since libc may have
00042    been compiled with different headers to the kernel it's running on.
00043    This test can't be done reliably in the general case.  We'll use
00044    /dev/null, which if it's not a device lots of stuff will break, as
00045    a guinea pig.  It may be missing in chroot environments, so we
00046    make sure to fail safe. */
00047 #ifdef O_DIRECTORY
00048 # ifdef O_DIRECTORY_WORKS
00049 #  define o_directory_works 1
00050 #  define tryopen_o_directory() while (1) /* This must not be called.  */
00051 # else
00052 static int o_directory_works;
00053 
00054 static void
00055 tryopen_o_directory (void)
00056 {
00057   int serrno = errno;
00058   int x = open_not_cancel_2 ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY);
00059 
00060   if (x >= 0)
00061     {
00062       close_not_cancel_no_status (x);
00063       o_directory_works = -1;
00064     }
00065   else if (errno != ENOTDIR)
00066     o_directory_works = -1;
00067   else
00068     o_directory_works = 1;
00069 
00070   __set_errno (serrno);
00071 }
00072 # endif
00073 # define EXTRA_FLAGS O_DIRECTORY
00074 #else
00075 # define EXTRA_FLAGS 0
00076 #endif
00077 
00078 
00079 /* Open a directory stream on NAME.  */
00080 DIR *
00081 __opendir (const char *name)
00082 {
00083   struct stat64 statbuf;
00084 
00085   if (__builtin_expect (name[0], '\1') == '\0')
00086     {
00087       /* POSIX.1-1990 says an empty name gets ENOENT;
00088         but `open' might like it fine.  */
00089       __set_errno (ENOENT);
00090       return NULL;
00091     }
00092 
00093 #ifdef O_DIRECTORY
00094   /* Test whether O_DIRECTORY works.  */
00095   if (o_directory_works == 0)
00096     tryopen_o_directory ();
00097 
00098   /* We can skip the expensive `stat' call if O_DIRECTORY works.  */
00099   if (o_directory_works < 0)
00100 #endif
00101     {
00102       /* We first have to check whether the name is for a directory.  We
00103         cannot do this after the open() call since the open/close operation
00104         performed on, say, a tape device might have undesirable effects.  */
00105       if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0)
00106        return NULL;
00107       if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0))
00108        {
00109          __set_errno (ENOTDIR);
00110          return NULL;
00111         }
00112     }
00113 
00114   int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE;
00115 #ifdef O_CLOEXEC
00116   flags |= O_CLOEXEC;
00117 #endif
00118   int fd = open_not_cancel_2 (name, flags);
00119   if (__builtin_expect (fd, 0) < 0)
00120     return NULL;
00121 
00122   /* Now make sure this really is a directory and nothing changed since
00123      the `stat' call.  We do not have to perform the test for the
00124      descriptor being associated with a directory if we know the
00125      O_DIRECTORY flag is honored by the kernel.  */
00126   if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0)
00127     goto lose;
00128 #ifdef O_DIRECTORY
00129   if (o_directory_works <= 0)
00130 #endif
00131     {
00132       if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0))
00133        {
00134          __set_errno (ENOTDIR);
00135        lose:
00136          close_not_cancel_no_status (fd);
00137          return NULL;
00138        }
00139     }
00140 
00141   return __alloc_dir (fd, true, &statbuf);
00142 }
00143 weak_alias (__opendir, opendir)
00144 
00145 
00146 #ifdef __ASSUME_O_CLOEXEC
00147 # define check_have_o_cloexec(fd) 1
00148 #else
00149 static int
00150 check_have_o_cloexec (int fd)
00151 {
00152   if (__have_o_cloexec == 0)
00153     __have_o_cloexec = (__fcntl (fd, F_GETFD, 0) & FD_CLOEXEC) == 0 ? -1 : 1;
00154   return __have_o_cloexec > 0;
00155 }
00156 #endif
00157 
00158 
00159 DIR *
00160 internal_function
00161 __alloc_dir (int fd, bool close_fd, const struct stat64 *statp)
00162 {
00163   /* We always have to set the close-on-exit flag if the user provided
00164      the file descriptor.  Otherwise only if we have no working
00165      O_CLOEXEC support.  */
00166 #ifdef O_CLOEXEC
00167   if (! close_fd || ! check_have_o_cloexec (fd))
00168 #endif
00169     {
00170       if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0)
00171        goto lose;
00172     }
00173 
00174   const size_t default_allocation = (BUFSIZ < sizeof (struct dirent64)
00175                                  ? sizeof (struct dirent64) : BUFSIZ);
00176   size_t allocation;
00177 #ifdef _STATBUF_ST_BLKSIZE
00178   if (__builtin_expect ((size_t) statp->st_blksize >= sizeof (struct dirent64),
00179                      1))
00180     allocation = statp->st_blksize;
00181   else
00182 #endif
00183     allocation = default_allocation;
00184 
00185   DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation);
00186   if (dirp == NULL)
00187     {
00188 #ifdef _STATBUF_ST_BLKSIZE
00189       if (allocation == statp->st_blksize
00190          && allocation != default_allocation)
00191        {
00192          allocation = default_allocation;
00193          dirp = (DIR *) malloc (sizeof (DIR) + allocation);
00194        }
00195       if (dirp == NULL)
00196 #endif
00197       lose:
00198        {
00199          if (close_fd)
00200            {
00201              int save_errno = errno;
00202              close_not_cancel_no_status (fd);
00203              __set_errno (save_errno);
00204            }
00205          return NULL;
00206        }
00207     }
00208 
00209   dirp->fd = fd;
00210 #ifndef NOT_IN_libc
00211   __libc_lock_init (dirp->lock);
00212 #endif
00213   dirp->allocation = allocation;
00214   dirp->size = 0;
00215   dirp->offset = 0;
00216   dirp->filepos = 0;
00217 
00218   return dirp;
00219 }