1 /* Copyright (C) 1991-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
21 #include <stdio.h> /* For BUFSIZ. */
22 #include <sys/param.h> /* For MIN and MAX. */
24 #include <not-cancel.h>
26 /* The st_blksize value of the directory is used as a hint for the
27 size of the buffer which receives struct dirent values from the
28 kernel. st_blksize is limited to MAX_DIR_BUFFER_SIZE, in case the
29 file system provides a bogus value. */
30 #define MAX_DIR_BUFFER_SIZE 1048576U
33 opendir_oflags
= O_RDONLY
|O_NDELAY
|O_DIRECTORY
|O_LARGEFILE
|O_CLOEXEC
37 invalid_name (const char *name
)
39 if (__glibc_unlikely (name
[0] == '\0'))
41 /* POSIX.1-1990 says an empty name gets ENOENT;
42 but `open' might like it fine. */
52 if (__glibc_unlikely (fd
< 0))
55 /* Now make sure this really is a directory and nothing changed since the
56 `stat' call. The S_ISDIR check is superfluous if O_DIRECTORY works,
57 but it's cheap and we need the stat call for st_blksize anyway. */
58 struct stat64 statbuf
;
59 if (__glibc_unlikely (__fxstat64 (_STAT_VER
, fd
, &statbuf
) < 0))
61 if (__glibc_unlikely (! S_ISDIR (statbuf
.st_mode
)))
63 __set_errno (ENOTDIR
);
65 __close_nocancel_nostatus (fd
);
69 return __alloc_dir (fd
, true, 0, &statbuf
);
75 __opendirat (int dfd
, const char *name
)
77 if (__glibc_unlikely (invalid_name (name
)))
80 return opendir_tail (__openat_nocancel (dfd
, name
, opendir_oflags
));
85 /* Open a directory stream on NAME. */
87 __opendir (const char *name
)
89 if (__glibc_unlikely (invalid_name (name
)))
92 return opendir_tail (__open_nocancel (name
, opendir_oflags
));
94 weak_alias (__opendir
, opendir
)
97 __alloc_dir (int fd
, bool close_fd
, int flags
, const struct stat64
*statp
)
99 /* We have to set the close-on-exit flag if the user provided the
102 && __builtin_expect (__fcntl (fd
, F_SETFD
, FD_CLOEXEC
), 0) < 0)
105 const size_t default_allocation
= (4 * BUFSIZ
< sizeof (struct dirent64
)
106 ? sizeof (struct dirent64
) : 4 * BUFSIZ
);
107 const size_t small_allocation
= (BUFSIZ
< sizeof (struct dirent64
)
108 ? sizeof (struct dirent64
) : BUFSIZ
);
109 size_t allocation
= default_allocation
;
110 #ifdef _STATBUF_ST_BLKSIZE
111 /* Increase allocation if requested, but not if the value appears to
114 allocation
= MIN (MAX ((size_t) statp
->st_blksize
, default_allocation
),
115 MAX_DIR_BUFFER_SIZE
);
118 DIR *dirp
= (DIR *) malloc (sizeof (DIR) + allocation
);
121 allocation
= small_allocation
;
122 dirp
= (DIR *) malloc (sizeof (DIR) + allocation
);
129 int save_errno
= errno
;
130 __close_nocancel_nostatus (fd
);
131 __set_errno (save_errno
);
139 __libc_lock_init (dirp
->lock
);
141 dirp
->allocation
= allocation
;