1 /* Diff files from a tar archive.
3 Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003, 2004, 2005, 2006 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 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 #include <system-ioctl.h>
26 # include <linux/fd.h>
34 /* Nonzero if we are verifying at the moment. */
37 /* File descriptor for the file we are diffing. */
38 static int diff_handle
;
40 /* Area for reading file contents into. */
41 static char *diff_buffer
;
43 /* Initialize for a diff operation. */
48 diff_buffer
= page_aligned_alloc (&ptr
, record_size
);
49 if (listed_incremental_option
)
50 read_directory_file ();
53 /* Sigh about something that differs by writing a MESSAGE to stdlis,
54 given MESSAGE is nonzero. Also set the exit status if not already. */
56 report_difference (struct tar_stat_info
*st
__attribute__ ((unused
)),
63 fprintf (stdlis
, "%s: ", quotearg_colon (current_stat_info
.file_name
));
65 vfprintf (stdlis
, fmt
, ap
);
67 fprintf (stdlis
, "\n");
70 if (exit_status
== TAREXIT_SUCCESS
)
71 exit_status
= TAREXIT_DIFFERS
;
74 /* Take a buffer returned by read_and_process and do nothing with it. */
76 process_noop (size_t size
__attribute__ ((unused
)),
77 char *data
__attribute__ ((unused
)))
83 process_rawdata (size_t bytes
, char *buffer
)
85 size_t status
= safe_read (diff_handle
, diff_buffer
, bytes
);
89 if (status
== SAFE_READ_ERROR
)
91 read_error (current_stat_info
.file_name
);
92 report_difference (¤t_stat_info
, NULL
);
96 report_difference (¤t_stat_info
,
97 ngettext ("Could only read %lu of %lu byte",
98 "Could only read %lu of %lu bytes",
100 (unsigned long) status
, (unsigned long) bytes
);
105 if (memcmp (buffer
, diff_buffer
, bytes
))
107 report_difference (¤t_stat_info
, _("Contents differ"));
114 /* Directory contents, only for GNUTYPE_DUMPDIR. */
116 static char *dumpdir_cursor
;
119 process_dumpdir (size_t bytes
, char *buffer
)
121 if (memcmp (buffer
, dumpdir_cursor
, bytes
))
123 report_difference (¤t_stat_info
, _("Contents differ"));
127 dumpdir_cursor
+= bytes
;
131 /* Some other routine wants SIZE bytes in the archive. For each chunk
132 of the archive, call PROCESSOR with the size of the chunk, and the
133 address of the chunk it can work with. The PROCESSOR should return
134 nonzero for success. It it return error once, continue skipping
135 without calling PROCESSOR anymore. */
138 read_and_process (struct tar_stat_info
*st
, int (*processor
) (size_t, char *))
140 union block
*data_block
;
142 size_t size
= st
->stat
.st_size
;
147 data_block
= find_next_block ();
150 ERROR ((0, 0, _("Unexpected EOF in archive")));
154 data_size
= available_space_after (data_block
);
155 if (data_size
> size
)
157 if (!(*processor
) (data_size
, data_block
->buffer
))
158 processor
= process_noop
;
159 set_next_block_after ((union block
*)
160 (data_block
->buffer
+ data_size
- 1));
167 /* Call either stat or lstat over STAT_DATA, depending on
168 --dereference (-h), for a file which should exist. Diagnose any
169 problem. Return nonzero for success, zero otherwise. */
171 get_stat_data (char const *file_name
, struct stat
*stat_data
)
173 int status
= deref_stat (dereference_option
, file_name
, stat_data
);
178 stat_warn (file_name
);
180 stat_error (file_name
);
181 report_difference (¤t_stat_info
, NULL
);
192 struct stat stat_data
;
194 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
197 if (!S_ISDIR (stat_data
.st_mode
))
198 report_difference (¤t_stat_info
, _("File type differs"));
199 else if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
200 (stat_data
.st_mode
& MODE_ALL
))
201 report_difference (¤t_stat_info
, _("Mode differs"));
207 char const *file_name
= current_stat_info
.file_name
;
208 struct stat stat_data
;
210 if (!get_stat_data (file_name
, &stat_data
))
212 else if (!S_ISREG (stat_data
.st_mode
))
214 report_difference (¤t_stat_info
, _("File type differs"));
219 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
220 (stat_data
.st_mode
& MODE_ALL
))
221 report_difference (¤t_stat_info
, _("Mode differs"));
223 if (!sys_compare_uid (&stat_data
, ¤t_stat_info
.stat
))
224 report_difference (¤t_stat_info
, _("Uid differs"));
225 if (!sys_compare_gid (&stat_data
, ¤t_stat_info
.stat
))
226 report_difference (¤t_stat_info
, _("Gid differs"));
228 if (tar_timespec_cmp (get_stat_mtime (&stat_data
),
229 current_stat_info
.mtime
))
230 report_difference (¤t_stat_info
, _("Mod time differs"));
231 if (current_header
->header
.typeflag
!= GNUTYPE_SPARSE
232 && stat_data
.st_size
!= current_stat_info
.stat
.st_size
)
234 report_difference (¤t_stat_info
, _("Size differs"));
240 (atime_preserve_option
== system_atime_preserve
244 diff_handle
= open (file_name
, O_RDONLY
| O_BINARY
| atime_flag
);
248 open_error (file_name
);
250 report_difference (¤t_stat_info
, NULL
);
256 if (current_stat_info
.is_sparse
)
257 sparse_diff_file (diff_handle
, ¤t_stat_info
);
259 read_and_process (¤t_stat_info
, process_rawdata
);
261 if (atime_preserve_option
== replace_atime_preserve
)
263 struct timespec ts
[2];
264 ts
[0] = get_stat_atime (&stat_data
);
265 ts
[1] = get_stat_mtime (&stat_data
);
266 if (set_file_atime (diff_handle
, file_name
, ts
) != 0)
267 utime_error (file_name
);
270 status
= close (diff_handle
);
272 close_error (file_name
);
281 struct stat file_data
;
282 struct stat link_data
;
284 if (get_stat_data (current_stat_info
.file_name
, &file_data
)
285 && get_stat_data (current_stat_info
.link_name
, &link_data
)
286 && !sys_compare_links (&file_data
, &link_data
))
287 report_difference (¤t_stat_info
,
288 _("Not linked to %s"),
289 quote (current_stat_info
.link_name
));
296 size_t len
= strlen (current_stat_info
.link_name
);
297 char *linkbuf
= alloca (len
+ 1);
299 int status
= readlink (current_stat_info
.file_name
, linkbuf
, len
+ 1);
304 readlink_warn (current_stat_info
.file_name
);
306 readlink_error (current_stat_info
.file_name
);
307 report_difference (¤t_stat_info
, NULL
);
309 else if (status
!= len
310 || strncmp (current_stat_info
.link_name
, linkbuf
, len
) != 0)
311 report_difference (¤t_stat_info
, _("Symlink differs"));
318 struct stat stat_data
;
320 /* FIXME: deal with umask. */
322 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
325 if (current_header
->header
.typeflag
== CHRTYPE
326 ? !S_ISCHR (stat_data
.st_mode
)
327 : current_header
->header
.typeflag
== BLKTYPE
328 ? !S_ISBLK (stat_data
.st_mode
)
329 : /* current_header->header.typeflag == FIFOTYPE */
330 !S_ISFIFO (stat_data
.st_mode
))
332 report_difference (¤t_stat_info
, _("File type differs"));
336 if ((current_header
->header
.typeflag
== CHRTYPE
337 || current_header
->header
.typeflag
== BLKTYPE
)
338 && current_stat_info
.stat
.st_rdev
!= stat_data
.st_rdev
)
340 report_difference (¤t_stat_info
, _("Device number differs"));
344 if ((current_stat_info
.stat
.st_mode
& MODE_ALL
) !=
345 (stat_data
.st_mode
& MODE_ALL
))
346 report_difference (¤t_stat_info
, _("Mode differs"));
352 char *dumpdir_buffer
;
356 if (deref_stat (true, current_stat_info
.file_name
, &stat
))
359 stat_warn (current_stat_info
.file_name
);
361 stat_error (current_stat_info
.file_name
);
366 dumpdir_buffer
= get_directory_contents (current_stat_info
.file_name
, dev
);
370 dumpdir_cursor
= dumpdir_buffer
;
371 read_and_process (¤t_stat_info
, process_dumpdir
);
372 free (dumpdir_buffer
);
375 read_and_process (¤t_stat_info
, process_noop
);
381 struct stat stat_data
;
385 if (current_stat_info
.had_trailing_slash
)
391 if (!get_stat_data (current_stat_info
.file_name
, &stat_data
))
394 if (!S_ISREG (stat_data
.st_mode
))
396 report_difference (¤t_stat_info
, _("File type differs"));
401 offset
= OFF_FROM_HEADER (current_header
->oldgnu_header
.offset
);
402 if (stat_data
.st_size
!= current_stat_info
.stat
.st_size
+ offset
)
404 report_difference (¤t_stat_info
, _("Size differs"));
409 fd
= open (current_stat_info
.file_name
, O_RDONLY
| O_BINARY
);
413 open_error (current_stat_info
.file_name
);
414 report_difference (¤t_stat_info
, NULL
);
419 if (lseek (fd
, offset
, SEEK_SET
) < 0)
421 seek_error_details (current_stat_info
.file_name
, offset
);
422 report_difference (¤t_stat_info
, NULL
);
426 read_and_process (¤t_stat_info
, process_rawdata
);
430 close_error (current_stat_info
.file_name
);
433 /* Diff a file against the archive. */
438 set_next_block_after (current_header
);
439 decode_header (current_header
, ¤t_stat_info
, ¤t_format
, 1);
441 /* Print the block from current_header and current_stat_info. */
446 fprintf (stdlis
, _("Verify "));
447 print_header (¤t_stat_info
, -1);
450 switch (current_header
->header
.typeflag
)
453 ERROR ((0, 0, _("%s: Unknown file type `%c', diffed as normal file"),
454 quotearg_colon (current_stat_info
.file_name
),
455 current_header
->header
.typeflag
));
463 /* Appears to be a file. See if it's really a directory. */
465 if (current_stat_info
.had_trailing_slash
)
487 case GNUTYPE_DUMPDIR
:
498 case GNUTYPE_MULTIVOL
:
506 if (removed_prefixes_p ())
509 _("Archive contains file names with leading prefixes removed.")));
511 _("Verification may fail to locate original files.")));
517 /* Verifying an archive is meant to check if the physical media got it
518 correctly, so try to defeat clever in-memory buffering pertaining to
519 this particular media. On Linux, for example, the floppy drive would
520 not even be accessed for the whole verification.
522 The code was using fsync only when the ioctl is unavailable, but
523 Marty Leisner says that the ioctl does not work when not preceded by
524 fsync. So, until we know better, or maybe to please Marty, let's do it
525 the unbelievable way :-). */
531 ioctl (archive
, FDFLUSH
);
536 struct mtop operation
;
539 operation
.mt_op
= MTBSF
;
540 operation
.mt_count
= 1;
541 if (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
), status
< 0)
544 || (status
= rmtioctl (archive
, MTIOCTOP
, (char *) &operation
),
548 if (rmtlseek (archive
, (off_t
) 0, SEEK_SET
) != 0)
550 /* Lseek failed. Try a different method. */
551 seek_warn (archive_name_array
[0]);
560 access_mode
= ACCESS_READ
;
566 enum read_header status
= read_header (false);
568 if (status
== HEADER_FAILURE
)
575 set_next_block_after (current_header
);
576 status
= read_header (false);
578 while (status
== HEADER_FAILURE
);
581 ngettext ("VERIFY FAILURE: %d invalid header detected",
582 "VERIFY FAILURE: %d invalid headers detected",
585 if (status
== HEADER_ZERO_BLOCK
|| status
== HEADER_END_OF_FILE
)
589 tar_stat_destroy (¤t_stat_info
);
590 xheader_destroy (&extended_header
);
593 access_mode
= ACCESS_WRITE
;