+ if ((flags & DTF_NODUP) && __kernel_supports_unionfs()) {
+ unionstack = __fd_is_on_union_mount(fd);
+ if (unionstack < 0)
+ goto fail;
+ } else {
+ unionstack = 0;
+ }
+
+ if (unionstack) {
+ if (!_filldir(dirp, use_current_pos))
+ goto fail;
+ dirp->dd_flags |= __DTF_READALL;
+ } else {
+ /*
+ * Start with a small-ish size to avoid allocating full pages.
+ * readdir() will allocate a larger buffer if it didn't fit
+ * to stay fast for large directories.
+ */
+ _Static_assert(GETDIRENTRIES64_EXTENDED_BUFSIZE <= READDIR_INITIAL_SIZE,
+ "Make sure we'll get extended metadata");
+ dirp->dd_len = READDIR_INITIAL_SIZE;
+ dirp->dd_buf = malloc(dirp->dd_len);
+ if (dirp->dd_buf == NULL)
+ goto fail;
+ if (use_current_pos) {
+ /*
+ * Read the first batch of directory entries
+ * to prime dd_seek. This also checks if the
+ * fd passed to fdopendir() is a directory.
+ */
+#if __DARWIN_64_BIT_INO_T
+ /*
+ * sufficiently recent kernels when the buffer is large enough,
+ * will use the last bytes of the buffer to return status.
+ *
+ * To support older kernels:
+ * - make sure it's 0 initialized
+ * - make sure it's past `dd_size` before reading it
+ */
+ getdirentries64_flags_t *gdeflags =
+ (getdirentries64_flags_t *)(dirp->dd_buf + dirp->dd_len -
+ sizeof(getdirentries64_flags_t));
+ *gdeflags = 0;
+ dirp->dd_size = (long)__getdirentries64(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len, &dirp->dd_td->seekoff);
+ if (dirp->dd_size >= 0 &&
+ dirp->dd_size <= dirp->dd_len - sizeof(getdirentries64_flags_t)) {
+ if (*gdeflags & GETDIRENTRIES64_EOF) {
+ dirp->dd_flags |= __DTF_ATEND;
+ }
+ }
+#else /* !__DARWIN_64_BIT_INO_T */
+ dirp->dd_size = _getdirentries(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+#endif /* __DARWIN_64_BIT_INO_T */
+ if (dirp->dd_size < 0) {
+ if (errno == EINVAL)
+ errno = ENOTDIR;
+ goto fail;
+ }
+ dirp->dd_flags |= __DTF_SKIPREAD;
+ } else {
+ dirp->dd_size = 0;
+#if __DARWIN_64_BIT_INO_T
+ dirp->dd_td->seekoff = 0;
+#else /* !__DARWIN_64_BIT_INO_T */
+ dirp->dd_seek = 0;
+#endif /* __DARWIN_64_BIT_INO_T */
+ }
+ }