DIR * __fdopendir (int fd) { struct stat64 statbuf; if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } /* Make sure the descriptor allows for reading. */ int flags = __fcntl (fd, F_GETFL); if (__builtin_expect (flags == -1, 0)) return NULL; if (__builtin_expect ((flags & O_ACCMODE) == O_WRONLY, 0)) { __set_errno (EINVAL); return NULL; } return __alloc_dir (fd, false, flags, &statbuf); }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { struct stat64 statbuf; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } int fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE); if (__builtin_expect (fd, 0) < 0) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. We do not have to perform the test for the descriptor being associated with a directory if we know the O_DIRECTORY flag is honored by the kernel. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } } return __alloc_dir (fd, true, &statbuf); }
static DIR * opendir_tail (int fd) { if (__glibc_unlikely (fd < 0)) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. The S_ISDIR check is superfluous if O_DIRECTORY works, but it's cheap and we need the stat call for st_blksize anyway. */ struct stat64 statbuf; if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &statbuf) < 0)) goto lose; if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } return __alloc_dir (fd, true, 0, &statbuf); }
internal_function __opendirat (int dfd, const char *name) { struct stat64 statbuf; struct stat64 *statp = NULL; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE; #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif int fd; #ifdef IS_IN_rtld assert (dfd == AT_FDCWD); fd = open_not_cancel_2 (name, flags); #else fd = openat_not_cancel_3 (dfd, name, flags); #endif if (__builtin_expect (fd, 0) < 0) return NULL; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { /* Now make sure this really is a directory and nothing changed since the `stat' call. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } statp = &statbuf; } return __alloc_dir (fd, true, 0, statp); }