crt: Fix ABI of POSIX ftw() and nftw() functions

There are 4 POSIX stat functions (stat32, stat32i64, stat64, stat64i32)
which differs in the stat structure point size. And there is additional
stat symbol which alias to one of those based on the _FILE_OFFSET_BITS and
_USE_32BIT_TIME_T settings.

As POSIX ftw() and nftw() functions takes also struct stat in its function
callback argument, it is required to properly provide for each settings of
_FILE_OFFSET_BITS and _USE_32BIT_TIME_T configuration, the appropriate
struct stat ABI compatible ftw and nftw symbol.

This change provides 4 new ftw function symbols: ftw32, ftw32i64, ftw64 and
ftw64i32. And same for nftw symbols: nftw32, nftw32i64, nftw64, nftw64i32.

So with this change, the call to the ftw() or nftw() function will respect
the _FILE_OFFSET_BITS and _USE_32BIT_TIME_T settings and provide correct
size of stat structure.

Function symbols for ftw and nftw are aliases to one of the fixed-size
symbol based on the _FILE_OFFSET_BITS and _USE_32BIT_TIME_T settings.

Signed-off-by: Martin Storsjö <martin@martin.st>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index a049274..195251a 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -1063,7 +1063,8 @@
   misc/wcstold.c \
   misc/wdirent.c         misc/winbs_uint64.c        misc/winbs_ulong.c      misc/winbs_ushort.c    \
   misc/wmemchr.c         misc/wmemcmp.c             misc/wmemcpy.c          misc/wmemmove.c              misc/wmempcpy.c        \
-  misc/wmemset.c         misc/ftw.c                 misc/ftw64.c            misc/mingw-access.c          \
+  misc/wmemset.c         misc/mingw-access.c \
+  misc/ftw32.c           misc/ftw32i64.c            misc/ftw64.c            misc/ftw64i32.c \
   \
   ssp/chk_fail.c         ssp/gets_chk.c             ssp/memcpy_chk.c        ssp/memmove_chk.c \
   ssp/mempcpy_chk.c \
@@ -4314,6 +4315,7 @@
   crt/CRT_noglob.c \
   crt/txtmode.c \
   crt/ucrtexe.c \
+  misc/ftw.c \
   profile/gcrt0.c \
   profile/COPYING \
   profile/CYGWIN_LICENSE \
diff --git a/mingw-w64-crt/misc/ftw.c b/mingw-w64-crt/misc/ftw.c
index 74d05aa..e87ab5e 100644
--- a/mingw-w64-crt/misc/ftw.c
+++ b/mingw-w64-crt/misc/ftw.c
@@ -15,11 +15,11 @@
 #include <dirent.h>
 #include <ftw.h>
 
-#ifdef IMPL_FTW64
-#define stat stat64
-#define nftw nftw64
-#define ftw ftw64
-#endif
+#undef stat64
+int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat);
+int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat);
+int __cdecl stat64(const char *_Filename, struct _stat64 *_Stat);
+int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat);
 
 typedef struct dir_data_t {
   DIR *h;
@@ -36,14 +36,14 @@
   dir_data_t **dirs;
   char *buf;
   struct FTW ftw;
-  int (*fcb) (const char *, const struct stat *, int , struct FTW *);
+  int (*fcb) (const char *, const STRUCT_STAT *, int , struct FTW *);
   size_t cur_dir, msz_dir, buf_sz;
   int flags;
   dev_t dev;
 } ctx_t;
 
 static int add_object (ctx_t *);
-static int do_dir (ctx_t *, struct stat *, dir_data_t *);
+static int do_dir (ctx_t *, STRUCT_STAT *, dir_data_t *);
 static int do_entity (ctx_t *, dir_data_t *, const char *, size_t);
 static int do_it (const char *, int, void *, int, int);
 
