* m4/mkfifoat.m4 (gl_FUNC_MKFIFOAT): Set also REPLACE_MKNODAT.
* lib/sys_stat.in.h (mknodat): Consider REPLACE_MKNODAT.
* lib/mknodat.c: Add an overriding implementation of mknodat().
* m4/sys_stat_h.m4 (gl_SYS_STAT_H_DEFAULTS): Initialize REPLACE_MKNODAT.
* modules/sys_stat (Makefile.am): Substitute REPLACE_MKNODAT.
* modules/mkfifoat (Depends-on, configure.ac): Consider REPLACE_MKNODAT.
* doc/posix-functions/mknodat.texi: Mention the AIX bug.
2021-01-04 Bruno Haible <bruno@clisp.org>
+ mkfifoat: Work around trailing slash bug in mknodat() on AIX 7.2.
+ * m4/mkfifoat.m4 (gl_FUNC_MKFIFOAT): Set also REPLACE_MKNODAT.
+ * lib/sys_stat.in.h (mknodat): Consider REPLACE_MKNODAT.
+ * lib/mknodat.c: Add an overriding implementation of mknodat().
+ * m4/sys_stat_h.m4 (gl_SYS_STAT_H_DEFAULTS): Initialize REPLACE_MKNODAT.
+ * modules/sys_stat (Makefile.am): Substitute REPLACE_MKNODAT.
+ * modules/mkfifoat (Depends-on, configure.ac): Consider REPLACE_MKNODAT.
+ * doc/posix-functions/mknodat.texi: Mention the AIX bug.
+
mkfifoat: Work around trailing slash bug in mkfifoat() on AIX 7.2.
* m4/mkfifoat.m4 (gl_FUNC_MKFIFOAT): Add a test whether mkfifoat rejects
trailing slashes. Set REPLACE_MKFIFOAT if not.
This function is missing on some platforms:
glibc 2.3.6, Mac OS X 10.13, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin 1.5.x, mingw, MSVC 14, Android 4.4.
But the replacement function is not safe to be used in libraries and is not multithread-safe.
+@item
+This function does not fail when the file name argument ends in a slash
+and (without the slash) names a nonexistent file, on some platforms:
+AIX 7.2.
@end itemize
Portability problems not fixed by Gnulib:
#include <stdlib.h>
-#if !HAVE_MKNOD
+#if HAVE_MKNODAT
# include <errno.h>
+# include <fcntl.h>
+# include <string.h>
+
+int
+rpl_mknodat (int fd, char const *file, mode_t mode, dev_t dev)
+#undef mknodat
+{
+ /* Use the original mknodat(), but correct the trailing slash handling. */
+ size_t len = strlen (file);
+ if (len && file[len - 1] == '/')
+ {
+ struct stat st;
+
+ if (fstatat (fd, file, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ {
+ if (errno == EOVERFLOW)
+ /* It's surely a file, not a directory. */
+ errno = ENOTDIR;
+ }
+ else
+ {
+ /* It's a directory, otherwise fstatat() would have reported an error
+ ENOTDIR. */
+ errno = EEXIST;
+ }
+ return -1;
+ }
+
+ return mknodat (fd, file, mode, dev);
+}
+
+#else
+
+# if !HAVE_MKNOD
+
+# include <errno.h>
/* Mingw lacks mknod, so this wrapper is trivial. */
return -1;
}
-#else
+# else
/* Create a file system node FILE relative to directory FD, with
access permissions and file type in MODE, and device type in DEV.
then mknod/restore_cwd. If either the save_cwd or the restore_cwd
fails, then give a diagnostic and exit nonzero. */
-# define AT_FUNC_NAME mknodat
-# define AT_FUNC_F1 mknod
-# define AT_FUNC_POST_FILE_PARAM_DECLS , mode_t mode, dev_t dev
-# define AT_FUNC_POST_FILE_ARGS , mode, dev
-# include "at-func.c"
-# undef AT_FUNC_NAME
-# undef AT_FUNC_F1
-# undef AT_FUNC_POST_FILE_PARAM_DECLS
-# undef AT_FUNC_POST_FILE_ARGS
+# define AT_FUNC_NAME mknodat
+# define AT_FUNC_F1 mknod
+# define AT_FUNC_POST_FILE_PARAM_DECLS , mode_t mode, dev_t dev
+# define AT_FUNC_POST_FILE_ARGS , mode, dev
+# include "at-func.c"
+# undef AT_FUNC_NAME
+# undef AT_FUNC_F1
+# undef AT_FUNC_POST_FILE_PARAM_DECLS
+# undef AT_FUNC_POST_FILE_ARGS
+
+# endif
#endif
#if @GNULIB_MKNODAT@
-# if !@HAVE_MKNODAT@
+# if @REPLACE_MKNODAT@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef mknodat
+# define mknodat rpl_mknodat
+# endif
+_GL_FUNCDECL_RPL (mknodat, int,
+ (int fd, char const *file, mode_t mode, dev_t dev)
+ _GL_ARG_NONNULL ((2)));
+_GL_CXXALIAS_RPL (mknodat, int,
+ (int fd, char const *file, mode_t mode, dev_t dev));
+# else
+# if !@HAVE_MKNODAT@
_GL_FUNCDECL_SYS (mknodat, int,
(int fd, char const *file, mode_t mode, dev_t dev)
_GL_ARG_NONNULL ((2)));
-# endif
+# endif
_GL_CXXALIAS_SYS (mknodat, int,
(int fd, char const *file, mode_t mode, dev_t dev));
+# endif
_GL_CXXALIASWARN (mknodat);
#elif defined GNULIB_POSIXCHECK
# undef mknodat
-# serial 4
+# serial 5
# See if we need to provide mkfifoat/mknodat replacement.
dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
])
case "$gl_cv_func_mkfifoat_works" in
*yes) ;;
- *) REPLACE_MKFIFOAT=1 ;;
+ *)
+ REPLACE_MKFIFOAT=1
+ dnl mknodat() has the same bug as mkfifoat().
+ REPLACE_MKNODAT=1
+ ;;
esac
else
# No known system has mkfifoat but not mknodat
-# sys_stat_h.m4 serial 37 -*- Autoconf -*-
+# sys_stat_h.m4 serial 38 -*- Autoconf -*-
dnl Copyright (C) 2006-2021 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
REPLACE_MKFIFO=0; AC_SUBST([REPLACE_MKFIFO])
REPLACE_MKFIFOAT=0; AC_SUBST([REPLACE_MKFIFOAT])
REPLACE_MKNOD=0; AC_SUBST([REPLACE_MKNOD])
+ REPLACE_MKNODAT=0; AC_SUBST([REPLACE_MKNODAT])
REPLACE_STAT=0; AC_SUBST([REPLACE_STAT])
REPLACE_UTIMENSAT=0; AC_SUBST([REPLACE_UTIMENSAT])
])
Depends-on:
sys_stat
extensions
-fstatat [test $REPLACE_MKFIFOAT = 1]
+fstatat [test $REPLACE_MKFIFOAT = 1 || test $REPLACE_MKNODAT = 1]
at-internal [test $HAVE_MKFIFOAT = 0 || test $HAVE_MKNODAT = 0]
errno [test $HAVE_MKFIFOAT = 0 || test $HAVE_MKNODAT = 0]
fchdir [test $HAVE_MKFIFOAT = 0 || test $HAVE_MKNODAT = 0]
if test $HAVE_MKFIFOAT = 0 || test $REPLACE_MKFIFOAT = 1; then
AC_LIBOBJ([mkfifoat])
fi
-if test $HAVE_MKNODAT = 0; then
+if test $HAVE_MKNODAT = 0 || test $REPLACE_MKNODAT = 1; then
AC_LIBOBJ([mknodat])
fi
gl_SYS_STAT_MODULE_INDICATOR([mkfifoat])
-e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \
-e 's|@''REPLACE_MKFIFOAT''@|$(REPLACE_MKFIFOAT)|g' \
-e 's|@''REPLACE_MKNOD''@|$(REPLACE_MKNOD)|g' \
+ -e 's|@''REPLACE_MKNODAT''@|$(REPLACE_MKNODAT)|g' \
-e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \
-e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \
-e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \