tape: introduce trait BlockRead

This commit is contained in:
Dietmar Maurer
2021-03-29 10:09:49 +02:00
parent c47609fedb
commit 0db5712493
6 changed files with 146 additions and 82 deletions

View File

@ -1,6 +1,7 @@
//! Driver for Linux SCSI tapes
use std::fs::{OpenOptions, File};
use std::io::Read;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::convert::TryFrom;
@ -24,6 +25,8 @@ use crate::{
LinuxDriveAndMediaStatus,
},
tape::{
BlockRead,
BlockReadStatus,
TapeRead,
TapeWrite,
drive::{
@ -507,7 +510,8 @@ impl TapeDriver for LinuxTapeHandle {
}
fn read_next_file<'a>(&'a mut self) -> Result<Option<Box<dyn TapeRead + 'a>>, std::io::Error> {
match BlockedReader::open(&mut self.file)? {
let reader = LinuxTapeReader::new(&mut self.file);
match BlockedReader::open(reader)? {
Some(reader) => Ok(Some(Box::new(reader))),
None => Ok(None),
}
@ -766,3 +770,50 @@ impl TapeWrite for TapeWriterHandle<'_> {
self.writer.logical_end_of_media()
}
}
pub struct LinuxTapeReader<'a> {
/// Assumes that 'file' is a linux tape device.
file: &'a mut File,
got_eof: bool,
}
impl <'a> LinuxTapeReader<'a> {
pub fn new(file: &'a mut File) -> Self {
Self { file, got_eof: false }
}
}
impl <'a> BlockRead for LinuxTapeReader<'a> {
/// Read a single block from a linux tape device
///
/// Return true on success, false on EOD
fn read_block(&mut self, buffer: &mut [u8]) -> Result<BlockReadStatus, std::io::Error> {
loop {
match self.file.read(buffer) {
Ok(0) => {
let eod = self.got_eof;
self.got_eof = true;
if eod {
return Ok(BlockReadStatus::EndOfStream);
} else {
return Ok(BlockReadStatus::EndOfFile);
}
}
Ok(count) => {
if count == buffer.len() {
return Ok(BlockReadStatus::Ok(count));
}
proxmox::io_bail!("short block read ({} < {}). Tape drive uses wrong block size.",
count, buffer.len());
}
// handle interrupted system call
Err(err) if err.kind() == std::io::ErrorKind::Interrupted => {
continue;
}
Err(err) => return Err(err),
}
}
}
}

View File

@ -222,8 +222,7 @@ impl TapeDriver for VirtualTapeHandle {
self.store_status(&status)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
let reader = Box::new(file);
let reader = Box::new(EmulateTapeReader::new(reader));
let reader = EmulateTapeReader::new(file);
match BlockedReader::open(reader)? {
Some(reader) => Ok(Some(Box::new(reader))),