authfs: Implement VerifiedFileEditor
VerifiedFileEditor is a logical file writer + reader that maintains
content integrity by leveraging MerkleLeaves in private memory. The
implementation manages the complexity of integrity and consistency,
regardless of where the actual data is stored (up to the implementation
of `writer:: RandomWrite` trait.
Major changes:
- writer.rs: implements VerifiedFileEditor
- common.rs: added ChunkedSizeIter which is renamed from fusefs.rs
Bug: 171279640
Test: atest authfs_device_test_src_lib
Change-Id: I7bcb0cd9404d2b5c18b6dc0837ee23847262a4f7
diff --git a/authfs/src/fusefs.rs b/authfs/src/fusefs.rs
index f5dd6ec..bbcb84f 100644
--- a/authfs/src/fusefs.rs
+++ b/authfs/src/fusefs.rs
@@ -29,7 +29,7 @@
use fuse::filesystem::{Context, DirEntry, DirectoryIterator, Entry, FileSystem, ZeroCopyWriter};
use fuse::mount::MountOption;
-use crate::common::{divide_roundup, CHUNK_SIZE};
+use crate::common::{divide_roundup, ChunkedSizeIter, CHUNK_SIZE};
use crate::fsverity::FsverityChunkedFileReader;
use crate::reader::{ChunkedFileReader, ReadOnlyDataByChunk};
use crate::remote_file::{RemoteChunkedFileReader, RemoteFsverityMerkleTreeReader};
@@ -111,35 +111,6 @@
Ok(st)
}
-/// An iterator that generates (offset, size) for a chunked read operation, where offset is the
-/// global file offset, and size is the amount of read from the offset.
-struct ChunkReadIter {
- remaining: usize,
- offset: u64,
-}
-
-impl ChunkReadIter {
- pub fn new(remaining: usize, offset: u64) -> Self {
- ChunkReadIter { remaining, offset }
- }
-}
-
-impl Iterator for ChunkReadIter {
- type Item = (u64, usize);
-
- fn next(&mut self) -> Option<Self::Item> {
- if self.remaining == 0 {
- return None;
- }
- let chunk_data_size =
- std::cmp::min(self.remaining, (CHUNK_SIZE - self.offset % CHUNK_SIZE) as usize);
- let retval = (self.offset, chunk_data_size);
- self.offset += chunk_data_size as u64;
- self.remaining = self.remaining.saturating_sub(chunk_data_size);
- Some(retval)
- }
-}
-
fn offset_to_chunk_index(offset: u64) -> u64 {
offset / CHUNK_SIZE
}
@@ -153,7 +124,7 @@
) -> io::Result<usize> {
let remaining = file_size.saturating_sub(offset);
let size_to_read = std::cmp::min(size as usize, remaining as usize);
- let total = ChunkReadIter::new(size_to_read, offset).try_fold(
+ let total = ChunkedSizeIter::new(size_to_read, offset, CHUNK_SIZE as usize).try_fold(
0,
|total, (current_offset, planned_data_size)| {
// TODO(victorhsieh): There might be a non-trivial way to avoid this copy. For example,
@@ -325,27 +296,3 @@
AuthFs::new(file_pool, max_write),
)
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn collect_chunk_read_iter(remaining: usize, offset: u64) -> Vec<(u64, usize)> {
- ChunkReadIter::new(remaining, offset).collect::<Vec<_>>()
- }
-
- #[test]
- fn test_chunk_read_iter() {
- assert_eq!(collect_chunk_read_iter(4096, 0), [(0, 4096)]);
- assert_eq!(collect_chunk_read_iter(8192, 0), [(0, 4096), (4096, 4096)]);
- assert_eq!(collect_chunk_read_iter(8192, 4096), [(4096, 4096), (8192, 4096)]);
-
- assert_eq!(
- collect_chunk_read_iter(16384, 1),
- [(1, 4095), (4096, 4096), (8192, 4096), (12288, 4096), (16384, 1)]
- );
-
- assert_eq!(collect_chunk_read_iter(0, 0), []);
- assert_eq!(collect_chunk_read_iter(0, 100), []);
- }
-}