]> Savannah Git Hosting - gnulib.git/commitdiff
canonicalize: do not assume symlinks have st_ino
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:29 +0000 (14:39 -0800)
* lib/canonicalize.c (canonicalize_filename_mode):
When checking for loops, use st_dev and st_ino from the parent
directory not from the symlink, as pre-2017 POSIX says these
members are not reliable for symlinks.  Couple this with START
(the remaining file name to be resolved), not NAME (the whole file
name with START as its suffix).
* modules/canonicalize (Depends-on): Depend on stat, not lstat.

ChangeLog
lib/canonicalize.c
modules/canonicalize

index 85f2c76a298fbafd944efdffacf1c48b9ef2ddc5..81d1c884f55adced4885766f87cdd4f1e794552c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2020-12-02  Paul Eggert  <eggert@cs.ucla.edu>
 
+       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
+       directory not from the symlink, as pre-2017 POSIX says these
+       members are not reliable for symlinks.  Couple this with START
+       (the remaining file name to be resolved), not NAME (the whole file
+       name with START as its suffix).
+       * modules/canonicalize (Depends-on): Depend on stat, not lstat.
+
        canonicalize: fix EOVERFLOW bug
        * lib/canonicalize.c (canonicalize_filename_mode):
        When testing whether a directory entry is a symbolic link, or a
index 7b838e68611e4670cbe6a3afc9f30b04619a2e07..d82ad50430692c8b536504d659faf0c364aefe52 100644 (file)
@@ -247,31 +247,39 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
           if (buf)
             {
               /* A physical traversal and RNAME is a symbolic link.  */
-              struct stat st;
-              if (lstat (rname, &st) != 0)
-                {
-                  saved_errno = errno;
-                  free (buf);
-                  goto error;
-                }
 
-              size_t n, len;
-
-              /* Detect loops.  We cannot use the cycle-check module here,
-                 since it's actually possible to encounter the same symlink
-                 more than once in a given traversal.  However, encountering
-                 the same symlink,NAME pair twice does indicate a loop.  */
-              if (seen_triple (&ht, name, &st))
+              if (*start)
                 {
-                  if (can_mode == CAN_MISSING)
-                    continue;
-                  saved_errno = ELOOP;
-                  free (buf);
-                  goto error;
+                  /* 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;
+                  if (stat (*rname ? rname : ".", &st) != 0)
+                    {
+                      saved_errno = errno;
+                      free (buf);
+                      goto error;
+                    }
+                  dest[- (end - start)] = *start;
+
+                  /* Detect loops.  We cannot use the cycle-check module here,
+                     since it's possible to encounter the same parent
+                     directory more than once in a given traversal.  However,
+                     encountering the same (parentdir, START) pair twice does
+                     indicate a loop.  */
+                  if (seen_triple (&ht, start, &st))
+                    {
+                      if (can_mode == CAN_MISSING)
+                        continue;
+                      saved_errno = ELOOP;
+                      free (buf);
+                      goto error;
+                    }
                 }
 
-              n = strlen (buf);
-              len = strlen (end);
+              size_t n = strlen (buf);
+              size_t len = strlen (end);
 
               if (!extra_len)
                 {
index a48d1930e7944cd4a27d03781eaa184f4036a448..d5eb4931177d658bbaad86b32b8e182b5937cdcc 100644 (file)
@@ -14,10 +14,10 @@ extensions
 file-set
 filename
 hash-triple-simple
-lstat
 memmove
 nocrash
 pathmax
+stat
 sys_stat
 xalloc
 xgetcwd