use super::ExtendedAttribute;
use super::Inode;
use super::InodeNumber;
use super::SuperBlock;
use crate::error::Error;
use crate::platform;
use crate::platform::ffi;
use std::fmt;
use std::path::Path;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ReadFileOptions {
pub offset: u64,
pub count: Option<usize>,
pub follow_symlinks: bool,
}
impl Default for ReadFileOptions {
fn default() -> Self {
Self {
offset: 0,
count: None,
follow_symlinks: true,
}
}
}
pub struct EXT4Reader {
handle: ffi::CzExt4Reader,
}
impl fmt::Debug for EXT4Reader {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("EXT4Reader").finish_non_exhaustive()
}
}
unsafe impl Send for EXT4Reader {}
impl EXT4Reader {
pub fn new(block_device: &Path) -> Result<Self, Error> {
let outcome = platform::outcome(
ffi::cz_ext4_reader_new(platform::path(block_device)?),
format!("read the filesystem in {}", block_device.display()),
)?;
Ok(Self {
handle: outcome.ext4_reader(),
})
}
pub fn super_block(&self) -> SuperBlock {
platform::from_bytes(&self.handle.super_block())
}
pub fn exists(&self, path: &Path, follow_symlinks: bool) -> Result<bool, Error> {
Ok(self.handle.exists(platform::path(path)?, follow_symlinks))
}
pub fn stat(&self, path: &Path, follow_symlinks: bool) -> Result<(InodeNumber, Inode), Error> {
platform::outcome(
self.handle.stat(platform::path(path)?, follow_symlinks),
format!("stat {}", path.display()),
)
.map(|outcome| (outcome.inode_number(), outcome.inode()))
}
pub fn list_directory(&self, path: &Path) -> Result<Vec<String>, Error> {
platform::outcome(
self.handle.list_directory(platform::path(path)?),
format!("list {}", path.display()),
)
.map(|outcome| outcome.strings())
}
pub fn read_file(&self, at: &Path, options: ReadFileOptions) -> Result<Vec<u8>, Error> {
platform::outcome(
self.handle.read_file(
platform::path(at)?,
options.offset,
options.count,
options.follow_symlinks,
),
format!("read {}", at.display()),
)
.map(|outcome| outcome.bytes())
}
pub fn export(&self, archive: &Path) -> Result<(), Error> {
platform::outcome(
self.handle.export(platform::path(archive)?),
format!("export the filesystem to {}", archive.display()),
)
.map(drop)
}
pub fn read_inline_extended_attributes(buffer: &[u8]) -> Result<Vec<ExtendedAttribute>, Error> {
attributes(
ffi::cz_ext4_reader_read_inline_extended_attributes(buffer.to_vec()),
"read inline extended attributes",
)
}
pub fn read_block_extended_attributes(buffer: &[u8]) -> Result<Vec<ExtendedAttribute>, Error> {
attributes(
ffi::cz_ext4_reader_read_block_extended_attributes(buffer.to_vec()),
"read a block's extended attributes",
)
}
}
pub(super) fn attributes(outcome: ffi::CzOutcome, action: &str) -> Result<Vec<ExtendedAttribute>, Error> {
platform::outcome(outcome, action).map(|outcome| {
(0..outcome.len())
.map(|_| ExtendedAttribute::opaque())
.collect()
})
}