-/*---.
-| ? |
-`---*/
-
-/* JK This routine should be used more often than it is ... look into
- that. Anyhow, what it does is translate the sparse information on the
- header, and in any subsequent extended headers, into an array of
- structures with true numbers, as opposed to character strings. It
- simply makes our life much easier, doing so many comparisong and such.
- */
-
-static void
-fill_in_sparse_array (void)
-{
- int counter;
-
- /* Allocate space for our scratch space; it's initially 10 elements
- long, but can change in this routine if necessary. */
-
- sp_array_size = 10;
- sparsearray = (struct sp_array *) xmalloc (sp_array_size * sizeof (struct sp_array));
-
- /* There are at most five of these structures in the header itself;
- read these in first. */
-
- for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
- {
- /* Compare to 0, or use !(int)..., for Pyramid's dumb compiler. */
- if (current_header->oldgnu_header.sp[counter].numbytes == 0)
- break;
-
- sparsearray[counter].offset =
- from_oct (1 + 12, current_header->oldgnu_header.sp[counter].offset);
- sparsearray[counter].numbytes =
- from_oct (1 + 12, current_header->oldgnu_header.sp[counter].numbytes);
- }
-
- /* If the header's extended, we gotta read in exhdr's till we're done. */
-
- if (current_header->oldgnu_header.isextended)
- {
- /* How far into the sparsearray we are `so far'. */
- static int so_far_ind = SPARSES_IN_OLDGNU_HEADER;
- union block *exhdr;
-
- while (1)
- {
- exhdr = find_next_block ();
- for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
- {
- if (counter + so_far_ind > sp_array_size - 1)
- {
- /* We just ran out of room in our scratch area -
- realloc it. */
-
- sp_array_size *= 2;
- sparsearray = (struct sp_array *)
- xrealloc (sparsearray,
- sp_array_size * sizeof (struct sp_array));
- }
-
- /* Convert the character strings into longs. */
-
- sparsearray[counter + so_far_ind].offset =
- from_oct (1 + 12, exhdr->sparse_header.sp[counter].offset);
- sparsearray[counter + so_far_ind].numbytes =
- from_oct (1 + 12, exhdr->sparse_header.sp[counter].numbytes);
- }
-
- /* If this is the last extended header for this file, we can
- stop. */
-
- if (!exhdr->sparse_header.isextended)
- break;
-
- so_far_ind += SPARSES_IN_SPARSE_HEADER;
- set_next_block_after (exhdr);
- }
-
- /* Be sure to skip past the last one. */
-
- set_next_block_after (exhdr);
- }
-}
-
-/*---.
-| ? |
-`---*/
-
-/* JK Diff'ing a sparse file with its counterpart on the tar file is a
- bit of a different story than a normal file. First, we must know what
- areas of the file to skip through, i.e., we need to contruct a
- sparsearray, which will hold all the information we need. We must
- compare small amounts of data at a time as we find it. */
-
-/* FIXME: This does not look very solid to me, at first glance. Zero areas
- are not checked, spurious sparse entries seemingly goes undetected, and
- I'm not sure overall identical sparsity is verified. */
-
-static void
-diff_sparse_files (int size_of_file)
-{
- int remaining_size = size_of_file;
- char *buffer = (char *) xmalloc (BLOCKSIZE * sizeof (char));
- int buffer_size = BLOCKSIZE;
- union block *data_block = NULL;
- int counter = 0;
- int different = 0;
-
- fill_in_sparse_array ();
-
- while (remaining_size > 0)
- {
- int status;
- long chunk_size;
-#if 0
- int amount_read = 0;
-#endif
-
- data_block = find_next_block ();
- chunk_size = sparsearray[counter].numbytes;
- if (!chunk_size)
- break;
-
- lseek (diff_handle, sparsearray[counter].offset, 0);
-
- /* Take care to not run out of room in our buffer. */
-
- while (buffer_size < chunk_size)
- {
- buffer_size *= 2;
- buffer = (char *) xrealloc (buffer, buffer_size * sizeof (char));
- }
-
- while (chunk_size > BLOCKSIZE)
- {
- if (status = read (diff_handle, buffer, BLOCKSIZE),
- status != BLOCKSIZE)
- {
- if (status < 0)
- {
- WARN ((0, errno, _("Cannot read %s"), current_file_name));
- report_difference (NULL);
- }
- else
- {
- char message[MESSAGE_BUFFER_SIZE];
-
- sprintf (message, _("Could only read %d of %ld bytes"),
- status, chunk_size);
- report_difference (message);
- }
- break;
- }
-
- if (memcmp (buffer, data_block->buffer, BLOCKSIZE))
- {
- different = 1;
- break;
- }
-
- chunk_size -= status;
- remaining_size -= status;
- set_next_block_after (data_block);
- data_block = find_next_block ();
- }
- if (status = read (diff_handle, buffer, (size_t) chunk_size),
- status != chunk_size)
- {
- if (status < 0)
- {
- WARN ((0, errno, _("Cannot read %s"), current_file_name));
- report_difference (NULL);
- }
- else
- {
- char message[MESSAGE_BUFFER_SIZE];
-
- sprintf (message, _("Could only read %d of %ld bytes"),
- status, chunk_size);
- report_difference (message);
- }
- break;
- }
-
- if (memcmp (buffer, data_block->buffer, (size_t) chunk_size))
- {
- different = 1;
- break;
- }
-#if 0
- amount_read += chunk_size;
- if (amount_read >= BLOCKSIZE)
- {
- amount_read = 0;
- set_next_block_after (data_block);
- data_block = find_next_block ();
- }
-#endif
- set_next_block_after (data_block);
- counter++;
- remaining_size -= chunk_size;
- }
-
-#if 0
- /* If the number of bytes read isn't the number of bytes supposedly in
- the file, they're different. */
-
- if (amount_read != size_of_file)
- different = 1;
-#endif
-
- set_next_block_after (data_block);
- free (sparsearray);
-
- if (different)
- report_difference (_("Data differs"));
-}
-
-/*---------------------------------------------------------------------.
-| Call either stat or lstat over STAT_DATA, depending on --dereference |
-| (-h), for a file which should exist. Diagnose any problem. Return |
-| nonzero for success, zero otherwise. |
-`---------------------------------------------------------------------*/
-