<pre style='margin:0'>
Ken (kencu) pushed a commit to branch master
in repository macports-legacy-support.
</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/8889f27039e355c2ccadda0240ddd540302e382f">https://github.com/macports/macports-legacy-support/commit/8889f27039e355c2ccadda0240ddd540302e382f</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'> new 8889f27 Fix fdopendir so dirfd stays open until closedir (for fstatat etc)
</span>8889f27 is described below
<span style='display:block; white-space:pre;color:#808000;'>commit 8889f27039e355c2ccadda0240ddd540302e382f
</span>Author: raf <raf@raf.org>
AuthorDate: Tue Jul 18 00:35:32 2023 +1000
<span style='display:block; white-space:pre;color:#404040;'> Fix fdopendir so dirfd stays open until closedir (for fstatat etc)
</span>---
Makefile | 4 +-
README.md | 5 +-
include/dirent.h | 51 +++++++++++-
src/best_fchdir.c | 6 +-
src/fdopendir.c | 128 ++++++++++++++++++++---------
test/test_fdopendir.c | 26 ++++++
test/test_fmemopen.c | 4 +-
test/test_traverse.c | 184 ++++++++++++++++++++++++++++++++++++++++++
test/test_traverse_cwd.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 566 insertions(+), 46 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 8d3e67a..a4cd05b 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;'>@@ -54,7 +54,7 @@ FORCE_ARCH ?=
</span> ARCHFLAGS ?=
LIPO ?= lipo
CC ?= cc $(ARCHFLAGS)
<span style='display:block; white-space:pre;background:#ffe0e0;'>-CFLAGS ?= -Os -Wall
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+CFLAGS ?= -Os -Wall -Wno-deprecated-declarations
</span> DLIBCFLAGS ?= -fPIC
SLIBCFLAGS ?=
CXX ?= c++ $(ARCHFLAGS)
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -84,7 +84,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 := # Used to have $(SRCDIR)/fdopendir.c because it used struct stat
</span> ADDSRCS := $(SRCDIR)/add_symbols.c
LIBSRCS := $(filter-out $(MULTISRCS) $(ADDSRCS),$(wildcard $(SRCDIR)/*.c))
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/README.md b/README.md
</span><span style='display:block; white-space:pre;color:#808080;'>index d7dce54..e0c8c23 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/README.md
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/README.md
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -41,7 +41,10 @@ Wrapped headers and replaced functions are:
</span> </tr>
<tr>
<td><code>dirent.h</code></td>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- <td>Adds <code>fdopendir</code> function</td>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ <td>Adds <code>fdopendir</code> function, and wraps <code>opendir</code>,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ <code>readdir</code>, <code>readdir_r</code>, <code>rewinddir</code>,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ <code>seekdir</code>, <code>telldir</code>, <code>dirfd</code>, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ <code>closedir</code>, to support <code>fdopendir</code></td>
</span> <td>OSX10.9</td>
</tr>
<tr>
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/dirent.h b/include/dirent.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 9e66955..983417b 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/dirent.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/dirent.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,6 +1,7 @@
</span>
/*
* Copyright (c) 2019
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2023 raf <raf@raf.org>, Tavian Barnes <tavianator@tavianator.com>
</span> *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -27,6 +28,14 @@
</span> /* fdopendir */
#if __MP_LEGACY_SUPPORT_FDOPENDIR__
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Wrapper struct for DIR */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct __MP_LEGACY_SUPPORT_DIR __MP_LEGACY_SUPPORT_DIR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct __MP_LEGACY_SUPPORT_DIR {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DIR *__mpls_dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int __mpls_dirfd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DIR __MP_LEGACY_SUPPORT_DIR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> __MP__BEGIN_DECLS
#ifndef __DARWIN_ALIAS_I
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -35,7 +44,47 @@ extern DIR *fdopendir(int fd) __DARWIN_ALIAS(fdopendir);
</span> extern DIR *fdopendir(int fd) __DARWIN_ALIAS_I(fdopendir);
#endif
<span style='display:block; white-space:pre;background:#ffe0e0;'>-__MP__END_DECLS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Wrapper functions/macros to support fdopendir */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern DIR *__mpls_opendir(const char *name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int __mpls_closedir(DIR *dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int __mpls_dirfd(DIR *dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define opendir(name) __mpls_opendir(name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define closedir(dir) __mpls_closedir(dir)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef __MP_LEGACY_SUPPORT_NO_DIRFD_MACRO
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef dirfd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define dirfd(dir) __mpls_dirfd(dir)
</span> #endif
<span style='display:block; white-space:pre;background:#e0ffe0;'>+static inline struct dirent *__mpls_readdir(DIR *dir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return readdir(dir->__mpls_dir);
</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;'>+static inline int __mpls_readdir_r(DIR *dir, struct dirent *entry, struct dirent **result) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return readdir_r(dir->__mpls_dir, entry, result);
</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;'>+static inline void __mpls_rewinddir(DIR *dir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rewinddir(dir->__mpls_dir);
</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;'>+static inline void __mpls_seekdir(DIR *dir, long loc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ seekdir(dir->__mpls_dir, loc);
</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;'>+static inline long __mpls_telldir(DIR *dir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return telldir(dir->__mpls_dir);
</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 readdir __mpls_readdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define readdir_r __mpls_readdir_r
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define rewinddir __mpls_rewinddir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define seekdir __mpls_seekdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define telldir __mpls_telldir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+__MP__END_DECLS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MP_LEGACY_SUPPORT_FDOPENDIR__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #endif /* _MACPORTS_DIRENT_H_ */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/best_fchdir.c b/src/best_fchdir.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 47417da..7ef41e7 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/best_fchdir.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/best_fchdir.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,5 +1,6 @@
</span> /*-
* Copyright (c) 2019
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2023 raf <raf@raf.org>
</span> *
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -30,7 +31,10 @@ int best_fchdir(int dirfd)
</span> return syscall(SYS___pthread_fchdir, dirfd);
#else
/* Tiger does not have kernel support for __pthread_fchdir, so we have to fall back to fchdir */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* unless we can come up with a per-thread compatible implementation that works on Tiger */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* unless we can come up with a per-thread compatible implementation that works on Tiger. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Accept dirfd == -1 (which is meaningful for __pthread_fchdir) but do nothing with it. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (dirfd == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span> return syscall(SYS_fchdir, dirfd);
#endif
}
<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 940f4ef..f6c7f46 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;'>@@ -1,6 +1,7 @@
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/*-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span> * Copyright (c) 2019
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2023 raf <raf@raf.org>, Tavian Barnes <tavianator@tavianator.com>
</span> *
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -22,11 +23,15 @@
</span>
#include "common-priv.h"
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_NO_DIRFD_MACRO
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span> #include <dirent.h>
#include <sys/errno.h>
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef DIR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef opendir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef closedir
</span>
/*
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -34,62 +39,107 @@
</span> *
* https://www.freebsd.org/cgi/man.cgi?query=fdopendir&sektion=3
* https://linux.die.net/man/3/fdopendir
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * On success, this function returns allocated memory that must be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * deallocated by __mpls_closedir() (see closedir() macro in <dirent.h>).
</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 st;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int oldCWD = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+__MP_LEGACY_SUPPORT_DIR *fdopendir(int dirfd) {
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (fstat(dirfd, &st) < 0)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Check dirfd here (for macos-10.4, see _ATCALL() and best_fchdir()) */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (!S_ISDIR(st.st_mode)) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- errno = ENOTDIR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (dirfd != AT_FDCWD && dirfd < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = EBADF;
</span> return 0;
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (dirfd == AT_FDCWD) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- dir = opendir (".");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* dirfd can be closed only upon success */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (dir) PROTECT_ERRNO(close(dirfd));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return dir;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Open the supplied directory safely */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- oldCWD = open(".", O_RDONLY);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (oldCWD == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DIR *dir = _ATCALL(dirfd, ".", NULL, opendir("."));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!dir)
</span> return 0;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if(best_fchdir(dirfd) < 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (oldCWD != -1) PROTECT_ERRNO(close(oldCWD));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Wrap it and return it (with the supplied directory file descriptor) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ __MP_LEGACY_SUPPORT_DIR *mplsdir = malloc(sizeof(*mplsdir));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!mplsdir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)closedir(dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = ENOMEM;
</span> return 0;
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- dir = opendir (".");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mplsdir->__mpls_dir = dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mplsdir->__mpls_dirfd = dirfd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return mplsdir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (best_fchdir(oldCWD) < 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (dir) PROTECT_ERRNO(closedir(dir));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (oldCWD != -1) PROTECT_ERRNO(close(oldCWD));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Wrapped version of opendir() for fdopendir() compatibility
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * On success, this function returns allocated memory that must be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * deallocated by __mpls_closedir() (see closedir() macro in <dirent.h>).
</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;'>+__MP_LEGACY_SUPPORT_DIR *__mpls_opendir(const char *name) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DIR *dir = opendir(name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!dir)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ __MP_LEGACY_SUPPORT_DIR *mplsdir = malloc(sizeof(*mplsdir));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!mplsdir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)closedir(dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = ENOMEM;
</span> return 0;
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (oldCWD != -1)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- PROTECT_ERRNO(close(oldCWD));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mplsdir->__mpls_dir = dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mplsdir->__mpls_dirfd = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return mplsdir;
</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;'>+ * Wrapped version of closedir() for fdopendir() compatibility (see
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * closedir() macro in <dirent.h>).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This function deallocates memory that was allocated by fdopendir() or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * __mpls_opendir().
</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 __mpls_closedir(__MP_LEGACY_SUPPORT_DIR *mplsdir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!mplsdir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = EBADF;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return -1;
</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 rc = closedir(mplsdir->__mpls_dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mplsdir->__mpls_dirfd != AT_FDCWD && mplsdir->__mpls_dirfd != -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ PROTECT_ERRNO(close(mplsdir->__mpls_dirfd));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mplsdir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return rc;
</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;'>+ * Wrapped version of dirfd() for fdopendir() compatibility because dirfd()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * itself is already a macro (see dirfd() macro in <dirent.h>).
</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 __mpls_dirfd(__MP_LEGACY_SUPPORT_DIR *mplsdir) {
</span>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Return the supplied directory file descriptor if there was one */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- /*
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * FIXME -- this recently added bit makes the fdopendir tests fail on Tiger.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * check the whole commit where it was added to make sure it is
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * doing the proper thing on all systems. Probably need more extensive tests
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * to execise the whole system more aggressively.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mplsdir->__mpls_dirfd != AT_FDCWD && mplsdir->__mpls_dirfd != -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return mplsdir->__mpls_dirfd;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* dirfd can be closed only upon success */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (dir && dirfd != -1) PROTECT_ERRNO(close(dirfd));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Otherwise call the underlying dirfd() macro */
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- return dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return dirfd(mplsdir->__mpls_dir);
</span> }
#endif /* __MP_LEGACY_SUPPORT_FDOPENDIR__ */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_fdopendir.c b/test/test_fdopendir.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 0cdd856..a83d7e6 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/test/test_fdopendir.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_fdopendir.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,6 +1,7 @@
</span>
/*
* Copyright (c) 2019
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2023 raf <raf@raf.org>
</span> *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -15,9 +16,11 @@
</span> * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span> #include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/errno.h>
</span> #include <unistd.h>
#include <limits.h>
#include <fcntl.h>
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -55,6 +58,29 @@ int main() {
</span> }
close(dfd);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Try to use fdopendir with stdin - Should fail with ENOTDIR */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((dir = fdopendir(STDIN_FILENO))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "fdopendir(stdin) should have failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)closedir(dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (errno != ENOTDIR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("fdopendir(stdin) should have failed with ENOTDIR");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</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;'>+ /* Try to use fdopendir with -1 - Should fail with EBADF */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((dir = fdopendir(-1))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "fdopendir(-1) should have failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)closedir(dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (errno != EBADF) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("fdopendir(-1) should have failed with EBADF");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> return 0;
}
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_fmemopen.c b/test/test_fmemopen.c
</span><span style='display:block; white-space:pre;color:#808080;'>index f7be90a..081d0b9 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/test/test_fmemopen.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_fmemopen.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -108,10 +108,10 @@ test_autoalloc()
</span> * Let fmemopen allocate the buffer.
*/
<span style='display:block; white-space:pre;background:#ffe0e0;'>- char str[] = "A quick test";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* char str[] = "A quick test"; */
</span> FILE *fp;
long pos;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- size_t nofw, nofr, i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size_t nofw, i;
</span> int rc;
/* Open a FILE * using fmemopen. */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_traverse.c b/test/test_traverse.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..6d94112
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_traverse.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,184 @@
</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;'>+ * Copyright (c) 2023 raf <raf@raf.org>
</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;'>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * SUCH DAMAGE.
</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;'>+Test directory traversal with macports legacysupport.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+This test creates ".test.dir", ".test.dir/subdir" and ".test.dir/subdir/file".
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+It then traverses the ".test.dir" directory.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+It then deletes ".test.dir" and its contents.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+The output should look something like:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cwd (before traverse) /.../macports-legacy-support
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fstatat(parent_fd=-2, .test.dir) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ openat(parent_fd=-2, .test.dir) = dir_fd=3 ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fdopendir(dir_fd=3) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ entry subdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fstatat(parent_fd=3, subdir) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ openat(parent_fd=3, subdir) = dir_fd=4 ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fdopendir(dir_fd=4) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ entry file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fstatat(parent_fd=4, file) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cwd (after traverse) /.../macports-legacy-support
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+This differs from test/test_traverse_cwd.c which
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+chdirs to the named directory and then traverses "."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+rather than a named directory. Originally, these
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exhibited different errors.
</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;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <dirent.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int traverse(int parent_fd, const char *name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Test: fstatat(AT_FDCWD, .test.dir) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct stat statbuf[1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (fstatat(parent_fd, name, statbuf, AT_SYMLINK_NOFOLLOW) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "fstatat(parent_fd=%d, %s) failed: %s\n", parent_fd, name, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ printf("fstatat(parent_fd=%d, %s) ok\n", parent_fd, name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If it's a directory, process its entries */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((statbuf->st_mode & S_IFMT) == S_IFDIR)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Open it with openat() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int dir_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((dir_fd = openat(parent_fd, name, O_RDONLY)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "openat(parent_fd=%d, %s) failed: %s\n", parent_fd, name, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ printf("openat(parent_fd=%d, %s) = dir_fd=%d ok\n", parent_fd, name, dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Open it for traversing with fdopendir() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DIR *dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(dir = fdopendir(dir_fd)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "fdopendir(dir_fd=%d, .test.dir) failed\n", dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ close(dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ printf("fdopendir(dir_fd=%d) ok\n", dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Apply recursively to this directory's entries */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct dirent *entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while ((entry = readdir(dir)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("entry %s\n", entry->d_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (traverse(dir_fd, entry->d_name) == EXIT_FAILURE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ closedir(dir);
</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;'>+ return EXIT_SUCCESS;
</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 main(int argc, char **argv)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Prepare: Create a directory */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ system("rm -rf .test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mkdir(".test.dir", (mode_t)0755) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("mkdir(.test.dir) failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(EXIT_FAILURE);
</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;'>+ /* And a directory within it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mkdir(".test.dir/subdir", (mode_t)0755) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("mkdir(.test.dir/subdir) failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir(".test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(EXIT_FAILURE);
</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;'>+ /* And a file within that */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((fd = creat(".test.dir/subdir/file", (mode_t)0644)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("creat(.test.dir/subdir/file) failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir(".test.dir/subdir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir(".test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(EXIT_FAILURE);
</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;'>+ close(fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Test directory traversal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char cwdbuf1[BUFSIZ];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("cwd (before traverse) %s\n", getcwd(cwdbuf1, BUFSIZ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int rc = traverse(AT_FDCWD, ".test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char cwdbuf2[BUFSIZ];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("cwd (after traverse) %s\n", getcwd(cwdbuf2, BUFSIZ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (strcmp(cwdbuf1, cwdbuf2)) /* Originally, this happened on macos-10.4 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Directory has changed while traversing!\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rc = EXIT_FAILURE;
</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;'>+ /* Cleanup */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (unlink(".test.dir/subdir/file") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("unlink .test.dir/subdir/file failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (rmdir(".test.dir/subdir") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("rmdir .test.dir/subdir failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (rmdir(".test.dir") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("rmdir .test.dir failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return rc;
</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;color:#808080;'>diff --git a/test/test_traverse_cwd.c b/test/test_traverse_cwd.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..8c01bb4
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_traverse_cwd.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,204 @@
</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;'>+ * Copyright (c) 2023 raf <raf@raf.org>
</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;'>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * SUCH DAMAGE.
</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;'>+Test directory traversal with macports legacysupport.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+This test creates ".test.dir", ".test.dir/subdir" and ".test.dir/subdir/file".
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+It then chdirs into ".test.dir" and then traverses ".".
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+It then chdirs to ".." afterwards.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+It then deletes ".test.dir" and its contents.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+The output should look something like:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fstatat(parent_fd=-2, .) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ openat(parent_fd=-2, .) = dir_fd=3 ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fdopendir(dir_fd=3) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ entry subdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fstatat(parent_fd=3, subdir) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ openat(parent_fd=3, subdir) = dir_fd=4 ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fdopendir(dir_fd=4) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ entry file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fstatat(parent_fd=4, file) ok
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cwd (before cd ..) /Users/.../macports-legacy-support/.test.dir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cwd (after cd ..) /Users/.../macports-legacy-support
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+This differs from test/test_traverse.c which traverses a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+named directory rather than ".". Originally, these
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exhibited different errors.
</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;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <dirent.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int traverse(int parent_fd, const char *name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Test: fstatat(AT_FDCWD, .test.dir) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct stat statbuf[1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (fstatat(parent_fd, name, statbuf, AT_SYMLINK_NOFOLLOW) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "fstatat(parent_fd=%d, %s) failed: %s\n", parent_fd, name, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ printf("fstatat(parent_fd=%d, %s) ok\n", parent_fd, name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If it's a directory, process its entries */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((statbuf->st_mode & S_IFMT) == S_IFDIR)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Open it with openat() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int dir_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((dir_fd = openat(parent_fd, name, O_RDONLY)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "openat(parent_fd=%d, %s) failed: %s\n", parent_fd, name, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ printf("openat(parent_fd=%d, %s) = dir_fd=%d ok\n", parent_fd, name, dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Open it for traversing with fdopendir() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DIR *dir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(dir = fdopendir(dir_fd)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "fdopendir(dir_fd=%d, dir) failed\n", dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ close(dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ printf("fdopendir(dir_fd=%d) ok\n", dir_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Apply recursively to this directory's entries */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct dirent *entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while ((entry = readdir(dir)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("entry %s\n", entry->d_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (traverse(dir_fd, entry->d_name) == EXIT_FAILURE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return EXIT_FAILURE;
</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;'>+ closedir(dir);
</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;'>+ return EXIT_SUCCESS;
</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 main(int argc, char **argv)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Prepare: Create a directory */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ system("rm -rf .test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mkdir(".test.dir", (mode_t)0755) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("mkdir(.test.dir) failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(EXIT_FAILURE);
</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;'>+ /* And a directory within it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mkdir(".test.dir/subdir", (mode_t)0755) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("mkdir(.test.dir/subdir) failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir(".test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(EXIT_FAILURE);
</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;'>+ /* And a file within that */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((fd = creat(".test.dir/subdir/file", (mode_t)0644)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("creat(.test.dir/subdir/file) failed\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir(".test.dir/subdir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir(".test.dir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(EXIT_FAILURE);
</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;'>+ close(fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Test directory traversal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "cd .test.dir\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (chdir(".test.dir") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("chdir(.test.dir) failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int rc = traverse(AT_FDCWD, ".");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char cwdbuf1[BUFSIZ];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char cwdbuf2[BUFSIZ];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("cwd (before cd ..) %s\n", getcwd(cwdbuf1, BUFSIZ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (chdir("..") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("chdir .. failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("cwd (after cd ..) %s\n", getcwd(cwdbuf2, BUFSIZ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(cwdbuf1, cwdbuf2))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Post-traversal chdir(..) silently failed to change directory!\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Replacing best_fchdir() in fdopendir() with fchdir() fixes this badly.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Using _ATCALL for opendir fixes this properly.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rc = EXIT_FAILURE;
</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;'>+ /* Cleanup */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (unlink(".test.dir/subdir/file") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("unlink .test.dir/subdir/file failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (rmdir(".test.dir/subdir") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("rmdir .test.dir/subdir failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (rmdir(".test.dir") == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("rmdir .test.dir failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If the above cleanup didn't work (because chdir .. silently failed to work) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(cwdbuf1, cwdbuf2))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Cleaning up\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)unlink("../.test.dir/subdir/file");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir("../.test.dir/subdir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void)rmdir("../.test.dir");
</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;'>+ return rc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span></pre><pre style='margin:0'>
</pre>