bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH 3/6] canonicalize: do not assume symlinks have st_ino


From: Paul Eggert
Subject: [PATCH 3/6] canonicalize: do not assume symlinks have st_ino
Date: Wed, 2 Dec 2020 14:39:43 -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            |  9 ++++++++
 lib/canonicalize.c   | 50 +++++++++++++++++++++++++-------------------
 modules/canonicalize |  2 +-
 3 files changed, 39 insertions(+), 22 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 85f2c76a2..81d1c884f 100644
--- 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
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 7b838e686..d82ad5043 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -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)
                 {
diff --git a/modules/canonicalize b/modules/canonicalize
index a48d1930e..d5eb49311 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -14,10 +14,10 @@ extensions
 file-set
 filename
 hash-triple-simple
-lstat
 memmove
 nocrash
 pathmax
+stat
 sys_stat
 xalloc
 xgetcwd
-- 
2.27.0




reply via email to

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