bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

utimensat: Work around trailing slash bug in utimensat() on AIX 7.2


From: Bruno Haible
Subject: utimensat: Work around trailing slash bug in utimensat() on AIX 7.2
Date: Wed, 06 Jan 2021 05:02:26 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-197-generic; KDE/5.18.0; x86_64; ; )

On AIX 7.2, I see these test failures:

FAIL: test-utimens
==================

../../gltests/test-utimens.h:94: assertion 'func (BASE "file/", ts) == -1' 
failed
FAIL test-utimens (exit status: 134)

FAIL: test-utimensat
====================

../../gltests/test-utimens.h:94: assertion 'func (BASE "file/", ts) == -1' 
failed
FAIL test-utimensat (exit status: 134)

FAIL: test-fdutimensat
======================

../../gltests/test-utimens.h:94: assertion 'func (BASE "file/", ts) == -1' 
failed
FAIL test-fdutimensat (exit status: 134)

This patch makes them go away, more precisely, it makes these tests fail later.


2021-01-05  Bruno Haible  <bruno@clisp.org>

        utimensat: Work around trailing slash bug in utimensat() on AIX 7.2.
        * m4/utimensat.m4 (gl_FUNC_UTIMENSAT): Require AC_CANONICAL_HOST. Add a
        test for trailing slash handling. Improve cross-compilation guesses.
        Conditionally define HAVE_NEARLY_WORKING_UTIMENSAT.
        * lib/utimensat.c (rpl_utimensat): Add alternative implementation when
        HAVE_NEARLY_WORKING_UTIMENSAT is defined.
        * lib/utimens.c: Use the overridden utimensat when
        HAVE_NEARLY_WORKING_UTIMENSAT is defined.
        * doc/posix-functions/utimensat.texi: Mention the AIX bug.

diff --git a/doc/glibc-functions/futimesat.texi 
b/doc/glibc-functions/futimesat.texi
index 537bf42..9c11368 100644
--- a/doc/glibc-functions/futimesat.texi
+++ b/doc/glibc-functions/futimesat.texi
@@ -16,7 +16,7 @@ Portability problems not fixed by Gnulib:
 This function is missing on some platforms:
 glibc 2.3.6, Mac OS X 10.13, FreeBSD 6.0, NetBSD 9.0, OpenBSD 6.7, Minix 
3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Cygwin 1.5.x, mingw, MSVC 14, Android 7.1.
 @item
-On some platforms, this function mis-handles trailing slash:
+On some platforms, this function mis-handles a trailing slash:
 Solaris 9.
 @item
 This function cannot set full timestamp resolution.  Use
diff --git a/doc/posix-functions/utime.texi b/doc/posix-functions/utime.texi
index 4e41e5d..79e97f5 100644
--- a/doc/posix-functions/utime.texi
+++ b/doc/posix-functions/utime.texi
@@ -25,7 +25,7 @@ Mac OS X 10.13.
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-On some platforms, this function mis-handles trailing slash:
+On some platforms, this function mis-handles a trailing slash:
 Solaris 9.
 @item
 This function cannot set full timestamp resolution.  Use
diff --git a/doc/posix-functions/utimensat.texi 
b/doc/posix-functions/utimensat.texi
index 92c2b8b..03a2912 100644
--- a/doc/posix-functions/utimensat.texi
+++ b/doc/posix-functions/utimensat.texi
@@ -36,6 +36,9 @@ Linux kernel 2.6.32, Mac OS X 10.13, NetBSD 9.0, Solaris 11.1.
 Out-of-range values of @code{tv_nsec} do not lead to a failure on some
 platforms:
 Linux kernel 2.6.22.19 on hppa.
+@item
+On some platforms, this function mis-handles a trailing slash:
+AIX 7.2.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/utimes.texi b/doc/posix-functions/utimes.texi
index 5505906..13ceb99 100644
--- a/doc/posix-functions/utimes.texi
+++ b/doc/posix-functions/utimes.texi
@@ -16,7 +16,7 @@ Portability problems not fixed by Gnulib:
 This function is missing on some platforms:
 Minix 3.1.8, mingw, MSVC 14.
 @item
-On some platforms, this function mis-handles trailing slash:
+On some platforms, this function mis-handles a trailing slash:
 FreeBSD 7.2, Solaris 9.
 @item
 This function cannot set full timestamp resolution.  In particular,
diff --git a/lib/utimens.c b/lib/utimens.c
index 677e833..44d1ea0 100644
--- a/lib/utimens.c
+++ b/lib/utimens.c
@@ -53,7 +53,9 @@
 
 /* Avoid recursion with rpl_futimens or rpl_utimensat.  */
 #undef futimens
-#undef utimensat
+#if !HAVE_NEARLY_WORKING_UTIMENSAT
+# undef utimensat
+#endif
 
 /* Solaris 9 mistakenly succeeds when given a non-directory with a
    trailing slash.  Force the use of rpl_stat for a fix.  */
