]> Dogcows Code - chaz/tar/blob - src/compare.c
GNU tar 1.12
[chaz/tar] / src / compare.c
1 /* Diff files from a tar archive.
2 Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
3 Written by John Gilmore, on 1987-04-30.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19 #include "system.h"
20
21 #if HAVE_LINUX_FD_H
22 # include <linux/fd.h>
23 #endif
24
25 #include "common.h"
26 #include "rmt.h"
27
28 /* Spare space for messages, hopefully safe even after gettext. */
29 #define MESSAGE_BUFFER_SIZE 100
30
31 /* Nonzero if we are verifying at the moment. */
32 int now_verifying = 0;
33
34 /* File descriptor for the file we are diffing. */
35 static int diff_handle;
36
37 /* Area for reading file contents into. */
38 static char *diff_buffer = NULL;
39
40 /*--------------------------------.
41 | Initialize for a diff operation |
42 `--------------------------------*/
43
44 void
45 diff_init (void)
46 {
47 diff_buffer = (char *) valloc ((unsigned) record_size);
48 if (!diff_buffer)
49 FATAL_ERROR ((0, 0,
50 _("Could not allocate memory for diff buffer of %d bytes"),
51 record_size));
52 }
53
54 /*------------------------------------------------------------------------.
55 | Sigh about something that differs by writing a MESSAGE to stdlis, given |
56 | MESSAGE is not NULL. Also set the exit status if not already. |
57 `------------------------------------------------------------------------*/
58
59 static void
60 report_difference (const char *message)
61 {
62 if (message)
63 fprintf (stdlis, "%s: %s\n", current_file_name, message);
64
65 if (exit_status == TAREXIT_SUCCESS)
66 exit_status = TAREXIT_DIFFERS;
67 }
68
69 /*-----------------------------------------------------------------------.
70 | Takes a buffer returned by read_and_process and does nothing with it. |
71 `-----------------------------------------------------------------------*/
72
73 /* Yes, I know. SIZE and DATA are unused in this function. Some compilers
74 may even report it. That's OK, just relax! */
75
76 static int
77 process_noop (long size, char *data)
78 {
79 return 1;
80 }
81
82 /*---.
83 | ? |
84 `---*/
85
86 static int
87 process_rawdata (long bytes, char *buffer)
88 {
89 int status = read (diff_handle, diff_buffer, (size_t) bytes);
90 char message[MESSAGE_BUFFER_SIZE];
91
92 if (status != bytes)
93 {
94 if (status < 0)
95 {
96 WARN ((0, errno, _("Cannot read %s"), current_file_name));
97 report_difference (NULL);
98 }
99 else
100 {
101 sprintf (message, _("Could only read %d of %ld bytes"),
102 status, bytes);
103 report_difference (message);
104 }
105 return 0;
106 }
107
108 if (memcmp (buffer, diff_buffer, (size_t) bytes))
109 {
110 report_difference (_("Data differs"));
111 return 0;
112 }
113
114 return 1;
115 }
116
117 /*---.
118 | ? |
119 `---*/
120
121 /* Directory contents, only for GNUTYPE_DUMPDIR. */
122
123 static char *dumpdir_cursor;
124
125 static int
126 process_dumpdir (long bytes, char *buffer)
127 {
128 if (memcmp (buffer, dumpdir_cursor, (size_t) bytes))
129 {
130 report_difference (_("Data differs"));
131 return 0;
132 }
133
134 dumpdir_cursor += bytes;
135 return 1;
136 }
137
138 /*------------------------------------------------------------------------.
139 | Some other routine wants SIZE bytes in the archive. For each chunk of |
140 | the archive, call PROCESSOR with the size of the chunk, and the address |
141 | of the chunk it can work with. The PROCESSOR should return nonzero for |
142 | success. It it return error once, continue skipping without calling |
143 | PROCESSOR anymore. |
144 `------------------------------------------------------------------------*/
145
146 static void
147 read_and_process (long size, int (*processor) (long, char *))
148 {
149 union block *data_block;
150 long data_size;
151
152 if (multi_volume_option)
153 save_sizeleft = size;
154 while (size)
155 {
156 data_block = find_next_block ();
157 if (data_block == NULL)
158 {
159 ERROR ((0, 0, _("Unexpected EOF on archive file")));
160 return;
161 }
162
163 data_size = available_space_after (data_block);
164 if (data_size > size)
165 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));
170 size -= data_size;
171 if (multi_volume_option)
172 save_sizeleft -= data_size;
173 }
174 }
175
176 /*---.
177 | ? |
178 `---*/
179
180 /* JK This routine should be used more often than it is ... look into
181 that. Anyhow, what it does is translate the sparse information on the
182 header, and in any subsequent extended headers, into an array of
183 structures with true numbers, as opposed to character strings. It
184 simply makes our life much easier, doing so many comparisong and such.
185 */
186
187 static void
188 fill_in_sparse_array (void)
189 {
190 int counter;
191
192 /* Allocate space for our scratch space; it's initially 10 elements
193 long, but can change in this routine if necessary. */
194
195 sp_array_size = 10;
196 sparsearray = (struct sp_array *) xmalloc (sp_array_size * sizeof (struct sp_array));
197
198 /* There are at most five of these structures in the header itself;
199 read these in first. */
200
201 for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
202 {
203 /* Compare to 0, or use !(int)..., for Pyramid's dumb compiler. */
204 if (current_header->oldgnu_header.sp[counter].numbytes == 0)
205 break;
206
207 sparsearray[counter].offset =
208 from_oct (1 + 12, current_header->oldgnu_header.sp[counter].offset);
209 sparsearray[counter].numbytes =
210 from_oct (1 + 12, current_header->oldgnu_header.sp[counter].numbytes);
211 }
212
213 /* If the header's extended, we gotta read in exhdr's till we're done. */
214
215 if (current_header->oldgnu_header.isextended)
216 {
217 /* How far into the sparsearray we are `so far'. */
218 static int so_far_ind = SPARSES_IN_OLDGNU_HEADER;
219 union block *exhdr;
220
221 while (1)
222 {
223 exhdr = find_next_block ();
224 for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
225 {
226 if (counter + so_far_ind > sp_array_size - 1)
227 {
228 /* We just ran out of room in our scratch area -
229 realloc it. */
230
231 sp_array_size *= 2;
232 sparsearray = (struct sp_array *)
233 xrealloc (sparsearray,
234 sp_array_size * sizeof (struct sp_array));
235 }
236
237 /* Convert the character strings into longs. */
238
239 sparsearray[counter + so_far_ind].offset =
240 from_oct (1 + 12, exhdr->sparse_header.sp[counter].offset);
241 sparsearray[counter + so_far_ind].numbytes =
242 from_oct (1 + 12, exhdr->sparse_header.sp[counter].numbytes);
243 }
244
245 /* If this is the last extended header for this file, we can
246 stop. */
247
248 if (!exhdr->sparse_header.isextended)
249 break;
250
251 so_far_ind += SPARSES_IN_SPARSE_HEADER;
252 set_next_block_after (exhdr);
253 }
254
255 /* Be sure to skip past the last one. */
256
257 set_next_block_after (exhdr);
258 }
259 }
260
261 /*---.
262 | ? |
263 `---*/
264
265 /* JK Diff'ing a sparse file with its counterpart on the tar file is a
266 bit of a different story than a normal file. First, we must know what
267 areas of the file to skip through, i.e., we need to contruct a
268 sparsearray, which will hold all the information we need. We must
269 compare small amounts of data at a time as we find it. */
270
271 /* FIXME: This does not look very solid to me, at first glance. Zero areas
272 are not checked, spurious sparse entries seemingly goes undetected, and
273 I'm not sure overall identical sparsity is verified. */
274
275 static void
276 diff_sparse_files (int size_of_file)
277 {
278 int remaining_size = size_of_file;
279 char *buffer = (char *) xmalloc (BLOCKSIZE * sizeof (char));
280 int buffer_size = BLOCKSIZE;
281 union block *data_block = NULL;
282 int counter = 0;
283 int different = 0;
284
285 fill_in_sparse_array ();
286
287 while (remaining_size > 0)
288 {
289 int status;
290 long chunk_size;
291 #if 0
292 int amount_read = 0;
293 #endif
294
295 data_block = find_next_block ();
296 chunk_size = sparsearray[counter].numbytes;
297 if (!chunk_size)
298 break;
299
300 lseek (diff_handle, sparsearray[counter].offset, 0);
301
302 /* Take care to not run out of room in our buffer. */
303
304 while (buffer_size < chunk_size)
305 {
306 buffer_size *= 2;
307 buffer = (char *) xrealloc (buffer, buffer_size * sizeof (char));
308 }
309
310 while (chunk_size > BLOCKSIZE)
311 {
312 if (status = read (diff_handle, buffer, BLOCKSIZE),
313 status != BLOCKSIZE)
314 {
315 if (status < 0)
316 {
317 WARN ((0, errno, _("Cannot read %s"), current_file_name));
318 report_difference (NULL);
319 }
320 else
321 {
322 char message[MESSAGE_BUFFER_SIZE];
323
324 sprintf (message, _("Could only read %d of %ld bytes"),
325 status, chunk_size);
326 report_difference (message);
327 }
328 break;
329 }
330
331 if (memcmp (buffer, data_block->buffer, BLOCKSIZE))
332 {
333 different = 1;
334 break;
335 }
336
337 chunk_size -= status;
338 remaining_size -= status;
339 set_next_block_after (data_block);
340 data_block = find_next_block ();
341 }
342 if (status = read (diff_handle, buffer, (size_t) chunk_size),
343 status != chunk_size)
344 {
345 if (status < 0)
346 {
347 WARN ((0, errno, _("Cannot read %s"), current_file_name));
348 report_difference (NULL);
349 }
350 else
351 {
352 char message[MESSAGE_BUFFER_SIZE];
353
354 sprintf (message, _("Could only read %d of %ld bytes"),
355 status, chunk_size);
356 report_difference (message);
357 }
358 break;
359 }
360
361 if (memcmp (buffer, data_block->buffer, (size_t) chunk_size))
362 {
363 different = 1;
364 break;
365 }
366 #if 0
367 amount_read += chunk_size;
368 if (amount_read >= BLOCKSIZE)
369 {
370 amount_read = 0;
371 set_next_block_after (data_block);
372 data_block = find_next_block ();
373 }
374 #endif
375 set_next_block_after (data_block);
376 counter++;
377 remaining_size -= chunk_size;
378 }
379
380 #if 0
381 /* If the number of bytes read isn't the number of bytes supposedly in
382 the file, they're different. */
383
384 if (amount_read != size_of_file)
385 different = 1;
386 #endif
387
388 set_next_block_after (data_block);
389 free (sparsearray);
390
391 if (different)
392 report_difference (_("Data differs"));
393 }
394
395 /*---------------------------------------------------------------------.
396 | Call either stat or lstat over STAT_DATA, depending on --dereference |
397 | (-h), for a file which should exist. Diagnose any problem. Return |
398 | nonzero for success, zero otherwise. |
399 `---------------------------------------------------------------------*/
400
401 static int
402 get_stat_data (struct stat *stat_data)
403 {
404 int status = (dereference_option
405 ? stat (current_file_name, stat_data)
406 : lstat (current_file_name, stat_data));
407
408 if (status < 0)
409 {
410 if (errno == ENOENT)
411 report_difference (_("File does not exist"));
412 else
413 {
414 ERROR ((0, errno, _("Cannot stat file %s"), current_file_name));
415 report_difference (NULL);
416 }
417 #if 0
418 skip_file ((long) current_stat.st_size);
419 #endif
420 return 0;
421 }
422
423 return 1;
424 }
425
426 /*----------------------------------.
427 | Diff a file against the archive. |
428 `----------------------------------*/
429
430 void
431 diff_archive (void)
432 {
433 struct stat stat_data;
434 int name_length;
435 int status;
436
437 errno = EPIPE; /* FIXME: errno should be read-only */
438 /* FIXME: remove perrors */
439
440 set_next_block_after (current_header);
441 decode_header (current_header, &current_stat, &current_format, 1);
442
443 /* Print the block from `current_header' and `current_stat'. */
444
445 if (verbose_option)
446 {
447 if (now_verifying)
448 fprintf (stdlis, _("Verify "));
449 print_header ();
450 }
451
452 switch (current_header->header.typeflag)
453 {
454 default:
455 WARN ((0, 0, _("Unknown file type '%c' for %s, diffed as normal file"),
456 current_header->header.typeflag, current_file_name));
457 /* Fall through. */
458
459 case AREGTYPE:
460 case REGTYPE:
461 case GNUTYPE_SPARSE:
462 case CONTTYPE:
463
464 /* Appears to be a file. See if it's really a directory. */
465
466 name_length = strlen (current_file_name) - 1;
467 if (current_file_name[name_length] == '/')
468 goto really_dir;
469
470 if (!get_stat_data (&stat_data))
471 {
472 if (current_header->oldgnu_header.isextended)
473 skip_extended_headers ();
474 skip_file ((long) current_stat.st_size);
475 goto quit;
476 }
477
478 if (!S_ISREG (stat_data.st_mode))
479 {
480 report_difference (_("Not a regular file"));
481 skip_file ((long) current_stat.st_size);
482 goto quit;
483 }
484
485 stat_data.st_mode &= 07777;
486 if (stat_data.st_mode != current_stat.st_mode)
487 report_difference (_("Mode differs"));
488
489 #if !MSDOS
490 /* stat() in djgpp's C library gives a constant number of 42 as the
491 uid and gid of a file. So, comparing an FTP'ed archive just after
492 unpack would fail on MSDOS. */
493 if (stat_data.st_uid != current_stat.st_uid)
494 report_difference (_("Uid differs"));
495 if (stat_data.st_gid != current_stat.st_gid)
496 report_difference (_("Gid differs"));
497 #endif
498
499 if (stat_data.st_mtime != current_stat.st_mtime)
500 report_difference (_("Mod time differs"));
501 if (current_header->header.typeflag != GNUTYPE_SPARSE &&
502 stat_data.st_size != current_stat.st_size)
503 {
504 report_difference (_("Size differs"));
505 skip_file ((long) current_stat.st_size);
506 goto quit;
507 }
508
509 diff_handle = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
510
511 if (diff_handle < 0 && !absolute_names_option)
512 {
513 char *tmpbuf = xmalloc (strlen (current_file_name) + 2);
514
515 *tmpbuf = '/';
516 strcpy (tmpbuf + 1, current_file_name);
517 diff_handle = open (tmpbuf, O_NDELAY | O_RDONLY);
518 free (tmpbuf);
519 }
520 if (diff_handle < 0)
521 {
522 ERROR ((0, errno, _("Cannot open %s"), current_file_name));
523 if (current_header->oldgnu_header.isextended)
524 skip_extended_headers ();
525 skip_file ((long) current_stat.st_size);
526 report_difference (NULL);
527 goto quit;
528 }
529
530 /* Need to treat sparse files completely differently here. */
531
532 if (current_header->header.typeflag == GNUTYPE_SPARSE)
533 diff_sparse_files (current_stat.st_size);
534 else
535 {
536 if (multi_volume_option)
537 {
538 assign_string (&save_name, current_file_name);
539 save_totsize = current_stat.st_size;
540 /* save_sizeleft is set in read_and_process. */
541 }
542
543 read_and_process ((long) (current_stat.st_size), process_rawdata);
544
545 if (multi_volume_option)
546 assign_string (&save_name, NULL);
547 }
548
549 status = close (diff_handle);
550 if (status < 0)
551 ERROR ((0, errno, _("Error while closing %s"), current_file_name));
552
553 quit:
554 break;
555
556 #if !MSDOS
557 case LNKTYPE:
558 {
559 dev_t dev;
560 ino_t ino;
561
562 if (!get_stat_data (&stat_data))
563 break;
564
565 dev = stat_data.st_dev;
566 ino = stat_data.st_ino;
567 status = stat (current_link_name, &stat_data);
568 if (status < 0)
569 {
570 if (errno == ENOENT)
571 report_difference (_("Does not exist"));
572 else
573 {
574 WARN ((0, errno, _("Cannot stat file %s"), current_file_name));
575 report_difference (NULL);
576 }
577 break;
578 }
579
580 if (stat_data.st_dev != dev || stat_data.st_ino != ino)
581 {
582 char *message = (char *)
583 xmalloc (MESSAGE_BUFFER_SIZE + strlen (current_link_name));
584
585 sprintf (message, _("Not linked to %s"), current_link_name);
586 report_difference (message);
587 free (message);
588 break;
589 }
590
591 break;
592 }
593 #endif /* not MSDOS */
594
595 #ifdef S_ISLNK
596 case SYMTYPE:
597 {
598 char linkbuf[NAME_FIELD_SIZE + 3]; /* FIXME: may be too short. */
599
600 status = readlink (current_file_name, linkbuf, (sizeof linkbuf) - 1);
601
602 if (status < 0)
603 {
604 if (errno == ENOENT)
605 report_difference (_("No such file or directory"));
606 else
607 {
608 WARN ((0, errno, _("Cannot read link %s"), current_file_name));
609 report_difference (NULL);
610 }
611 break;
612 }
613
614 linkbuf[status] = '\0'; /* null-terminate it */
615 if (strncmp (current_link_name, linkbuf, (size_t) status) != 0)
616 report_difference (_("Symlink differs"));
617
618 break;
619 }
620 #endif /* not S_ISLNK */
621
622 #ifdef S_IFCHR
623 case CHRTYPE:
624 current_stat.st_mode |= S_IFCHR;
625 goto check_node;
626 #endif /* not S_IFCHR */
627
628 #ifdef S_IFBLK
629 /* If local system doesn't support block devices, use default case. */
630
631 case BLKTYPE:
632 current_stat.st_mode |= S_IFBLK;
633 goto check_node;
634 #endif /* not S_IFBLK */
635
636 #ifdef S_ISFIFO
637 /* If local system doesn't support FIFOs, use default case. */
638
639 case FIFOTYPE:
640 # ifdef S_IFIFO
641 current_stat.st_mode |= S_IFIFO;
642 # endif
643 current_stat.st_rdev = 0; /* FIXME: do we need this? */
644 goto check_node;
645 #endif /* S_ISFIFO */
646
647 check_node:
648 /* FIXME: deal with umask. */
649
650 if (!get_stat_data (&stat_data))
651 break;
652
653 if (current_stat.st_rdev != stat_data.st_rdev)
654 {
655 report_difference (_("Device numbers changed"));
656 break;
657 }
658
659 if (
660 #ifdef S_IFMT
661 current_stat.st_mode != stat_data.st_mode
662 #else
663 /* POSIX lossage. */
664 (current_stat.st_mode & 07777) != (stat_data.st_mode & 07777)
665 #endif
666 )
667 {
668 report_difference (_("Mode or device-type changed"));
669 break;
670 }
671
672 break;
673
674 case GNUTYPE_DUMPDIR:
675 {
676 char *dumpdir_buffer = get_directory_contents (current_file_name, 0);
677
678 if (multi_volume_option)
679 {
680 assign_string (&save_name, current_file_name);
681 save_totsize = current_stat.st_size;
682 /* save_sizeleft is set in read_and_process. */
683 }
684
685 if (dumpdir_buffer)
686 {
687 dumpdir_cursor = dumpdir_buffer;
688 read_and_process ((long) (current_stat.st_size), process_dumpdir);
689 free (dumpdir_buffer);
690 }
691 else
692 read_and_process ((long) (current_stat.st_size), process_noop);
693
694 if (multi_volume_option)
695 assign_string (&save_name, NULL);
696 /* Fall through. */
697 }
698
699 case DIRTYPE:
700 /* Check for trailing /. */
701
702 name_length = strlen (current_file_name) - 1;
703
704 really_dir:
705 while (name_length && current_file_name[name_length] == '/')
706 current_file_name[name_length--] = '\0'; /* zap / */
707
708 if (!get_stat_data (&stat_data))
709 break;
710
711 if (!S_ISDIR (stat_data.st_mode))
712 {
713 report_difference (_("No longer a directory"));
714 break;
715 }
716
717 if ((stat_data.st_mode & 07777) != (current_stat.st_mode & 07777))
718 report_difference (_("Mode differs"));
719 break;
720
721 case GNUTYPE_VOLHDR:
722 break;
723
724 case GNUTYPE_MULTIVOL:
725 {
726 off_t offset;
727
728 name_length = strlen (current_file_name) - 1;
729 if (current_file_name[name_length] == '/')
730 goto really_dir;
731
732 if (!get_stat_data (&stat_data))
733 break;
734
735 if (!S_ISREG (stat_data.st_mode))
736 {
737 report_difference (_("Not a regular file"));
738 skip_file ((long) current_stat.st_size);
739 break;
740 }
741
742 stat_data.st_mode &= 07777;
743 offset = from_oct (1 + 12, current_header->oldgnu_header.offset);
744 if (stat_data.st_size != current_stat.st_size + offset)
745 {
746 report_difference (_("Size differs"));
747 skip_file ((long) current_stat.st_size);
748 break;
749 }
750
751 diff_handle = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
752
753 if (diff_handle < 0)
754 {
755 WARN ((0, errno, _("Cannot open file %s"), current_file_name));
756 report_difference (NULL);
757 skip_file ((long) current_stat.st_size);
758 break;
759 }
760
761 status = lseek (diff_handle, offset, 0);
762 if (status != offset)
763 {
764 WARN ((0, errno, _("Cannot seek to %ld in file %s"),
765 offset, current_file_name));
766 report_difference (NULL);
767 break;
768 }
769
770 if (multi_volume_option)
771 {
772 assign_string (&save_name, current_file_name);
773 save_totsize = stat_data.st_size;
774 /* save_sizeleft is set in read_and_process. */
775 }
776
777 read_and_process ((long) (current_stat.st_size), process_rawdata);
778
779 if (multi_volume_option)
780 assign_string (&save_name, NULL);
781
782 status = close (diff_handle);
783 if (status < 0)
784 ERROR ((0, errno, _("Error while closing %s"), current_file_name));
785
786 break;
787 }
788 }
789 }
790
791 /*---.
792 | ? |
793 `---*/
794
795 void
796 verify_volume (void)
797 {
798 if (!diff_buffer)
799 diff_init ();
800
801 /* Verifying an archive is meant to check if the physical media got it
802 correctly, so try to defeat clever in-memory buffering pertaining to
803 this particular media. On Linux, for example, the floppy drive would
804 not even be accessed for the whole verification.
805
806 The code was using fsync only when the ioctl is unavailable, but
807 Marty Leisner says that the ioctl does not work when not preceded by
808 fsync. So, until we know better, or maybe to please Marty, let's do it
809 the unbelievable way :-). */
810
811 #if HAVE_FSYNC
812 fsync (archive);
813 #endif
814 #ifdef FDFLUSH
815 ioctl (archive, FDFLUSH);
816 #endif
817
818 #ifdef MTIOCTOP
819 {
820 struct mtop operation;
821 int status;
822
823 operation.mt_op = MTBSF;
824 operation.mt_count = 1;
825 if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation), status < 0)
826 {
827 if (errno != EIO
828 || (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
829 status < 0))
830 {
831 #endif
832 if (rmtlseek (archive, 0L, 0) != 0)
833 {
834 /* Lseek failed. Try a different method. */
835
836 WARN ((0, errno,
837 _("Could not rewind archive file for verify")));
838 return;
839 }
840 #ifdef MTIOCTOP
841 }
842 }
843 }
844 #endif
845
846 access_mode = ACCESS_READ;
847 now_verifying = 1;
848
849 flush_read ();
850 while (1)
851 {
852 enum read_header status = read_header ();
853
854 if (status == HEADER_FAILURE)
855 {
856 int counter = 0;
857
858 while (status == HEADER_FAILURE);
859 {
860 counter++;
861 status = read_header ();
862 }
863 ERROR ((0, 0,
864 _("VERIFY FAILURE: %d invalid header(s) detected"), counter));
865 }
866 if (status == HEADER_ZERO_BLOCK || status == HEADER_END_OF_FILE)
867 break;
868
869 diff_archive ();
870 }
871
872 access_mode = ACCESS_WRITE;
873 now_verifying = 0;
874 }
This page took 0.074739 seconds and 5 git commands to generate.