Skip to main content

erofs/
readers.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::ops::Range;
6use std::sync::Arc;
7use thiserror::Error;
8use zerocopy::{FromBytes, IntoBytes};
9
10/// Errors that can occur during reading from a reader.
11#[derive(Error, Debug, Clone, PartialEq)]
12pub enum ReaderError {
13    #[error("Failed to set up reader with status: {}", _0)]
14    Setup(zx::Status),
15    #[error("Read error at 0x{:X}..0x{:X} with status: {}", _0.start, _0.end, _1)]
16    Read(Range<u64>, zx::Status),
17    #[error("Out of bound read 0x{:X}..0x{:X} when size is 0x{:X}", _0.start, _0.end, _1)]
18    OutOfBounds(Range<u64>, u64),
19}
20
21/// A reader for reading data from a source.
22pub trait Reader: Send + Sync {
23    /// Reads `data.len()` bytes from the reader at the given `offset`.
24    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError>;
25}
26
27pub trait ReaderExt {
28    fn read_object<T>(&self, offset: u64) -> Result<T, ReaderError>
29    where
30        T: FromBytes + IntoBytes + Sized;
31}
32
33impl ReaderExt for dyn Reader + '_ {
34    fn read_object<T>(&self, offset: u64) -> Result<T, ReaderError>
35    where
36        T: FromBytes + IntoBytes + Sized,
37    {
38        let mut object = T::new_zeroed();
39        self.read(offset, object.as_mut_bytes())?;
40        Ok(object)
41    }
42}
43
44impl Reader for Box<dyn Reader> {
45    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
46        self.as_ref().read(offset, data)
47    }
48}
49
50impl Reader for Arc<dyn Reader> {
51    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
52        self.as_ref().read(offset, data)
53    }
54}
55
56/// A reader that reads from a vector of bytes.
57pub struct VecReader {
58    data: Vec<u8>,
59}
60
61impl Reader for VecReader {
62    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
63        let data_len = data.len() as u64;
64        let self_data_len = self.data.len() as u64;
65        let offset_max = offset + data_len;
66        if offset_max > self_data_len {
67            return Err(ReaderError::OutOfBounds(offset..offset_max, self_data_len));
68        }
69
70        let offset_for_range: usize = offset.try_into().unwrap();
71        // UNWRAP SAFETY: we already checked the bounds.
72        let slice = self.data.get(offset_for_range..offset_for_range + data.len()).unwrap();
73        data.clone_from_slice(slice);
74        Ok(())
75    }
76}
77
78impl VecReader {
79    /// Creates a new reader from a vector of bytes.
80    pub fn new(filesystem: Vec<u8>) -> Self {
81        VecReader { data: filesystem }
82    }
83}
84
85/// A reader that reads from a VMO.
86pub struct VmoReader {
87    vmo: Arc<zx::Vmo>,
88    size: u64,
89}
90
91impl Reader for VmoReader {
92    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
93        match self.vmo.read(data, offset) {
94            Ok(_) => Ok(()),
95            Err(zx::Status::OUT_OF_RANGE) => {
96                Err(ReaderError::OutOfBounds(offset..offset + data.len() as u64, self.size))
97            }
98            Err(status) => Err(ReaderError::Read(offset..offset + data.len() as u64, status)),
99        }
100    }
101}
102
103impl VmoReader {
104    /// Creates a new reader from a VMO.
105    pub fn new(vmo: Arc<zx::Vmo>) -> Result<Self, ReaderError> {
106        let size = vmo.get_size().map_err(|status| ReaderError::Setup(status))?;
107        Ok(VmoReader { vmo, size })
108    }
109}