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 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
26// For simpler usage of Reader trait objects with Parser, we also implement the Reader trait
27// for Arc and Box. This allows callers of Parser::new to pass trait objects or real objects
28// without having to create custom wrappers or duplicate implementations.
29
30impl 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
42/// IoAdapter wraps any reader that supports std::io::{Read|Seek}.
43pub 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}