pin-utils = "0.1.0"
pin-project = "0.4"
pathpatterns = "0.1.2"
-proxmox = { version = "0.8.0", features = [ "sortable-macro", "api-macro", "websocket" ] }
+proxmox = { version = "0.8.1", features = [ "sortable-macro", "api-macro", "websocket" ] }
#proxmox = { git = "git://git.proxmox.com/git/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro", "websocket" ] }
proxmox-fuse = "0.1.0"
--- /dev/null
+use std::io::{self, Read};
+
+use crate::tape::file_formats::PROXMOX_TAPE_BLOCK_SIZE;
+
+/// Emulate tape read behavior on a normal Reader
+///
+/// Tapes reads are always return one whole block PROXMOX_TAPE_BLOCK_SIZE.
+pub struct EmulateTapeReader<R> {
+ reader: R,
+}
+
+impl <R: Read> EmulateTapeReader<R> {
+
+ pub fn new(reader: R) -> Self {
+ Self { reader }
+ }
+}
+
+impl <R: Read> Read for EmulateTapeReader<R> {
+
+ fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, io::Error> {
+
+ let initial_buffer_len = buffer.len(); // store, check later
+
+ let mut bytes = 0;
+
+ while !buffer.is_empty() {
+ match self.reader.read(buffer) {
+ Ok(0) => break,
+ Ok(n) => {
+ bytes += n;
+ let tmp = buffer;
+ buffer = &mut tmp[n..];
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ if bytes == 0 {
+ return Ok(0);
+ }
+
+ // test buffer len after EOF test (to allow EOF test with small buffers in BufferedReader)
+ if initial_buffer_len != PROXMOX_TAPE_BLOCK_SIZE {
+ proxmox::io_bail!("EmulateTapeReader: got read with wrong block size ({} != {})",
+ buffer.len(), PROXMOX_TAPE_BLOCK_SIZE);
+ }
+
+ if !buffer.is_empty() {
+ Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
+ } else {
+ Ok(bytes)
+ }
+ }
+}
--- /dev/null
+use std::io::{self, Write};
+
+use crate::tape::file_formats::PROXMOX_TAPE_BLOCK_SIZE;
+
+/// Emulate tape write behavior on a normal Writer
+///
+/// Data need to be written in blocks of size PROXMOX_TAPE_BLOCK_SIZE.
+/// Before reaching the EOT, the writer returns ENOSPC (like a linux
+/// tape device).
+pub struct EmulateTapeWriter<W> {
+ block_nr: usize,
+ max_blocks: usize,
+ writer: W,
+ leom_sent: bool,
+}
+
+impl <W: Write> EmulateTapeWriter<W> {
+
+ /// Create a new instance allowing to write about max_size bytes
+ pub fn new(writer: W, max_size: usize) -> Self {
+
+ let mut max_blocks = max_size/PROXMOX_TAPE_BLOCK_SIZE;
+
+ if max_blocks < 2 {
+ max_blocks = 2; // at least 2 blocks
+ }
+
+ Self {
+ block_nr: 0,
+ leom_sent: false,
+ writer,
+ max_blocks,
+ }
+ }
+}
+
+impl <W: Write> Write for EmulateTapeWriter<W> {
+
+ fn write(&mut self, buffer: &[u8]) -> Result<usize, io::Error> {
+
+ if buffer.len() != PROXMOX_TAPE_BLOCK_SIZE {
+ proxmox::io_bail!("EmulateTapeWriter: got write with wrong block size ({} != {}",
+ buffer.len(), PROXMOX_TAPE_BLOCK_SIZE);
+ }
+
+ if self.block_nr >= self.max_blocks + 2 {
+ return Err(io::Error::from_raw_os_error(nix::errno::Errno::ENOSPC as i32));
+ }
+
+ if self.block_nr >= self.max_blocks {
+ if !self.leom_sent {
+ self.leom_sent = true;
+ return Err(io::Error::from_raw_os_error(nix::errno::Errno::ENOSPC as i32));
+ } else {
+ self.leom_sent = false;
+ }
+ }
+
+ self.writer.write_all(buffer)?;
+ self.block_nr += 1;
+
+ Ok(buffer.len())
+ }
+
+ fn flush(&mut self) -> Result<(), io::Error> {
+ proxmox::io_bail!("EmulateTapeWriter does not support flush");
+ }
+}
--- /dev/null
+mod emulate_tape_writer;
+pub use emulate_tape_writer::*;
+
+mod emulate_tape_reader;
+pub use emulate_tape_reader::*;
mod tape_read;
pub use tape_read::*;
+mod helpers;
+pub use helpers::*;
+
mod inventory;
pub use inventory::*;