+/*---.
+| ? |
+`---*/
+
+static void
+extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name)
+{
+ int sparse_ind = 0;
+ size_t written;
+ ssize_t count;
+
+ /* assuming sizeleft is initially totalsize */
+
+ while (*sizeleft > 0)
+ {
+ union block *data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF on archive file")));
+ return;
+ }
+ if (lseek (fd, sparsearray[sparse_ind].offset, SEEK_SET) < 0)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ ERROR ((0, errno, _("%s: lseek error at byte %s"),
+ STRINGIFY_BIGINT (sparsearray[sparse_ind].offset, buf),
+ name));
+ return;
+ }
+ written = sparsearray[sparse_ind++].numbytes;
+ while (written > BLOCKSIZE)
+ {
+ count = full_write (fd, data_block->buffer, BLOCKSIZE);
+ if (count < 0)
+ ERROR ((0, errno, _("%s: Could not write to file"), name));
+ written -= count;
+ *sizeleft -= count;
+ set_next_block_after (data_block);
+ data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF on archive file")));
+ return;
+ }
+ }
+
+ count = full_write (fd, data_block->buffer, written);
+
+ if (count < 0)
+ ERROR ((0, errno, _("%s: Could not write to file"), name));
+ else if (count != written)
+ {
+ char buf1[UINTMAX_STRSIZE_BOUND];
+ char buf2[UINTMAX_STRSIZE_BOUND];
+ ERROR ((0, 0, _("%s: Could only write %s of %s bytes"),
+ name,
+ STRINGIFY_BIGINT (totalsize - *sizeleft, buf1),
+ STRINGIFY_BIGINT (totalsize, buf2)));
+ skip_file (*sizeleft);
+ }
+
+ written -= count;
+ *sizeleft -= count;
+ set_next_block_after (data_block);
+ }
+
+ free (sparsearray);
+}
+
+/*----------------------------------.
+| Extract a file from the archive. |
+`----------------------------------*/