summaryrefslogtreecommitdiff
path: root/lib/utimecmp.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2006-08-21 07:26:38 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2006-08-21 07:26:38 +0000
commit0f7a044109b860443ecaa4f8a37652b1b4423057 (patch)
treeb5834ed9867213221a2636e0fa7e8da178749a76 /lib/utimecmp.c
parent11fd62b0080ce376b26241bd789b7e7390befef6 (diff)
downloadcoreutils-0f7a044109b860443ecaa4f8a37652b1b4423057.tar.xz
Remove from CVS, since the bootstrap script generates them automatically.
Diffstat (limited to 'lib/utimecmp.c')
-rw-r--r--lib/utimecmp.c337
1 files changed, 0 insertions, 337 deletions
diff --git a/lib/utimecmp.c b/lib/utimecmp.c
deleted file mode 100644
index 9d07e9fd3..000000000
--- a/lib/utimecmp.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/* utimecmp.c -- compare file time stamps
-
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
-
- 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.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- 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. */
-
-/* Written by Paul Eggert. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#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 <stdlib.h>
-#include "hash.h"
-#include "intprops.h"
-#include "stat-time.h"
-#include "timespec.h"
-#include "utimens.h"
-#include "verify.h"
-#include "xalloc.h"
-
-#ifndef MAX
-# 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))
-enum { SYSCALL_RESOLUTION = 1000 };
-#else
-enum { SYSCALL_RESOLUTION = BILLION };
-#endif
-
-/* Describe a file system and its time stamp resolution in nanoseconds. */
-struct fs_res
-{
- /* Device number of file system. */
- dev_t dev;
-
- /* An upper bound on the time stamp resolution of this file system,
- ignoring any resolution that cannot be set via utimens. It is
- represented by an integer count of nanoseconds. It must be
- either 2 billion, or a power of 10 that is no greater than a
- billion and is no less than SYSCALL_RESOLUTION. */
- int resolution;
-
- /* True if RESOLUTION is known to be exact, and is not merely an
- upper bound on the true resolution. */
- bool exact;
-};
-
-/* Hash some device info. */
-static size_t
-dev_info_hash (void const *x, size_t table_size)
-{
- struct fs_res const *p = x;
-
- /* Beware signed arithmetic gotchas. */
- if (TYPE_SIGNED (dev_t) && SIZE_MAX < MAX (INT_MAX, TYPE_MAXIMUM (dev_t)))
- {
- uintmax_t dev = p->dev;
- return dev % table_size;
- }
-
- return p->dev % table_size;
-}
-
-/* Compare two dev_info structs. */
-static bool
-dev_info_compare (void const *x, void const *y)
-{
- struct fs_res const *a = x;
- struct fs_res const *b = y;
- return a->dev == b->dev;
-}
-
-/* Return -1, 0, 1 based on whether the destination file (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.
-
- 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
- determined; this can happen only if the time stamps are very close and
- there is some trouble accessing the file system (e.g., the user does not
- have permission to futz with the destination's time stamps). */
-
-int
-utimecmp (char const *dst_name,
- struct stat const *dst_stat,
- struct stat const *src_stat,
- int options)
-{
- /* Things to watch out for:
-
- The code uses a static hash table internally and is not safe in the
- presence of signals, multiple threads, etc.
-
- int and long int might be 32 bits. Many of the calculations store
- numbers up to 2 billion, and multiply by 10; they have to avoid
- multiplying 2 billion by 10, as this exceeds 32-bit capabilities.
-
- time_t might be unsigned. */
-
- verify (TYPE_IS_INTEGER (time_t));
- verify (TYPE_TWOS_COMPLEMENT (int));
-
- /* Destination and source time stamps. */
- time_t dst_s = dst_stat->st_mtime;
- time_t src_s = src_stat->st_mtime;
- int dst_ns = get_stat_mtime_ns (dst_stat);
- int src_ns = get_stat_mtime_ns (src_stat);
-
- if (options & UTIMECMP_TRUNCATE_SOURCE)
- {
- /* Look up the time stamp resolution for the destination device. */
-
- /* Hash table for devices. */
- static Hash_table *ht;
-
- /* Information about the destination file system. */
- static struct fs_res *new_dst_res;
- struct fs_res *dst_res;
-
- /* Time stamp resolution in nanoseconds. */
- int res;
-
- if (! ht)
- ht = hash_initialize (16, NULL, dev_info_hash, dev_info_compare, free);
- if (! new_dst_res)
- {
- new_dst_res = xmalloc (sizeof *new_dst_res);
- new_dst_res->resolution = 2 * BILLION;
- new_dst_res->exact = false;
- }
- new_dst_res->dev = dst_stat->st_dev;
- dst_res = hash_insert (ht, new_dst_res);
- if (! dst_res)
- xalloc_die ();
-
- if (dst_res == new_dst_res)
- {
- /* NEW_DST_RES is now in use in the hash table, so allocate a
- new entry next time. */
- new_dst_res = NULL;
- }
-
- res = dst_res->resolution;
-
- if (! dst_res->exact)
- {
- /* This file system's resolution is not known exactly.
- Deduce it, and store the result in the hash table. */
-
- time_t dst_a_s = dst_stat->st_atime;
- time_t dst_c_s = dst_stat->st_ctime;
- time_t dst_m_s = dst_s;
- int dst_a_ns = get_stat_atime_ns (dst_stat);
- int dst_c_ns = get_stat_ctime_ns (dst_stat);
- int dst_m_ns = dst_ns;
-
- /* Set RES to an upper bound on the file system resolution
- (after truncation due to SYSCALL_RESOLUTION) by inspecting
- the atime, ctime and mtime of the existing destination.
- We don't know of any file system that stores atime or
- ctime with a higher precision than mtime, so it's valid to
- look at them too. */
- {
- bool odd_second = (dst_a_s | dst_c_s | dst_m_s) & 1;
-
- if (SYSCALL_RESOLUTION == BILLION)
- {
- if (odd_second | dst_a_ns | dst_c_ns | dst_m_ns)
- res = BILLION;
- }
- else
- {
- int a = dst_a_ns;
- int c = dst_c_ns;
- int m = dst_m_ns;
-
- /* Write it this way to avoid mistaken GCC warning
- about integer overflow in constant expression. */
- int SR10 = SYSCALL_RESOLUTION; SR10 *= 10;
-
- if ((a % SR10 | c % SR10 | m % SR10) != 0)
- res = SYSCALL_RESOLUTION;
- else
- for (res = SR10, a /= SR10, c /= SR10, m /= SR10;
- (res < dst_res->resolution
- && (a % 10 | c % 10 | m % 10) == 0);
- res *= 10, a /= 10, c /= 10, m /= 10)
- if (res == BILLION)
- {
- if (! odd_second)
- res *= 2;
- break;
- }
- }
-
- dst_res->resolution = res;
- }
-
- if (SYSCALL_RESOLUTION < res)
- {
- struct timespec timespec[2];
- struct stat dst_status;
-
- /* Ignore source time stamp information that must necessarily
- be lost when filtered through utimens. */
- src_ns -= src_ns % SYSCALL_RESOLUTION;
-
- /* If the time stamps disagree widely enough, there's no need
- to interrogate the file system to deduce the exact time
- stamp resolution; return the answer directly. */
- {
- time_t s = src_s & ~ (res == 2 * BILLION);
- if (src_s < dst_s || (src_s == dst_s && src_ns <= dst_ns))
- return 1;
- if (dst_s < s
- || (dst_s == s && dst_ns < src_ns - src_ns % res))
- return -1;
- }
-
- /* Determine the actual time stamp resolution for the
- destination file system (after truncation due to
- SYSCALL_RESOLUTION) by setting the access time stamp of the
- destination to the existing access time, except with
- trailing nonzero digits. */
-
- timespec[0].tv_sec = dst_a_s;
- timespec[0].tv_nsec = dst_a_ns;
- 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)
- || 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. */
- {
- int stat_result = stat (dst_name, &dst_status);
-
- if (stat_result
- | (dst_status.st_mtime ^ dst_m_s)
- | (get_stat_mtime_ns (&dst_status) ^ dst_m_ns))
- {
- /* The modification time changed, or we can't tell whether
- 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 (stat_result != 0)
- return -2;
- }
-
- /* Determine the exact resolution from the modification time
- that was read back. */
- {
- int old_res = res;
- int a = (BILLION * (dst_status.st_mtime & 1)
- + get_stat_mtime_ns (&dst_status));
-
- res = SYSCALL_RESOLUTION;
-
- for (a /= res; a % 10 != 0; a /= 10)
- {
- if (res == BILLION)
- {
- res *= 2;
- break;
- }
- res *= 10;
- if (res == old_res)
- break;
- }
- }
- }
-
- dst_res->resolution = res;
- dst_res->exact = true;
- }
-
- /* Truncate the source's time stamp according to the resolution. */
- src_s &= ~ (res == 2 * BILLION);
- src_ns -= src_ns % res;
- }
-
- /* Compare the time stamps and return -1, 0, 1 accordingly. */
- return (dst_s < src_s ? -1
- : dst_s > src_s ? 1
- : dst_ns < src_ns ? -1
- : dst_ns > src_ns);
-}