bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH 1/2] same: new function same_nameat


From: Paul Eggert
Subject: [PATCH 1/2] same: new function same_nameat
Date: Tue, 20 Feb 2018 09:08:32 -0800

* lib/same.c: Include fcntl.h.
* lib/same.c (same_nameat): New function, generalizing same_name.
(same_name): Now a thin layer around same_nameat.
* m4/same.m4 (gl_SAME): Check for fpathconf, not pathconf.
* modules/same (Depends-on): Depend on fstatat, openat.
---
 ChangeLog    |  9 +++++++
 lib/same.c   | 86 +++++++++++++++++++++++++++++++++++++++---------------------
 lib/same.h   |  1 +
 m4/same.m4   |  4 +--
 modules/same |  2 ++
 5 files changed, 70 insertions(+), 32 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 798dbb378..3d9335f80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2018-02-20  Paul Eggert  <address@hidden>
+
+       same: new function same_nameat
+       * lib/same.c: Include fcntl.h.
+       * lib/same.c (same_nameat): New function, generalizing same_name.
+       (same_name): Now a thin layer around same_nameat.
+       * m4/same.m4 (gl_SAME): Check for fpathconf, not pathconf.
+       * modules/same (Depends-on): Depend on fstatat, openat.
+
 2018-02-18  Eric Gallager  <address@hidden>  (tiny change)
 
        warnings: Add support for Objective C.
diff --git a/lib/same.c b/lib/same.c
index 39d7be5ad..47b50be96 100644
--- a/lib/same.c
+++ b/lib/same.c
@@ -19,6 +19,7 @@
 
 #include <config.h>
 
+#include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -44,11 +45,30 @@
 # define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
+/* Whether file name components are silently truncated (behavior that
+   POSIX stopped allowing in 2008).  This enables checks whether
+   truncated base names are the same, while checking the directories.  */
+#if !_POSIX_NO_TRUNC && HAVE_FPATHCONF && defined _PC_NAME_MAX
+# define CHECK_TRUNCATION true
+#else
+# define CHECK_TRUNCATION false
+#endif
+
 /* Return nonzero if SOURCE and DEST point to the same name in the same
    directory.  */
 
 bool
 same_name (const char *source, const char *dest)
+{
+  return same_nameat (AT_FDCWD, source, AT_FDCWD, dest);
+}
+
+/* Likewise, but interpret the file names relative to SOURCE_FD and DEST_FD,
+   in the style of openat.  */
+
+bool
+same_nameat (int source_dfd, char const *source,
+             int dest_dfd, char const *dest)
 {
   /* Compare the basenames.  */
   char const *source_basename = last_component (source);
@@ -61,10 +81,7 @@ same_name (const char *source, const char *dest)
   bool compare_dirs = identical_basenames;
   bool same = false;
 
-#if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
-  /* This implementation silently truncates components of file names.  If
-     the base names might be truncated, check whether the truncated
-     base names are the same, while checking the directories.  */
+#if CHECK_TRUNCATION
   size_t slen_max = HAVE_LONG_FILE_NAMES ? 255 : _POSIX_NAME_MAX;
   size_t min_baselen = MIN (source_baselen, dest_baselen);
   if (slen_max <= min_baselen
@@ -76,46 +93,55 @@ same_name (const char *source, const char *dest)
     {
       struct stat source_dir_stats;
       struct stat dest_dir_stats;
-      char *source_dirname, *dest_dirname;
 
       /* Compare the parent directories (via the device and inode numbers).  */
-      source_dirname = dir_name (source);
-      dest_dirname = dir_name (dest);
-
-      if (stat (source_dirname, &source_dir_stats))
+      char *source_dirname = dir_name (source);
+      int flags = AT_SYMLINK_NOFOLLOW;
+      if (fstatat (source_dfd, source_dirname, &source_dir_stats, flags) != 0)
         {
           /* Shouldn't happen.  */
           error (1, errno, "%s", source_dirname);
         }
+      free (source_dirname);
 
-      if (stat (dest_dirname, &dest_dir_stats))
-        {
-          /* Shouldn't happen.  */
-          error (1, errno, "%s", dest_dirname);
-        }
-
-      same = SAME_INODE (source_dir_stats, dest_dir_stats);
+      char *dest_dirname = dir_name (dest);
+      int destdir_errno = 0;
 
-#if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
-      if (same && ! identical_basenames)
+#if CHECK_TRUNCATION
+      int open_flags = O_SEARCH | O_CLOEXEC | O_DIRECTORY;
+      int destdir_fd = openat (dest_dfd, dest_dirname, open_flags);
+      if (destdir_fd < 0 || fstat (destdir_fd, &dest_dir_stats) != 0)
+        destdir_errno = errno;
+      else if (SAME_INODE (source_dir_stats, dest_dir_stats))
         {
-          long name_max = (errno = 0, pathconf (dest_dirname, _PC_NAME_MAX));
-          if (name_max < 0)
+          same = identical_basenames;
+          if (! same)
             {
-              if (errno)
-                {
-                  /* Shouldn't happen.  */
-                  error (1, errno, "%s", dest_dirname);
-                }
-              same = false;
+              errno = 0;
+              long name_max = fpathconf (destdir_fd, _PC_NAME_MAX);
+              if (name_max < 0)
+                destdir_errno = errno;
+              else
+                same = (name_max <= min_baselen
+                        && (memcmp (source_basename, dest_basename, name_max)
+                            == 0));
             }
-          else
-            same = (name_max <= min_baselen
-                    && memcmp (source_basename, dest_basename, name_max) == 0);
         }
+      close (destdir_fd);
+      if (destdir_errno != 0)
+        {
+          /* Shouldn't happen.  */
+          error (1, destdir_errno, "%s", dest_dirname);
+        }
+#else
+      if (fstatat (dest_dfd, dest_dirname, &dest_dir_stats, flags) != 0)
+        {
+          /* Shouldn't happen.  */
+          error (1, errno, "%s", dest_dirname);
+        }
+      same = SAME_INODE (source_dir_stats, dest_dir_stats);
 #endif
 
-      free (source_dirname);
       free (dest_dirname);
     }
 
diff --git a/lib/same.h b/lib/same.h
index cf40b1c09..859c18eb0 100644
--- a/lib/same.h
+++ b/lib/same.h
@@ -21,5 +21,6 @@
 # include <stdbool.h>
 
 bool same_name (const char *source, const char *dest);
+bool same_nameat (int, char const *, int, char const *);
 
 #endif /* SAME_H_ */
diff --git a/m4/same.m4 b/m4/same.m4
index e29a7231b..1dcc003c4 100644
--- a/m4/same.m4
+++ b/m4/same.m4
@@ -1,4 +1,4 @@
-#serial 9
+#serial 10
 dnl Copyright (C) 2002-2003, 2005-2006, 2009-2018 Free Software Foundation,
 dnl Inc.
 dnl This file is free software; the Free Software Foundation
@@ -9,5 +9,5 @@ dnl Prerequisites of lib/same.c.
 AC_DEFUN([gl_SAME],
 [
   AC_REQUIRE([AC_SYS_LONG_FILE_NAMES])
-  AC_CHECK_FUNCS_ONCE([pathconf])
+  AC_CHECK_FUNCS_ONCE([fpathconf])
 ])
diff --git a/modules/same b/modules/same
index 6401dfba6..889ccbd55 100644
--- a/modules/same
+++ b/modules/same
@@ -10,6 +10,8 @@ m4/same.m4
 Depends-on:
 error
 dirname
+fstatat
+openat
 same-inode
 stat
 stdbool
-- 
2.14.3




reply via email to

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