diff --git a/lib/utimensat.c b/lib/utimensat.c
index 1daff88..9fdecd6 100644
--- a/lib/utimensat.c
+++ b/lib/utimensat.c
@@ -31,9 +31,33 @@
 #include "timespec.h"
 #include "utimens.h"
 
-#if HAVE_UTIMENSAT
+#if HAVE_NEARLY_WORKING_UTIMENSAT
 
+/* Use the original utimensat(), but correct the trailing slash handling.  */
+int
+rpl_utimensat (int fd, char const *file, struct timespec const times[2],
+               int flag)
 # undef utimensat
+{
+  size_t len = strlen (file);
+  if (len && file[len - 1] == '/')
+    {
+      struct stat st;
+      if (fstatat (fd, file, &st, flag & AT_SYMLINK_NOFOLLOW) < 0)
+        return -1;
+      if (!S_ISDIR (st.st_mode))
+        {
+          errno = ENOTDIR;
+          return -1;
+        }
+    }
+
+  return utimensat (fd, file, times, flag);
+}
+
+#else
+
+# if HAVE_UTIMENSAT
 
 /* If we have a native utimensat, but are compiling this file, then
    utimensat was defined to rpl_utimensat by our replacement
@@ -44,24 +68,25 @@
    local_utimensat provides the fallback manipulation.  */
 
 static int local_utimensat (int, char const *, struct timespec const[2], int);
-# define AT_FUNC_NAME local_utimensat
+#  define AT_FUNC_NAME local_utimensat
 
 /* Like utimensat, but work around native bugs.  */
 
 int
 rpl_utimensat (int fd, char const *file, struct timespec const times[2],
                int flag)