@@ -225,7 +225,7 @@
 static int
 do_entity (ctx_t *ctx, dir_data_t *dir, const char *name, size_t namlen)
 {
-  struct stat st;
+  STRUCT_STAT st;
   char *h;
   size_t cnt_sz;
   int ret = 0, flag = 0;
@@ -249,7 +249,7 @@
 
   name = ctx->buf;
 
-  if (stat (name, &st) < 0)
+  if (FUNC_STAT (name, &st) < 0)
     {
       if (errno != EACCES && errno != ENOENT)
 	ret = -1;
@@ -257,7 +257,7 @@
 	flag = FTW_NS;
 
       if (!(ctx->flags & FTW_PHYS))
-	stat (name, &st);
+	FUNC_STAT (name, &st);
     }
   else
     flag = (S_ISDIR (st.st_mode) ? FTW_D : FTW_F);
@@ -281,7 +281,7 @@
 
 
 static int
-do_dir (ctx_t *ctx, struct stat *st, __UNUSED_PARAM(dir_data_t *old_dir))
+do_dir (ctx_t *ctx, STRUCT_STAT *st, __UNUSED_PARAM(dir_data_t *old_dir))
 {
   dir_data_t dir;
   struct dirent *d;
@@ -378,7 +378,7 @@
 do_it (const char *dir, __UNUSED_PARAM(int is_nftw), void *fcb, int descriptors, int flags)
 {
   struct ctx_t ctx;
-  struct stat st;
+  STRUCT_STAT st;
   int ret = 0;
   int sv_e;
   char *cp;
@@ -417,12 +417,12 @@
   ctx.ftw.level = 0;
   ctx.ftw.base = cp - ctx.buf;
   ctx.flags = flags;
-  ctx.fcb = (int (*) (const char *, const struct stat *, int , struct FTW *)) fcb;
+  ctx.fcb = (int (*) (const char *, const STRUCT_STAT *, int , struct FTW *)) fcb;
   ctx.objs = NULL;
 
   if (!ret)
     {
-      if (stat (ctx.buf, &st) < 0)
+      if (FUNC_STAT (ctx.buf, &st) < 0)
 	ret = -1;
       else if (S_ISDIR (st.st_mode))
 	{
@@ -451,13 +451,17 @@
 }
 
 int
-ftw (const char *path, int (*fcb) (const char *, const struct stat *, int), int descriptors)
+FUNC_FTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int), int descriptors);
+int
+FUNC_FTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int), int descriptors)
 {
   return do_it (path, 0, fcb, descriptors, 0);
 }
 
 int
-nftw (const char *path, int (*fcb) (const char *, const struct stat *, int , struct FTW *), int descriptors, int flags)
+FUNC_NFTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int , struct FTW *), int descriptors, int flags);
+int
+FUNC_NFTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int , struct FTW *), int descriptors, int flags)
 {
   return do_it (path, 1, fcb, descriptors, flags);
 }
diff --git a/mingw-w64-crt/misc/ftw32.c b/mingw-w64-crt/misc/ftw32.c
new file mode 100644
index 0000000..5eb9e37
--- /dev/null
+++ b/mingw-w64-crt/misc/ftw32.c
@@ -0,0 +1,19 @@
+/**
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#define FUNC_FTW ftw32
+#define FUNC_NFTW nftw32
+#define FUNC_STAT stat32
+#define STRUCT_STAT struct _stat32
+#include "ftw.c"
+
+/* On 32-bit systems is stat ABI compatible with stat32 */
+#ifndef _WIN64
+#undef nftw
+#undef ftw
+struct stat;
+int __attribute__ ((alias ("nftw32"))) __cdecl nftw(const char *, int (*) (const char *, const struct stat *, int, struct FTW *), int, int);
+int __attribute__ ((alias ("ftw32"))) __cdecl ftw(const char *, int (*) (const char *, const struct stat *, int), int);
+#endif
diff --git a/mingw-w64-crt/misc/ftw32i64.c b/mingw-w64-crt/misc/ftw32i64.c
new file mode 100644
index 0000000..20985fb
--- /dev/null
+++ b/mingw-w64-crt/misc/ftw32i64.c
@@ -0,0 +1,10 @@
+/**
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#define FUNC_FTW ftw32i64
+#define FUNC_NFTW nftw32i64
+#define FUNC_STAT stat32i64
+#define STRUCT_STAT struct _stat32i64
+#include "ftw.c"
diff --git a/mingw-w64-crt/misc/ftw64.c b/mingw-w64-crt/misc/ftw64.c
index 3e45847..5595e76 100644
--- a/mingw-w64-crt/misc/ftw64.c
+++ b/mingw-w64-crt/misc/ftw64.c
@@ -3,6 +3,8 @@
  * No warranty is given; refer to the file DISCLAIMER within this package.
  */
 
-#define IMPL_FTW64 1
-
+#define FUNC_FTW ftw64
+#define FUNC_NFTW nftw64
+#define FUNC_STAT stat64
+#define STRUCT_STAT struct _stat64
 #include "ftw.c"
diff --git a/mingw-w64-crt/misc/ftw64i32.c b/mingw-w64-crt/misc/ftw64i32.c
new file mode 100644
index 0000000..2ded6ec
--- /dev/null
+++ b/mingw-w64-crt/misc/ftw64i32.c
@@ -0,0 +1,19 @@
+/**
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#define FUNC_FTW ftw64i32
+#define FUNC_NFTW nftw64i32
+#define FUNC_STAT stat64i32
+#define STRUCT_STAT struct _stat64i32
+#include "ftw.c"
+
+/* On 64-bit systems is stat ABI compatible with stat64i32 */
+#ifdef _WIN64
+#undef nftw
+#undef ftw
+struct stat;
+int __attribute__ ((alias ("nftw64i32"))) __cdecl nftw(const char *, int (*) (const char *, const struct stat *, int, struct FTW *), int, int);
+int __attribute__ ((alias ("ftw64i32"))) __cdecl ftw(const char *, int (*) (const char *, const struct stat *, int), int);
+#endif