ext4_read_only/
readers.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::io::{Read, Seek, SeekFrom};
use std::sync::{Arc, Mutex};
use thiserror::Error;
use tracing::error;

#[cfg(target_os = "fuchsia")]
pub use self::fuchsia::*;

#[derive(Error, Debug, PartialEq)]
pub enum ReaderError {
    #[error("Read error at: 0x{:X}", _0)]
    Read(u64),
    #[error("Out of bound read 0x{:X} when size is 0x{:X}", _0, _1)]
    OutOfBounds(u64, u64),
}

pub trait Reader: Send + Sync {
    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError>;
}

// For simpler usage of Reader trait objects with Parser, we also implement the Reader trait
// for Arc and Box. This allows callers of Parser::new to pass trait objects or real objects
// without having to create custom wrappers or duplicate implementations.

impl Reader for Box<dyn Reader> {
    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
        self.as_ref().read(offset, data)
    }
}

impl Reader for Arc<dyn Reader> {
    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
        self.as_ref().read(offset, data)
    }
}

/// IoAdapter wraps any reader that supports std::io::{Read|Seek}.
pub struct IoAdapter<T>(Mutex<T>);

impl<T> IoAdapter<T> {
    pub fn new(inner: T) -> Self {
        Self(Mutex::new(inner))
    }
}

impl<T: Read + Seek + Send + Sync> Reader for IoAdapter<T> {
    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
        let mut reader = self.0.lock().unwrap();
        reader.seek(SeekFrom::Start(offset)).map_err(|_| ReaderError::Read(offset))?;
        reader.read_exact(data).map_err(|_| ReaderError::Read(offset))
    }
}

pub struct VecReader {
    data: Vec<u8>,
}

impl Reader for VecReader {
    fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
        let data_len = data.len() as u64;
        let self_data_len = self.data.len() as u64;
        let offset_max = offset + data_len;
        if offset_max > self_data_len {
            return Err(ReaderError::OutOfBounds(offset_max, self_data_len));
        }

        let offset_for_range: usize = offset.try_into().unwrap();

        match self.data.get(offset_for_range..offset_for_range + data.len()) {
            Some(slice) => {
                data.clone_from_slice(slice);
                Ok(())
            }
            None => Err(ReaderError::Read(offset)),
        }
    }
}

impl VecReader {
    pub fn new(filesystem: Vec<u8>) -> Self {
        VecReader { data: filesystem }
    }
}

#[cfg(target_os = "fuchsia")]
mod fuchsia {
    use super::{Reader, ReaderError};
    use anyhow::Error;
    use block_client::{Cache, RemoteBlockClientSync};
    use fidl::endpoints::ClientEnd;
    use fidl_fuchsia_hardware_block::BlockMarker;

    use std::sync::{Arc, Mutex};
    use tracing::error;

    pub struct VmoReader {
        vmo: Arc<zx::Vmo>,
    }

    impl Reader for VmoReader {
        fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
            match self.vmo.read(data, offset) {
                Ok(_) => Ok(()),
                Err(zx::Status::OUT_OF_RANGE) => {
                    let size = self.vmo.get_size().map_err(|_| ReaderError::Read(u64::MAX))?;
                    Err(ReaderError::OutOfBounds(offset, size))
                }
                Err(_) => Err(ReaderError::Read(offset)),
            }
        }
    }

    impl VmoReader {
        pub fn new(vmo: Arc<zx::Vmo>) -> Self {
            VmoReader { vmo }
        }
    }

    pub struct BlockDeviceReader {
        block_cache: Mutex<Cache>,
    }

    impl Reader for BlockDeviceReader {
        fn read(&self, offset: u64, data: &mut [u8]) -> Result<(), ReaderError> {
            self.block_cache.lock().unwrap().read_at(data, offset).map_err(|e| {
                error!("Encountered error while reading block device: {}", e);
                ReaderError::Read(offset)
            })
        }
    }

    impl BlockDeviceReader {
        pub fn from_client_end(client_end: ClientEnd<BlockMarker>) -> Result<Self, Error> {
            Ok(Self {
                block_cache: Mutex::new(Cache::new(RemoteBlockClientSync::new(client_end)?)?),
            })
        }
    }
}