ext4_read_only/
readers.rs1use fuchsia_sync::Mutex;
6use log::error;
7use std::io::{Read, Seek, SeekFrom};
8use std::sync::Arc;
9use thiserror::Error;
10
11#[cfg(target_os = "fuchsia")]
12pub use self::fuchsia::*;
13
14#[derive(Error, Debug, PartialEq)]
15pub enum ReaderError {
16 #[error("Read error at: 0x{:X}", _0)]
17 Read(u64),
18 #[error("Out of bound read 0x{:X} when size is 0x{:X}", _0, _1)]
19 OutOfBounds(u64, u64),
20}
21
22pub trait Reader: Send + Sync {
23 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError>;
24}
25
26impl Reader for Box<dyn Reader> {
31 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
32 self.as_ref().read(offset, data)
33 }
34}
35
36impl Reader for Arc<dyn Reader> {
37 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
38 self.as_ref().read(offset, data)
39 }
40}
41
42pub struct IoAdapter<T>(Mutex<T>);
44
45impl<T> IoAdapter<T> {
46 pub fn new(inner: T) -> Self {
47 Self(Mutex::new(inner))
48 }
49}
50
51impl<T: Read + Seek + Send + Sync> Reader for IoAdapter<T> {
52 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
53 let mut reader = self.0.lock();
54 reader.seek(SeekFrom::Start(offset)).map_err(|_| ReaderError::Read(offset))?;
55 reader.read_exact(data).map_err(|_| ReaderError::Read(offset))
56 }
57}
58
59pub struct VecReader {
60 data: Vec<u8>,
61}
62
63impl Reader for VecReader {
64 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
65 let data_len = data.len() as u64;
66 let self_data_len = self.data.len() as u64;
67 let offset_max = offset + data_len;
68 if offset_max > self_data_len {
69 return Err(ReaderError::OutOfBounds(offset_max, self_data_len));
70 }
71
72 let offset_for_range: usize = offset.try_into().unwrap();
73
74 match self.data.get(offset_for_range..offset_for_range + data.len()) {
75 Some(slice) => {
76 data.clone_from_slice(slice);
77 Ok(())
78 }
79 None => Err(ReaderError::Read(offset)),
80 }
81 }
82}
83
84impl VecReader {
85 pub fn new(filesystem: Vec<u8>) -> Self {
86 VecReader { data: filesystem }
87 }
88}
89
90#[cfg(target_os = "fuchsia")]
91mod fuchsia {
92 use super::{Reader, ReaderError};
93 use anyhow::Error;
94 use block_client::{Cache, RemoteBlockClientSync};
95 use fidl::endpoints::ClientEnd;
96 use fidl_fuchsia_hardware_block::BlockMarker;
97 use fuchsia_sync::Mutex;
98 use log::error;
99 use std::sync::Arc;
100
101 pub struct VmoReader {
102 vmo: Arc<zx::Vmo>,
103 }
104
105 impl Reader for VmoReader {
106 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
107 match self.vmo.read(data, offset) {
108 Ok(_) => Ok(()),
109 Err(zx::Status::OUT_OF_RANGE) => {
110 let size = self.vmo.get_size().map_err(|_| ReaderError::Read(u64::MAX))?;
111 Err(ReaderError::OutOfBounds(offset, size))
112 }
113 Err(_) => Err(ReaderError::Read(offset)),
114 }
115 }
116 }
117
118 impl VmoReader {
119 pub fn new(vmo: Arc<zx::Vmo>) -> Self {
120 VmoReader { vmo }
121 }
122 }
123
124 pub struct BlockDeviceReader {
125 block_cache: Mutex<Cache>,
126 }
127
128 impl Reader for BlockDeviceReader {
129 fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
130 self.block_cache.lock().read_at(data, offset).map_err(|e| {
131 error!("Encountered error while reading block device: {}", e);
132 ReaderError::Read(offset)
133 })
134 }
135 }
136
137 impl BlockDeviceReader {
138 pub fn from_client_end(client_end: ClientEnd<BlockMarker>) -> Result<Self, Error> {
139 Ok(Self {
140 block_cache: Mutex::new(Cache::new(RemoteBlockClientSync::new(client_end)?)?),
141 })
142 }
143 }
144}