canonicalize-lgpl: fix AIX test failures
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 17 Dec 2020 09:22:55 +0000 (01:22 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 17 Dec 2020 09:39:46 +0000 (01:39 -0800)
This merges the recent canonicalize.c fix into canonicalize-lgpl.c.
Problem reported by Bruno Haible in:
https://lists.gnu.org/r/bug-gnulib/2020-12/msg00138.html
* lib/canonicalize-lgpl.c: Include sys/stat.h.
(__realpath): When testing a file name ending in '/', use stat
rather than readlink, so that it does the right thing on AIX.
* modules/canonicalize-lgpl (Depends-on): Add stat, sys_stat.

ChangeLog
lib/canonicalize-lgpl.c
modules/canonicalize-lgpl

index fccedabe31e74101b6a37207027b6a97c36d8859..74f2ceb34cd77f253dfccd8588a0f2e265dcaa47 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2020-12-17  Paul Eggert  <eggert@cs.ucla.edu>
 
+       canonicalize-lgpl: fix AIX test failures
+       This merges the recent canonicalize.c fix into canonicalize-lgpl.c.
+       Problem reported by Bruno Haible in:
+       https://lists.gnu.org/r/bug-gnulib/2020-12/msg00138.html
+       * lib/canonicalize-lgpl.c: Include sys/stat.h.
+       (__realpath): When testing a file name ending in '/', use stat
+       rather than readlink, so that it does the right thing on AIX.
+       * modules/canonicalize-lgpl (Depends-on): Add stat, sys_stat.
+
        canonicalize: omit second readlink when not needed
        * lib/canonicalize.c (canonicalize_filename_mode_stk):
        Omit second readlink when (can_exist != CAN_MISSING
index 2c86330c056c1ca9aa5b9a0e9ecfc52ff84eb279..1440dad343feeacc151392eaac1c015620f047d6 100644 (file)
@@ -33,6 +33,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include <scratch_buffer.h>
@@ -237,24 +238,28 @@ __realpath (const char *name, char *resolved)
           dest = __mempcpy (dest, start, startlen);
           *dest = '\0';
 
+          /* If STARTLEN == 0, RNAME ends in '/'; use stat rather than
+             readlink, because readlink might fail with EINVAL without
+             checking whether RNAME sans '/' is valid.  */
+          struct stat st;
+          char *buf = NULL;
           ssize_t n;
-          char *buf;
-          while (true)
+          if (startlen != 0)
             {
-              buf = link_buffer.data;
-              idx_t bufsize = link_buffer.length;
-              n = __readlink (rname, buf, bufsize - 1);
-              if (n < bufsize - 1)
-                break;
-              if (!scratch_buffer_grow (&link_buffer))
-                goto error_nomem;
-            }
-          if (n < 0)
-            {
-              if (errno != EINVAL)
-                goto error;
+              while (true)
+                {
+                  buf = link_buffer.data;
+                  idx_t bufsize = link_buffer.length;
+                  n = __readlink (rname, buf, bufsize - 1);
+                  if (n < bufsize - 1)
+                    break;
+                  if (!scratch_buffer_grow (&link_buffer))
+                    goto error_nomem;
+                }
+              if (n < 0)
+                buf = NULL;
             }
-          else
+          if (buf)
             {
               if (++num_links > __eloop_threshold ())
                 {
@@ -310,6 +315,10 @@ __realpath (const char *name, char *resolved)
                     dest++;
                 }
             }
+          else if (! (startlen == 0
+                      ? stat (rname, &st) == 0 || errno == EOVERFLOW
+                      : errno == EINVAL))
+            goto error;
         }
     }
   if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
index 9cd3df7bb31649bf673a0639206c385eea30d154..d4dfcc9057ad8fa5d5e262cb2e5c98ea27ca8f4d 100644 (file)
@@ -23,7 +23,9 @@ pathmax           [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONI
 rawmemchr         [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1]
 readlink          [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1]
 scratch_buffer    [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1]
+stat              [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1]
 stdbool           [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1]
+sys_stat          [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1]
 
 configure.ac:
 gl_CANONICALIZE_LGPL