Discussion:
[PATCH 1/2] same: new function same_nameat
Paul Eggert
2018-02-20 17:08:32 UTC
Permalink
* 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 <***@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 <***@gwmail.gwu.edu> (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
Paul Eggert
2018-02-20 17:08:33 UTC
Permalink
* lib/utimecmp.c: Include fcntl.h, sys/stat.h and dirname.h.
Do not include utimens.h.
(utimecmpat): New function, generalizing utimecmp.
(utimecmp): Now a thin layer around utimecmpat.
* modules/utimecmp (Depends-on): Depend on dirname-lgpl, fstatat,
utimensat instead of on lstat and utimens.
---
ChangeLog | 8 ++++++++
lib/utimecmp.c | 52 ++++++++++++++++++++++++++++++++++++----------------
lib/utimecmp.h | 2 ++
modules/utimecmp | 5 +++--
4 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 3d9335f80..15fad2bb5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2018-02-20 Paul Eggert <***@cs.ucla.edu>

+ utimecmp: new function utimecmpat
+ * lib/utimecmp.c: Include fcntl.h, sys/stat.h and dirname.h.
+ Do not include utimens.h.
+ (utimecmpat): New function, generalizing utimecmp.
+ (utimecmp): Now a thin layer around utimecmpat.
+ * modules/utimecmp (Depends-on): Depend on dirname-lgpl, fstatat,
+ utimensat instead of on lstat and utimens.
+
same: new function same_nameat
* lib/same.c: Include fcntl.h.
* lib/same.c (same_nameat): New function, generalizing same_name.
diff --git a/lib/utimecmp.c b/lib/utimecmp.c
index be9b32364..b92797a6b 100644
--- a/lib/utimecmp.c
+++ b/lib/utimecmp.c
@@ -21,17 +21,19 @@

#include "utimecmp.h"

+#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
+#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

+#include "dirname.h"
#include "hash.h"
#include "intprops.h"
#include "stat-time.h"
-#include "utimens.h"
#include "verify.h"

#ifndef MAX
@@ -103,7 +105,8 @@ dev_info_compare (void const *x, void const *y)
return a->dev == b->dev;
}

-/* Return -1, 0, 1 based on whether the destination file (with name
+/* Return -1, 0, 1 based on whether the destination file (relative
+ to openat-like directory file descriptor DFD with name
DST_NAME and status DST_STAT) is older than SRC_STAT, the same age
as SRC_STAT, or newer than SRC_STAT, respectively.

@@ -121,6 +124,15 @@ utimecmp (char const *dst_name,
struct stat const *dst_stat,
struct stat const *src_stat,
int options)
+{
+ return utimecmpat (AT_FDCWD, dst_name, dst_stat, src_stat, options);
+}
+
+int
+utimecmpat (int dfd, char const *dst_name,
+ struct stat const *dst_stat,
+ struct stat const *src_stat,
+ int options)
{
/* Things to watch out for:

@@ -216,7 +228,24 @@ utimecmp (char const *dst_name,
/* If the system will tell us the resolution, we're set! */
if (! dst_res->exact)
{
- res = pathconf (dst_name, _PC_TIMESTAMP_RESOLUTION);
+ res = -1;
+ if (dfd == AT_FDCWD)
+ res = pathconf (dst_name, _PC_TIMESTAMP_RESOLUTION);
+ else
+ {
+ char *dstdir = mdir_name (dst_name);
+ if (dstdir)
+ {
+ int destdirfd = openat (dfd, dstdir,
+ O_SEARCH | O_CLOEXEC | O_DIRECTORY);
+ if (0 <= destdirfd)
+ {
+ res = fpathconf (destdirfd, _PC_TIMESTAMP_RESOLUTION);
+ close (destdirfd);
+ }
+ free (dstdir);
+ }
+ }
if (0 < res)
{
dst_res->resolution = res;
@@ -311,19 +340,13 @@ utimecmp (char const *dst_name,
timespec[1].tv_sec = dst_m_s | (res == 2 * BILLION);
timespec[1].tv_nsec = dst_m_ns + res / 9;

- /* Set the modification time. But don't try to set the
- modification time of symbolic links; on many hosts this sets
- the time of the pointed-to file. */
- if ((S_ISLNK (dst_stat->st_mode)
- ? lutimens (dst_name, timespec)
- : utimens (dst_name, timespec)) != 0)
+ if (utimensat (dfd, dst_name, timespec, AT_SYMLINK_NOFOLLOW))
return -2;

/* Read the modification time that was set. */
{
- int stat_result = (S_ISLNK (dst_stat->st_mode)
- ? lstat (dst_name, &dst_status)
- : stat (dst_name, &dst_status));
+ int stat_result
+ = fstatat (dfd, dst_name, &dst_status, AT_SYMLINK_NOFOLLOW);

if (stat_result
| (dst_status.st_mtime ^ dst_m_s)
@@ -333,10 +356,7 @@ utimecmp (char const *dst_name,
it changed. Change it back as best we can. */
timespec[1].tv_sec = dst_m_s;
timespec[1].tv_nsec = dst_m_ns;
- if (S_ISLNK (dst_stat->st_mode))
- lutimens (dst_name, timespec);
- else
- utimens (dst_name, timespec);
+ utimensat (dfd, dst_name, timespec, AT_SYMLINK_NOFOLLOW);
}

if (stat_result != 0)
diff --git a/lib/utimecmp.h b/lib/utimecmp.h
index 65003ff07..ef05a57cb 100644
--- a/lib/utimecmp.h
+++ b/lib/utimecmp.h
@@ -33,5 +33,7 @@ enum
};

int utimecmp (char const *, struct stat const *, struct stat const *, int);
+int utimecmpat (int, char const *, struct stat const *, struct stat const *,
+ int);

#endif
diff --git a/modules/utimecmp b/modules/utimecmp
index c7eee89ce..8a3303cc0 100644
--- a/modules/utimecmp
+++ b/modules/utimecmp
@@ -7,12 +7,13 @@ lib/utimecmp.c
m4/utimecmp.m4

Depends-on:
+dirname-lgpl
+fstatat
hash
stat-time
time
-utimens
+utimensat
intprops
-lstat
stdbool
stdint
verify
--
2.14.3
Loading...