summaryrefslogtreecommitdiffstats
path: root/lib/access.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/access.c')
-rw-r--r--lib/access.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/lib/access.c b/lib/access.c
index e2c12b1..c3bdbff 100644
--- a/lib/access.c
+++ b/lib/access.c
@@ -1,5 +1,5 @@
/* Test the access rights of a file.
- Copyright (C) 2019-2023 Free Software Foundation, Inc.
+ Copyright (C) 2019-2024 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -19,13 +19,53 @@
/* Specification. */
#include <unistd.h>
+#include <errno.h>
#include <fcntl.h>
-#include <io.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+# include <io.h>
+#endif
int
access (const char *file, int mode)
+#undef access
{
+ int ret;
+
+#if defined _WIN32 && !defined __CYGWIN__
if ((mode & X_OK) != 0)
mode = (mode & ~X_OK) | R_OK;
- return _access (file, mode);
+ ret = _access (file, mode);
+#else
+ ret = access (file, mode);
+#endif
+
+#if (defined _WIN32 && !defined __CYGWIN__) || ACCESS_TRAILING_SLASH_BUG
+# if defined _WIN32 && !defined __CYGWIN__
+ if (ret == 0 || errno == EINVAL)
+# else
+ if (ret == 0)
+# endif
+ {
+ size_t file_len = strlen (file);
+ if (file_len > 0 && file[file_len - 1] == '/')
+ {
+ struct stat st;
+ if (stat (file, &st) == 0)
+ {
+ if (! S_ISDIR (st.st_mode))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
+ else
+ return (mode == F_OK && errno == EOVERFLOW ? 0 : -1);
+ }
+ }
+#endif
+ return ret;
}