authfs: Reorganize modules & rename flags/classes/vars

This change adjusts the module/directory layout to make it easier to
reason.

 - File "transports" are now under file/. Common traits are defined in
   file.rs.

 - All fs-verity related modules are now under fsverity/. This includes
   VerifiedFileReader, which implements traits in the file module to
   provide transparent verification.

 - Rename structs for better consistency.  Drop "Chunked" for
   simplicity.

    ChunkedFileReader          ->  LocalFileReader
    RemoteChunkedFileReader    ->  RemoteFileReader
    FsverityChunkedFileReader  ->  VerifiedFileReader

 - Move and rename get_local_service from remote_file.rs to file.rs.

Also, rename command line flags and related class/field names in main.rs
so that later the name of new read-writable file can fit in more consistently.

New layours:
  src/
  |-- auth.rs
  |-- common.rs
  |-- crypto.hpp
  |-- crypto.rs
  |-- file.rs
  |-- file
  |   |-- local_file.rs
  |   `-- remote_file.rs
  |-- fsverity.rs
  |-- fsverity
  |   |-- builder.rs
  |   |-- common.rs
  |   |-- sys.rs
  |   |-- verifier.rs
  |   `-- editor.rs
  |-- fusefs.rs
  `-- main.rs

Bug: 171279640
Test: atest

Change-Id: Ib257a37df89c6b813f4d97978678db3483d28b57
diff --git a/authfs/src/file/local_file.rs b/authfs/src/file/local_file.rs
new file mode 100644
index 0000000..0692767
--- /dev/null
+++ b/authfs/src/file/local_file.rs
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::fs::File;
+use std::io::Result;
+use std::os::unix::fs::FileExt;
+
+use super::ReadOnlyDataByChunk;
+use crate::common::CHUNK_SIZE;
+
+fn chunk_index_to_range(size: u64, chunk_index: u64) -> Result<(u64, u64)> {
+    let start = chunk_index * CHUNK_SIZE;
+    assert!(start < size);
+    let end = std::cmp::min(size, start + CHUNK_SIZE);
+    Ok((start, end))
+}
+
+/// A read-only file that can be read by chunks.
+pub struct LocalFileReader {
+    file: File,
+    size: u64,
+}
+
+impl LocalFileReader {
+    /// Creates a `LocalFileReader` to read from for the specified `path`.
+    pub fn new(file: File) -> Result<LocalFileReader> {
+        let size = file.metadata()?.len();
+        Ok(LocalFileReader { file, size })
+    }
+
+    pub fn len(&self) -> u64 {
+        self.size
+    }
+}
+
+impl ReadOnlyDataByChunk for LocalFileReader {
+    fn read_chunk(&self, chunk_index: u64, buf: &mut [u8]) -> Result<usize> {
+        debug_assert!(buf.len() as u64 >= CHUNK_SIZE);
+        let (start, end) = chunk_index_to_range(self.size, chunk_index)?;
+        let size = (end - start) as usize;
+        self.file.read_at(&mut buf[..size], start)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::env::temp_dir;
+
+    #[test]
+    fn test_read_4k_file() -> Result<()> {
+        let file_reader = LocalFileReader::new(File::open("testdata/input.4k")?)?;
+        let mut buf = [0u8; 4096];
+        let size = file_reader.read_chunk(0, &mut buf)?;
+        assert_eq!(size, buf.len());
+        Ok(())
+    }
+
+    #[test]
+    fn test_read_4k1_file() -> Result<()> {
+        let file_reader = LocalFileReader::new(File::open("testdata/input.4k1")?)?;
+        let mut buf = [0u8; 4096];
+        let size = file_reader.read_chunk(0, &mut buf)?;
+        assert_eq!(size, buf.len());
+        let size = file_reader.read_chunk(1, &mut buf)?;
+        assert_eq!(size, 1);
+        Ok(())
+    }
+
+    #[test]
+    fn test_read_4m_file() -> Result<()> {
+        let file_reader = LocalFileReader::new(File::open("testdata/input.4m")?)?;
+        for index in 0..file_reader.len() / 4096 {
+            let mut buf = [0u8; 4096];
+            let size = file_reader.read_chunk(index, &mut buf)?;
+            assert_eq!(size, buf.len());
+        }
+        Ok(())
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_read_beyond_file_size() {
+        let file_reader = LocalFileReader::new(File::open("testdata/input.4k").unwrap()).unwrap();
+        let mut buf = [0u8; 4096];
+        let _ = file_reader.read_chunk(1u64, &mut buf); // should panic
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_read_empty_file() {
+        let mut temp_file = temp_dir();
+        temp_file.push("authfs_test_empty_file");
+        let file_reader = LocalFileReader::new(File::create(temp_file).unwrap()).unwrap();
+        let mut buf = [0u8; 4096];
+        let _ = file_reader.read_chunk(0, &mut buf); // should panic
+    }
+}
diff --git a/authfs/src/file/remote_file.rs b/authfs/src/file/remote_file.rs
new file mode 100644
index 0000000..b87891b
--- /dev/null
+++ b/authfs/src/file/remote_file.rs
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::convert::TryFrom;
+use std::io;
+use std::io::Write;
+use std::sync::{Arc, Mutex};
+
+use super::{RandomWrite, ReadOnlyDataByChunk};
+use crate::common::CHUNK_SIZE;
+
+use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService;
+use authfs_aidl_interface::binder::Strong;
+
+type VirtFdService = Strong<dyn IVirtFdService::IVirtFdService>;
+
+fn remote_read_chunk(
+    service: &Arc<Mutex<VirtFdService>>,
+    remote_fd: i32,
+    chunk_index: u64,
+    mut buf: &mut [u8],
+) -> io::Result<usize> {
+    let offset = i64::try_from(chunk_index * CHUNK_SIZE)
+        .map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
+
+    let chunk = service
+        .lock()
+        .unwrap()
+        .readFile(remote_fd, offset, buf.len() as i32)
+        .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
+    buf.write(&chunk)
+}
+
+pub struct RemoteFileReader {
+    // This needs to have Sync trait to be used in fuse::worker::start_message_loop.
+    service: Arc<Mutex<VirtFdService>>,
+    file_fd: i32,
+}
+
+impl RemoteFileReader {
+    pub fn new(service: Arc<Mutex<VirtFdService>>, file_fd: i32) -> Self {
+        RemoteFileReader { service, file_fd }
+    }
+}
+
+impl ReadOnlyDataByChunk for RemoteFileReader {
+    fn read_chunk(&self, chunk_index: u64, buf: &mut [u8]) -> io::Result<usize> {
+        remote_read_chunk(&self.service, self.file_fd, chunk_index, buf)
+    }
+}
+
+pub struct RemoteMerkleTreeReader {
+    // This needs to be a Sync to be used in fuse::worker::start_message_loop.
+    // TODO(victorhsieh): change to Strong<> once binder supports it.
+    service: Arc<Mutex<VirtFdService>>,
+    file_fd: i32,
+}
+
+impl RemoteMerkleTreeReader {
+    pub fn new(service: Arc<Mutex<VirtFdService>>, file_fd: i32) -> Self {
+        RemoteMerkleTreeReader { service, file_fd }
+    }
+}
+
+impl ReadOnlyDataByChunk for RemoteMerkleTreeReader {
+    fn read_chunk(&self, chunk_index: u64, mut buf: &mut [u8]) -> io::Result<usize> {
+        let offset = i64::try_from(chunk_index * CHUNK_SIZE)
+            .map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
+
+        let chunk = self
+            .service
+            .lock()
+            .unwrap()
+            .readFsverityMerkleTree(self.file_fd, offset, buf.len() as i32)
+            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
+        buf.write(&chunk)
+    }
+}
+
+pub struct RemoteFileEditor {
+    // This needs to have Sync trait to be used in fuse::worker::start_message_loop.
+    service: Arc<Mutex<VirtFdService>>,
+    file_fd: i32,
+}
+
+impl RemoteFileEditor {
+    #[allow(dead_code)]
+    pub fn new(service: Arc<Mutex<VirtFdService>>, file_fd: i32) -> Self {
+        RemoteFileEditor { service, file_fd }
+    }
+}
+
+impl RandomWrite for RemoteFileEditor {
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        let offset =
+            i64::try_from(offset).map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
+        let size = self
+            .service
+            .lock()
+            .unwrap()
+            .writeFile(self.file_fd, &buf, offset)
+            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
+        Ok(size as usize) // within range because size is supposed to <= buf.len(), which is a usize
+    }
+}
+
+impl ReadOnlyDataByChunk for RemoteFileEditor {
+    fn read_chunk(&self, chunk_index: u64, buf: &mut [u8]) -> io::Result<usize> {
+        remote_read_chunk(&self.service, self.file_fd, chunk_index, buf)
+    }
+}