/* utimecmp.c -- compare file time stamps
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software
+ Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
#include "utimecmp.h"
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#if HAVE_STDINT_H
-# include <stdint.h>
-#endif
-
#include <limits.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
#include "hash.h"
#include "intprops.h"
#include "stat-time.h"
-#include "timespec.h"
#include "utimens.h"
#include "verify.h"
#include "xalloc.h"
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-
enum { BILLION = 1000 * 1000 * 1000 };
/* Best possible resolution that utimens can set and stat can return,
due to system-call limitations. It must be a power of 10 that is
no greater than 1 billion. */
-#if (HAVE_WORKING_UTIMES \
- && (defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC \
- || defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC \
- || defined HAVE_STRUCT_STAT_ST_ATIMENSEC \
- || defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC \
- || defined HAVE_STRUCT_STAT_ST_SPARE1))
+#if HAVE_UTIMENSAT
+enum { SYSCALL_RESOLUTION = 1 };
+#elif ((HAVE_FUTIMESAT || HAVE_WORKING_UTIMES) \
+ && (defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC \
+ || defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC \
+ || defined HAVE_STRUCT_STAT_ST_ATIMENSEC \
+ || defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC \
+ || defined HAVE_STRUCT_STAT_ST_SPARE1))
enum { SYSCALL_RESOLUTION = 1000 };
#else
enum { SYSCALL_RESOLUTION = BILLION };
DST_NAME and status DST_STAT) is older than SRC_STAT, the same age
as SRC_STAT, or newer than SRC_STAT, respectively.
+ DST_NAME may be NULL if OPTIONS is 0.
+
If OPTIONS & UTIMECMP_TRUNCATE_SOURCE, do the comparison after SRC is
converted to the destination's timestamp resolution as filtered through
utimens. In this case, return -2 if the exact answer cannot be
/* Time stamp resolution in nanoseconds. */
int res;
+ /* Quick exit, if possible. Since the worst resolution is 2
+ seconds, anything that differs by more than that does not
+ needs source truncation. */
+ if (dst_s == src_s && dst_ns == src_ns)
+ return 0;
+ if (dst_s <= src_s - 2)
+ return -1;
+ if (src_s <= dst_s - 2)
+ return 1;
+
if (! ht)
ht = hash_initialize (16, NULL, dev_info_hash, dev_info_compare, free);
if (! new_dst_res)
res = dst_res->resolution;
+#ifdef _PC_TIMESTAMP_RESOLUTION
+ /* If the system will tell us the resolution, we're set! */
+ if (! dst_res->exact)
+ {
+ res = pathconf (dst_name, _PC_TIMESTAMP_RESOLUTION);
+ if (0 < res)
+ {
+ dst_res->resolution = res;
+ dst_res->exact = true;
+ }
+ }
+#endif
+
if (! dst_res->exact)
{
/* This file system's resolution is not known exactly.
/* 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)
- || utimens (dst_name, timespec) != 0)
+ if ((S_ISLNK (dst_stat->st_mode)
+ ? lutimens (dst_name, timespec)
+ : utimens (dst_name, timespec)) != 0)
return -2;
- /* Read the modification time that was set. It's safe to call
- 'stat' here instead of worrying about 'lstat'; either the
- caller used 'stat', or the caller used 'lstat' and found
- something other than a symbolic link. */
+ /* Read the modification time that was set. */
{
- int stat_result = stat (dst_name, &dst_status);
+ int stat_result = (S_ISLNK (dst_stat->st_mode)
+ ? lstat (dst_name, &dst_status)
+ : stat (dst_name, &dst_status));
if (stat_result
| (dst_status.st_mtime ^ dst_m_s)
it changed. Change it back as best we can. */
timespec[1].tv_sec = dst_m_s;
timespec[1].tv_nsec = dst_m_ns;
- utimens (dst_name, timespec);
+ if (S_ISLNK (dst_stat->st_mode))
+ lutimens (dst_name, timespec);
+ else
+ utimens (dst_name, timespec);
}
if (stat_result != 0)