+#  undef utimensat
 {
-# if defined __linux__ || defined __sun
+#  if defined __linux__ || defined __sun
   struct timespec ts[2];
-# endif
+#  endif
 
   /* See comments in utimens.c for details.  */
   static int utimensat_works_really; /* 0 = unknown, 1 = yes, -1 = no.  */
   if (0 <= utimensat_works_really)
     {
       int result;
-# if defined __linux__ || defined __sun
+#  if defined __linux__ || defined __sun
       struct stat st;
       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
@@ -92,7 +117,7 @@ rpl_utimensat (int fd, char const *file, struct timespec 
const times[2],
             ts[1] = times[1];
           times = ts;
         }
-#  ifdef __hppa__
+#   ifdef __hppa__
       /* Linux kernel 2.6.22.19 on hppa does not reject invalid tv_nsec
          values.  */
       else if (times
@@ -106,9 +131,9 @@ rpl_utimensat (int fd, char const *file, struct timespec 
const times[2],
           errno = EINVAL;
           return -1;
         }
+#   endif
 #  endif
-# endif
-# if defined __APPLE__ && defined __MACH__
+#  if defined __APPLE__ && defined __MACH__
       /* macOS 10.13 does not reject invalid tv_nsec values either.  */
       if (times
           && ((times[0].tv_nsec != UTIME_OMIT
@@ -135,7 +160,7 @@ rpl_utimensat (int fd, char const *file, struct timespec 
const times[2],
               return -1;
             }
         }
-# endif
+#  endif
       result = utimensat (fd, file, times, flag);
       /* Linux kernel 2.6.25 has a bug where it returns EINVAL for
          UTIME_NOW or UTIME_OMIT with non-zero tv_sec, which
@@ -159,11 +184,11 @@ rpl_utimensat (int fd, char const *file, struct timespec 
const times[2],
   return local_utimensat (fd, file, times, flag);
 }
 
-#else /* !HAVE_UTIMENSAT */
+# else /* !HAVE_UTIMENSAT */
 
-# define AT_FUNC_NAME utimensat
+#  define AT_FUNC_NAME utimensat
 
-#endif /* !HAVE_UTIMENSAT */
+# endif /* !HAVE_UTIMENSAT */
 
 /* Set the access and modification timestamps of FILE to be
    TIMESPEC[0] and TIMESPEC[1], respectively; relative to directory
@@ -176,15 +201,17 @@ rpl_utimensat (int fd, char const *file, struct timespec 
const times[2],
    Return 0 on success, -1 (setting errno) on failure.  */
 
 /* AT_FUNC_NAME is now utimensat or local_utimensat.  */
-#define AT_FUNC_F1 lutimens
-#define AT_FUNC_F2 utimens
-#define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW
-#define AT_FUNC_POST_FILE_PARAM_DECLS , struct timespec const ts[2], int flag
-#define AT_FUNC_POST_FILE_ARGS        , ts
-#include "at-func.c"
-#undef AT_FUNC_NAME
-#undef AT_FUNC_F1
-#undef AT_FUNC_F2
-#undef AT_FUNC_USE_F1_COND
-#undef AT_FUNC_POST_FILE_PARAM_DECLS
-#undef AT_FUNC_POST_FILE_ARGS
+# define AT_FUNC_F1 lutimens
+# define AT_FUNC_F2 utimens
+# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW
+# define AT_FUNC_POST_FILE_PARAM_DECLS , struct timespec const ts[2], int flag
+# define AT_FUNC_POST_FILE_ARGS        , ts
+# include "at-func.c"
+# undef AT_FUNC_NAME
+# undef AT_FUNC_F1
+# undef AT_FUNC_F2
+# undef AT_FUNC_USE_F1_COND
+# undef AT_FUNC_POST_FILE_PARAM_DECLS
+# undef AT_FUNC_POST_FILE_ARGS
+
+#endif /* !HAVE_NEARLY_WORKING_UTIMENSAT */
diff --git a/m4/utimensat.m4 b/m4/utimensat.m4
index bdabe24..cd0128a 100644
--- a/m4/utimensat.m4
+++ b/m4/utimensat.m4
@@ -1,4 +1,4 @@
-# serial 7
+# serial 8
 # See if we need to provide utimensat replacement.
 
 dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
@@ -12,6 +12,7 @@ AC_DEFUN([gl_FUNC_UTIMENSAT],
 [
   AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
   AC_CHECK_FUNCS_ONCE([utimensat])
   if test $ac_cv_func_utimensat = no; then
     HAVE_UTIMENSAT=0
@@ -28,10 +29,19 @@ AC_DEFUN([gl_FUNC_UTIMENSAT],
               const char *f = "conftest.file";
               if (close (creat (f, 0600)))
                 return 1;
+              /* Test whether a trailing slash is handled correctly.
+                 This fails on AIX 7.2.  */
+              {
+                struct timespec ts[2];
+                ts[0].tv_sec = 345183300; ts[0].tv_nsec = 0;
+                ts[1] = ts[0];
+                if (utimensat (AT_FDCWD, "conftest.file/", ts, 0) == 0)
+                  result |= 2;
+              }
               /* Test whether the AT_SYMLINK_NOFOLLOW flag is supported.  */
               {
                 if (utimensat (AT_FDCWD, f, NULL, AT_SYMLINK_NOFOLLOW))
-                  result |= 2;
+                  result |= 4;
               }
               /* Test whether UTIME_NOW and UTIME_OMIT work.  */
               {
@@ -41,7 +51,7 @@ AC_DEFUN([gl_FUNC_UTIMENSAT],
                 ts[1].tv_sec = 1;
                 ts[1].tv_nsec = UTIME_NOW;
                 if (utimensat (AT_FDCWD, f, ts, 0))
-                  result |= 4;
+                  result |= 8;
               }
               sleep (1);
               {
@@ -52,19 +62,44 @@ AC_DEFUN([gl_FUNC_UTIMENSAT],
                 ts[1].tv_sec = 1;
                 ts[1].tv_nsec = UTIME_OMIT;
                 if (utimensat (AT_FDCWD, f, ts, 0))
-                  result |= 8;
-                if (stat (f, &st))
                   result |= 16;
-                else if (st.st_ctime < st.st_atime)
+                if (stat (f, &st))
                   result |= 32;
+                else if (st.st_ctime < st.st_atime)
+                  result |= 64;
               }
               return result;
             ]])],
          [gl_cv_func_utimensat_works=yes],
-         [gl_cv_func_utimensat_works=no],
-         [gl_cv_func_utimensat_works="guessing yes"])])
-    if test "$gl_cv_func_utimensat_works" = no; then
-      REPLACE_UTIMENSAT=1
-    fi
+         [case $? in
+            2) gl_cv_func_utimensat_works='nearly' ;;
+            *) gl_cv_func_utimensat_works=no ;;
+          esac
+         ],
+         [case "$host_os" in
+            # Guess yes on Linux or glibc systems.
+            linux-* | linux | *-gnu* | gnu*)
+              gl_cv_func_utimensat_works="guessing yes" ;;
+            # Guess 'nearly' on AIX.
+            aix*)
+              gl_cv_func_utimensat_works="guessing nearly" ;;
+            # If we don't know, obey --enable-cross-guesses.
+            *)
+              gl_cv_func_utimensat_works="$gl_cross_guess_normal" ;;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_utimensat_works" in
+      *yes)
+        ;;
+      *nearly)
+        AC_DEFINE([HAVE_NEARLY_WORKING_UTIMENSAT], [1],
+          [Define to 1 of utimensat works, except for the trailing slash 
handling.])
+        REPLACE_UTIMENSAT=1
+        ;;
+      *)
+        REPLACE_UTIMENSAT=1
+        ;;
+    esac
   fi
 ])




reply via email to

[Prev in Thread] Current Thread [Next in Thread]