]>
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. */
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
__attribute__ ((unused
)),
72 fprintf (stdlis
, "%s: ", quotearg_colon (current_stat_info
.file_name
));
74 vfprintf (stdlis
, fmt
, ap
);
76 fprintf (stdlis
, "\n");
79 if (exit_status
== TAREXIT_SUCCESS
)
80 exit_status
= TAREXIT_DIFFERS
;
83 /* Take a buffer returned by read_and_process and do nothing with it. */
85 process_noop (size_t size
__attribute__ ((unused
)),
86 char *data
__attribute__ ((unused
)))
92 process_rawdata (size_t bytes
, char *buffer
)
94 size_t status
= safe_read (diff_handle
, diff_buffer
, bytes
);
98 if (status
== SAFE_READ_ERROR
)
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_stat_info
.is_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 file_data
;
312 struct stat link_data
;
314 if (!get_stat_data (current_stat_info
.file_name
, &file_data
))
316 if (!get_stat_data (current_stat_info
.link_name
, &link_data
))
318 if (!sys_compare_links (&file_data
, &link_data
))
319 report_difference (¤t_stat_info
,
320 _("Not linked to %s"),
321 quote (current_stat_info
.link_name
));
328 size_t len
= strlen (current_stat_info
.link_name
);
329 char *linkbuf
= alloca (len
+ 1);
331 status
= readlink (current_stat_info
.file_name
, linkbuf
, len
+ 1);
336 readlink_warn (current_stat_info
.file_name
);
338 readlink_error (current_stat_info
.file_name
);
339 report_difference (¤t_stat_info
, NULL
);
341 else if (status
!= len
342 || strncmp (current_stat_info
.link_name
, linkbuf
, len
) != 0)
343 report_difference (¤t_stat_info
, _("Symlink differs"));
353 /* FIXME: deal with umask. */
355 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
358 if (current_header
->header
.typeflag
== CHRTYPE
359 ? !S_ISCHR (stat_data
.st_mode
)
360 : current_header
->header
.typeflag
== BLKTYPE
361 ? !S_ISBLK (stat_data
.st_mode
)
362 : /* current_header->header.typeflag == FIFOTYPE */
363 !S_ISFIFO (stat_data
.st_mode
))
365 report_difference (¤t_stat_info
, _("File type differs"));
369 if ((current_header
->header
.typeflag
== CHRTYPE
370 || current_header
->header
.typeflag
== BLKTYPE
)
371 && current_stat_info
.stat
.st_rdev
!= stat_data
.st_rdev
)
373 report_difference (¤t_stat_info
, _("Device number differs"));
377 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) != (stat_data
.st_mode
& MODE_ALL
))
379 report_difference (¤t_stat_info
, _("Mode differs"));
385 case GNUTYPE_DUMPDIR
:
387 char *dumpdir_buffer
= get_directory_contents (current_stat_info
.file_name
, 0);
389 if (multi_volume_option
)
391 assign_string (&save_name
, current_stat_info
.file_name
);
392 save_totsize
= current_stat_info
.stat
.st_size
;
393 /* save_sizeleft is set in read_and_process. */
398 dumpdir_cursor
= dumpdir_buffer
;
399 read_and_process (current_stat_info
.stat
.st_size
, process_dumpdir
);
400 free (dumpdir_buffer
);
403 read_and_process (current_stat_info
.stat
.st_size
, process_noop
);
405 if (multi_volume_option
)
406 assign_string (&save_name
, 0);
412 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
415 if (!S_ISDIR (stat_data
.st_mode
))
417 report_difference (¤t_stat_info
, _("File type differs"));
421 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) != (stat_data
.st_mode
& MODE_ALL
))
423 report_difference (¤t_stat_info
, _("Mode differs"));
432 case GNUTYPE_MULTIVOL
:
436 if (current_stat_info
.had_trailing_slash
)
439 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
442 if (!S_ISREG (stat_data
.st_mode
))
444 report_difference (¤t_stat_info
, _("File type differs"));
449 offset
= OFF_FROM_HEADER (current_header
->oldgnu_header
.offset
);
450 if (stat_data
.st_size
!= current_stat_info
.stat
.st_size
+ offset
)
452 report_difference (¤t_stat_info
, _("Size differs"));
457 diff_handle
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
461 open_error (current_stat_info
.file_name
);
462 report_difference (¤t_stat_info
, NULL
);
467 if (lseek (diff_handle
, offset
, SEEK_SET
) < 0)
469 seek_error_details (current_stat_info
.file_name
, offset
);
470 report_difference (¤t_stat_info
, NULL
);
474 if (multi_volume_option
)
476 assign_string (&save_name
, current_stat_info
.file_name
);
477 save_totsize
= stat_data
.st_size
;
478 /* save_sizeleft is set in read_and_process. */
481 read_and_process (current_stat_info
.stat
.st_size
, process_rawdata
);
483 if (multi_volume_option
)
484 assign_string (&save_name
, 0);
486 status
= close (diff_handle
);
488 close_error (current_stat_info
.file_name
);
501 /* Verifying an archive is meant to check if the physical media got it
502 correctly, so try to defeat clever in-memory buffering pertaining to
503 this particular media. On Linux, for example, the floppy drive would
504 not even be accessed for the whole verification.
506 The code was using fsync only when the ioctl is unavailable, but
507 Marty Leisner says that the ioctl does not work when not preceded by
508 fsync. So, until we know better, or maybe to please Marty, let's do it
509 the unbelievable way :-). */
515 ioctl (archive
, FDFLUSH
);
520 struct mtop operation
;
523 operation
.mt_op
= MTBSF
;
524 operation
.mt_count
= 1;
525 if (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
), status
< 0)
528 || (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
),
532 if (rmtlseek (archive
, (off_t
) 0, SEEK_SET
) != 0)
534 /* Lseek failed. Try a different method. */
535 seek_warn (archive_name_array
[0]);
544 access_mode
= ACCESS_READ
;
550 enum read_header status
= read_header (false);
552 if (status
== HEADER_FAILURE
)
559 status
= read_header (false);
561 while (status
== HEADER_FAILURE
);
564 ngettext ("VERIFY FAILURE: %d invalid header detected",
565 "VERIFY FAILURE: %d invalid headers detected",
568 if (status
== HEADER_ZERO_BLOCK
|| status
== HEADER_END_OF_FILE
)
574 access_mode
= ACCESS_WRITE
;
This page took 0.06217 seconds and 4 git commands to generate.