- } else if (difference < 0) {
- /* Seeking backwards */
- if (!tape_device_bsf(self, -difference, d_self->file)) {
- tape_rewind(self->fd);
- device_set_error(d_self,
- vstrallocf(_("Could not seek backward to file %d"), file),
- DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
- return NULL;
- }
+ } else { /* (difference <= 0) */
+ /* Seeking backwards, or to this file itself */
+
+ /* if the drive supports bsf, we can do this the fancy way */
+ if (self->bsf) {
+ /* bsf one more than the difference */
+ if (!tape_bsf(self->fd, -difference + 1)) {
+ tape_rewind(self->fd);
+ device_set_error(d_self,
+ vstrallocf(_("Could not seek backward to file %d"), file),
+ DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
+ return NULL;
+ }
+
+ /* now we are on the BOT side of the desired filemark, so FSF to get to the
+ * EOT side of it */
+ if (!tape_device_fsf(self, 1)) {
+ tape_rewind(self->fd);
+ device_set_error(d_self,
+ vstrallocf(_("Could not seek forward to file %d"), file),
+ DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
+ return NULL;
+ }
+ } else {
+ /* no BSF, so just rewind and seek forward */
+ if (!tape_rewind(self->fd)) {
+ device_set_error(d_self,
+ vstrallocf(_("Could not rewind device while emulating BSF")),
+ DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
+ return FALSE;
+ }
+
+ if (!tape_device_fsf(self, file)) {
+ tape_rewind(self->fd);
+ device_set_error(d_self,
+ vstrallocf(_("Could not seek forward to file %d"), file),
+ DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
+ return NULL;
+ }
+ }
+ }
+
+ /* double-check that we're on the right fileno, if possible. This is most
+ * likely a programming error if it occurs, but could also be due to a weird
+ * tape drive or driver (and that would *never* happen, right?) */
+ got_file = tape_fileno(self->fd);
+ if (got_file >= 0 && (guint)got_file != file) {
+ device_set_error(d_self,
+ vstrallocf(_("Could not seek to file %d correctly; got %d"),
+ file, got_file),
+ DEVICE_STATUS_DEVICE_ERROR);
+ d_self->file = (guint)got_file;
+ return NULL;