#if HAVE_OPENAT_SUPPORT
int fd = AT_FDCWD;
bool fd_needs_closing = false;
+# if defined __linux__
+ bool proc_fs_not_mounted = false;
+# endif
#else
char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
char *dotlist = dots;
thisdev = dotdev;
thisino = dotino;
+
+#if HAVE_OPENAT_SUPPORT
+ /* On some platforms, a system call returns the directory that FD points
+ to. This is useful if some of the ancestor directories of the
+ directory are unreadable, because in this situation the loop that
+ climbs up the ancestor hierarchy runs into an EACCES error.
+ For example, in some Android app, /data/data/com.termux is readable,
+ but /data/data and /data are not. */
+# if defined __linux__
+ /* On Linux, in particular, if /proc is mounted,
+ readlink ("/proc/self/fd/<fd>")
+ returns the directory, if its length is < 4096. (If the length is
+ >= 4096, it fails with error ENAMETOOLONG, even if the buffer that we
+ pass to the readlink function would be large enough.) */
+ if (!proc_fs_not_mounted)
+ {
+ char namebuf[14 + 10 + 1];
+ sprintf (namebuf, "/proc/self/fd/%u", (unsigned int) fd);
+ char linkbuf[4096];
+ ssize_t linklen = readlink (namebuf, linkbuf, sizeof linkbuf);
+ if (linklen < 0)
+ {
+ if (errno != ENAMETOOLONG)
+ /* If this call was not successful, the next one will likely be
+ not successful either. */
+ proc_fs_not_mounted = true;
+ }
+ else
+ {
+ dirroom = dirp - dir;
+ if (dirroom < linklen)
+ {
+ if (size != 0)
+ {
+ __set_errno (ERANGE);
+ goto lose;
+ }
+ else
+ {
+ char *tmp;
+ size_t oldsize = allocated;
+
+ allocated += linklen - dirroom;
+ if (allocated < oldsize
+ || ! (tmp = realloc (dir, allocated)))
+ goto memory_exhausted;
+
+ /* Move current contents up to the end of the buffer. */
+ dirp = memmove (tmp + dirroom + (allocated - oldsize),
+ tmp + dirroom,
+ oldsize - dirroom);
+ dir = tmp;
+ }
+ }
+ dirp -= linklen;
+ memcpy (dirp, linkbuf, linklen);
+ break;
+ }
+ }
+# endif
+#endif
}
if (dirstream && __closedir (dirstream) != 0)