2004-10-15 Jakub Jelinek <jakub@redhat.com>
[kopensolaris-gnu/glibc.git] / sysdeps / unix / opendir.c
1 /* Copyright (C) 1991-1996,98,2000-2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <errno.h>
20 #include <limits.h>
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <dirstream.h>
32 #include <not-cancel.h>
33
34
35 /* opendir() must not accidentally open something other than a directory.
36    Some OS's have kernel support for that, some don't.  In the worst
37    case we have to stat() before the open() AND fstat() after.
38
39    We have to test at runtime for kernel support since libc may have
40    been compiled with different headers to the kernel it's running on.
41    This test can't be done reliably in the general case.  We'll use
42    /dev/null, which if it's not a device lots of stuff will break, as
43    a guinea pig.  It may be missing in chroot environments, so we
44    make sure to fail safe. */
45 #ifdef O_DIRECTORY
46 # ifdef O_DIRECTORY_WORKS
47 #  define o_directory_works 1
48 #  define tryopen_o_directory() while (1) /* This must not be called.  */
49 # else
50 static int o_directory_works;
51
52 static void
53 tryopen_o_directory (void)
54 {
55   int serrno = errno;
56   int x = open_not_cancel_2 ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY);
57
58   if (x >= 0)
59     {
60       close_not_cancel_no_status (x);
61       o_directory_works = -1;
62     }
63   else if (errno != ENOTDIR)
64     o_directory_works = -1;
65   else
66     o_directory_works = 1;
67
68   __set_errno (serrno);
69 }
70 # endif
71 # define EXTRA_FLAGS O_DIRECTORY
72 #else
73 # define EXTRA_FLAGS 0
74 #endif
75
76
77 /* Open a directory stream on NAME.  */
78 DIR *
79 __opendir (const char *name)
80 {
81   DIR *dirp;
82   struct stat64 statbuf;
83   int fd;
84   size_t allocation;
85   int save_errno;
86
87   if (__builtin_expect (name[0], '\1') == '\0')
88     {
89       /* POSIX.1-1990 says an empty name gets ENOENT;
90          but `open' might like it fine.  */
91       __set_errno (ENOENT);
92       return NULL;
93     }
94
95 #ifdef O_DIRECTORY
96   /* Test whether O_DIRECTORY works.  */
97   if (o_directory_works == 0)
98     tryopen_o_directory ();
99
100   /* We can skip the expensive `stat' call if O_DIRECTORY works.  */
101   if (o_directory_works < 0)
102 #endif
103     {
104       /* We first have to check whether the name is for a directory.  We
105          cannot do this after the open() call since the open/close operation
106          performed on, say, a tape device might have undesirable effects.  */
107       if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0)
108         return NULL;
109       if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0))
110         {
111           __set_errno (ENOTDIR);
112           return NULL;
113          }
114     }
115
116   fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE);
117   if (__builtin_expect (fd, 0) < 0)
118     return NULL;
119
120   /* Now make sure this really is a directory and nothing changed since
121      the `stat' call.  We do not have to perform the test for the
122      descriptor being associated with a directory if we know the
123      O_DIRECTORY flag is honored by the kernel.  */
124   if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0)
125     goto lose;
126 #ifdef O_DIRECTORY
127   if (o_directory_works <= 0)
128 #endif
129     {
130       if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0))
131         {
132           save_errno = ENOTDIR;
133           goto lose;
134         }
135     }
136
137   if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0)
138     goto lose;
139
140 #ifdef _STATBUF_ST_BLKSIZE
141   if (__builtin_expect ((size_t) statbuf.st_blksize >= sizeof (struct dirent64),
142                         1))
143     allocation = statbuf.st_blksize;
144   else
145 #endif
146     allocation = (BUFSIZ < sizeof (struct dirent64)
147                   ? sizeof (struct dirent64) : BUFSIZ);
148
149   const int pad = -sizeof (DIR) % __alignof__ (struct dirent64);
150
151   dirp = (DIR *) malloc (sizeof (DIR) + allocation + pad);
152   if (dirp == NULL)
153   lose:
154     {
155       save_errno = errno;
156       close_not_cancel_no_status (fd);
157       __set_errno (save_errno);
158       return NULL;
159     }
160   memset (dirp, '\0', sizeof (DIR));
161   dirp->data = (char *) (dirp + 1) + pad;
162   dirp->allocation = allocation;
163   dirp->fd = fd;
164
165   __libc_lock_init (dirp->lock);
166
167   return dirp;
168 }
169 weak_alias (__opendir, opendir)