/* Diff files from a tar archive.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003, 2004, 2005 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Written by John Gilmore, on 1987-04-30.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <system.h>
+#include <system-ioctl.h>
#if HAVE_LINUX_FD_H
# include <linux/fd.h>
#endif
-#include <quotearg.h>
-#include <utimens.h>
-
#include "common.h"
+#include <quotearg.h>
#include <rmt.h>
#include <stdarg.h>
/* Sigh about something that differs by writing a MESSAGE to stdlis,
given MESSAGE is nonzero. Also set the exit status if not already. */
void
-report_difference (struct tar_stat_info *st __attribute__ ((unused)),
- const char *fmt, ...)
+report_difference (struct tar_stat_info *st, const char *fmt, ...)
{
if (fmt)
{
va_list ap;
- fprintf (stdlis, "%s: ", quotearg_colon (current_stat_info.file_name));
+ fprintf (stdlis, "%s: ", quotearg_colon (st->file_name));
va_start (ap, fmt);
vfprintf (stdlis, fmt, ap);
va_end (ap);
address of the chunk it can work with. The PROCESSOR should return
nonzero for success. It it return error once, continue skipping
without calling PROCESSOR anymore. */
+
static void
-read_and_process (off_t size, int (*processor) (size_t, char *))
+read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
{
union block *data_block;
size_t data_size;
+ size_t size = st->stat.st_size;
- if (multi_volume_option)
- save_sizeleft = size;
+ mv_begin (st);
while (size)
{
data_block = find_next_block ();
set_next_block_after ((union block *)
(data_block->buffer + data_size - 1));
size -= data_size;
- if (multi_volume_option)
- save_sizeleft -= data_size;
+ mv_size_left (size);
}
+ mv_end ();
}
/* Call either stat or lstat over STAT_DATA, depending on
static void
diff_file (void)
{
+ char const *file_name = current_stat_info.file_name;
struct stat stat_data;
- if (!get_stat_data (current_stat_info.file_name, &stat_data))
+ if (!get_stat_data (file_name, &stat_data))
skip_member ();
else if (!S_ISREG (stat_data.st_mode))
{
if (!sys_compare_gid (&stat_data, ¤t_stat_info.stat))
report_difference (¤t_stat_info, _("Gid differs"));
- if (stat_data.st_mtime != current_stat_info.stat.st_mtime)
+ if (tar_timespec_cmp (get_stat_mtime (&stat_data),
+ current_stat_info.mtime))
report_difference (¤t_stat_info, _("Mod time differs"));
- if (current_header->header.typeflag != GNUTYPE_SPARSE &&
- stat_data.st_size != current_stat_info.stat.st_size)
+ if (current_header->header.typeflag != GNUTYPE_SPARSE
+ && stat_data.st_size != current_stat_info.stat.st_size)
{
report_difference (¤t_stat_info, _("Size differs"));
skip_member ();
}
else
{
- diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
+ int atime_flag =
+ (atime_preserve_option == system_atime_preserve
+ ? O_NOATIME
+ : 0);
+
+ diff_handle = open (file_name, O_RDONLY | O_BINARY | atime_flag);
if (diff_handle < 0)
{
- open_error (current_stat_info.file_name);
+ open_error (file_name);
skip_member ();
report_difference (¤t_stat_info, NULL);
}
if (current_stat_info.is_sparse)
sparse_diff_file (diff_handle, ¤t_stat_info);
else
- {
- if (multi_volume_option)
- {
- assign_string (&save_name,
- current_stat_info.orig_file_name);
- save_totsize = current_stat_info.stat.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- read_and_process (current_stat_info.stat.st_size,
- process_rawdata);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
- }
-
- status = close (diff_handle);
- if (status != 0)
- close_error (current_stat_info.file_name);
+ read_and_process (¤t_stat_info, process_rawdata);
- if (atime_preserve_option)
+ if (atime_preserve_option == replace_atime_preserve)
{
struct timespec ts[2];
ts[0] = get_stat_atime (&stat_data);
ts[1] = get_stat_mtime (&stat_data);
- if (utimens (current_stat_info.file_name, ts) != 0)
- utime_error (current_stat_info.file_name);
+ if (set_file_atime (diff_handle, file_name, ts) != 0)
+ utime_error (file_name);
}
+
+ status = close (diff_handle);
+ if (status != 0)
+ close_error (file_name);
}
}
}
static void
diff_dumpdir (void)
{
- char *dumpdir_buffer = get_directory_contents (current_stat_info.file_name,
- 0);
+ char *dumpdir_buffer;
+ dev_t dev = 0;
+ struct stat stat;
- if (multi_volume_option)
+ if (deref_stat (true, current_stat_info.file_name, &stat))
{
- assign_string (&save_name, current_stat_info.orig_file_name);
- save_totsize = current_stat_info.stat.st_size;
- /* save_sizeleft is set in read_and_process. */
+ if (errno == ENOENT)
+ stat_warn (current_stat_info.file_name);
+ else
+ stat_error (current_stat_info.file_name);
}
+ else
+ dev = stat.st_dev;
+
+ dumpdir_buffer = get_directory_contents (current_stat_info.file_name, dev);
if (dumpdir_buffer)
{
dumpdir_cursor = dumpdir_buffer;
- read_and_process (current_stat_info.stat.st_size, process_dumpdir);
+ read_and_process (¤t_stat_info, process_dumpdir);
free (dumpdir_buffer);
}
else
- read_and_process (current_stat_info.stat.st_size, process_noop);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
+ read_and_process (¤t_stat_info, process_noop);
}
static void
return;
}
- if (multi_volume_option)
- {
- assign_string (&save_name, current_stat_info.orig_file_name);
- save_totsize = stat_data.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- read_and_process (current_stat_info.stat.st_size, process_rawdata);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
+ read_and_process (¤t_stat_info, process_rawdata);
status = close (fd);
if (status != 0)