Struct Image
pub struct Image<R> {
source: R,
block_size: u32,
blocks: u32,
offsets: HeaderOffsets,
}Expand description
UBI image whose volumes are read through the headers of its blocks.
It reads only the EC and VID headers to find the blocks of a volume, and
reads data only when asked. Unlike super::ImageReader, it doesn’t
need a block buffer.
Any invalid header in the image is an error, also in blocks of other volumes. When the kernel attaches a device, it skips some damaged blocks instead.
use std::fs::File;
use flashkit_ubi::flashkit_io::ReadAt as _;
use flashkit_ubi::{HeaderOffsets, Image, VolumeTable};
let offsets = HeaderOffsets::from_io_sizes(4096, 4096).ok_or("invalid I/O size")?;
let image = Image::new(File::open("system.ubi")?, 256 * 1024, offsets)?;
let mut buffer = vec![0; VolumeTable::BUFFER_LEN];
let table = image.volume_table(&mut buffer)?;
let (id, record) = table.find(b"rootfs").ok_or("no rootfs volume")?;
let map = vec![0; usize::try_from(record.reserved_blocks)?];
let rootfs = image.volume(id, &record, map)?;
let mut magic = [0; 4];
rootfs.read_exact_at(0, &mut magic)?;Fields§
§source: R§block_size: u32§blocks: u32§offsets: HeaderOffsetsImplementations§
§impl<R: ReadAt> Image<R>
impl<R: ReadAt> Image<R>
pub fn new(
source: R,
block_size: u32,
offsets: HeaderOffsets,
) -> Result<Self, ImageError<R::Error>>
pub fn new( source: R, block_size: u32, offsets: HeaderOffsets, ) -> Result<Self, ImageError<R::Error>>
Opens the image in source.
block_size must be the erase block size of the flash the image was
built for, and every block with an EC header must have offsets. See
super::ImageReader::new.
§Errors
Returns ImageError::Offsets if the kernel rejects offsets for
this block size, ImageError::Size if the size of the image can’t
be read, ImageError::PartialBlock if the image ends in the middle
of a block and ImageError::TooManyBlocks if the image has more
blocks than fit into a u32.
pub fn into_inner(self) -> R
pub fn into_inner(self) -> R
Returns the source of the image.
pub fn volume_table<'b>(
&self,
buffer: &'b mut [u8],
) -> Result<VolumeTable<'b>, ImageError<R::Error>>
pub fn volume_table<'b>( &self, buffer: &'b mut [u8], ) -> Result<VolumeTable<'b>, ImageError<R::Error>>
Reads the volume table into buffer.
buffer must fit the table. VolumeTable::BUFFER_LEN bytes are
always enough. Like the kernel, it uses the copy in LEB 0 of the
layout volume, or the copy in LEB 1 if LEB 0 is invalid. An image
without any data has an empty table.
§Errors
Returns ImageError::BufferLength if buffer is too short,
ImageError::NoVolumeTable if the image contains data but no layout
volume, ImageError::VolumeTable if neither copy is valid, and
another error if a block can’t be read or has an invalid header.
pub fn volume<M: AsRef<[u32]> + AsMut<[u32]>>(
&self,
id: u32,
record: &VolumeRecord<'_>,
map: M,
) -> Result<VolumeReader<'_, R, M>, ImageError<R::Error>>
pub fn volume<M: AsRef<[u32]> + AsMut<[u32]>>( &self, id: u32, record: &VolumeRecord<'_>, map: M, ) -> Result<VolumeReader<'_, R, M>, ImageError<R::Error>>
Finds the blocks of volume id and returns a reader over its data.
record is the record of the volume in the volume table. map stores
the block of each logical eraseblock. It must have exactly
record.reserved_blocks entries, and their values are overwritten. Pass
a slice, an array or a Vec.
If two blocks contain the same logical eraseblock, it uses the one with the higher sequence number, like the kernel. If that block is a copy that wear leveling made and its data doesn’t match its CRC, it uses the other one.
§Errors
Returns ImageError::UpdateMarker if the volume has an unfinished
update, ImageError::BufferLength if map has the wrong length,
ImageError::Header if a block has an invalid header or doesn’t
match record, ImageError::DuplicateBlock if two blocks contain
the same logical eraseblock with the same sequence number,
ImageError::MissingBlock if a static volume misses a logical
eraseblock, and ImageError::Read if a block can’t be read.
fn scan(
&self,
id: u32,
map: &mut [u32],
each: impl FnMut(u32, &VidHeader) -> Result<(), ImageError<R::Error>>,
) -> Result<bool, ImageError<R::Error>>
fn scan( &self, id: u32, map: &mut [u32], each: impl FnMut(u32, &VidHeader) -> Result<(), ImageError<R::Error>>, ) -> Result<bool, ImageError<R::Error>>
Fills map with the blocks of volume id and calls each for each
block of the volume. Returns whether any block contains data.
fn vid_header(
&self,
block: u32,
headers: &mut ImageHeaders,
) -> Result<Option<VidHeader>, ImageError<R::Error>>
fn vid_header( &self, block: u32, headers: &mut ImageHeaders, ) -> Result<Option<VidHeader>, ImageError<R::Error>>
Reads the headers of block and returns its VID header, if it contains
data.
fn newer(
&self,
first: u32,
second: u32,
vid: &VidHeader,
) -> Result<u32, ImageError<R::Error>>
fn newer( &self, first: u32, second: u32, vid: &VidHeader, ) -> Result<u32, ImageError<R::Error>>
Returns which of two blocks with the same logical eraseblock the
kernel uses, like its ubi_compare_lebs.
fn data_crc_matches(
&self,
block: u32,
vid: &VidHeader,
) -> Result<bool, ImageError<R::Error>>
fn data_crc_matches( &self, block: u32, vid: &VidHeader, ) -> Result<bool, ImageError<R::Error>>
Returns whether the data of a copied block matches its CRC.