]> Savannah Git Hosting - gnulib.git/commitdiff
same: new function same_nameat
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 20 Feb 2018 17:05:48 +0000 (09:05 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 20 Feb 2018 17:08:15 +0000 (09:08 -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
lib/same.c
lib/same.h
m4/same.m4
modules/same

index 798dbb3788e0de52ddf7865a1e191dcdbd98f606..3d9335f80d3a63a53c31172390f96977bb959535 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2018-02-20  Paul Eggert  <eggert@cs.ucla.edu>
+
+       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  <egall@gwmail.gwu.edu>  (tiny change)
 
        warnings: Add support for Objective C.
index 39d7be5ad94f35c645ceddcf5b34aa507c73706e..47b50be96b280bea0a5897683c3c4b11d85c7620 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <config.h>
 
+#include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <unistd.h>
 # 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);
     }
 
index cf40b1c092e5218def6b71e1f5fa9a1861a6f51b..859c18eb08dd0d0b27f97c2cc3909e90cc7e5e84 100644 (file)
@@ -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_ */
index e29a7231b70bdcc67801654e817eafe675a0cd72..1dcc003c41e0b941d53b120b7408b8960ae3d0f0 100644 (file)
@@ -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])
 ])
index 6401dfba6d4ffaad0558db46c1f959a20cf71882..889ccbd55b4c06fb3d6b3f7a3a83a34bf560a3ff 100644 (file)
@@ -10,6 +10,8 @@ m4/same.m4
 Depends-on:
 error
 dirname
+fstatat
+openat
 same-inode
 stat
 stdbool