+2023-10-03 Bruno Haible <bruno@clisp.org>
+
+ access: Work around trailing slash bug on Mac OS X 10.5.
+ * m4/access.m4 (gl_FUNC_ACCESS): Test whether access honors a trailing
+ slash. Set REPLACE_ACCESS to 1 and define ACCESS_TRAILING_SLASH_BUG if
+ not.
+ * lib/access.c (access): Add an implementation for Unix-like platforms.
+ * tests/test-access.c (main): Test for result if the argument has a
+ trailing slash.
+ * modules/access-tests (Depends-on): Add 'symlink'.
+ * doc/posix-functions/access.texi: Mention the Mac OS X bug.
+
2023-10-03 Bruno Haible <bruno@clisp.org>
update-copyright tests: Fix test failure (regression 2023-06-18).
@item
This function does not support the @code{X_OK} mode on some platforms:
MSVC 14.
+@item
+This function does not reject trailing slashes on symlinks to non-directories
+on some platforms:
+Mac OS X 10.5.
@end itemize
Portability problems not fixed by Gnulib:
#include <unistd.h>
#include <fcntl.h>
-#include <io.h>
+
+#if defined _WIN32 && ! defined __CYGWIN__
+
+# include <io.h>
int
access (const char *file, int mode)
mode = (mode & ~X_OK) | R_OK;
return _access (file, mode);
}
+
+#else
+
+# include <errno.h>
+# include <string.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+
+int
+access (const char *file, int mode)
+# undef access
+{
+ int ret = access (file, mode);
+# if ACCESS_TRAILING_SLASH_BUG
+ if (ret == 0)
+ {
+ size_t file_len = strlen (file);
+ if (file_len > 0 && file[file_len - 1] == '/')
+ {
+ struct stat st;
+ if (stat (file, &st) == 0 && ! S_ISDIR (st.st_mode))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
+ }
+# endif
+ return ret;
+}
+
+#endif
-# access.m4 serial 2
+# access.m4 serial 3
dnl Copyright (C) 2019-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl On native Windows, access (= _access) does not support the X_OK mode.
dnl It works by chance on some versions of mingw.
case "$host_os" in
- mingw* | windows*) REPLACE_ACCESS=1 ;;
+ mingw* | windows*)
+ REPLACE_ACCESS=1
+ ;;
+ *)
+ dnl Mac OS X 10.5 mistakenly allows access("link-to-file/",amode).
+ AC_CHECK_FUNCS_ONCE([lstat])
+ AC_CACHE_CHECK([whether access honors trailing slash],
+ [gl_cv_func_access_slash_works],
+ [# Assume that if we have lstat, we can also check symlinks.
+ if test $ac_cv_func_lstat = yes; then
+ rm -rf conftest.f conftest.lnk
+ touch conftest.f || AC_MSG_ERROR([cannot create temporary files])
+ ln -s conftest.f conftest.lnk
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+ #include <unistd.h>
+ ]],
+ [[int result = 0;
+ if (access ("conftest.lnk/", R_OK) == 0)
+ result |= 1;
+ return result;
+ ]])],
+ [gl_cv_func_access_slash_works=yes],
+ [gl_cv_func_access_slash_works=no],
+ dnl When crosscompiling, assume access is broken.
+ [case "$host_os" in
+ # Guess yes on Linux systems.
+ linux-* | linux) gl_cv_func_access_slash_works="guessing yes" ;;
+ # Guess yes on systems that emulate the Linux system calls.
+ midipix*) gl_cv_func_access_slash_works="guessing yes" ;;
+ # Guess yes on glibc systems.
+ *-gnu*) gl_cv_func_access_slash_works="guessing yes" ;;
+ # If we don't know, obey --enable-cross-guesses.
+ *) gl_cv_func_access_slash_works="$gl_cross_guess_normal" ;;
+ esac
+ ])
+ rm -rf conftest.f conftest.lnk
+ else
+ gl_cv_func_access_slash_works="guessing yes"
+ fi
+ ])
+ case "$gl_cv_func_access_slash_works" in
+ *yes) ;;
+ *)
+ REPLACE_ACCESS=1
+ AC_DEFINE([ACCESS_TRAILING_SLASH_BUG], [1],
+ [Define if access does not correctly handle trailing slashes.])
+ ;;
+ esac
+ ;;
esac
])
Depends-on:
creat
root-uid
+symlink
configure.ac:
AC_CHECK_FUNCS_ONCE([geteuid])
unlink (BASE "f1");
chmod (BASE "f2", 0600);
unlink (BASE "f2");
+ unlink (BASE "sl");
{
errno = 0;
{
ASSERT (close (creat (BASE "f1", 0700)) == 0);
+ ASSERT (access (BASE "f1", F_OK) == 0);
ASSERT (access (BASE "f1", R_OK) == 0);
ASSERT (access (BASE "f1", W_OK) == 0);
ASSERT (access (BASE "f1", X_OK) == 0);
+
+ ASSERT (access (BASE "f1/", F_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ ASSERT (access (BASE "f1/", R_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ ASSERT (access (BASE "f1/", W_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ ASSERT (access (BASE "f1/", X_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+
+ if (symlink (BASE "f1", BASE "sl") == 0)
+ {
+ ASSERT (access (BASE "sl/", F_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ ASSERT (access (BASE "sl/", R_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ ASSERT (access (BASE "sl/", W_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ ASSERT (access (BASE "sl/", X_OK) == -1);
+ ASSERT (errno == ENOTDIR);
+ }
}
{
ASSERT (close (creat (BASE "f2", 0600)) == 0);
ASSERT (unlink (BASE "f1") == 0);
ASSERT (chmod (BASE "f2", 0600) == 0);
ASSERT (unlink (BASE "f2") == 0);
+ unlink (BASE "sl");
return 0;
}