Skip to main content

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    #[error("Write error at: 0x{:X}", _0)]
20    Write(u64),
21    #[error("{} not supported", _0)]
22    NotSupported(String),
23    #[error("Write flush error")]
24    WriteFlush,
25}
26
27pub trait Reader: Send + Sync {
28    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError>;
29}
30
31// For simpler usage of Reader trait objects with Parser, we also implement the Reader trait
32// for Arc and Box. This allows callers of Parser::new to pass trait objects or real objects
33// without having to create custom wrappers or duplicate implementations.
34impl Reader for Box<dyn Reader> {
35    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
36        self.as_ref().read(offset, data)
37    }
38}
39
40impl Reader for Arc<dyn Reader> {
41    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
42        self.as_ref().read(offset, data)
43    }
44}
45
46// Same as Reader but has write capability.
47pub trait ReaderWriter: Reader {
48    fn write(&self, _offset: u64, _data: &[u8]) -> Result<(), ReaderError> {
49        Err(ReaderError::NotSupported("Write".to_string()))
50    }
51    fn sync(&self) -> Result<(), ReaderError> {
52        Ok(())
53    }
54}
55
56impl Reader for Box<dyn ReaderWriter> {
57    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
58        self.as_ref().read(offset, data)
59    }
60}
61
62impl ReaderWriter for Box<dyn ReaderWriter> {
63    fn write(&self, offset: u64, data: &[u8]) -> Result<(), ReaderError> {
64        self.as_ref().write(offset, data)
65    }
66    fn sync(&self) -> Result<(), ReaderError> {
67        self.as_ref().sync()
68    }
69}
70
71impl Reader for Arc<dyn ReaderWriter> {
72    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
73        self.as_ref().read(offset, data)
74    }
75}
76
77impl ReaderWriter for Arc<dyn ReaderWriter> {
78    fn write(&self, offset: u64, data: &[u8]) -> Result<(), ReaderError> {
79        self.as_ref().write(offset, data)
80    }
81    fn sync(&self) -> Result<(), ReaderError> {
82        self.as_ref().sync()
83    }
84}
85
86/// IoAdapter wraps any reader that supports std::io::{Read|Seek}.
87pub struct IoAdapter<T>(Mutex<T>);
88
89impl<T> IoAdapter<T> {
90    pub fn new(inner: T) -> Self {
91        Self(Mutex::new(inner))
92    }
93}
94
95impl<T: Read + Seek + Send + Sync> Reader for IoAdapter<T> {
96    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
97        let mut reader = self.0.lock();
98        reader.seek(SeekFrom::Start(offset)).map_err(|_| ReaderError::Read(offset))?;
99        reader.read_exact(data).map_err(|_| ReaderError::Read(offset))
100    }
101}
102
103impl<T: Read + Seek + Send + Sync> ReaderWriter for IoAdapter<T> {}
104
105pub struct VecReader {
106    data: Vec<u8>,
107}
108
109impl Reader for VecReader {
110    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
111        let data_len = data.len() as u64;
112        let self_data_len = self.data.len() as u64;
113        let offset_max = offset + data_len;
114        if offset_max > self_data_len {
115            return Err(ReaderError::OutOfBounds(offset_max, self_data_len));
116        }
117
118        let offset_for_range: usize = offset.try_into().unwrap();
119
120        match self.data.get(offset_for_range..offset_for_range + data.len()) {
121            Some(slice) => {
122                data.clone_from_slice(slice);
123                Ok(())
124            }
125            None => Err(ReaderError::Read(offset)),
126        }
127    }
128}
129
130impl ReaderWriter for VecReader {
131    fn write(&self, _offset: u64, _data: &[u8]) -> Result<(), ReaderError> {
132        Err(ReaderError::NotSupported("Write".to_string()))
133    }
134}
135
136impl VecReader {
137    pub fn new(filesystem: Vec<u8>) -> Self {
138        VecReader { data: filesystem }
139    }
140}
141
142#[cfg(target_os = "fuchsia")]
143mod fuchsia {
144    use super::{Reader, ReaderError, ReaderWriter};
145    use anyhow::Error;
146    use block_client::{Cache, RemoteBlockClientSync};
147    use fidl::endpoints::ClientEnd;
148    use fidl_fuchsia_storage_block::BlockMarker;
149    use fuchsia_sync::Mutex;
150    use log::error;
151    use std::io::Write as _;
152    use std::sync::Arc;
153
154    pub struct VmoReader {
155        vmo: Arc<zx::Vmo>,
156    }
157
158    impl Reader for VmoReader {
159        fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
160            match self.vmo.read(data, offset) {
161                Ok(_) => Ok(()),
162                Err(zx::Status::OUT_OF_RANGE) => {
163                    let size = self.vmo.get_size().map_err(|_| ReaderError::Read(u64::MAX))?;
164                    Err(ReaderError::OutOfBounds(offset, size))
165                }
166                Err(_) => Err(ReaderError::Read(offset)),
167            }
168        }
169    }
170
171    impl ReaderWriter for VmoReader {
172        fn write(&self, _offset: u64, _data: &[u8]) -> Result<(), ReaderError> {
173            Err(ReaderError::NotSupported("Write".to_string()))
174        }
175    }
176
177    impl VmoReader {
178        pub fn new(vmo: Arc<zx::Vmo>) -> Self {
179            VmoReader { vmo }
180        }
181    }
182
183    pub struct BlockDeviceReader {
184        block_cache: Mutex<Cache>,
185    }
186
187    impl Reader for BlockDeviceReader {
188        fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
189            self.block_cache.lock().read_at(data, offset).map_err(|e| {
190                error!("Encountered error while reading block device: {}", e);
191                ReaderError::Read(offset)
192            })
193        }
194    }
195
196    impl ReaderWriter for BlockDeviceReader {
197        fn write(&self, offset: u64, data: &[u8]) -> Result<(), ReaderError> {
198            self.block_cache.lock().write_at(data, offset).map_err(|e| {
199                error!("Encountered error while writing block device: {}", e);
200                ReaderError::Write(offset)
201            })
202        }
203
204        fn sync(&self) -> Result<(), ReaderError> {
205            self.block_cache.lock().flush().map_err(|e| {
206                error!("Encountered error while flushing block cache: {}", e);
207                ReaderError::WriteFlush
208            })
209        }
210    }
211
212    impl BlockDeviceReader {
213        pub fn from_client_end(client_end: ClientEnd<BlockMarker>) -> Result<Self, Error> {
214            Ok(Self {
215                block_cache: Mutex::new(Cache::new(RemoteBlockClientSync::new(client_end)?)?),
216            })
217        }
218    }
219}