]> Savannah Git Hosting - gnulib.git/commitdiff
canonicalize: fix most of another EOVERFLOW issue
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 2 Dec 2020 22:25:42 +0000 (14:25 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 2 Dec 2020 22:39:30 +0000 (14:39 -0800)
* lib/canonicalize.c (canonicalize_filename_mode):
Do not call stat if fewer than 20 symlinks have been traversed.
This avoids EOVERFLOW failure in the common case where there
are not that many symlinks, while continuing to catch loops
(or fail due to EOVERFLOW) in the unusual case when there
are many symlinks to traverse.

ChangeLog
lib/canonicalize.c

index 81d1c884f55adced4885766f87cdd4f1e794552c..a2af24dc41554d12826626acb48f6f3bf5d6007a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2020-12-02  Paul Eggert  <eggert@cs.ucla.edu>
 
+       canonicalize: fix most of another EOVERFLOW issue
+       * lib/canonicalize.c (canonicalize_filename_mode):
+       Do not call stat if fewer than 20 symlinks have been traversed.
+       This avoids EOVERFLOW failure in the common case where there
+       are not that many symlinks, while continuing to catch loops
+       (or fail due to EOVERFLOW) in the unusual case when there
+       are many symlinks to traverse.
+
        canonicalize: do not assume symlinks have st_ino
        * lib/canonicalize.c (canonicalize_filename_mode):
        When checking for loops, use st_dev and st_ino from the parent
index d82ad50430692c8b536504d659faf0c364aefe52..2618844e80e2bae8a5d026c7db57822831f5dbd7 100644 (file)
@@ -107,6 +107,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
   int saved_errno;
   int can_flags = can_mode & ~CAN_MODE_MASK;
   bool logical = can_flags & CAN_NOLINKS;
+  int num_links = 0;
   size_t prefix_len;
 
   can_mode &= CAN_MODE_MASK;
@@ -248,9 +249,13 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
             {
               /* A physical traversal and RNAME is a symbolic link.  */
 
-              if (*start)
+              if (num_links < 20)
+                num_links++;
+              else if (*start)
                 {
-                  /* Get the device and inode of the parent directory, as
+                  /* Enough symlinks have been seen that it is time to
+                     worry about being in a symlink cycle.
+                     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';