1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use std::cmp::min;
18 use std::convert::TryFrom;
19 use std::io;
20 use std::path::Path;
21 
22 use super::{ChunkBuffer, RandomWrite, ReadByChunk, VirtFdService};
23 use crate::common::CHUNK_SIZE;
24 
remote_read_chunk( service: &VirtFdService, remote_fd: i32, chunk_index: u64, buf: &mut ChunkBuffer, ) -> io::Result<usize>25 fn remote_read_chunk(
26     service: &VirtFdService,
27     remote_fd: i32,
28     chunk_index: u64,
29     buf: &mut ChunkBuffer,
30 ) -> io::Result<usize> {
31     let offset = i64::try_from(chunk_index * CHUNK_SIZE)
32         .map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
33 
34     let chunk = service
35         .readFile(remote_fd, offset, buf.len() as i32)
36         .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
37     let size = min(buf.len(), chunk.len());
38     buf[..size].copy_from_slice(&chunk[..size]);
39     Ok(size)
40 }
41 
42 pub struct RemoteFileReader {
43     service: VirtFdService,
44     file_fd: i32,
45 }
46 
47 impl RemoteFileReader {
new(service: VirtFdService, file_fd: i32) -> Self48     pub fn new(service: VirtFdService, file_fd: i32) -> Self {
49         RemoteFileReader { service, file_fd }
50     }
51 
new_by_path( service: VirtFdService, dir_fd: i32, related_path: &Path, ) -> io::Result<Self>52     pub fn new_by_path(
53         service: VirtFdService,
54         dir_fd: i32,
55         related_path: &Path,
56     ) -> io::Result<Self> {
57         let file_fd =
58             service.openFileInDirectory(dir_fd, related_path.to_str().unwrap()).map_err(|e| {
59                 io::Error::new(
60                     io::ErrorKind::Other,
61                     format!(
62                         "Failed to create a remote file reader by path {}: {}",
63                         related_path.display(),
64                         e.get_description()
65                     ),
66                 )
67             })?;
68         Ok(RemoteFileReader { service, file_fd })
69     }
70 
get_remote_fd(&self) -> i3271     pub fn get_remote_fd(&self) -> i32 {
72         self.file_fd
73     }
74 }
75 
76 impl ReadByChunk for RemoteFileReader {
read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize>77     fn read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize> {
78         remote_read_chunk(&self.service, self.file_fd, chunk_index, buf)
79     }
80 }
81 
82 pub struct RemoteMerkleTreeReader {
83     service: VirtFdService,
84     file_fd: i32,
85 }
86 
87 impl RemoteMerkleTreeReader {
new(service: VirtFdService, file_fd: i32) -> Self88     pub fn new(service: VirtFdService, file_fd: i32) -> Self {
89         RemoteMerkleTreeReader { service, file_fd }
90     }
91 }
92 
93 impl ReadByChunk for RemoteMerkleTreeReader {
read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize>94     fn read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize> {
95         let offset = i64::try_from(chunk_index * CHUNK_SIZE)
96             .map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
97 
98         let chunk = self
99             .service
100             .readFsverityMerkleTree(self.file_fd, offset, buf.len() as i32)
101             .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
102         let size = min(buf.len(), chunk.len());
103         buf[..size].copy_from_slice(&chunk[..size]);
104         Ok(size)
105     }
106 }
107 
108 pub struct RemoteFileEditor {
109     service: VirtFdService,
110     file_fd: i32,
111 }
112 
113 impl RemoteFileEditor {
new(service: VirtFdService, file_fd: i32) -> Self114     pub fn new(service: VirtFdService, file_fd: i32) -> Self {
115         RemoteFileEditor { service, file_fd }
116     }
117 }
118 
119 impl RandomWrite for RemoteFileEditor {
write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>120     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
121         let offset =
122             i64::try_from(offset).map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
123         let size = self
124             .service
125             .writeFile(self.file_fd, buf, offset)
126             .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
127         Ok(size as usize) // within range because size is supposed to <= buf.len(), which is a usize
128     }
129 
resize(&self, size: u64) -> io::Result<()>130     fn resize(&self, size: u64) -> io::Result<()> {
131         let size =
132             i64::try_from(size).map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
133         self.service
134             .resize(self.file_fd, size)
135             .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
136         Ok(())
137     }
138 }
139 
140 impl ReadByChunk for RemoteFileEditor {
read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize>141     fn read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize> {
142         remote_read_chunk(&self.service, self.file_fd, chunk_index, buf)
143     }
144 }
145