ext4_read_only/
readers.rs

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