<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.
</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/d43551c9c9fa8bda04b32d50f364d2b40bf757cf">https://github.com/macports/macports-legacy-support/commit/d43551c9c9fa8bda04b32d50f364d2b40bf757cf</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit d43551c9c9fa8bda04b32d50f364d2b40bf757cf
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Sat Nov 23 13:30:18 2024 -0800
<span style='display:block; white-space:pre;color:#404040;'> fdopendir: Rework to handle variants directly in source.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This reworks the fdopendir code to directly build all the needed
</span><span style='display:block; white-space:pre;color:#404040;'> variants, instead of the horrible splitandfilterandmergemultiarch
</span><span style='display:block; white-space:pre;color:#404040;'> kludge in the Makefile. Not only does it reduce code duplication, but
</span><span style='display:block; white-space:pre;color:#404040;'> it also drastically improves readability. It does not change the
</span><span style='display:block; white-space:pre;color:#404040;'> underlying logic in the "guts", but merely changes the interfacing to
</span><span style='display:block; white-space:pre;color:#404040;'> the different variants.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This was the only use of splitandfilterandmergemultiarch, which will
</span><span style='display:block; white-space:pre;color:#404040;'> be excised in a subsequent commit.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> A subtle problem that this introduced is that the empty object filter
</span><span style='display:block; white-space:pre;color:#404040;'> for the static library was previously failing to filter fdopendir.o
</span><span style='display:block; white-space:pre;color:#404040;'> due to the way it was constructed, but fixing that resulted in a truly
</span><span style='display:block; white-space:pre;color:#404040;'> empty static library on 10.15+ platforms. This is actually illegal,
</span><span style='display:block; white-space:pre;color:#404040;'> so there's now a hack to put one dummy object into the archive in this
</span><span style='display:block; white-space:pre;color:#404040;'> case. The dummy object defines a single global symbol, thereby
</span><span style='display:block; white-space:pre;color:#404040;'> avoiding the "has no symbols" warning from 'ar' and other tools.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'> Builds and passes all tests (including the new one in a subsequent
</span><span style='display:block; white-space:pre;color:#404040;'> commit), on all platforms.
</span>---
Makefile | 12 ++-
src/dummylib.xxc | 13 ++++
src/fdopendir.c | 217 +++++++++++++++++++++++++++++++++++++++++++++----------
3 files changed, 204 insertions(+), 38 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/Makefile b/Makefile
</span><span style='display:block; white-space:pre;color:#808080;'>index 3890f57..12bae93 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/Makefile
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/Makefile
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -99,7 +99,7 @@ FIND_LIBHEADERS := find $(SRCINCDIR) -type f \( -name '*.h' -o \
</span> LIBHEADERS := $(shell $(FIND_LIBHEADERS))
ALLHEADERS := $(LIBHEADERS) $(wildcard $(SRCDIR)/*.h)
<span style='display:block; white-space:pre;background:#ffe0e0;'>-MULTISRCS := $(SRCDIR)/fdopendir.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+MULTISRCS :=
</span> ADDSRCS := $(SRCDIR)/add_symbols.c
LIBSRCS := $(filter-out $(MULTISRCS) $(ADDSRCS),$(wildcard $(SRCDIR)/*.c))
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -125,10 +125,16 @@ ALLSYSLIBOBJS := $(ALLDLIBOBJS) $(ADDOBJS)
</span> # This not only reduces the size of the static library a bit, but also
# avoids the "no symbols" warnings when creating it.
#
<span style='display:block; white-space:pre;background:#e0ffe0;'>+# A complication is that a completely empty static library is illegal,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# so we provide a dummy object to be used when the library is logically
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# empty.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span> # This treatment is only applicable to the static library.
EMPTY = empty_source_content
EMPTYSOBJ = $(SRCDIR)/$(EMPTY)$(SLIBOBJEXT)
SOBJLIST = $(SRCDIR)/slibobjs.tmp
<span style='display:block; white-space:pre;background:#e0ffe0;'>+DUMMYSRC = $(SRCDIR)/dummylib.xxc
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+DUMMYOBJ = $(SRCDIR)/dummylib.o
</span>
# Automatic tests that don't use the library, and are OK with -fno-builtin
XTESTDIR = xtest
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -337,9 +343,13 @@ slibobjs: $(ALLSLIBOBJS)
</span> allobjs: dlibobjs slibobjs syslibobjs
# Create a list of nonempty static object files.
<span style='display:block; white-space:pre;background:#e0ffe0;'>+# Since completely empty archives are illegal, we use our dummy if there
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# would otherwise be no objects.
</span> $(SOBJLIST): $(ALLSLIBOBJS)
$(CC) -c $(ALLCFLAGS) $(SLIBCFLAGS) -xc /dev/null -o $(EMPTYSOBJ)
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ $(CC) -c $(ALLCFLAGS) $(SLIBCFLAGS) -xc $(DUMMYSRC) -o $(DUMMYOBJ)
</span> for f in $^; do cmp -s $(EMPTYSOBJ) $$f || echo $$f; done > $@
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if [ ! -s $@ ]; then echo $(DUMMYOBJ) > $@; fi
</span>
# Make the directories separate targets to avoid collisions in parallel builds.
$(BUILDLIBDIR) $(DESTDIR)$(LIBDIR):
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/dummylib.xxc b/src/dummylib.xxc
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..5172d75
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/dummylib.xxc
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,13 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* dummylib - mostly empty item containing one global definition. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * When the legacy-support library becomes logically empty, it still needs
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to contain at least one object to keep the tools happy. It also needs
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to define at least one global to avoid "no symbols" warnings. This
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * source is used to provide such an object. Currently this happens on
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 10.15+.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This source is actually C, but uses a different extension to defend
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * against wildcarding in the Makefile.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int __LEGACY_SUPPORT_LIBRARY_IS_INTENTIONALLY_LEFT_BLANK__ = 0;
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/fdopendir.c b/src/fdopendir.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 3af64b0..f11d9c5 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/fdopendir.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/fdopendir.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -21,66 +21,209 @@
</span> /* Do our SDK-related setup */
#include <_macports_extras/sdkversion.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Implementation behavior largely follows these man page descriptions:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * https://www.freebsd.org/cgi/man.cgi?query=fdopendir&sektion=3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * https://linux.die.net/man/3/fdopendir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #if __MPLS_LIB_SUPPORT_FDOPENDIR__
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#include "common-priv.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Set up to use ino32 variants where possible. This results in generating
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the "unadorned" names, which we augment with explicit suffixes where
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * needed. Similarly, we use the non-POSIX form in 32-bit builds.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The ino32 variants are known to be unavailable in arm64 builds, but are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * available in all OS versions that need our fdopendir().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Although the struct dirent is formatted differently for ino32 and ino64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * we never directly reference it here. The only difference in DIR is the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * format of the private struct _telldir pointed to by the __dd_td field,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * which we also never reference here. Hence, we don't care which variant
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * we're using, except for passing the choice through to the underlying
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * functions.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * In the case of struct stat, we provide our own ino64 variant where needed.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define _DARWIN_NO_64_BIT_INODE 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !__MPLS_64BIT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define _NONSTD_SOURCE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span>
#include <dirent.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stddef.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #include <sys/stat.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "common-priv.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #if __MPLS_SDK_MAJOR < 1050
#define __dd_fd dd_fd
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#endif /* __MPLS_SDK_MAJOR < 1050 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MPLS_SDK_MAJOR < 1050
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Define an ino64 struct stat if possible, else fall back to standard. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef __DARWIN_STRUCT_STAT64
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct local_stat64 __DARWIN_STRUCT_STAT64;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ typedef struct local_stat64 local_stat64_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ typedef struct stat local_stat64_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Universal stat buffer, accommodating both formats */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+union stat_u {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct stat s;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ local_stat64_t s64;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Type declarations for external functions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int (stat_fn_t)(int fd, struct stat *buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int (stat64_fn_t)(int fd, local_stat64_t *buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef DIR * (opn_fn_t)(const char *dirname);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef void (rwd_fn_t)(DIR *dirp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Structure for per-variant dispatch table */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct funcs_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ stat_fn_t *do_fstat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ stat64_fn_t *do_fstat64;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ opn_fn_t *do_open;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rwd_fn_t *do_rewind;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} funcs_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Common function used by all variants - controlled by a dispatch table */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static DIR *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fdopendir_internal(int fd, const funcs_t *funcs) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DIR *dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mode_t mode;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ union stat_u stbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Do the appropriate fstat() on the supplied fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (funcs->do_fstat64) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = (*funcs->do_fstat64)(fd, &stbuf.s64);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mode = stbuf.s64.st_mode;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (funcs->do_fstat) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = (*funcs->do_fstat)(fd, &stbuf.s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mode = stbuf.s.st_mode;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = EINVAL; /* Should be impossible */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Fail if fd isn't a valid open fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (err < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Fail if fd isn't a directory */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!S_ISDIR(mode)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = ENOTDIR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Open given directory fd safely for iteration via readdir */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dir = _ATCALL(fd, ".", NULL, (*funcs->do_open)("."));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!dir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Replace underlying fd with supplied fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * A subsequent closedir() will close fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)close(dir->__dd_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dir->__dd_fd = fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Rewind to the start of the directory, in case the underlying file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * is not positioned at the start
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (*funcs->do_rewind)(dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Close given fd on exec (as per fdopendir() docs) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span>
/*
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Implementation behavior largely follows these man page descriptions:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Now to handle all the variants:
</span> *
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * https://www.freebsd.org/cgi/man.cgi?query=fdopendir&sektion=3
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * https://linux.die.net/man/3/fdopendir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Define a macro listing all variants supported by the OS/arch.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 10.4 lacks the INODE64 variants.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 64-bit builds lack the UNIX2003 variants.
</span> */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-DIR *fdopendir(int dirfd) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- DIR *dir;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- struct stat dirstat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MPLS_TARGET_OSVER < 1050
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !__MPLS_64BIT
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /* Fail if dirfd isn't a valid open fd */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (fstat(dirfd, &dirstat) < 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return NULL;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ALL_VARIANTS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(basic,,,) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(posix,,$UNIX2003,)
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /* Fail if dirfd isn't a directory */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (!S_ISDIR(dirstat.st_mode)) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- errno = ENOTDIR;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return NULL;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else /* __MPLS_64BIT */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /* Open given directory fd safely for iteration via readdir */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ALL_VARIANTS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(basic,,,)
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- dir = _ATCALL(dirfd, ".", NULL, opendir("."));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (!dir) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return NULL;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MPLS_64BIT */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else /* __MPLS_TARGET_OSVER >= 1050 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !__MPLS_64BIT
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /*
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * Replace underlying fd with supplied dirfd
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * A subsequent closedir() will close dirfd
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ALL_VARIANTS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(basic,,,) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(posix,,$UNIX2003,) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(ino64,$INODE64,$UNIX2003,64)
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- (void)close(dir->__dd_fd);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- dir->__dd_fd = dirfd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else /* __MPLS_64BIT */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /*
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * Rewind to the start of the directory, in case the underlying file
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * is not positioned at the start
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ALL_VARIANTS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(basic,,,) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ VARIANT_ENT(ino64,$INODE64,,64)
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- rewinddir(dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MPLS_64BIT */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MPLS_TARGET_OSVER >= 1050 */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /* Close given fd on exec (as per fdopendir() docs) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Declare all called functions with appropriate suffixes. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* The "basic" case is redundant but serves as an error check. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define VARIANT_ENT(name,isfx,usfx,is64) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+stat##is64##_fn_t fstat##isfx; \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+opn_fn_t opendir##isfx##usfx; \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+rwd_fn_t rewinddir##isfx##usfx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ALL_VARIANTS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef VARIANT_ENT
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- (void)fcntl(dirfd, F_SETFD, FD_CLOEXEC);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Generate dispatch tables. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Since compilers aren't smart enough to avoid complaining about mismatched
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * types from values made irrelevant by compile-time constants, we include
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * technically incorrect casts to shut them up.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define VARIANT_ENT(name,isfx,usfx,is64) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const funcs_t name = { \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .do_fstat = 0##is64 ? NULL : (stat_fn_t *) &fstat##isfx, \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .do_fstat64 = 0##is64 ? (stat64_fn_t *) &fstat##isfx : NULL, \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .do_open = &opendir##isfx##usfx, \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .do_rewind = &rewinddir##isfx##usfx, \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ALL_VARIANTS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef VARIANT_ENT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Now generate the functions. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define VARIANT_ENT(name,isfx,usfx,is64) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+DIR * \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fdopendir##isfx##usfx(int fd) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{ \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return fdopendir_internal(fd, &name); \
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ALL_VARIANTS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef VARIANT_ENT
</span>
#endif /* __MPLS_LIB_SUPPORT_FDOPENDIR__ */
</pre><pre style='margin:0'>
</pre>