Add __mingw_access() that works the same for all msvcr*/ucrt libs

Old versions of MSVCRT _access() just ignored X_OK, while the
version shipped with Vista, returns an error code.
_access() from msvcr110/120 returns an error code for nul file.

Signed-off-by: Mateusz Brzostek <mateuszb@poczta.onet.pl>
Signed-off-by: Liu Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index f8b0623..10f3b04 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -330,7 +330,7 @@
   misc/wcstoimax.c       misc/wcstold.c             misc/wcstoumax.c        misc/wctob.c                 misc/wctrans.c         \
   misc/wctype.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/wmemset.c         misc/ftw.c                 misc/ftw64.c            misc/mingw-access.c          \
   \
   stdio/mingw_pformat.h    \
   stdio/vfscanf2.S         stdio/vfwscanf2.S         stdio/vscanf2.S          stdio/vsscanf2.S          stdio/vswscanf2.S \
diff --git a/mingw-w64-crt/misc/mingw-access.c b/mingw-w64-crt/misc/mingw-access.c
new file mode 100644
index 0000000..6f405ab
--- /dev/null
+++ b/mingw-w64-crt/misc/mingw-access.c
@@ -0,0 +1,54 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#include <windows.h>
+#include <errno.h>
+#include <io.h>
+
+int __cdecl __mingw_access(const char *fname, int mode);
+
+int __cdecl __mingw_access(const char *fname, int mode)
+{
+  DWORD attr;
+
+  if (fname == NULL || (mode & ~(F_OK | X_OK | W_OK | R_OK)))
+  {
+    errno = EINVAL;
+    return -1;
+  }
+
+  attr = GetFileAttributesA(fname);
+  if (attr == INVALID_FILE_ATTRIBUTES)
+  {
+    switch (GetLastError())
+    {
+      case ERROR_FILE_NOT_FOUND:
+      case ERROR_PATH_NOT_FOUND:
+        errno = ENOENT;
+        break;
+      case ERROR_ACCESS_DENIED:
+        errno = EACCES;
+        break;
+      default:
+        errno = EINVAL;
+    }
+    return -1;
+  }
+
+  if (attr & FILE_ATTRIBUTE_DIRECTORY)
+  {
+    /* All directories have read & write access */
+    return 0;
+  }
+
+  if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
+  {
+    /* no write permission on file */
+    errno = EACCES;
+    return -1;
+  }
+  else
+    return 0;
+}
diff --git a/mingw-w64-headers/crt/io.h b/mingw-w64-headers/crt/io.h
index a7cc5fc..4a5b08b 100644
--- a/mingw-w64-headers/crt/io.h
+++ b/mingw-w64-headers/crt/io.h
@@ -365,9 +365,7 @@
 /*  Old versions of MSVCRT access() just ignored X_OK, while the version
     shipped with Vista, returns an error code.  This will restore the
     old behaviour  */
-static inline int __mingw_access (const char *__fname, int __mode) {
-  return  _access (__fname, __mode & ~X_OK);
-}
+int __cdecl __mingw_access (const char *__fname, int __mode);
 
 #define access(__f,__m)  __mingw_access (__f, __m)
 #endif