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/common.rs b/authfs/src/common.rs
index 522397f..6556fde 100644
--- a/authfs/src/common.rs
+++ b/authfs/src/common.rs
@@ -20,3 +20,59 @@
 pub fn divide_roundup(dividend: u64, divisor: u64) -> u64 {
     (dividend + divisor - 1) / divisor
 }
+
+/// Given `offset` and `length`, generates (offset, size) tuples that together form the same length,
+/// and aligned to `alignment`.
+pub struct ChunkedSizeIter {
+    remaining: usize,
+    offset: u64,
+    alignment: usize,
+}
+
+impl ChunkedSizeIter {
+    pub fn new(remaining: usize, offset: u64, alignment: usize) -> Self {
+        ChunkedSizeIter { remaining, offset, alignment }
+    }
+}
+
+impl Iterator for ChunkedSizeIter {
+    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,
+            self.alignment - (self.offset % self.alignment as u64) 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)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn collect_chunk_read_iter(remaining: usize, offset: u64) -> Vec<(u64, usize)> {
+        ChunkedSizeIter::new(remaining, offset, 4096).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), []);
+    }
+}