-} direntry;
-_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count)
-#define OPENDIR(f) open(f, O_RDONLY | O_NOATIME | O_DIRECTORY)
-#define DIRVALID(dh) ((dh) >= 0)
-#define READDIR(dh,de) ((de).curr = (de).data, (de).pos = 0, \
- ((de).endpos = getdents((dh), (de).data, sizeof((de).data))) > 0)
-#define DENAME(de) ((de).curr->d_name)
-#define DEDONE(de) ((de).pos >= (de).endpos)
-#define DEADVANCE(de) ((de).pos += (de).curr->d_reclen, \
- (de).curr = (struct dirent *)((char *)(de).data + (de).pos))
-#define CLOSEDIR(dh) close(dh)
-#else
+} dirhandle;
+
+int open_dir(const char *path, dirhandle *dh)
+{
+ dh->fd = open(path, O_RDONLY | O_NOATIME | O_DIRECTORY);
+ if (dh->fd < 0) {
+ /*
+ * Opening a file with O_NOATIME is not unconditionally
+ * permitted by the Linux kernel. As far as I can tell,
+ * it's permitted only for files on which the user would
+ * have been able to call utime(2): in other words, files
+ * for which the user could have deliberately set the
+ * atime back to its original value after finishing with
+ * it. Hence, O_NOATIME has no security implications; it's
+ * simply a cleaner, faster and more race-condition-free
+ * alternative to stat(), a normal open(), and a utimes()
+ * when finished.
+ *
+ * The upshot of all of which, for these purposes, is that
+ * we must be prepared to try again without O_NOATIME if
+ * we receive EPERM.
+ */
+ if (errno == EPERM)
+ dh->fd = open(path, O_RDONLY | O_DIRECTORY);
+ if (dh->fd < 0)
+ return -1;
+ }
+
+ dh->pos = dh->endpos = 0;
+
+ return 0;
+}
+
+const char *read_dir(dirhandle *dh)
+{
+ const char *ret;
+
+ if (dh->pos >= dh->endpos) {
+ dh->curr = dh->data;
+ dh->pos = 0;
+ dh->endpos = getdents(dh->fd, dh->data, sizeof(dh->data));
+ if (dh->endpos <= 0)
+ return NULL;
+ }
+
+ ret = dh->curr->d_name;
+
+ dh->pos += dh->curr->d_reclen;
+ dh->curr = (struct dirent *)((char *)dh->data + dh->pos);
+
+ return ret;
+}
+
+void close_dir(dirhandle *dh)
+{
+ close(dh->fd);
+}
+
+#else /* __linux__ */
+
+/*
+ * This branch of the ifdef is a simple exercise of ordinary POSIX
+ * opendir/readdir.
+ */
+