tape: rust fmt

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht
2022-04-10 17:49:03 +02:00
parent 429bc9d0a2
commit 4de1c42c20
29 changed files with 1183 additions and 1116 deletions

View File

@ -11,30 +11,28 @@
//!
//! - unability to detect EOT (you just get EIO)
use std::convert::TryInto;
use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::convert::TryInto;
use anyhow::{bail, format_err, Error};
use proxmox_uuid::Uuid;
use pbs_api_types::{
Fingerprint, MamAttribute, LtoDriveAndMediaStatus, LtoTapeDrive, Lp17VolumeStatistics,
Fingerprint, Lp17VolumeStatistics, LtoDriveAndMediaStatus, LtoTapeDrive, MamAttribute,
};
use pbs_config::key_config::KeyConfig;
use proxmox_sys::command::run_command;
use pbs_tape::{
TapeWrite, TapeRead, BlockReadError, MediaContentHeader,
sg_tape::{SgTape, TapeAlertFlags},
linux_list_drives::open_lto_tape_device,
sg_tape::{SgTape, TapeAlertFlags},
BlockReadError, MediaContentHeader, TapeRead, TapeWrite,
};
use proxmox_sys::command::run_command;
use crate::{
tape::{
drive::TapeDriver,
file_formats::{PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, MediaSetLabel},
},
use crate::tape::{
drive::TapeDriver,
file_formats::{MediaSetLabel, PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0},
};
/// Open a tape device
@ -46,7 +44,6 @@ use crate::{
/// - check block size
/// - for autoloader only, try to reload ejected tapes
pub fn open_lto_tape_drive(config: &LtoTapeDrive) -> Result<LtoTapeHandle, Error> {
proxmox_lang::try_block!({
let file = open_lto_tape_device(&config.path)?;
@ -64,7 +61,15 @@ pub fn open_lto_tape_drive(config: &LtoTapeDrive) -> Result<LtoTapeHandle, Error
handle.set_default_options()?;
Ok(handle)
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", config.name, config.path, err))
})
.map_err(|err: Error| {
format_err!(
"open drive '{}' ({}) failed - {}",
config.name,
config.path,
err
)
})
}
/// Lto Tape device handle
@ -73,7 +78,6 @@ pub struct LtoTapeHandle {
}
impl LtoTapeHandle {
/// Creates a new instance
pub fn new(file: File) -> Result<Self, Error> {
let sg_tape = SgTape::new(file)?;
@ -93,7 +97,8 @@ impl LtoTapeHandle {
block_length: Option<u32>,
buffer_mode: Option<bool>,
) -> Result<(), Error> {
self.sg_tape.set_drive_options(compression, block_length, buffer_mode)
self.sg_tape
.set_drive_options(compression, block_length, buffer_mode)
}
/// Write a single EOF mark without flushing buffers
@ -102,7 +107,7 @@ impl LtoTapeHandle {
}
/// Get Tape and Media status
pub fn get_drive_and_media_status(&mut self) -> Result<LtoDriveAndMediaStatus, Error> {
pub fn get_drive_and_media_status(&mut self) -> Result<LtoDriveAndMediaStatus, Error> {
self.sg_tape.get_drive_and_media_status()
}
@ -123,7 +128,7 @@ impl LtoTapeHandle {
}
/// Position the tape after filemark count. Count 0 means BOT.
pub fn locate_file(&mut self, position: u64) -> Result<(), Error> {
pub fn locate_file(&mut self, position: u64) -> Result<(), Error> {
self.sg_tape.locate_file(position)
}
@ -131,14 +136,14 @@ impl LtoTapeHandle {
self.sg_tape.erase_media(fast)
}
pub fn load(&mut self) -> Result<(), Error> {
pub fn load(&mut self) -> Result<(), Error> {
self.sg_tape.load()
}
/// Read Cartridge Memory (MAM Attributes)
pub fn cartridge_memory(&mut self) -> Result<Vec<MamAttribute>, Error> {
self.sg_tape.cartridge_memory()
}
}
/// Read Volume Statistics
pub fn volume_statistics(&mut self) -> Result<Lp17VolumeStatistics, Error> {
@ -146,21 +151,21 @@ impl LtoTapeHandle {
}
/// Lock the drive door
pub fn lock(&mut self) -> Result<(), Error> {
self.sg_tape.set_medium_removal(false)
pub fn lock(&mut self) -> Result<(), Error> {
self.sg_tape
.set_medium_removal(false)
.map_err(|err| format_err!("lock door failed - {}", err))
}
/// Unlock the drive door
pub fn unlock(&mut self) -> Result<(), Error> {
self.sg_tape.set_medium_removal(true)
pub fn unlock(&mut self) -> Result<(), Error> {
self.sg_tape
.set_medium_removal(true)
.map_err(|err| format_err!("unlock door failed - {}", err))
}
}
impl TapeDriver for LtoTapeHandle {
fn sync(&mut self) -> Result<(), Error> {
self.sg_tape.sync()?;
Ok(())
@ -172,7 +177,6 @@ impl TapeDriver for LtoTapeHandle {
}
fn move_to_last_file(&mut self) -> Result<(), Error> {
self.move_to_eom(false)?;
self.sg_tape.check_filemark()?;
@ -226,7 +230,6 @@ impl TapeDriver for LtoTapeHandle {
media_set_label: &MediaSetLabel,
key_config: Option<&KeyConfig>,
) -> Result<(), Error> {
let file_number = self.current_file_number()?;
if file_number != 1 {
self.rewind()?;
@ -235,12 +238,16 @@ impl TapeDriver for LtoTapeHandle {
let file_number = self.current_file_number()?;
if file_number != 1 {
bail!("write_media_set_label failed - got wrong file number ({} != 1)", file_number);
bail!(
"write_media_set_label failed - got wrong file number ({} != 1)",
file_number
);
}
self.set_encryption(None)?;
{ // limit handle scope
{
// limit handle scope
let mut handle = self.write_file()?;
let mut value = serde_json::to_value(media_set_label)?;
@ -257,7 +264,8 @@ impl TapeDriver for LtoTapeHandle {
let raw = serde_json::to_string_pretty(&value)?;
let header = MediaContentHeader::new(PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, raw.len() as u32);
let header =
MediaContentHeader::new(PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, raw.len() as u32);
handle.write_header(&header, raw.as_bytes())?;
handle.finish(false)?;
}
@ -285,15 +293,11 @@ impl TapeDriver for LtoTapeHandle {
&mut self,
key_fingerprint: Option<(Fingerprint, Uuid)>,
) -> Result<(), Error> {
if nix::unistd::Uid::effective().is_root() {
if let Some((ref key_fingerprint, ref uuid)) = key_fingerprint {
let (key_map, _digest) = pbs_config::tape_encryption_keys::load_keys()?;
match key_map.get(key_fingerprint) {
Some(item) => {
// derive specialized key for each media-set
let mut tape_key = [0u8; 32];
@ -305,7 +309,8 @@ impl TapeDriver for LtoTapeHandle {
&uuid_bytes,
10,
openssl::hash::MessageDigest::sha256(),
&mut tape_key)?;
&mut tape_key,
)?;
return self.sg_tape.set_encryption(Some(tape_key));
}
@ -318,10 +323,11 @@ impl TapeDriver for LtoTapeHandle {
let output = if let Some((fingerprint, uuid)) = key_fingerprint {
let fingerprint = fingerprint.signature();
run_sg_tape_cmd("encryption", &[
"--fingerprint", &fingerprint,
"--uuid", &uuid.to_string(),
], self.sg_tape.file_mut().as_raw_fd())?
run_sg_tape_cmd(
"encryption",
&["--fingerprint", &fingerprint, "--uuid", &uuid.to_string()],
self.sg_tape.file_mut().as_raw_fd(),
)?
} else {
run_sg_tape_cmd("encryption", &[], self.sg_tape.file_mut().as_raw_fd())?
};
@ -331,12 +337,12 @@ impl TapeDriver for LtoTapeHandle {
}
fn run_sg_tape_cmd(subcmd: &str, args: &[&str], fd: RawFd) -> Result<String, Error> {
let mut command = std::process::Command::new(
"/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd");
let mut command =
std::process::Command::new("/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd");
command.args(&[subcmd]);
command.args(&["--stdin"]);
command.args(args);
let device_fd = nix::unistd::dup(fd)?;
command.stdin(unsafe { std::process::Stdio::from_raw_fd(device_fd)});
command.stdin(unsafe { std::process::Stdio::from_raw_fd(device_fd) });
run_command(command, None)
}

View File

@ -8,55 +8,40 @@ pub use lto::*;
use std::path::PathBuf;
use anyhow::{bail, format_err, Error};
use serde::Deserialize;
use serde_json::Value;
use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
use serde::Deserialize;
use serde_json::Value;
use proxmox_sys::fs::{
lock_file,
atomic_open_or_create_file,
file_read_optional_string,
replace_file,
CreateOptions,
atomic_open_or_create_file, file_read_optional_string, lock_file, replace_file, CreateOptions,
};
use proxmox_io::ReadExt;
use proxmox_section_config::SectionConfigData;
use proxmox_uuid::Uuid;
use proxmox_sys::{task_log, WorkerTaskContext};
use proxmox_uuid::Uuid;
use pbs_api_types::{VirtualTapeDrive, LtoTapeDrive, Fingerprint};
use pbs_api_types::{Fingerprint, LtoTapeDrive, VirtualTapeDrive};
use pbs_config::key_config::KeyConfig;
use pbs_tape::{
TapeWrite, TapeRead, BlockReadError, MediaContentHeader,
sg_tape::TapeAlertFlags,
};
use pbs_tape::{sg_tape::TapeAlertFlags, BlockReadError, MediaContentHeader, TapeRead, TapeWrite};
use crate::{
server::send_load_media_email,
tape::{
MediaId,
drive::{
virtual_tape::open_virtual_tape_drive,
},
changer::{MediaChange, MtxMediaChanger},
drive::virtual_tape::open_virtual_tape_drive,
file_formats::{
PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0,
MediaLabel, MediaSetLabel, PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0,
PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0,
MediaLabel,
MediaSetLabel,
},
changer::{
MediaChange,
MtxMediaChanger,
},
MediaId,
},
};
/// Tape driver interface
pub trait TapeDriver {
/// Flush all data to the tape
fn sync(&mut self) -> Result<(), Error>;
@ -90,14 +75,14 @@ pub trait TapeDriver {
/// Write label to tape (erase tape content)
fn label_tape(&mut self, label: &MediaLabel) -> Result<(), Error> {
self.set_encryption(None)?;
self.format_media(true)?; // this rewinds the tape
let raw = serde_json::to_string_pretty(&serde_json::to_value(&label)?)?;
let header = MediaContentHeader::new(PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0, raw.len() as u32);
let header =
MediaContentHeader::new(PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0, raw.len() as u32);
{
let mut writer = self.write_file()?;
@ -125,7 +110,6 @@ pub trait TapeDriver {
/// This tries to read both media labels (label and
/// media_set_label). Also returns the optional encryption key configuration.
fn read_label(&mut self) -> Result<(Option<MediaId>, Option<KeyConfig>), Error> {
self.rewind()?;
let label = {
@ -143,7 +127,7 @@ pub trait TapeDriver {
};
let header: MediaContentHeader = unsafe { reader.read_le_value()? };
header.check(PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0, 1, 64*1024)?;
header.check(PROXMOX_BACKUP_MEDIA_LABEL_MAGIC_1_0, 1, 64 * 1024)?;
let data = reader.read_exact_allocated(header.size as usize)?;
let label: MediaLabel = serde_json::from_slice(&data)
@ -157,7 +141,10 @@ pub trait TapeDriver {
label
};
let mut media_id = MediaId { label, media_set_label: None };
let mut media_id = MediaId {
label,
media_set_label: None,
};
// try to read MediaSet label
let mut reader = match self.read_next_file() {
@ -174,7 +161,7 @@ pub trait TapeDriver {
};
let header: MediaContentHeader = unsafe { reader.read_le_value()? };
header.check(PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, 1, 64*1024)?;
header.check(PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, 1, 64 * 1024)?;
let data = reader.read_exact_allocated(header.size as usize)?;
let mut data: Value = serde_json::from_slice(&data)
@ -238,28 +225,25 @@ pub fn media_changer(
config: &SectionConfigData,
drive: &str,
) -> Result<Option<(Box<dyn MediaChange>, String)>, Error> {
match config.sections.get(drive) {
Some((section_type_name, config)) => {
match section_type_name.as_ref() {
"virtual" => {
let tape = VirtualTapeDrive::deserialize(config)?;
Ok(Some((Box::new(tape), drive.to_string())))
}
"lto" => {
let drive_config = LtoTapeDrive::deserialize(config)?;
match drive_config.changer {
Some(ref changer_name) => {
let changer = MtxMediaChanger::with_drive_config(&drive_config)?;
let changer_name = changer_name.to_string();
Ok(Some((Box::new(changer), changer_name)))
}
None => Ok(None),
}
}
ty => bail!("unknown drive type '{}' - internal error", ty),
Some((section_type_name, config)) => match section_type_name.as_ref() {
"virtual" => {
let tape = VirtualTapeDrive::deserialize(config)?;
Ok(Some((Box::new(tape), drive.to_string())))
}
}
"lto" => {
let drive_config = LtoTapeDrive::deserialize(config)?;
match drive_config.changer {
Some(ref changer_name) => {
let changer = MtxMediaChanger::with_drive_config(&drive_config)?;
let changer_name = changer_name.to_string();
Ok(Some((Box::new(changer), changer_name)))
}
None => Ok(None),
}
}
ty => bail!("unknown drive type '{}' - internal error", ty),
},
None => {
bail!("no such drive '{}'", drive);
}
@ -274,40 +258,30 @@ pub fn required_media_changer(
drive: &str,
) -> Result<(Box<dyn MediaChange>, String), Error> {
match media_changer(config, drive) {
Ok(Some(result)) => {
Ok(result)
}
Ok(Some(result)) => Ok(result),
Ok(None) => {
bail!("drive '{}' has no associated changer device", drive);
},
Err(err) => {
Err(err)
}
Err(err) => Err(err),
}
}
/// Opens a tape drive (this fails if there is no media loaded)
pub fn open_drive(
config: &SectionConfigData,
drive: &str,
) -> Result<Box<dyn TapeDriver>, Error> {
pub fn open_drive(config: &SectionConfigData, drive: &str) -> Result<Box<dyn TapeDriver>, Error> {
match config.sections.get(drive) {
Some((section_type_name, config)) => {
match section_type_name.as_ref() {
"virtual" => {
let tape = VirtualTapeDrive::deserialize(config)?;
let handle = open_virtual_tape_drive(&tape)?;
Ok(Box::new(handle))
}
"lto" => {
let tape = LtoTapeDrive::deserialize(config)?;
let handle = open_lto_tape_drive(&tape)?;
Ok(Box::new(handle))
}
ty => bail!("unknown drive type '{}' - internal error", ty),
Some((section_type_name, config)) => match section_type_name.as_ref() {
"virtual" => {
let tape = VirtualTapeDrive::deserialize(config)?;
let handle = open_virtual_tape_drive(&tape)?;
Ok(Box::new(handle))
}
}
"lto" => {
let tape = LtoTapeDrive::deserialize(config)?;
let handle = open_lto_tape_drive(&tape)?;
Ok(Box::new(handle))
}
ty => bail!("unknown drive type '{}' - internal error", ty),
},
None => {
bail!("no such drive '{}'", drive);
}
@ -328,7 +302,7 @@ impl std::fmt::Display for TapeRequestError {
match self {
TapeRequestError::None => {
write!(f, "no error")
},
}
TapeRequestError::OpenFailed(reason) => {
write!(f, "tape open failed - {}", reason)
}
@ -336,7 +310,10 @@ impl std::fmt::Display for TapeRequestError {
write!(f, "wrong media label {}", label)
}
TapeRequestError::EmptyTape => {
write!(f, "found empty media without label (please label all tapes first)")
write!(
f,
"found empty media without label (please label all tapes first)"
)
}
TapeRequestError::ReadFailed(reason) => {
write!(f, "tape read failed - {}", reason)
@ -356,11 +333,7 @@ pub fn request_and_load_media(
drive: &str,
label: &MediaLabel,
notify_email: &Option<String>,
) -> Result<(
Box<dyn TapeDriver>,
MediaId,
), Error> {
) -> Result<(Box<dyn TapeDriver>, MediaId), Error> {
let check_label = |handle: &mut dyn TapeDriver, uuid: &proxmox_uuid::Uuid| {
if let Ok((Some(media_id), _)) = handle.read_label() {
task_log!(
@ -399,13 +372,18 @@ pub fn request_and_load_media(
let label_text = label.label_text.clone();
if drive_config.changer.is_some() {
task_log!(worker, "loading media '{}' into drive '{}'", label_text, drive);
task_log!(
worker,
"loading media '{}' into drive '{}'",
label_text,
drive
);
let mut changer = MtxMediaChanger::with_drive_config(&drive_config)?;
changer.load_media(&label_text)?;
let mut handle: Box<dyn TapeDriver> = Box::new(open_lto_tape_drive(&drive_config)?);
let mut handle: Box<dyn TapeDriver> =
Box::new(open_lto_tape_drive(&drive_config)?);
let media_id = check_label(handle.as_mut(), &label.uuid)?;
@ -415,34 +393,34 @@ pub fn request_and_load_media(
let mut last_error = TapeRequestError::None;
let update_and_log_request_error =
|old: &mut TapeRequestError, new: TapeRequestError| -> Result<(), Error>
{
if new != *old {
task_log!(worker, "{}", new);
task_log!(
worker,
"Please insert media '{}' into drive '{}'",
label_text,
drive
);
if let Some(to) = notify_email {
send_load_media_email(
drive,
&label_text,
to,
Some(new.to_string()),
)?;
|old: &mut TapeRequestError, new: TapeRequestError| -> Result<(), Error> {
if new != *old {
task_log!(worker, "{}", new);
task_log!(
worker,
"Please insert media '{}' into drive '{}'",
label_text,
drive
);
if let Some(to) = notify_email {
send_load_media_email(
drive,
&label_text,
to,
Some(new.to_string()),
)?;
}
*old = new;
}
*old = new;
}
Ok(())
};
Ok(())
};
loop {
worker.check_abort()?;
if last_error != TapeRequestError::None {
for _ in 0..50 { // delay 5 seconds
for _ in 0..50 {
// delay 5 seconds
worker.check_abort()?;
std::thread::sleep(std::time::Duration::from_millis(100));
}
@ -484,12 +462,8 @@ pub fn request_and_load_media(
);
TapeRequestError::WrongLabel(label_string)
}
Ok((None, _)) => {
TapeRequestError::EmptyTape
}
Err(err) => {
TapeRequestError::ReadFailed(err.to_string())
}
Ok((None, _)) => TapeRequestError::EmptyTape,
Err(err) => TapeRequestError::ReadFailed(err.to_string()),
};
update_and_log_request_error(&mut last_error, request_error)?;
@ -537,11 +511,7 @@ pub fn lock_tape_device(
/// Writes the given state for the specified drive
///
/// This function does not lock, so make sure the drive is locked
pub fn set_tape_device_state(
drive: &str,
state: &str,
) -> Result<(), Error> {
pub fn set_tape_device_state(drive: &str, state: &str) -> Result<(), Error> {
let mut path = PathBuf::from(crate::tape::DRIVE_STATE_DIR);
path.push(drive);
@ -571,19 +541,12 @@ pub fn get_tape_device_state(
}
}
fn tape_device_path(
config: &SectionConfigData,
drive: &str,
) -> Result<String, Error> {
fn tape_device_path(config: &SectionConfigData, drive: &str) -> Result<String, Error> {
match config.sections.get(drive) {
Some((section_type_name, config)) => {
let path = match section_type_name.as_ref() {
"virtual" => {
VirtualTapeDrive::deserialize(config)?.path
}
"lto" => {
LtoTapeDrive::deserialize(config)?.path
}
"virtual" => VirtualTapeDrive::deserialize(config)?.path,
"lto" => LtoTapeDrive::deserialize(config)?.path,
ty => bail!("unknown drive type '{}' - internal error", ty),
};
Ok(path)
@ -622,7 +585,7 @@ fn open_device_lock(device_path: &str) -> Result<std::fs::File, Error> {
// Acquires an exclusive lock on `device_path`
//
fn lock_device_path(device_path: &str) -> Result<DeviceLockGuard, TapeLockError> {
let mut file = open_device_lock(device_path)?;
let mut file = open_device_lock(device_path)?;
let timeout = std::time::Duration::new(10, 0);
if let Err(err) = lock_file(&mut file, true, Some(timeout)) {
if err.kind() == std::io::ErrorKind::Interrupted {
@ -638,13 +601,12 @@ fn lock_device_path(device_path: &str) -> Result<DeviceLockGuard, TapeLockError>
// Same logic as lock_device_path, but uses a timeout of 0, making it
// non-blocking, and returning if the file is locked or not
fn test_device_path_lock(device_path: &str) -> Result<bool, Error> {
let mut file = open_device_lock(device_path)?;
let mut file = open_device_lock(device_path)?;
let timeout = std::time::Duration::new(0, 0);
match lock_file(&mut file, true, Some(timeout)) {
// file was not locked, continue
Ok(()) => {},
Ok(()) => {}
// file was locked, return true
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => return Ok(true),
Err(err) => bail!("{}", err),

View File

@ -4,40 +4,19 @@ use std::fs::File;
use std::io;
use anyhow::{bail, format_err, Error};
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use proxmox_sys::{
fs::{replace_file, CreateOptions},
};
use proxmox_sys::fs::{replace_file, CreateOptions};
use pbs_config::key_config::KeyConfig;
use pbs_tape::{
TapeWrite,
TapeRead,
BlockedReader,
BlockedWriter,
BlockReadError,
MtxStatus,
DriveStatus,
ElementStatus,
StorageElementStatus,
MediaContentHeader,
EmulateTapeReader,
EmulateTapeWriter,
BlockReadError, BlockedReader, BlockedWriter, DriveStatus, ElementStatus, EmulateTapeReader,
EmulateTapeWriter, MediaContentHeader, MtxStatus, StorageElementStatus, TapeRead, TapeWrite,
};
use crate::{
tape::{
drive::{
VirtualTapeDrive,
TapeDriver,
MediaChange,
},
file_formats::{
MediaSetLabel,
PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0,
},
},
use crate::tape::{
drive::{MediaChange, TapeDriver, VirtualTapeDrive},
file_formats::{MediaSetLabel, PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0},
};
/// This needs to lock the drive
@ -53,24 +32,32 @@ pub fn open_virtual_tape_drive(config: &VirtualTapeDrive) -> Result<VirtualTapeH
Ok(VirtualTapeHandle {
_lock: lock,
drive_name: config.name.clone(),
max_size: config.max_size.unwrap_or(64*1024*1024),
max_size: config.max_size.unwrap_or(64 * 1024 * 1024),
path: std::path::PathBuf::from(&config.path),
})
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", config.name, config.path, err))
})
.map_err(|err: Error| {
format_err!(
"open drive '{}' ({}) failed - {}",
config.name,
config.path,
err
)
})
}
#[derive(Serialize,Deserialize)]
#[derive(Serialize, Deserialize)]
struct VirtualTapeStatus {
name: String,
pos: usize,
}
#[derive(Serialize,Deserialize)]
#[derive(Serialize, Deserialize)]
struct VirtualDriveStatus {
current_tape: Option<VirtualTapeStatus>,
}
#[derive(Serialize,Deserialize)]
#[derive(Serialize, Deserialize)]
struct TapeIndex {
files: usize,
}
@ -83,7 +70,6 @@ pub struct VirtualTapeHandle {
}
impl VirtualTapeHandle {
fn status_file_path(&self) -> std::path::PathBuf {
let mut path = self.path.clone();
path.push("drive-status.json");
@ -121,11 +107,11 @@ impl VirtualTapeHandle {
Ok(())
}
fn truncate_tape(&self, tape_name: &str, pos: usize) -> Result<usize, Error> {
fn truncate_tape(&self, tape_name: &str, pos: usize) -> Result<usize, Error> {
let mut index = self.load_tape_index(tape_name)?;
if index.files <= pos {
return Ok(index.files)
return Ok(index.files);
}
for i in pos..index.files {
@ -143,9 +129,7 @@ impl VirtualTapeHandle {
fn load_status(&self) -> Result<VirtualDriveStatus, Error> {
let path = self.status_file_path();
let default = serde_json::to_value(VirtualDriveStatus {
current_tape: None,
})?;
let default = serde_json::to_value(VirtualDriveStatus { current_tape: None })?;
let data = proxmox_sys::fs::file_get_json(&path, Some(default))?;
let status: VirtualDriveStatus = serde_json::from_value(data)?;
@ -183,9 +167,12 @@ impl VirtualTapeHandle {
fn forward_space_count_files(&mut self, count: usize) -> Result<(), Error> {
let mut status = self.load_status()?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
let index = self.load_tape_index(name)
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
let index = self
.load_tape_index(name)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
let new_pos = *pos + count;
@ -210,7 +197,6 @@ impl VirtualTapeHandle {
let mut status = self.load_status()?;
match status.current_tape {
Some(VirtualTapeStatus { ref mut pos, .. }) => {
if count <= *pos {
*pos = *pos - count;
} else {
@ -225,28 +211,26 @@ impl VirtualTapeHandle {
None => bail!("drive is empty (no tape loaded)."),
}
}
}
impl TapeDriver for VirtualTapeHandle {
fn sync(&mut self) -> Result<(), Error> {
Ok(()) // do nothing for now
}
fn current_file_number(&mut self) -> Result<u64, Error> {
let status = self.load_status()
let status = self
.load_status()
.map_err(|err| format_err!("current_file_number failed: {}", err.to_string()))?;
match status.current_tape {
Some(VirtualTapeStatus { pos, .. }) => { Ok(pos as u64)},
Some(VirtualTapeStatus { pos, .. }) => Ok(pos as u64),
None => bail!("current_file_number failed: drive is empty (no tape loaded)."),
}
}
/// Move to last file
fn move_to_last_file(&mut self) -> Result<(), Error> {
self.move_to_eom(false)?;
if self.current_file_number()? == 0 {
@ -261,9 +245,12 @@ impl TapeDriver for VirtualTapeHandle {
fn move_to_file(&mut self, file: u64) -> Result<(), Error> {
let mut status = self.load_status()?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
let index = self.load_tape_index(name)
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
let index = self
.load_tape_index(name)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
if file as usize > index.files {
@ -282,46 +269,55 @@ impl TapeDriver for VirtualTapeHandle {
}
fn read_next_file(&mut self) -> Result<Box<dyn TapeRead>, BlockReadError> {
let mut status = self.load_status()
.map_err(|err| BlockReadError::Error(io::Error::new(io::ErrorKind::Other, err.to_string())))?;
let mut status = self.load_status().map_err(|err| {
BlockReadError::Error(io::Error::new(io::ErrorKind::Other, err.to_string()))
})?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
let index = self.load_tape_index(name)
.map_err(|err| BlockReadError::Error(io::Error::new(io::ErrorKind::Other, err.to_string())))?;
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
let index = self.load_tape_index(name).map_err(|err| {
BlockReadError::Error(io::Error::new(io::ErrorKind::Other, err.to_string()))
})?;
if *pos >= index.files {
return Err(BlockReadError::EndOfStream);
}
let path = self.tape_file_path(name, *pos);
let file = std::fs::OpenOptions::new()
.read(true)
.open(path)?;
let file = std::fs::OpenOptions::new().read(true).open(path)?;
*pos += 1;
self.store_status(&status)
.map_err(|err| BlockReadError::Error(io::Error::new(io::ErrorKind::Other, err.to_string())))?;
self.store_status(&status).map_err(|err| {
BlockReadError::Error(io::Error::new(io::ErrorKind::Other, err.to_string()))
})?;
let reader = EmulateTapeReader::new(file);
let reader = BlockedReader::open(reader)?;
Ok(Box::new(reader))
}
None => {
return Err(BlockReadError::Error(proxmox_lang::io_format_err!("drive is empty (no tape loaded).")));
return Err(BlockReadError::Error(proxmox_lang::io_format_err!(
"drive is empty (no tape loaded)."
)));
}
}
}
fn write_file(&mut self) -> Result<Box<dyn TapeWrite>, io::Error> {
let mut status = self.load_status()
let mut status = self
.load_status()
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
let mut index = self.load_tape_index(name)
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
let mut index = self
.load_tape_index(name)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
for i in *pos..index.files {
@ -333,7 +329,6 @@ impl TapeDriver for VirtualTapeHandle {
for i in 0..*pos {
let path = self.tape_file_path(name, i);
used_space += path.metadata()?.len() as usize;
}
index.files = *pos + 1;
@ -369,9 +364,12 @@ impl TapeDriver for VirtualTapeHandle {
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 }) => {
let index = self.load_tape_index(name)
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
let index = self
.load_tape_index(name)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
*pos = index.files;
@ -400,7 +398,10 @@ impl TapeDriver for VirtualTapeHandle {
fn format_media(&mut self, _fast: bool) -> Result<(), Error> {
let mut status = self.load_status()?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
*pos = self.truncate_tape(name, 0)?;
self.store_status(&status)?;
Ok(())
@ -414,7 +415,6 @@ impl TapeDriver for VirtualTapeHandle {
media_set_label: &MediaSetLabel,
key_config: Option<&KeyConfig>,
) -> Result<(), Error> {
self.set_encryption(None)?;
if key_config.is_some() {
@ -423,7 +423,10 @@ impl TapeDriver for VirtualTapeHandle {
let mut status = self.load_status()?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
Some(VirtualTapeStatus {
ref name,
ref mut pos,
}) => {
*pos = self.truncate_tape(name, 1)?;
let pos = *pos;
self.store_status(&status)?;
@ -432,11 +435,17 @@ impl TapeDriver for VirtualTapeHandle {
bail!("media is empty (no label).");
}
if pos != 1 {
bail!("write_media_set_label: truncate failed - got wrong pos '{}'", pos);
bail!(
"write_media_set_label: truncate failed - got wrong pos '{}'",
pos
);
}
let raw = serde_json::to_string_pretty(&serde_json::to_value(media_set_label)?)?;
let header = MediaContentHeader::new(PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0, raw.len() as u32);
let header = MediaContentHeader::new(
PROXMOX_BACKUP_MEDIA_SET_LABEL_MAGIC_1_0,
raw.len() as u32,
);
{
let mut writer = self.write_file()?;
@ -451,15 +460,12 @@ impl TapeDriver for VirtualTapeHandle {
}
fn eject_media(&mut self) -> Result<(), Error> {
let status = VirtualDriveStatus {
current_tape: None,
};
let status = VirtualDriveStatus { current_tape: None };
self.store_status(&status)
}
}
impl MediaChange for VirtualTapeHandle {
fn drive_number(&self) -> u64 {
0
}
@ -469,7 +475,6 @@ impl MediaChange for VirtualTapeHandle {
}
fn status(&mut self) -> Result<MtxStatus, Error> {
let drive_status = self.load_status()?;
let mut drives = Vec::new();
@ -482,7 +487,7 @@ impl MediaChange for VirtualTapeHandle {
vendor: None,
model: None,
element_address: 0,
});
});
}
// This implementation is lame, because we do not have fixed
@ -490,7 +495,7 @@ impl MediaChange for VirtualTapeHandle {
let mut slots = Vec::new();
let label_texts = self.online_media_label_texts()?;
let max_slots = ((label_texts.len() + 7)/8) * 8;
let max_slots = ((label_texts.len() + 7) / 8) * 8;
for i in 0..max_slots {
let status = if let Some(label_text) = label_texts.get(i) {
@ -505,7 +510,11 @@ impl MediaChange for VirtualTapeHandle {
});
}
Ok(MtxStatus { drives, slots, transports: Vec::new() })
Ok(MtxStatus {
drives,
slots,
transports: Vec::new(),
})
}
fn transfer_media(&mut self, _from: u64, _to: u64) -> Result<MtxStatus, Error> {
@ -568,7 +577,6 @@ impl MediaChange for VirtualTapeHandle {
}
impl MediaChange for VirtualTapeDrive {
fn drive_number(&self) -> u64 {
0
}