]>
Dogcows Code - chaz/tar/blob - src/compare.c
1 /* Diff files from a tar archive.
3 Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003, 2004 Free Software Foundation, Inc.
6 Written by John Gilmore, on 1987-04-30.
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any later
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
35 # include <linux/fd.h>
44 /* Nonzero if we are verifying at the moment. */
47 /* File descriptor for the file we are diffing. */
48 static int diff_handle
;
50 /* Area for reading file contents into. */
51 static char *diff_buffer
;
53 /* Initialize for a diff operation. */
58 diff_buffer
= page_aligned_alloc (&ptr
, record_size
);
61 /* Sigh about something that differs by writing a MESSAGE to stdlis,
62 given MESSAGE is nonzero. Also set the exit status if not already. */
64 report_difference (struct tar_stat_info
*st
__attribute__ ((unused
)),
71 fprintf (stdlis
, "%s: ", quotearg_colon (current_stat_info
.file_name
));
73 vfprintf (stdlis
, fmt
, ap
);
75 fprintf (stdlis
, "\n");
78 if (exit_status
== TAREXIT_SUCCESS
)
79 exit_status
= TAREXIT_DIFFERS
;
82 /* Take a buffer returned by read_and_process and do nothing with it. */
84 process_noop (size_t size
__attribute__ ((unused
)),
85 char *data
__attribute__ ((unused
)))
91 process_rawdata (size_t bytes
, char *buffer
)
93 size_t status
= safe_read (diff_handle
, diff_buffer
, bytes
);
97 if (status
== SAFE_READ_ERROR
)
99 read_error (current_stat_info
.file_name
);
100 report_difference (¤t_stat_info
, NULL
);
104 report_difference (¤t_stat_info
,
105 ngettext ("Could only read %lu of %lu byte",
106 "Could only read %lu of %lu bytes",
108 (unsigned long) status
, (unsigned long) bytes
);
113 if (memcmp (buffer
, diff_buffer
, bytes
))
115 report_difference (¤t_stat_info
, _("Contents differ"));
122 /* Directory contents, only for GNUTYPE_DUMPDIR. */
124 static char *dumpdir_cursor
;
127 process_dumpdir (size_t bytes
, char *buffer
)
129 if (memcmp (buffer
, dumpdir_cursor
, bytes
))
131 report_difference (¤t_stat_info
, _("Contents differ"));
135 dumpdir_cursor
+= bytes
;
139 /* Some other routine wants SIZE bytes in the archive. For each chunk
140 of the archive, call PROCESSOR with the size of the chunk, and the
141 address of the chunk it can work with. The PROCESSOR should return
142 nonzero for success. It it return error once, continue skipping
143 without calling PROCESSOR anymore. */
145 read_and_process (off_t size
, int (*processor
) (size_t, char *))
147 union block
*data_block
;
150 if (multi_volume_option
)
151 save_sizeleft
= size
;
154 data_block
= find_next_block ();
157 ERROR ((0, 0, _("Unexpected EOF in archive")));
161 data_size
= available_space_after (data_block
);
162 if (data_size
> size
)
164 if (!(*processor
) (data_size
, data_block
->buffer
))
165 processor
= process_noop
;
166 set_next_block_after ((union block
*)
167 (data_block
->buffer
+ data_size
- 1));
169 if (multi_volume_option
)
170 save_sizeleft
-= data_size
;
174 /* Call either stat or lstat over STAT_DATA, depending on
175 --dereference (-h), for a file which should exist. Diagnose any
176 problem. Return nonzero for success, zero otherwise. */
178 get_stat_data (char const *file_name
, struct stat
*stat_data
)
180 int status
= deref_stat (dereference_option
, file_name
, stat_data
);
185 stat_warn (file_name
);
187 stat_error (file_name
);
188 report_difference (¤t_stat_info
, NULL
);
199 struct stat stat_data
;
201 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
204 if (!S_ISDIR (stat_data
.st_mode
))
205 report_difference (¤t_stat_info
, _("File type differs"));
206 else if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
207 (stat_data
.st_mode
& MODE_ALL
))
208 report_difference (¤t_stat_info
, _("Mode differs"));
214 struct stat stat_data
;
216 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
218 else if (!S_ISREG (stat_data
.st_mode
))
220 report_difference (¤t_stat_info
, _("File type differs"));
225 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
226 (stat_data
.st_mode
& MODE_ALL
))
227 report_difference (¤t_stat_info
, _("Mode differs"));
229 if (!sys_compare_uid (&stat_data
, ¤t_stat_info
.stat
))
230 report_difference (¤t_stat_info
, _("Uid differs"));
231 if (!sys_compare_gid (&stat_data
, ¤t_stat_info
.stat
))
232 report_difference (¤t_stat_info
, _("Gid differs"));
234 if (stat_data
.st_mtime
!= current_stat_info
.stat
.st_mtime
)
235 report_difference (¤t_stat_info
, _("Mod time differs"));
236 if (current_header
->header
.typeflag
!= GNUTYPE_SPARSE
&&
237 stat_data
.st_size
!= current_stat_info
.stat
.st_size
)
239 report_difference (¤t_stat_info
, _("Size differs"));
244 int fd
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
248 open_error (current_stat_info
.file_name
);
250 report_difference (¤t_stat_info
, NULL
);
255 struct utimbuf restore_times
;
257 restore_times
.actime
= stat_data
.st_atime
;
258 restore_times
.modtime
= stat_data
.st_mtime
;
260 if (current_stat_info
.is_sparse
)
261 sparse_diff_file (diff_handle
, ¤t_stat_info
);
264 if (multi_volume_option
)
266 assign_string (&save_name
, current_stat_info
.file_name
);
267 save_totsize
= current_stat_info
.stat
.st_size
;
268 /* save_sizeleft is set in read_and_process. */
271 read_and_process (current_stat_info
.stat
.st_size
,
274 if (multi_volume_option
)
275 assign_string (&save_name
, 0);
280 close_error (current_stat_info
.file_name
);
282 if (atime_preserve_option
)
283 utime (current_stat_info
.file_name
, &restore_times
);
292 struct stat file_data
;
293 struct stat link_data
;
295 if (get_stat_data (current_stat_info
.file_name
, &file_data
)
296 && get_stat_data (current_stat_info
.link_name
, &link_data
)
297 && !sys_compare_links (&file_data
, &link_data
))
298 report_difference (¤t_stat_info
,
299 _("Not linked to %s"),
300 quote (current_stat_info
.link_name
));
307 size_t len
= strlen (current_stat_info
.link_name
);
308 char *linkbuf
= alloca (len
+ 1);
310 int status
= readlink (current_stat_info
.file_name
, linkbuf
, len
+ 1);
315 readlink_warn (current_stat_info
.file_name
);
317 readlink_error (current_stat_info
.file_name
);
318 report_difference (¤t_stat_info
, NULL
);
320 else if (status
!= len
321 || strncmp (current_stat_info
.link_name
, linkbuf
, len
) != 0)
322 report_difference (¤t_stat_info
, _("Symlink differs"));
329 struct stat stat_data
;
331 /* FIXME: deal with umask. */
333 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
336 if (current_header
->header
.typeflag
== CHRTYPE
337 ? !S_ISCHR (stat_data
.st_mode
)
338 : current_header
->header
.typeflag
== BLKTYPE
339 ? !S_ISBLK (stat_data
.st_mode
)
340 : /* current_header->header.typeflag == FIFOTYPE */
341 !S_ISFIFO (stat_data
.st_mode
))
343 report_difference (¤t_stat_info
, _("File type differs"));
347 if ((current_header
->header
.typeflag
== CHRTYPE
348 || current_header
->header
.typeflag
== BLKTYPE
)
349 && current_stat_info
.stat
.st_rdev
!= stat_data
.st_rdev
)
351 report_difference (¤t_stat_info
, _("Device number differs"));
355 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
356 (stat_data
.st_mode
& MODE_ALL
))
357 report_difference (¤t_stat_info
, _("Mode differs"));
363 char *dumpdir_buffer
= get_directory_contents (current_stat_info
.file_name
,
366 if (multi_volume_option
)
368 assign_string (&save_name
, current_stat_info
.file_name
);
369 save_totsize
= current_stat_info
.stat
.st_size
;
370 /* save_sizeleft is set in read_and_process. */
375 dumpdir_cursor
= dumpdir_buffer
;
376 read_and_process (current_stat_info
.stat
.st_size
, process_dumpdir
);
377 free (dumpdir_buffer
);
380 read_and_process (current_stat_info
.stat
.st_size
, process_noop
);
382 if (multi_volume_option
)
383 assign_string (&save_name
, 0);
389 struct stat stat_data
;
393 if (current_stat_info
.had_trailing_slash
)
399 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
402 if (!S_ISREG (stat_data
.st_mode
))
404 report_difference (¤t_stat_info
, _("File type differs"));
409 offset
= OFF_FROM_HEADER (current_header
->oldgnu_header
.offset
);
410 if (stat_data
.st_size
!= current_stat_info
.stat
.st_size
+ offset
)
412 report_difference (¤t_stat_info
, _("Size differs"));
417 fd
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
421 open_error (current_stat_info
.file_name
);
422 report_difference (¤t_stat_info
, NULL
);
427 if (lseek (fd
, offset
, SEEK_SET
) < 0)
429 seek_error_details (current_stat_info
.file_name
, offset
);
430 report_difference (¤t_stat_info
, NULL
);
434 if (multi_volume_option
)
436 assign_string (&save_name
, current_stat_info
.file_name
);
437 save_totsize
= stat_data
.st_size
;
438 /* save_sizeleft is set in read_and_process. */
441 read_and_process (current_stat_info
.stat
.st_size
, process_rawdata
);
443 if (multi_volume_option
)
444 assign_string (&save_name
, 0);
448 close_error (current_stat_info
.file_name
);
451 /* Diff a file against the archive. */
456 set_next_block_after (current_header
);
457 decode_header (current_header
, ¤t_stat_info
, ¤t_format
, 1);
459 /* Print the block from current_header and current_stat_info. */
464 fprintf (stdlis
, _("Verify "));
465 print_header (¤t_stat_info
, -1);
468 switch (current_header
->header
.typeflag
)
471 ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
472 quotearg_colon (current_stat_info
.file_name
),
473 current_header
->header
.typeflag
));
481 /* Appears to be a file. See if it's really a directory. */
483 if (current_stat_info
.had_trailing_slash
)
505 case GNUTYPE_DUMPDIR
:
516 case GNUTYPE_MULTIVOL
:
524 if (removed_prefixes_p ())
527 _("Archive contains file names with leading prefixes removed.")));
529 _("Verification may fail to locate original files.")));
535 /* Verifying an archive is meant to check if the physical media got it
536 correctly, so try to defeat clever in-memory buffering pertaining to
537 this particular media. On Linux, for example, the floppy drive would
538 not even be accessed for the whole verification.
540 The code was using fsync only when the ioctl is unavailable, but
541 Marty Leisner says that the ioctl does not work when not preceded by
542 fsync. So, until we know better, or maybe to please Marty, let's do it
543 the unbelievable way :-). */
549 ioctl (archive
, FDFLUSH
);
554 struct mtop operation
;
557 operation
.mt_op
= MTBSF
;
558 operation
.mt_count
= 1;
559 if (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
), status
< 0)
562 || (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
),
566 if (rmtlseek (archive
, (off_t
) 0, SEEK_SET
) != 0)
568 /* Lseek failed. Try a different method. */
569 seek_warn (archive_name_array
[0]);
578 access_mode
= ACCESS_READ
;
584 enum read_header status
= read_header (false);
586 if (status
== HEADER_FAILURE
)
593 set_next_block_after (current_header
);
594 status
= read_header (false);
596 while (status
== HEADER_FAILURE
);
599 ngettext ("VERIFY FAILURE: %d invalid header detected",
600 "VERIFY FAILURE: %d invalid headers detected",
603 if (status
== HEADER_ZERO_BLOCK
|| status
== HEADER_END_OF_FILE
)
607 tar_stat_destroy (¤t_stat_info
);
608 xheader_destroy (&extended_header
);
611 access_mode
= ACCESS_WRITE
;
This page took 0.059256 seconds and 4 git commands to generate.