]> Savannah Git Hosting - gnulib.git/commitdiff
canonicalize: fix AIX test failures
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 14 Dec 2020 01:16:01 +0000 (17:16 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 14 Dec 2020 01:34:15 +0000 (17:34 -0800)
Problem reported by Bruno Haible in:
https://lists.gnu.org/r/bug-gnulib/2020-12/msg00109.html
* lib/canonicalize.c (canonicalize_filename_mode):
When testing a file name ending in '/', use stat rather than
readlink, so that it does the right thing on AIX.
* modules/canonicalize (Depends-on): Add readlink, to pull in the
recent changes in the Gnulib readlink module.

ChangeLog
lib/canonicalize.c
modules/canonicalize

index 1c5fd762d44f372c4b278c075a1fa3205ae54a38..b8213ada07df210777bf0a2c0d7e26d62e9a62f0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2020-12-13  Paul Eggert  <eggert@cs.ucla.edu>
 
+       canonicalize: fix AIX test failures
+       Problem reported by Bruno Haible in:
+       https://lists.gnu.org/r/bug-gnulib/2020-12/msg00109.html
+       * lib/canonicalize.c (canonicalize_filename_mode):
+       When testing a file name ending in '/', use stat rather than
+       readlink, so that it does the right thing on AIX.
+       * modules/canonicalize (Depends-on): Add readlink, to pull in the
+       recent changes in the Gnulib readlink module.
+
        Assume readlink/readlinkat ERANGE fix
        * lib/areadlink-with-size.c (areadlink_with_size):
        * lib/areadlinkat-with-size.c (areadlinkat_with_size):
index e44793d142a6d19908bd435c47bad9333f50a7fe..e50347b1011ac2e2fc6a04b246baf6375925078f 100644 (file)
@@ -211,9 +211,13 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
       for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
-      if (end - start == 1 && start[0] == '.')
+      /* Length of this file name component; it can be zero if a file
+         name ends in '/'.  */
+      idx_t startlen = end - start;
+
+      if (startlen == 1 && start[0] == '.')
         /* nothing */;
-      else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+      else if (startlen == 2 && start[0] == '.' && start[1] == '.')
         {
           /* Back up to previous component, ignore if at root already.  */
           if (dest > rname + prefix_len + 1)
@@ -228,27 +232,28 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
           if (!ISSLASH (dest[-1]))
             *dest++ = '/';
 
-          if (rname_limit - dest <= end - start)
+          if (rname_limit - dest <= startlen)
             {
               idx_t dest_offset = dest - rname;
               idx_t new_size = rname_limit - rname;
 
-              if (end - start + 1 > PATH_MAX)
-                new_size += end - start + 1;
-              else
-                new_size += PATH_MAX;
+              new_size = startlen + 1 <= PATH_MAX ? startlen + 1 : PATH_MAX;
               rname = xrealloc (rname, new_size);
               rname_limit = rname + new_size;
 
               dest = rname + dest_offset;
             }
 
-          dest = memcpy (dest, start, end - start);
-          dest += end - start;
+          dest = memcpy (dest, start, startlen);
+          dest += 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.  */
           char discard;
-          char *buf = logical ? NULL : areadlink (rname);
+          struct stat st;
+          char *buf = logical || startlen == 0 ? NULL : areadlink (rname);
           if (buf)
             {
               /* A physical traversal and RNAME is a symbolic link.  */
@@ -262,15 +267,14 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
                      Get the device and inode of the parent directory, as
                      pre-2017 POSIX says this info is not reliable for
                      symlinks.  */
-                  dest[- (end - start)] = '\0';
-                  struct stat st;
+                  dest[- startlen] = '\0';
                   if (stat (*rname ? rname : ".", &st) != 0)
                     {
                       saved_errno = errno;
                       free (buf);
                       goto error;
                     }
-                  dest[- (end - start)] = *start;
+                  dest[- startlen] = *start;
 
                   /* Detect loops.  We cannot use the cycle-check module here,
                      since it's possible to encounter the same parent
@@ -338,13 +342,16 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
               free (buf);
             }
           else if (can_exist != CAN_MISSING
-                   && (!logical || readlink (rname, &discard, 1) < 0))
+                   && (startlen == 0
+                       ? stat (rname, &st) < 0
+                       : !logical && readlink (rname, &discard, 1) < 0))
             {
               saved_errno = errno;
               switch (saved_errno)
                 {
                 case EINVAL:
-                  /* RNAME exists and is not symbolic link.  */
+                case EOVERFLOW: /* Possible with stat.  */
+                  /* RNAME exists and is not a symbolic link.  */
                   break;
 
                 case ENOENT:
index 65c5011f757eac24b94809228be60f17065231b1..ae3fbd3abf2d09fadd1166ab7fc1708816144fd4 100644 (file)
@@ -18,6 +18,7 @@ idx
 memmove
 nocrash
 pathmax
+readlink
 stat
 sys_stat
 xalloc