diff --git a/src/tape/changer/mod.rs b/src/tape/changer/mod.rs index 8d23133b..0125ec13 100644 --- a/src/tape/changer/mod.rs +++ b/src/tape/changer/mod.rs @@ -10,7 +10,7 @@ pub use mtx_wrapper::*; mod mtx; pub use mtx::*; -use anyhow::Error; +use anyhow::{bail, Error}; /// Interface to media change devices pub trait MediaChange { @@ -18,6 +18,11 @@ pub trait MediaChange { /// Returns the changer status fn status(&mut self) -> Result; + /// Transfer media from on slot to another (storage or import export slots) + /// + /// Target slot needs to be empty + fn transfer(&mut self, from: u64, to: u64) -> Result<(), Error>; + /// Load media from storage slot into drive fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error>; @@ -69,4 +74,40 @@ pub trait MediaChange { /// This fail if there is no cleaning cartridge online. Any media /// inside the drive is automatically unloaded. fn clean_drive(&mut self) -> Result<(), Error>; + + /// Export media + /// + /// By moving the media to an empty import-export slot. Returns + /// Some(slot) if the media was exported. Returns None if the media is + /// not online (already exported). + fn export_media(&mut self, changer_id: &str) -> Result, Error> { + let status = self.status()?; + + let mut from = None; + let mut to = None; + + for (i, (import_export, element_status)) in status.slots.iter().enumerate() { + if *import_export { + if to.is_some() { continue; } + if let ElementStatus::Empty = element_status { + to = Some(i as u64 + 1); + } + } else { + if let ElementStatus::VolumeTag(ref tag) = element_status { + if tag == changer_id { + from = Some(i as u64 + 1); + } + } + } + } + match (from, to) { + (Some(from), Some(to)) => { + self.transfer(from, to); + Ok(Some(to)) + } + (Some(from), None) => bail!("unable to find free export slot"), + (None, _) => Ok(None), // not online + } + } + } diff --git a/src/tape/changer/mtx.rs b/src/tape/changer/mtx.rs index f21bd1a3..fb009f98 100644 --- a/src/tape/changer/mtx.rs +++ b/src/tape/changer/mtx.rs @@ -6,6 +6,7 @@ use crate::{ MtxStatus, ElementStatus, mtx_status, + mtx_transfer, mtx_load, mtx_unload, }, @@ -71,6 +72,10 @@ impl MediaChange for MtxMediaChanger { mtx_status(&self.config) } + fn transfer(&mut self, from: u64, to: u64) -> Result<(), Error> { + mtx_transfer(&self.config.path, from, to) + } + fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> { mtx_load(&self.config.path, slot, self.drivenum) } diff --git a/src/tape/drive/virtual_tape.rs b/src/tape/drive/virtual_tape.rs index 606c2202..3967388c 100644 --- a/src/tape/drive/virtual_tape.rs +++ b/src/tape/drive/virtual_tape.rs @@ -393,6 +393,10 @@ impl MediaChange for VirtualTapeHandle { Ok(MtxStatus { drives, slots }) } + fn transfer(&mut self, from: u64, to: u64) -> Result<(), Error> { + bail!("medfia tranfer is not implemented!"); + } + fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> { if slot < 1 { bail!("invalid slot ID {}", slot); @@ -452,6 +456,11 @@ impl MediaChange for VirtualTapeDrive { handle.status() } + fn transfer(&mut self, from: u64, to: u64) -> Result<(), Error> { + let mut handle = self.open()?; + handle.transfer(from, to) + } + fn load_media_from_slot(&mut self, slot: u64) -> Result<(), Error> { let mut handle = self.open()?; handle.load_media_from_slot(slot)