+
+ record_end = record_start + (record_size - left) / BLOCKSIZE;
+ records_read++;
+}
+
+/* Flush the current buffer to/from the archive. */
+void
+flush_archive (void)
+{
+ size_t buffer_level = current_block->buffer - record_start->buffer;
+ record_start_block += record_end - record_start;
+ current_block = record_start;
+ record_end = record_start + blocking_factor;
+
+ if (access_mode == ACCESS_READ && time_to_start_writing)
+ {
+ access_mode = ACCESS_WRITE;
+ time_to_start_writing = false;
+ backspace_output ();
+ }
+
+ switch (access_mode)
+ {
+ case ACCESS_READ:
+ flush_read ();
+ break;
+
+ case ACCESS_WRITE:
+ flush_write_ptr (buffer_level);
+ break;
+
+ case ACCESS_UPDATE:
+ abort ();
+ }
+}
+
+/* Backspace the archive descriptor by one record worth. If it's a
+ tape, MTIOCTOP will work. If it's something else, try to seek on
+ it. If we can't seek, we lose! */
+static void
+backspace_output (void)
+{
+#ifdef MTIOCTOP
+ {
+ struct mtop operation;
+
+ operation.mt_op = MTBSR;
+ operation.mt_count = 1;
+ if (rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
+ return;
+ if (errno == EIO && rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
+ return;
+ }
+#endif
+
+ {
+ off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR);
+
+ /* Seek back to the beginning of this record and start writing there. */
+
+ position -= record_size;
+ if (position < 0)
+ position = 0;
+ if (rmtlseek (archive, position, SEEK_SET) != position)
+ {
+ /* Lseek failed. Try a different method. */
+
+ WARN ((0, 0,
+ _("Cannot backspace archive file; it may be unreadable without -i")));
+
+ /* Replace the first part of the record with NULs. */
+
+ if (record_start->buffer != output_start)
+ memset (record_start->buffer, 0,
+ output_start - record_start->buffer);
+ }
+ }
+}
+
+off_t
+seek_archive (off_t size)
+{
+ off_t start = current_block_ordinal ();
+ off_t offset;
+ off_t nrec, nblk;
+ off_t skipped = (blocking_factor - (current_block - record_start))
+ * BLOCKSIZE;
+
+ if (size <= skipped)
+ return 0;
+
+ /* Compute number of records to skip */
+ nrec = (size - skipped) / record_size;
+ if (nrec == 0)
+ return 0;
+ offset = rmtlseek (archive, nrec * record_size, SEEK_CUR);
+ if (offset < 0)
+ return offset;
+
+ if (offset % record_size)
+ FATAL_ERROR ((0, 0, _("rmtlseek not stopped at a record boundary")));
+
+ /* Convert to number of records */
+ offset /= BLOCKSIZE;
+ /* Compute number of skipped blocks */
+ nblk = offset - start;
+
+ /* Update buffering info */
+ records_read += nblk / blocking_factor;
+ record_start_block = offset - blocking_factor;
+ current_block = record_end;
+
+ return nblk;
+}
+
+/* Close the archive file. */
+void
+close_archive (void)
+{
+ if (time_to_start_writing || access_mode == ACCESS_WRITE)