lamexfat 0.1.0

no_std read-only exFAT reader for UEFI bootloaders (removable media)
Documentation
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The `BlockRead` trait — the byte source `lamexfat` reads a volume through.

/// Block-level reads for a mounted volume.
///
/// `lamexfat` never seeks; it asks for a byte range starting at an absolute
/// offset and expects the implementor to fill the whole buffer. Identical in
/// shape to `lambutter::BlockRead` / `lamxfs::BlockRead`, so a consumer that
/// already provides one needs only a one-line adapter to satisfy all of them.
pub trait BlockRead {
    /// Error type surfaced by the underlying device.
    type Error: core::fmt::Debug;

    /// Fill `buf` entirely from the volume starting at `offset_bytes`. A short
    /// read (fewer bytes available than `buf.len()`) is an error — the caller
    /// always sizes `buf` to exactly the range it needs.
    fn read_at(&mut self, offset_bytes: u64, buf: &mut [u8]) -> Result<(), Self::Error>;
}

/// Fill `buf` from the volume at `off`, mapping any device failure to a typed
/// [`Error::Io`](crate::error::Error::Io) carrying the stable `token` — the one
/// place the `R::Error` is dropped, at the `lamexfat` boundary.
pub(crate) fn read_exact<R: BlockRead>(
    reader: &mut R,
    off: u64,
    buf: &mut [u8],
    token: &'static str,
) -> crate::error::Result<()> {
    reader
        .read_at(off, buf)
        .map_err(|_| crate::error::Error::Io { token, offset: off })
}

// Little-endian on-disk accessors (exFAT is little-endian). Each returns `None`
// on an out-of-range offset so the caller surfaces a typed error rather than
// panicking on hostile media.
#[inline]
pub(crate) fn u16_at(b: &[u8], o: usize) -> Option<u16> {
    b.get(o..o + 2)?.try_into().ok().map(u16::from_le_bytes)
}
#[inline]
pub(crate) fn u32_at(b: &[u8], o: usize) -> Option<u32> {
    b.get(o..o + 4)?.try_into().ok().map(u32::from_le_bytes)
}
#[inline]
pub(crate) fn u64_at(b: &[u8], o: usize) -> Option<u64> {
    b.get(o..o + 8)?.try_into().ok().map(u64::from_le_bytes)
}