#![deny(missing_docs)]
#![allow(unexpected_cfgs)]
extern crate bitflags;
extern crate libc;
#[macro_use]
extern crate log;
extern crate vm_memory;
use std::ffi::{CStr, FromBytesWithNulError};
use std::io::ErrorKind;
use std::{error, fmt, io};
use vm_memory::bitmap::BitmapSlice;
#[derive(Debug)]
pub enum Error {
DecodeMessage(io::Error),
EncodeMessage(io::Error),
MissingParameter,
InvalidCString(FromBytesWithNulError),
InvalidHeaderLength,
InvalidXattrSize((u32, usize)),
InvalidMessage(io::Error),
FailedToWrite(io::Error),
FailedToSplitWriter(transport::Error),
FailedToRemapID((u32, u32)),
}
impl error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match self {
DecodeMessage(err) => write!(f, "failed to decode fuse message: {err}"),
EncodeMessage(err) => write!(f, "failed to encode fuse message: {err}"),
MissingParameter => write!(f, "one or more parameters are missing"),
InvalidHeaderLength => write!(f, "the `len` field of the header is too small"),
InvalidCString(err) => write!(f, "a c string parameter is invalid: {err}"),
InvalidXattrSize((size, len)) => write!(
f,
"The `size` field of the `SetxattrIn` message does not match the length of the \
decoded value: size = {size}, value.len() = {len}"
),
InvalidMessage(err) => write!(f, "cannot process fuse message: {err}"),
FailedToWrite(err) => write!(f, "cannot write to buffer: {err}"),
FailedToSplitWriter(err) => write!(f, "cannot split a writer: {err}"),
FailedToRemapID((uid, gid)) => write!(
f,
"failed to remap the context of user (uid={uid}, gid={gid})."
),
}
}
}
pub type Result<T> = ::std::result::Result<T, Error>;
pub mod abi;
pub mod api;
#[cfg(all(any(feature = "fusedev", feature = "virtiofs"), target_os = "linux"))]
pub mod overlayfs;
#[cfg(all(any(feature = "fusedev", feature = "virtiofs"), target_os = "linux"))]
pub mod passthrough;
pub mod transport;
pub mod common;
pub use self::common::*;
pub fn encode_io_error_kind(kind: ErrorKind) -> i32 {
match kind {
ErrorKind::PermissionDenied => libc::EPERM | libc::EACCES,
ErrorKind::NotFound => libc::ENOENT,
ErrorKind::Interrupted => libc::EINTR,
ErrorKind::AlreadyExists => libc::EEXIST,
ErrorKind::WouldBlock => libc::EWOULDBLOCK,
_ => libc::EIO,
}
}
pub fn bytes_to_cstr(buf: &[u8]) -> Result<&CStr> {
match buf.iter().position(|x| *x == 0) {
Some(pos) => CStr::from_bytes_with_nul(&buf[0..=pos]).map_err(Error::InvalidCString),
None => {
CStr::from_bytes_with_nul(buf).map_err(Error::InvalidCString)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bytes_to_cstr() {
assert_eq!(
bytes_to_cstr(&[0x1u8, 0x2u8, 0x0]).unwrap(),
CStr::from_bytes_with_nul(&[0x1u8, 0x2u8, 0x0]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x1u8, 0x2u8, 0x0, 0x0]).unwrap(),
CStr::from_bytes_with_nul(&[0x1u8, 0x2u8, 0x0]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x1u8, 0x2u8, 0x0, 0x1]).unwrap(),
CStr::from_bytes_with_nul(&[0x1u8, 0x2u8, 0x0]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x1u8, 0x2u8, 0x0, 0x0, 0x1]).unwrap(),
CStr::from_bytes_with_nul(&[0x1u8, 0x2u8, 0x0]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x1u8, 0x2u8, 0x0, 0x1, 0x0]).unwrap(),
CStr::from_bytes_with_nul(&[0x1u8, 0x2u8, 0x0]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x0u8, 0x2u8, 0x0]).unwrap(),
CStr::from_bytes_with_nul(&[0x0u8]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x0u8, 0x0]).unwrap(),
CStr::from_bytes_with_nul(&[0x0u8]).unwrap()
);
assert_eq!(
bytes_to_cstr(&[0x0u8]).unwrap(),
CStr::from_bytes_with_nul(&[0x0u8]).unwrap()
);
bytes_to_cstr(&[0x1u8]).unwrap_err();
bytes_to_cstr(&[0x1u8, 0x1]).unwrap_err();
}
#[test]
fn test_encode_io_error_kind() {
assert_eq!(encode_io_error_kind(ErrorKind::NotFound), libc::ENOENT);
assert_eq!(encode_io_error_kind(ErrorKind::Interrupted), libc::EINTR);
assert_eq!(encode_io_error_kind(ErrorKind::AlreadyExists), libc::EEXIST);
assert_eq!(
encode_io_error_kind(ErrorKind::WouldBlock),
libc::EWOULDBLOCK
);
assert_eq!(encode_io_error_kind(ErrorKind::TimedOut), libc::EIO);
}
}