diff --git a/src/bin/pmt.rs b/src/bin/pmt.rs index 15fa591d..a1a6a612 100644 --- a/src/bin/pmt.rs +++ b/src/bin/pmt.rs @@ -36,6 +36,12 @@ pub const FILE_MARK_COUNT_SCHEMA: Schema = .maximum(i32::MAX as isize) .schema(); +pub const FILE_MARK_POSITION_SCHEMA: Schema = + IntegerSchema::new("File mark position (0 is BOT).") + .minimum(0) + .maximum(i32::MAX as isize) + .schema(); + pub const RECORD_COUNT_SCHEMA: Schema = IntegerSchema::new("Record count.") .minimum(1) @@ -128,22 +134,18 @@ fn get_tape_handle(param: &Value) -> Result { optional: true, }, count: { - schema: FILE_MARK_COUNT_SCHEMA, + schema: FILE_MARK_POSITION_SCHEMA, }, }, }, )] -/// Position the tape at the beginning of the count file. -/// -/// Positioning is done by first rewinding the tape and then spacing -/// forward over count file marks. -fn asf(count: usize, param: Value) -> Result<(), Error> { +/// Position the tape at the beginning of the count file (after +/// filemark count) +fn asf(count: u64, param: Value) -> Result<(), Error> { let mut handle = get_tape_handle(¶m)?; - handle.rewind()?; - - handle.forward_space_count_files(count)?; + handle.locate_file(count)?; Ok(()) } diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs index de997cde..ef5d8865 100644 --- a/src/tape/drive/lto/mod.rs +++ b/src/tape/drive/lto/mod.rs @@ -17,7 +17,7 @@ pub use sg_tape::*; use std::fs::{OpenOptions, File}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::convert::TryFrom; +use std::convert::TryInto; use anyhow::{bail, format_err, Error}; use nix::fcntl::{fcntl, FcntlArg, OFlag}; @@ -38,7 +38,6 @@ use crate::{ MamAttribute, LtoDriveAndMediaStatus, LtoTapeDrive, - TapeDensity, }, tape::{ TapeRead, @@ -133,7 +132,7 @@ impl LtoTapeHandle { blocksize: drive_status.block_length, compression: drive_status.compression, buffer_mode: drive_status.buffer_mode, - density: TapeDensity::try_from(drive_status.density_code)?, + density: drive_status.density_code.try_into()?, alert_flags, write_protect: None, file_number: None, @@ -188,19 +187,47 @@ impl LtoTapeHandle { } pub fn forward_space_count_files(&mut self, count: usize) -> Result<(), Error> { - self.sg_tape.space_filemarks(isize::try_from(count)?) + self.sg_tape.space_filemarks(count.try_into()?) } pub fn backward_space_count_files(&mut self, count: usize) -> Result<(), Error> { - self.sg_tape.space_filemarks(-isize::try_from(count)?) + self.sg_tape.space_filemarks(-count.try_into()?) } pub fn forward_space_count_records(&mut self, count: usize) -> Result<(), Error> { - self.sg_tape.space_blocks(isize::try_from(count)?) + self.sg_tape.space_blocks(count.try_into()?) } pub fn backward_space_count_records(&mut self, count: usize) -> Result<(), Error> { - self.sg_tape.space_blocks(-isize::try_from(count)?) + self.sg_tape.space_blocks(-count.try_into()?) + } + + /// Position the tape after filemark count. Count 0 means BOT. + /// + /// Note: we dont use LOCATE(10), because that needs LTO5 + pub fn locate_file(&mut self, position: u64) -> Result<(), Error> { + + if position == 0 { + return self.rewind(); + } + + let current_position = self.current_file_number()?; + + if current_position == position { + // make sure we are immediated afer the filemark + self.sg_tape.space_filemarks(-1)?; + self.sg_tape.space_filemarks(1)?; + } else if current_position < position { + let diff = position - current_position; + self.sg_tape.space_filemarks(diff.try_into()?)?; + } else { + let diff = current_position - position + 1; + self.sg_tape.space_filemarks(-diff.try_into()?)?; + // move to EOT side of filemark + self.sg_tape.space_filemarks(1)?; + } + + Ok(()) } pub fn erase_media(&mut self, fast: bool) -> Result<(), Error> { diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs index 19c6aabf..54c990cf 100644 --- a/src/tape/drive/lto/sg_tape.rs +++ b/src/tape/drive/lto/sg_tape.rs @@ -257,28 +257,6 @@ impl SgTape { Ok(position.logical_file_id) } - // fixme: dont use - needs LTO5 - pub fn locate_file(&mut self, position: u64) -> Result<(), Error> { - let mut sg_raw = SgRaw::new(&mut self.file, 16)?; - sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); - let mut cmd = Vec::new(); - cmd.extend(&[0x92, 0b000_01_000, 0, 0]); // LOCATE(16) filemarks - cmd.extend(&position.to_be_bytes()); - cmd.extend(&[0, 0, 0, 0]); - - sg_raw.do_command(&cmd) - .map_err(|err| format_err!("locate file {} failed - {}", position, err))?; - - // move to other side of filemark - cmd.truncate(0); - cmd.extend(&[0x11, 0x01, 0, 0, 1, 0]); // SPACE(6) one filemarks - - sg_raw.do_command(&cmd) - .map_err(|err| format_err!("locate file {} (space) failed - {}", position, err))?; - - Ok(()) - } - /// Check if we are positioned after a filemark (or BOT) pub fn check_filemark(&mut self) -> Result {