]>
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 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. */
57 diff_buffer
= valloc (record_size
);
62 /* Sigh about something that differs by writing a MESSAGE to stdlis,
63 given MESSAGE is nonzero. Also set the exit status if not already. */
65 report_difference (struct tar_stat_info
*st
, const char *fmt
, ...)
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
, char *data
)
86 /* Yes, I know. SIZE and DATA are unused in this function. Some
87 compilers may even report it. That's OK, just relax! */
92 process_rawdata (size_t bytes
, char *buffer
)
94 ssize_t status
= safe_read (diff_handle
, diff_buffer
, bytes
);
100 read_error (current_stat_info
.file_name
);
101 report_difference (¤t_stat_info
, NULL
);
105 report_difference (¤t_stat_info
,
106 ngettext ("Could only read %lu of %lu byte",
107 "Could only read %lu of %lu bytes",
109 (unsigned long) status
, (unsigned long) bytes
);
114 if (memcmp (buffer
, diff_buffer
, bytes
))
116 report_difference (¤t_stat_info
,
117 _("Contents differ"));
124 /* Directory contents, only for GNUTYPE_DUMPDIR. */
126 static char *dumpdir_cursor
;
129 process_dumpdir (size_t bytes
, char *buffer
)
131 if (memcmp (buffer
, dumpdir_cursor
, bytes
))
133 report_difference (¤t_stat_info
, _("Contents differ"));
137 dumpdir_cursor
+= bytes
;
141 /* Some other routine wants SIZE bytes in the archive. For each chunk
142 of the archive, call PROCESSOR with the size of the chunk, and the
143 address of the chunk it can work with. The PROCESSOR should return
144 nonzero for success. It it return error once, continue skipping
145 without calling PROCESSOR anymore. */
147 read_and_process (off_t size
, int (*processor
) (size_t, char *))
149 union block
*data_block
;
152 if (multi_volume_option
)
153 save_sizeleft
= size
;
156 data_block
= find_next_block ();
159 ERROR ((0, 0, _("Unexpected EOF in archive")));
163 data_size
= available_space_after (data_block
);
164 if (data_size
> size
)
166 if (!(*processor
) (data_size
, data_block
->buffer
))
167 processor
= process_noop
;
168 set_next_block_after ((union block
*)
169 (data_block
->buffer
+ data_size
- 1));
171 if (multi_volume_option
)
172 save_sizeleft
-= data_size
;
176 /* Call either stat or lstat over STAT_DATA, depending on
177 --dereference (-h), for a file which should exist. Diagnose any
178 problem. Return nonzero for success, zero otherwise. */
180 get_stat_data (char const *file_name
, struct stat
*stat_data
)
182 int status
= deref_stat (dereference_option
, file_name
, stat_data
);
187 stat_warn (file_name
);
189 stat_error (file_name
);
190 report_difference (¤t_stat_info
, NULL
);
197 /* Diff a file against the archive. */
201 struct stat stat_data
;
203 struct utimbuf restore_times
;
205 set_next_block_after (current_header
);
206 decode_header (current_header
, ¤t_stat_info
, ¤t_format
, 1);
208 /* Print the block from current_header and current_stat_info. */
213 fprintf (stdlis
, _("Verify "));
214 print_header (¤t_stat_info
, -1);
217 switch (current_header
->header
.typeflag
)
220 ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
221 quotearg_colon (current_stat_info
.file_name
),
222 current_header
->header
.typeflag
));
230 /* Appears to be a file. See if it's really a directory. */
232 if (current_stat_info
.had_trailing_slash
)
235 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
241 if (!S_ISREG (stat_data
.st_mode
))
243 report_difference (¤t_stat_info
, _("File type differs"));
248 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
249 (stat_data
.st_mode
& MODE_ALL
))
250 report_difference (¤t_stat_info
, _("Mode differs"));
252 if (!sys_compare_uid (&stat_data
, ¤t_stat_info
.stat
))
253 report_difference (¤t_stat_info
, _("Uid differs"));
254 if (!sys_compare_gid (&stat_data
, ¤t_stat_info
.stat
))
255 report_difference (¤t_stat_info
, _("Gid differs"));
257 if (stat_data
.st_mtime
!= current_stat_info
.stat
.st_mtime
)
258 report_difference (¤t_stat_info
, _("Mod time differs"));
259 if (current_header
->header
.typeflag
!= GNUTYPE_SPARSE
&&
260 stat_data
.st_size
!= current_stat_info
.stat
.st_size
)
262 report_difference (¤t_stat_info
, _("Size differs"));
267 diff_handle
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
271 open_error (current_stat_info
.file_name
);
273 report_difference (¤t_stat_info
, NULL
);
277 restore_times
.actime
= stat_data
.st_atime
;
278 restore_times
.modtime
= stat_data
.st_mtime
;
280 /* Need to treat sparse files completely differently here. */
282 if (current_header
->header
.typeflag
== GNUTYPE_SPARSE
)
283 sparse_diff_file (diff_handle
, ¤t_stat_info
);
286 if (multi_volume_option
)
288 assign_string (&save_name
, current_stat_info
.file_name
);
289 save_totsize
= current_stat_info
.stat
.st_size
;
290 /* save_sizeleft is set in read_and_process. */
293 read_and_process (current_stat_info
.stat
.st_size
, process_rawdata
);
295 if (multi_volume_option
)
296 assign_string (&save_name
, 0);
299 status
= close (diff_handle
);
301 close_error (current_stat_info
.file_name
);
303 if (atime_preserve_option
)
304 utime (current_stat_info
.file_name
, &restore_times
);
311 struct stat link_data
, stat_data
;
313 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
315 if (!get_stat_data (current_stat_info
.link_name
, &link_data
))
317 if (!sys_compare_links (&stat_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
);
500 /* Verifying an archive is meant to check if the physical media got it
501 correctly, so try to defeat clever in-memory buffering pertaining to
502 this particular media. On Linux, for example, the floppy drive would
503 not even be accessed for the whole verification.
505 The code was using fsync only when the ioctl is unavailable, but
506 Marty Leisner says that the ioctl does not work when not preceded by
507 fsync. So, until we know better, or maybe to please Marty, let's do it
508 the unbelievable way :-). */
514 ioctl (archive
, FDFLUSH
);
519 struct mtop operation
;
522 operation
.mt_op
= MTBSF
;
523 operation
.mt_count
= 1;
524 if (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
), status
< 0)
527 || (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
),
531 if (rmtlseek (archive
, (off_t
) 0, SEEK_SET
) != 0)
533 /* Lseek failed. Try a different method. */
534 seek_warn (archive_name_array
[0]);
543 access_mode
= ACCESS_READ
;
549 enum read_header status
= read_header (false);
551 if (status
== HEADER_FAILURE
)
558 status
= read_header (false);
560 while (status
== HEADER_FAILURE
);
563 ngettext ("VERIFY FAILURE: %d invalid header detected",
564 "VERIFY FAILURE: %d invalid headers detected",
567 if (status
== HEADER_ZERO_BLOCK
|| status
== HEADER_END_OF_FILE
)
573 access_mode
= ACCESS_WRITE
;
This page took 0.057794 seconds and 4 git commands to generate.