]>
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
,
116 _("Contents differ"));
123 /* Directory contents, only for GNUTYPE_DUMPDIR. */
125 static char *dumpdir_cursor
;
128 process_dumpdir (size_t bytes
, char *buffer
)
130 if (memcmp (buffer
, dumpdir_cursor
, bytes
))
132 report_difference (¤t_stat_info
, _("Contents differ"));
136 dumpdir_cursor
+= bytes
;
140 /* Some other routine wants SIZE bytes in the archive. For each chunk
141 of the archive, call PROCESSOR with the size of the chunk, and the
142 address of the chunk it can work with. The PROCESSOR should return
143 nonzero for success. It it return error once, continue skipping
144 without calling PROCESSOR anymore. */
146 read_and_process (off_t size
, int (*processor
) (size_t, char *))
148 union block
*data_block
;
151 if (multi_volume_option
)
152 save_sizeleft
= size
;
155 data_block
= find_next_block ();
158 ERROR ((0, 0, _("Unexpected EOF in archive")));
162 data_size
= available_space_after (data_block
);
163 if (data_size
> size
)
165 if (!(*processor
) (data_size
, data_block
->buffer
))
166 processor
= process_noop
;
167 set_next_block_after ((union block
*)
168 (data_block
->buffer
+ data_size
- 1));
170 if (multi_volume_option
)
171 save_sizeleft
-= data_size
;
175 /* Call either stat or lstat over STAT_DATA, depending on
176 --dereference (-h), for a file which should exist. Diagnose any
177 problem. Return nonzero for success, zero otherwise. */
179 get_stat_data (char const *file_name
, struct stat
*stat_data
)
181 int status
= deref_stat (dereference_option
, file_name
, stat_data
);
186 stat_warn (file_name
);
188 stat_error (file_name
);
189 report_difference (¤t_stat_info
, NULL
);
196 /* Diff a file against the archive. */
200 struct stat stat_data
;
202 struct utimbuf restore_times
;
204 set_next_block_after (current_header
);
205 decode_header (current_header
, ¤t_stat_info
, ¤t_format
, 1);
207 /* Print the block from current_header and current_stat_info. */
212 fprintf (stdlis
, _("Verify "));
213 print_header (¤t_stat_info
, -1);
216 switch (current_header
->header
.typeflag
)
219 ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
220 quotearg_colon (current_stat_info
.file_name
),
221 current_header
->header
.typeflag
));
229 /* Appears to be a file. See if it's really a directory. */
231 if (current_stat_info
.had_trailing_slash
)
234 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
240 if (!S_ISREG (stat_data
.st_mode
))
242 report_difference (¤t_stat_info
, _("File type differs"));
247 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
248 (stat_data
.st_mode
& MODE_ALL
))
249 report_difference (¤t_stat_info
, _("Mode differs"));
251 if (!sys_compare_uid (&stat_data
, ¤t_stat_info
.stat
))
252 report_difference (¤t_stat_info
, _("Uid differs"));
253 if (!sys_compare_gid (&stat_data
, ¤t_stat_info
.stat
))
254 report_difference (¤t_stat_info
, _("Gid differs"));
256 if (stat_data
.st_mtime
!= current_stat_info
.stat
.st_mtime
)
257 report_difference (¤t_stat_info
, _("Mod time differs"));
258 if (current_header
->header
.typeflag
!= GNUTYPE_SPARSE
&&
259 stat_data
.st_size
!= current_stat_info
.stat
.st_size
)
261 report_difference (¤t_stat_info
, _("Size differs"));
266 diff_handle
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
270 open_error (current_stat_info
.file_name
);
272 report_difference (¤t_stat_info
, NULL
);
276 restore_times
.actime
= stat_data
.st_atime
;
277 restore_times
.modtime
= stat_data
.st_mtime
;
279 /* Need to treat sparse files completely differently here. */
281 if (current_stat_info
.is_sparse
)
282 sparse_diff_file (diff_handle
, ¤t_stat_info
);
285 if (multi_volume_option
)
287 assign_string (&save_name
, current_stat_info
.file_name
);
288 save_totsize
= current_stat_info
.stat
.st_size
;
289 /* save_sizeleft is set in read_and_process. */
292 read_and_process (current_stat_info
.stat
.st_size
, process_rawdata
);
294 if (multi_volume_option
)
295 assign_string (&save_name
, 0);
298 status
= close (diff_handle
);
300 close_error (current_stat_info
.file_name
);
302 if (atime_preserve_option
)
303 utime (current_stat_info
.file_name
, &restore_times
);
310 struct stat file_data
;
311 struct stat link_data
;
313 if (!get_stat_data (current_stat_info
.file_name
, &file_data
))
315 if (!get_stat_data (current_stat_info
.link_name
, &link_data
))
317 if (!sys_compare_links (&file_data
, &link_data
))
318 report_difference (¤t_stat_info
,
319 _("Not linked to %s"),
320 quote (current_stat_info
.link_name
));
327 size_t len
= strlen (current_stat_info
.link_name
);
328 char *linkbuf
= alloca (len
+ 1);
330 status
= readlink (current_stat_info
.file_name
, linkbuf
, len
+ 1);
335 readlink_warn (current_stat_info
.file_name
);
337 readlink_error (current_stat_info
.file_name
);
338 report_difference (¤t_stat_info
, NULL
);
340 else if (status
!= len
341 || strncmp (current_stat_info
.link_name
, linkbuf
, len
) != 0)
342 report_difference (¤t_stat_info
, _("Symlink differs"));
352 /* FIXME: deal with umask. */
354 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
357 if (current_header
->header
.typeflag
== CHRTYPE
358 ? !S_ISCHR (stat_data
.st_mode
)
359 : current_header
->header
.typeflag
== BLKTYPE
360 ? !S_ISBLK (stat_data
.st_mode
)
361 : /* current_header->header.typeflag == FIFOTYPE */
362 !S_ISFIFO (stat_data
.st_mode
))
364 report_difference (¤t_stat_info
, _("File type differs"));
368 if ((current_header
->header
.typeflag
== CHRTYPE
369 || current_header
->header
.typeflag
== BLKTYPE
)
370 && current_stat_info
.stat
.st_rdev
!= stat_data
.st_rdev
)
372 report_difference (¤t_stat_info
, _("Device number differs"));
376 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) != (stat_data
.st_mode
& MODE_ALL
))
378 report_difference (¤t_stat_info
, _("Mode differs"));
384 case GNUTYPE_DUMPDIR
:
386 char *dumpdir_buffer
= get_directory_contents (current_stat_info
.file_name
, 0);
388 if (multi_volume_option
)
390 assign_string (&save_name
, current_stat_info
.file_name
);
391 save_totsize
= current_stat_info
.stat
.st_size
;
392 /* save_sizeleft is set in read_and_process. */
397 dumpdir_cursor
= dumpdir_buffer
;
398 read_and_process (current_stat_info
.stat
.st_size
, process_dumpdir
);
399 free (dumpdir_buffer
);
402 read_and_process (current_stat_info
.stat
.st_size
, process_noop
);
404 if (multi_volume_option
)
405 assign_string (&save_name
, 0);
411 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
414 if (!S_ISDIR (stat_data
.st_mode
))
416 report_difference (¤t_stat_info
, _("File type differs"));
420 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) != (stat_data
.st_mode
& MODE_ALL
))
422 report_difference (¤t_stat_info
, _("Mode differs"));
431 case GNUTYPE_MULTIVOL
:
435 if (current_stat_info
.had_trailing_slash
)
438 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
441 if (!S_ISREG (stat_data
.st_mode
))
443 report_difference (¤t_stat_info
, _("File type differs"));
448 offset
= OFF_FROM_HEADER (current_header
->oldgnu_header
.offset
);
449 if (stat_data
.st_size
!= current_stat_info
.stat
.st_size
+ offset
)
451 report_difference (¤t_stat_info
, _("Size differs"));
456 diff_handle
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
460 open_error (current_stat_info
.file_name
);
461 report_difference (¤t_stat_info
, NULL
);
466 if (lseek (diff_handle
, offset
, SEEK_SET
) < 0)
468 seek_error_details (current_stat_info
.file_name
, offset
);
469 report_difference (¤t_stat_info
, NULL
);
473 if (multi_volume_option
)
475 assign_string (&save_name
, current_stat_info
.file_name
);
476 save_totsize
= stat_data
.st_size
;
477 /* save_sizeleft is set in read_and_process. */
480 read_and_process (current_stat_info
.stat
.st_size
, process_rawdata
);
482 if (multi_volume_option
)
483 assign_string (&save_name
, 0);
485 status
= close (diff_handle
);
487 close_error (current_stat_info
.file_name
);
497 if (removed_prefixes_p ())
500 _("Archive contains file names with leading prefixes removed.")));
502 _("Verification may fail to locate original files.")));
508 /* Verifying an archive is meant to check if the physical media got it
509 correctly, so try to defeat clever in-memory buffering pertaining to
510 this particular media. On Linux, for example, the floppy drive would
511 not even be accessed for the whole verification.
513 The code was using fsync only when the ioctl is unavailable, but
514 Marty Leisner says that the ioctl does not work when not preceded by
515 fsync. So, until we know better, or maybe to please Marty, let's do it
516 the unbelievable way :-). */
522 ioctl (archive
, FDFLUSH
);
527 struct mtop operation
;
530 operation
.mt_op
= MTBSF
;
531 operation
.mt_count
= 1;
532 if (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
), status
< 0)
535 || (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
),
539 if (rmtlseek (archive
, (off_t
) 0, SEEK_SET
) != 0)
541 /* Lseek failed. Try a different method. */
542 seek_warn (archive_name_array
[0]);
551 access_mode
= ACCESS_READ
;
557 enum read_header status
= read_header (false);
559 if (status
== HEADER_FAILURE
)
566 set_next_block_after (current_header
);
567 status
= read_header (false);
569 while (status
== HEADER_FAILURE
);
572 ngettext ("VERIFY FAILURE: %d invalid header detected",
573 "VERIFY FAILURE: %d invalid headers detected",
576 if (status
== HEADER_ZERO_BLOCK
|| status
== HEADER_END_OF_FILE
)
580 tar_stat_destroy (¤t_stat_info
);
581 xheader_destroy (&extended_header
);
584 access_mode
= ACCESS_WRITE
;
This page took 0.064473 seconds and 4 git commands to generate.