+ fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY |
+ O_LARGEFILE | O_DIRECTORY);
+ if (fd < 0)
+ return -1;
+ }
+
+ *dh = fdopendir(fd);
+#else
+ *dh = opendir(path);
+#endif
+
+ if (!*dh)
+ return -1;
+ return 0;
+}
+
+const char *read_dir(dirhandle *dh)
+{
+ struct dirent *de = readdir(*dh);
+ return de ? de->d_name : NULL;
+}
+
+void close_dir(dirhandle *dh)
+{
+ closedir(*dh);
+}
+
+#else /* defined __linux__ && !defined HAVE_FDOPENDIR */
+
+/*
+ * Earlier versions of glibc do not have fdopendir(). Therefore,
+ * if we are on Linux and still wish to make use of O_NOATIME, we
+ * have no option but to talk directly to the kernel system call
+ * interface which underlies the POSIX opendir/readdir machinery.
+ */
+
+#define __KERNEL__
+#include <linux/types.h>
+#include <linux/dirent.h>
+#include <linux/unistd.h>
+
+_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count)
+
+typedef struct {
+ int fd;
+ struct dirent data[32];
+ struct dirent *curr;
+ int pos, endpos;
+} dirhandle;
+
+int open_dir(const char *path, dirhandle *dh)
+{
+ /*
+ * As above, we try with O_NOATIME and then fall back to
+ * trying without it.
+ */
+ dh->fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_LARGEFILE |
+ O_NOATIME | O_DIRECTORY);
+ if (dh->fd < 0) {
+ if (errno == EPERM)
+ dh->fd = open(path, O_RDONLY | O_NONBLOCK | O_NOCTTY |
+ O_LARGEFILE | O_DIRECTORY);