1 /* 2 * Copyright (C) 2022 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 log::error; 18 use std::convert::TryInto; 19 use std::io; 20 use std::path::PathBuf; 21 use std::sync::Mutex; 22 23 use crate::file::{ 24 ChunkBuffer, EagerChunkReader, ReadByChunk, RemoteFileReader, RemoteMerkleTreeReader, 25 VirtFdService, 26 }; 27 use crate::fsverity::{merkle_tree_size, VerifiedFileReader}; 28 29 enum FileInfo { 30 ByPathUnderDirFd(i32, PathBuf), 31 ByFd(i32), 32 } 33 34 type Reader = VerifiedFileReader<RemoteFileReader, EagerChunkReader>; 35 36 /// A lazily created read-only file that is verified against the given fs-verity digest. 37 /// 38 /// The main purpose of this struct is to wrap and construct `VerifiedFileReader` lazily. 39 pub struct LazyVerifiedReadonlyFile { 40 expected_digest: Vec<u8>, 41 42 service: VirtFdService, 43 file_info: FileInfo, 44 45 /// A lazily instantiated reader. 46 reader: Mutex<Option<Reader>>, 47 } 48 49 impl LazyVerifiedReadonlyFile { 50 /// Prepare the file by a remote path, related to a remote directory FD. prepare_by_path( service: VirtFdService, remote_dir_fd: i32, remote_path: PathBuf, expected_digest: Vec<u8>, ) -> Self51 pub fn prepare_by_path( 52 service: VirtFdService, 53 remote_dir_fd: i32, 54 remote_path: PathBuf, 55 expected_digest: Vec<u8>, 56 ) -> Self { 57 LazyVerifiedReadonlyFile { 58 service, 59 file_info: FileInfo::ByPathUnderDirFd(remote_dir_fd, remote_path), 60 expected_digest, 61 reader: Mutex::new(None), 62 } 63 } 64 65 /// Prepare the file by a remote file FD. prepare_by_fd(service: VirtFdService, remote_fd: i32, expected_digest: Vec<u8>) -> Self66 pub fn prepare_by_fd(service: VirtFdService, remote_fd: i32, expected_digest: Vec<u8>) -> Self { 67 LazyVerifiedReadonlyFile { 68 service, 69 file_info: FileInfo::ByFd(remote_fd), 70 expected_digest, 71 reader: Mutex::new(None), 72 } 73 } 74 ensure_init_then<F, T>(&self, callback: F) -> io::Result<T> where F: FnOnce(&Reader) -> io::Result<T>,75 fn ensure_init_then<F, T>(&self, callback: F) -> io::Result<T> 76 where 77 F: FnOnce(&Reader) -> io::Result<T>, 78 { 79 let mut reader = self.reader.lock().unwrap(); 80 if reader.is_none() { 81 let remote_file = match &self.file_info { 82 FileInfo::ByPathUnderDirFd(dir_fd, related_path) => { 83 RemoteFileReader::new_by_path(self.service.clone(), *dir_fd, related_path)? 84 } 85 FileInfo::ByFd(file_fd) => RemoteFileReader::new(self.service.clone(), *file_fd), 86 }; 87 let remote_fd = remote_file.get_remote_fd(); 88 let file_size = self 89 .service 90 .getFileSize(remote_fd) 91 .map_err(|e| { 92 error!("Failed to get file size of remote fd {}: {}", remote_fd, e); 93 io::Error::from_raw_os_error(libc::EIO) 94 })? 95 .try_into() 96 .map_err(|e| { 97 error!("Failed convert file size: {}", e); 98 io::Error::from_raw_os_error(libc::EIO) 99 })?; 100 let instance = VerifiedFileReader::new( 101 remote_file, 102 file_size, 103 &self.expected_digest, 104 EagerChunkReader::new( 105 RemoteMerkleTreeReader::new(self.service.clone(), remote_fd), 106 merkle_tree_size(file_size), 107 )?, 108 ) 109 .map_err(|e| { 110 error!("Failed instantiate a verified file reader: {}", e); 111 io::Error::from_raw_os_error(libc::EIO) 112 })?; 113 *reader = Some(instance); 114 } 115 callback(reader.as_ref().unwrap()) 116 } 117 file_size(&self) -> io::Result<u64>118 pub fn file_size(&self) -> io::Result<u64> { 119 self.ensure_init_then(|reader| Ok(reader.file_size)) 120 } 121 } 122 123 impl ReadByChunk for LazyVerifiedReadonlyFile { read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize>124 fn read_chunk(&self, chunk_index: u64, buf: &mut ChunkBuffer) -> io::Result<usize> { 125 self.ensure_init_then(|reader| reader.read_chunk(chunk_index, buf)) 126 } 127 } 128