diff --git a/src/bin/pmt.rs b/src/bin/pmt.rs index da0d4fd9..854364c7 100644 --- a/src/bin/pmt.rs +++ b/src/bin/pmt.rs @@ -383,7 +383,7 @@ fn eject(param: Value) -> Result<(), Error> { fn eod(param: Value) -> Result<(), Error> { let mut handle = get_tape_handle(¶m)?; - handle.move_to_eom()?; + handle.move_to_eom(false)?; Ok(()) } diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs index 2a784632..f1de6236 100644 --- a/src/bin/proxmox-tape.rs +++ b/src/bin/proxmox-tape.rs @@ -551,7 +551,7 @@ fn move_to_eom(mut param: Value) -> Result<(), Error> { let mut drive = open_drive(&config, &drive)?; - drive.move_to_eom()?; + drive.move_to_eom(false)?; Ok(()) } diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs index 25df897f..7fcef8a0 100644 --- a/src/tape/drive/lto/mod.rs +++ b/src/tape/drive/lto/mod.rs @@ -215,13 +215,15 @@ impl TapeDriver for LtoTapeHandle { } /// Go to the end of the recorded media (for appending files). - fn move_to_eom(&mut self) -> Result<(), Error> { - self.sg_tape.move_to_eom() + fn move_to_eom(&mut self, write_missing_eof: bool) -> Result<(), Error> { + self.sg_tape.move_to_eom(write_missing_eof) } fn move_to_last_file(&mut self) -> Result<(), Error> { - self.move_to_eom()?; + self.move_to_eom(false)?; + + self.sg_tape.check_filemark()?; let pos = self.current_file_number()?; diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs index fd1a067a..53cdd855 100644 --- a/src/tape/drive/lto/sg_tape.rs +++ b/src/tape/drive/lto/sg_tape.rs @@ -190,8 +190,6 @@ impl SgTape { bail!("detecthed partitioned tape - not supported"); } - println!("DATA: {:?}", page); - Ok(page) } @@ -222,7 +220,35 @@ impl SgTape { Ok(()) } - pub fn move_to_eom(&mut self) -> Result<(), Error> { + /// Check if we are positioned after a filemark (or BOT) + pub fn check_filemark(&mut self) -> Result { + + let pos = self.position()?; + if pos.logical_object_number == 0 { + // at BOT, Ok (no filemark required) + return Ok(true); + } + + // Note: SPACE blocks returns Err at filemark + match self.space(-1, true) { + Ok(_) => { + self.space(1, true) // move back to end + .map_err(|err| format_err!("check_filemark failed (space forward) - {}", err))?; + Ok(false) + } + Err(ScsiError::Sense(SenseInfo { sense_key: 0, asc: 0, ascq: 1 })) => { + // Filemark detected - good + self.space(1, false) // move to EOT side of filemark + .map_err(|err| format_err!("check_filemark failed (move to EOT side of filemark) - {}", err))?; + Ok(true) + } + Err(err) => { + bail!("check_filemark failed - {:?}", err); + } + } + } + + pub fn move_to_eom(&mut self, write_missing_eof: bool) -> 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(); @@ -231,35 +257,60 @@ impl SgTape { sg_raw.do_command(&cmd) .map_err(|err| format_err!("move to EOD failed - {}", err))?; + if write_missing_eof { + if !self.check_filemark()? { + self.write_filemarks(1, false)?; + } + } + Ok(()) } - pub fn space_filemarks(&mut self, count: isize) -> Result<(), Error> { + fn space(&mut self, count: isize, blocks: bool) -> Result<(), ScsiError> { let mut sg_raw = SgRaw::new(&mut self.file, 16)?; sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); let mut cmd = Vec::new(); // Use short command if possible (supported by all drives) if (count <= 0x7fffff) && (count > -0x7fffff) { - cmd.extend(&[0x11, 0x01]); // SPACE(6) with filemarks + cmd.push(0x11); // SPACE(6) + if blocks { + cmd.push(0); // blocks + } else { + cmd.push(1); // filemarks + } cmd.push(((count >> 16) & 0xff) as u8); cmd.push(((count >> 8) & 0xff) as u8); cmd.push((count & 0xff) as u8); cmd.push(0); //control byte } else { - - cmd.extend(&[0x91, 0x01, 0, 0]); // SPACE(16) with filemarks + cmd.push(0x91); // SPACE(16) + if blocks { + cmd.push(0); // blocks + } else { + cmd.push(1); // filemarks + } + cmd.extend(&[0, 0]); // reserved let count: i64 = count as i64; cmd.extend(&count.to_be_bytes()); - cmd.extend(&[0, 0, 0, 0]); + cmd.extend(&[0, 0, 0, 0]); // reserved } - sg_raw.do_command(&cmd) - .map_err(|err| format_err!("space filemarks failed - {}", err))?; + sg_raw.do_command(&cmd)?; Ok(()) } + pub fn space_filemarks(&mut self, count: isize) -> Result<(), Error> { + self.space(count, false) + .map_err(|err| format_err!("space filemarks failed - {}", err)) + } + + pub fn space_blocks(&mut self, count: isize) -> Result<(), Error> { + self.space(count, true) + .map_err(|err| format_err!("space blocks failed - {}", err)) + } + pub fn eject(&mut self) -> Result<(), Error> { let mut sg_raw = SgRaw::new(&mut self.file, 16)?; sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index 28ff0a3a..cd02e16d 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -84,8 +84,10 @@ pub trait TapeDriver { /// Move to end of recorded data /// - /// We assume this flushes the tape write buffer. - fn move_to_eom(&mut self) -> Result<(), Error>; + /// We assume this flushes the tape write buffer. if + /// write_missing_eof is true, we verify that there is a filemark + /// at the end. If not, we write one. + fn move_to_eom(&mut self, write_missing_eof: bool) -> Result<(), Error>; /// Move to last file fn move_to_last_file(&mut self) -> Result<(), Error>; diff --git a/src/tape/drive/virtual_tape.rs b/src/tape/drive/virtual_tape.rs index bb4b4e3c..a852056a 100644 --- a/src/tape/drive/virtual_tape.rs +++ b/src/tape/drive/virtual_tape.rs @@ -249,7 +249,7 @@ impl TapeDriver for VirtualTapeHandle { /// Move to last file fn move_to_last_file(&mut self) -> Result<(), Error> { - self.move_to_eom()?; + self.move_to_eom(false)?; if self.current_file_number()? == 0 { bail!("move_to_last_file failed - media contains no data"); @@ -347,7 +347,7 @@ impl TapeDriver for VirtualTapeHandle { } } - fn move_to_eom(&mut self) -> Result<(), Error> { + fn move_to_eom(&mut self, _write_missing_eof: bool) -> Result<(), Error> { let mut status = self.load_status()?; match status.current_tape { Some(VirtualTapeStatus { ref name, ref mut pos }) => { diff --git a/src/tape/pool_writer/mod.rs b/src/tape/pool_writer/mod.rs index 05aa52a4..99fdb48c 100644 --- a/src/tape/pool_writer/mod.rs +++ b/src/tape/pool_writer/mod.rs @@ -297,7 +297,7 @@ impl PoolWriter { if !status.at_eom { worker.log(String::from("moving to end of media")); - status.drive.move_to_eom()?; + status.drive.move_to_eom(true)?; status.at_eom = true; }