#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate nydus_error;
#[macro_use]
extern crate nydus_storage as storage;
use std::any::Any;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::fs::File;
use std::io::{BufWriter, Error, Read, Result, Seek, SeekFrom, Write};
use std::os::unix::io::AsRawFd;
use std::path::Path;
pub mod fs;
pub mod metadata;
#[cfg(test)]
pub mod mock;
#[derive(Debug)]
pub enum RafsError {
Unsupported,
Uninitialized,
AlreadyMounted,
ReadMetadata(Error, String),
LoadConfig(Error),
ParseConfig(serde_json::Error),
SwapBackend(Error),
FillSuperblock(Error),
CreateDevice(Error),
Prefetch(String),
Configure(String),
Incompatible(u16),
IllegalMetaStruct(MetaType, String),
}
impl std::error::Error for RafsError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl Display for RafsError {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{:?}", self)?;
Ok(())
}
}
#[derive(Debug)]
pub enum MetaType {
Regular,
Dir,
Symlink,
}
pub type RafsResult<T> = std::result::Result<T, RafsError>;
pub type RafsIoReader = Box<dyn RafsIoRead>;
pub trait RafsIoRead: Read + AsRawFd + Seek + Send {}
impl RafsIoRead for File {}
pub type RafsIoWriter = Box<dyn RafsIoWrite>;
pub trait RafsIoWrite: Write + Seek + 'static {
fn as_any(&self) -> &dyn Any;
fn validate_alignment(&mut self, size: usize, alignment: usize) -> Result<usize> {
if alignment != 0 {
let cur = self.seek(SeekFrom::Current(0))?;
if (size & (alignment - 1) != 0) || (cur & (alignment as u64 - 1) != 0) {
return Err(einval!("unaligned data"));
}
}
Ok(size)
}
fn write_padding(&mut self, size: usize) -> Result<()> {
if size > WRITE_PADDING_DATA.len() {
return Err(einval!("invalid padding size"));
}
self.write_all(&WRITE_PADDING_DATA[0..size])
}
fn seek_to_end(&mut self) -> Result<u64> {
self.seek(SeekFrom::End(0)).map_err(|e| {
error!("Seeking to end fails, {}", e);
e
})
}
fn seek_offset(&mut self, offset: u64) -> Result<u64> {
self.seek(SeekFrom::Start(offset)).map_err(|e| {
error!("Seeking to offset {} from start fails, {}", offset, e);
e
})
}
fn seek_current(&mut self, offset: i64) -> Result<u64> {
self.seek(SeekFrom::Current(offset))
}
fn finalize(&mut self, _name: Option<String>) -> anyhow::Result<()> {
Ok(())
}
fn data(&self) -> &[u8] {
unimplemented!();
}
}
impl RafsIoWrite for File {
fn as_any(&self) -> &dyn Any {
self
}
}
impl RafsIoWrite for BufWriter<File> {
fn as_any(&self) -> &dyn Any {
self
}
}
const WRITE_PADDING_DATA: [u8; 64] = [0u8; 64];
impl dyn RafsIoRead {
pub fn seek_to_next_aligned(&mut self, last_read_len: usize, alignment: usize) -> Result<u64> {
let suffix = last_read_len & (alignment - 1);
let offset = if suffix == 0 { 0 } else { alignment - suffix };
self.seek(SeekFrom::Current(offset as i64)).map_err(|e| {
error!("Seeking to offset {} from current fails, {}", offset, e);
e
})
}
pub fn seek_plus_offset(&mut self, plus_offset: i64) -> Result<u64> {
self.seek(SeekFrom::Current(plus_offset)).map_err(|e| {
error!(
"Seeking to offset {} from current fails, {}",
plus_offset, e
);
e
})
}
pub fn seek_to_offset(&mut self, offset: u64) -> Result<u64> {
self.seek(SeekFrom::Start(offset)).map_err(|e| {
error!("Seeking to offset {} from start fails, {}", offset, e);
e
})
}
pub fn seek_to_end(&mut self, offset: i64) -> Result<u64> {
self.seek(SeekFrom::End(offset)).map_err(|e| {
error!("Seeking to end fails, {}", e);
e
})
}
pub fn from_file(path: impl AsRef<Path>) -> RafsResult<RafsIoReader> {
let f = File::open(&path).map_err(|e| {
RafsError::ReadMetadata(e, path.as_ref().to_string_lossy().into_owned())
})?;
Ok(Box::new(f))
}
}
#[cfg(test)]
mod tests {
use super::*;
use vmm_sys_util::tempfile::TempFile;
#[test]
fn test_rafs_io_writer() {
let mut file = TempFile::new().unwrap().into_file();
assert!(file.validate_alignment(2, 8).is_err());
assert!(file.validate_alignment(7, 8).is_err());
assert!(file.validate_alignment(9, 8).is_err());
assert!(file.validate_alignment(8, 8).is_ok());
file.write_all(&[0x0u8; 7]).unwrap();
assert!(file.validate_alignment(8, 8).is_err());
{
let obj: &mut dyn RafsIoWrite = &mut file;
obj.write_padding(1).unwrap();
}
assert!(file.validate_alignment(8, 8).is_ok());
file.write_all(&[0x0u8; 1]).unwrap();
assert!(file.validate_alignment(8, 8).is_err());
let obj: &mut dyn RafsIoRead = &mut file;
assert_eq!(obj.seek_to_offset(0).unwrap(), 0);
assert_eq!(obj.seek_plus_offset(7).unwrap(), 7);
assert_eq!(obj.seek_to_next_aligned(7, 8).unwrap(), 8);
assert_eq!(obj.seek_plus_offset(7).unwrap(), 15);
}
}