Subject: Re: bug#29231: 26.0.90; invald file name for symbolic files

From: Paul Eggert <[email-masked]>
Date: Sat, 11 Nov 2017 23:19:05 -0800

Paul Eggert wrote:
> Alan Third wrote:
>> Only with symlinks faccessat returns success if it’s pointing to a
>> file and you put ‘/’ on the end.
> 
> This is a well-known problem on macOS, and Emacs is supposed to compile a 
> replacement fstatat function

Whoops, you were writing about faccessat whereas I was thinking about fstatat. 
Please ignore my previous email, and sorry about the confusion.

Apparently macOS faccessat has a problem similar to fstatat. Gnulib did not work 
around the faccessat problem, so I wrote and installed a fix for this into 
Gnulib and installed the attached patch into the emacs-26 branch. Please give it 
a try.
From 7775c4729814431608c943643a490ad5f1f68a99 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Sat, 11 Nov 2017 23:11:03 -0800
Subject: [PATCH] Merge from Gnulib

This incorporates:
2017-11-11 faccessat: port to macOS (Bug#29231)
2017-11-05 fstatat: pacify GCC on unusual platform
* build-aux/config.guess, build-aux/config.sub:
* doc/misc/texinfo.tex, lib/faccessat.c, lib/fstatat.c:
* lib/unistd.in.h, m4/faccessat.m4, m4/unistd_h.m4:
Copy from Gnulib.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
---
 build-aux/config.guess |  9 +++++---
 build-aux/config.sub   |  5 ++---
 doc/misc/texinfo.tex   |  4 +++-
 lib/faccessat.c        | 60 ++++++++++++++++++++++++++++++++++++++++++++------
 lib/fstatat.c          |  2 +-
 lib/gnulib.mk.in       |  2 ++
 lib/unistd.in.h        | 16 ++++++++++++--
 m4/faccessat.m4        |  6 +++--
 m4/gnulib-comp.m4      | 10 ++++-----
 m4/unistd_h.m4         |  3 ++-
 10 files changed, 92 insertions(+), 25 deletions(-)

diff --git a/build-aux/config.guess b/build-aux/config.guess
index 2773ac4..31e01ef 100755
--- a/build-aux/config.guess
+++ b/build-aux/config.guess
@@ -2,7 +2,7 @@
 # Attempt to guess a canonical system name.
 #   Copyright 1992-2017 Free Software Foundation, Inc.
 
-timestamp='2017-11-01'
+timestamp='2017-11-07'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ usage=
 
 Output the configuration name of the system \`$me' is run on.
 
-Operation modes:
+Options:
   -h, --help         print this help, then exit
   -t, --time-stamp   print date of last modification, then exit
   -v, --version      print version number, then exit
@@ -244,6 +244,9 @@ UNAME_VERSION=
 	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
 	echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
 	exit ;;
+    *:MidnightBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-midnightbsd${UNAME_RELEASE}
+	exit ;;
     *:ekkoBSD:*:*)
 	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
 	exit ;;
@@ -479,7 +482,7 @@ UNAME_VERSION=
 #endif
 	#if defined (host_mips) && defined (MIPSEB)
 	#if defined (SYSTYPE_SYSV)
-	  printf ("mips-mips-risco0s%ssysv\\n", argv[1]); exit (0);
+	  printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
 	#endif
 	#if defined (SYSTYPE_SVR4)
 	  printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
diff --git a/build-aux/config.sub b/build-aux/config.sub
index bbad4c4..fb57947 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -2,7 +2,7 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2017 Free Software Foundation, Inc.
 
-timestamp='2017-11-01'
+timestamp='2017-11-04'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -57,7 +57,7 @@ usage=
 
 Canonicalize a configuration name.
 
-Operation modes:
+Options:
   -h, --help         print this help, then exit
   -t, --time-stamp   print date of last modification, then exit
   -v, --version      print version number, then exit
@@ -313,7 +313,6 @@ maybe_os=
 	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
 	| visium \
 	| wasm32 \
-	| we32k \
 	| x86 | xc16x | xstormy16 | xtensa \
 	| z8k | z80)
 		basic_machine=$basic_machine-unknown
diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex
index 9bd75b9..022c3f5 100644
--- a/doc/misc/texinfo.tex
+++ b/doc/misc/texinfo.tex
@@ -3,7 +3,7 @@
 % Load plain if necessary, i.e., if running under initex.
 \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
 %
-\def\texinfoversion{2017-09-16.10}
+\def\texinfoversion{2017-09-11.18}
 %
 % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
 % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
@@ -11425,9 +11425,11 @@
   %
   \dimen0 = #1\relax
   \advance\dimen0 by \voffset
+  \advance\dimen0 by 1in % reference point for DVI is 1 inch from top of page
   %
   \dimen2 = \hsize
   \advance\dimen2 by \normaloffset
+  \advance\dimen2 by 1in % reference point is 1 inch from left edge of page
   %
   \internalpagesizes{#1}{\hsize}%
                     {\voffset}{\normaloffset}%
diff --git a/lib/faccessat.c b/lib/faccessat.c
index 6cf9c99..fa92358 100644
--- a/lib/faccessat.c
+++ b/lib/faccessat.c
@@ -16,10 +16,31 @@
 
 /* written by Eric Blake */
 
+/* If the user's config.h happens to include <unistd.h>, let it include only
+   the system's <unistd.h> here, so that orig_faccessat doesn't recurse to
+   rpl_faccessat.  */
+#define _GL_INCLUDING_UNISTD_H
 #include <config.h>
 
 #include <unistd.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#undef _GL_INCLUDING_UNISTD_H
+
+#if HAVE_FACCESSAT
+static int
+orig_faccessat (int fd, char const *name, int mode, int flag)
+{
+  return faccessat (fd, name, mode, flag);
+}
+#endif
+
+/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc
+   eliminates this include because of the preliminary #include <unistd.h>
+   above.  */
+#include "unistd.h"
 
 #ifndef HAVE_ACCESS
 /* Mingw lacks access, but it also lacks real vs. effective ids, so
@@ -28,6 +49,29 @@
 # define access euidaccess
 #endif
 
+#if HAVE_FACCESSAT
+
+int
+rpl_faccessat (int fd, char const *file, int mode, int flag)
+{
+  int result = orig_faccessat (fd, file, mode, flag);
+
+  if (result == 0 && file[strlen (file) - 1] == '/')
+    {
+      struct stat st;
+      result = fstatat (fd, file, &st, 0);
+      if (result == 0 && !S_ISDIR (st.st_mode))
+        {
+          errno = ENOTDIR;
+          return -1;
+        }
+    }
+
+  return result;
+}
+
+#else /* !HAVE_FACCESSAT */
+
 /* Invoke access or euidaccess on file, FILE, using mode MODE, in the directory
    open on descriptor FD.  If possible, do it without changing the
    working directory.  Otherwise, resort to using save_cwd/fchdir, then
@@ -36,10 +80,12 @@
    Note that this implementation only supports AT_EACCESS, although some
    native versions also support AT_SYMLINK_NOFOLLOW.  */
 
-#define AT_FUNC_NAME faccessat
-#define AT_FUNC_F1 euidaccess
-#define AT_FUNC_F2 access
-#define AT_FUNC_USE_F1_COND AT_EACCESS
-#define AT_FUNC_POST_FILE_PARAM_DECLS , int mode, int flag
-#define AT_FUNC_POST_FILE_ARGS        , mode
-#include "at-func.c"
+# define AT_FUNC_NAME faccessat
+# define AT_FUNC_F1 euidaccess
+# define AT_FUNC_F2 access
+# define AT_FUNC_USE_F1_COND AT_EACCESS
+# define AT_FUNC_POST_FILE_PARAM_DECLS , int mode, int flag
+# define AT_FUNC_POST_FILE_ARGS        , mode
+# include "at-func.c"
+
+#endif
diff --git a/lib/fstatat.c b/lib/fstatat.c
index 67e48d9..294861f 100644
--- a/lib/fstatat.c
+++ b/lib/fstatat.c
@@ -28,7 +28,7 @@
 #include <sys/stat.h>
 #undef __need_system_sys_stat_h
 
-#if HAVE_FSTATAT
+#if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG
 static int
 orig_fstatat (int fd, char const *filename, struct stat *buf, int flags)
 {
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 0f795b3..c510a0e 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -689,6 +689,7 @@ REPLACE_DIRFD = @REPLACE_DIRFD@
 REPLACE_DPRINTF = @REPLACE_DPRINTF@
 REPLACE_DUP = @REPLACE_DUP@
 REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_FACCESSAT = @REPLACE_FACCESSAT@
 REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
 REPLACE_FCLOSE = @REPLACE_FCLOSE@
 REPLACE_FCNTL = @REPLACE_FCNTL@
@@ -2986,6 +2987,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
 	      -e 's|@''REPLACE_CLOSE''@|$(REPLACE_CLOSE)|g' \
 	      -e 's|@''REPLACE_DUP''@|$(REPLACE_DUP)|g' \
 	      -e 's|@''REPLACE_DUP2''@|$(REPLACE_DUP2)|g' \
+	      -e 's|@''REPLACE_FACCESSAT''@|$(REPLACE_FACCESSAT)|g' \
 	      -e 's|@''REPLACE_FCHOWNAT''@|$(REPLACE_FCHOWNAT)|g' \
 	      -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \
 	      -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \
diff --git a/lib/unistd.in.h b/lib/unistd.in.h
index ca8090a..9144783 100644
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -461,13 +461,25 @@ _GL_WARN_ON_USE (euidaccess, "euidaccess is unportable - "

 #if @GNULIB_FACCESSAT@
-# if !@HAVE_FACCESSAT@
+# if @REPLACE_FACCESSAT@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef faccessat
+#   define faccessat rpl_faccessat
+#  endif
+_GL_FUNCDECL_RPL (faccessat, int,
+                  (int fd, char const *name, int mode, int flag)
+                  _GL_ARG_NONNULL ((2)));
+_GL_CXXALIAS_RPL (faccessat, int,
+                  (int fd, char const *name, int mode, int flag));
+# else
+#  if !@HAVE_FACCESSAT@
 _GL_FUNCDECL_SYS (faccessat, int,
                   (int fd, char const *file, int mode, int flag)
                   _GL_ARG_NONNULL ((2)));
-# endif
+#  endif
 _GL_CXXALIAS_SYS (faccessat, int,
                   (int fd, char const *file, int mode, int flag));
+# endif
 _GL_CXXALIASWARN (faccessat);
 #elif defined GNULIB_POSIXCHECK
 # undef faccessat
diff --git a/m4/faccessat.m4 b/m4/faccessat.m4
index 837ae54..f4cb49d 100644
--- a/m4/faccessat.m4
+++ b/m4/faccessat.m4
@@ -1,4 +1,4 @@
-# serial 6
+# serial 7
 # See if we need to provide faccessat replacement.
 
 dnl Copyright (C) 2009-2017 Free Software Foundation, Inc.
@@ -18,10 +18,12 @@ AC_DEFUN
   AC_CHECK_FUNCS_ONCE([faccessat])
   if test $ac_cv_func_faccessat = no; then
     HAVE_FACCESSAT=0
+  elif test "$gl_cv_func_lstat_dereferences_slashed_symlink" != yes; then
+    REPLACE_FACCESSAT=1
   fi
 ])
 
-# Prerequisites of lib/faccessat.m4.
+# Prerequisites of lib/faccessat.c.
 AC_DEFUN([gl_PREREQ_FACCESSAT],
 [
   AC_CHECK_FUNCS([access])
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index c551752..13459f9 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -222,7 +222,7 @@ AC_DEFUN
   gl_STRING_MODULE_INDICATOR([explicit_bzero])
   AC_REQUIRE([gl_EXTERN_INLINE])
   gl_FUNC_FACCESSAT
-  if test $HAVE_FACCESSAT = 0; then
+  if test $HAVE_FACCESSAT = 0 || test $REPLACE_FACCESSAT = 1; then
     AC_LIBOBJ([faccessat])
     gl_PREREQ_FACCESSAT
   fi
@@ -593,16 +593,16 @@ AC_DEFUN
       gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=true
     fi
   }
-  if test $HAVE_FACCESSAT = 0; then
+  if test $HAVE_FACCESSAT = 0 || test $REPLACE_FACCESSAT = 1; then
     func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
   fi
-  if test $HAVE_FACCESSAT = 0; then
+  if test $HAVE_FACCESSAT = 0 || test $REPLACE_FACCESSAT = 1; then
     func_gl_gnulib_m4code_dosname
   fi
-  if test $HAVE_FACCESSAT = 0; then
+  if test $HAVE_FACCESSAT = 0 || test $REPLACE_FACCESSAT = 1; then
     func_gl_gnulib_m4code_euidaccess
   fi
-  if test $HAVE_FACCESSAT = 0; then
+  if test $HAVE_FACCESSAT = 0 || test $REPLACE_FACCESSAT = 1; then
     func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
   fi
   if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4
index cc44677..60e7ea4 100644
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 70
+# unistd_h.m4 serial 71
 dnl Copyright (C) 2006-2017 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -159,6 +159,7 @@ AC_DEFUN
   REPLACE_CLOSE=0;        AC_SUBST([REPLACE_CLOSE])
   REPLACE_DUP=0;          AC_SUBST([REPLACE_DUP])
   REPLACE_DUP2=0;         AC_SUBST([REPLACE_DUP2])
+  REPLACE_FACCESSAT=0;    AC_SUBST([REPLACE_FACCESSAT])
   REPLACE_FCHOWNAT=0;     AC_SUBST([REPLACE_FCHOWNAT])
   REPLACE_FTRUNCATE=0;    AC_SUBST([REPLACE_FTRUNCATE])
   REPLACE_GETCWD=0;       AC_SUBST([REPLACE_GETCWD])
-- 
2.7.4