authfs: support resizing file

There are three major changes:
1. Add resize() to MerkleLeaves as the simple hash container.
2. Handle resize for a writable file. The special case is that the hash
   of the new last chunk can change, and the only way to calculate is to
   read the original data back.
3. Handle the size change in FUSE.

Bug: 186265793
Test: atest
Test: dex2oat succeeds (with more local changes)

Change-Id: I1ec20b6f0c69fd3ec24a6d04fc34583962265479
diff --git a/authfs/src/fusefs.rs b/authfs/src/fusefs.rs
index 0cd8b68..d2948c7 100644
--- a/authfs/src/fusefs.rs
+++ b/authfs/src/fusefs.rs
@@ -15,6 +15,7 @@
  */
 
 use anyhow::Result;
+use log::{debug, warn};
 use std::collections::BTreeMap;
 use std::convert::TryFrom;
 use std::ffi::CStr;
@@ -27,8 +28,8 @@
 use std::time::Duration;
 
 use fuse::filesystem::{
-    Context, DirEntry, DirectoryIterator, Entry, FileSystem, FsOptions, ZeroCopyReader,
-    ZeroCopyWriter,
+    Context, DirEntry, DirectoryIterator, Entry, FileSystem, FsOptions, SetattrValid,
+    ZeroCopyReader, ZeroCopyWriter,
 };
 use fuse::mount::MountOption;
 
@@ -325,6 +326,54 @@
             _ => Err(io::Error::from_raw_os_error(libc::EBADF)),
         }
     }
+
+    fn setattr(
+        &self,
+        _ctx: Context,
+        inode: Inode,
+        attr: libc::stat64,
+        _handle: Option<Handle>,
+        valid: SetattrValid,
+    ) -> io::Result<(libc::stat64, Duration)> {
+        match self.get_file_config(&inode)? {
+            FileConfig::RemoteVerifiedNewFile { editor } => {
+                // Initialize the default stat.
+                let mut new_attr = create_stat(inode, editor.size(), FileMode::ReadWrite)?;
+                // `valid` indicates what fields in `attr` are valid. Update to return correctly.
+                if valid.contains(SetattrValid::SIZE) {
+                    // st_size is i64, but the cast should be safe since kernel should not give a
+                    // negative size.
+                    debug_assert!(attr.st_size >= 0);
+                    new_attr.st_size = attr.st_size;
+                    editor.resize(attr.st_size as u64)?;
+                }
+
+                if valid.contains(SetattrValid::MODE) {
+                    warn!("Changing st_mode is not currently supported");
+                    return Err(io::Error::from_raw_os_error(libc::ENOSYS));
+                }
+                if valid.contains(SetattrValid::UID) {
+                    warn!("Changing st_uid is not currently supported");
+                    return Err(io::Error::from_raw_os_error(libc::ENOSYS));
+                }
+                if valid.contains(SetattrValid::GID) {
+                    warn!("Changing st_gid is not currently supported");
+                    return Err(io::Error::from_raw_os_error(libc::ENOSYS));
+                }
+                if valid.contains(SetattrValid::CTIME) {
+                    debug!("Ignoring ctime change as authfs does not maintain timestamp currently");
+                }
+                if valid.intersects(SetattrValid::ATIME | SetattrValid::ATIME_NOW) {
+                    debug!("Ignoring atime change as authfs does not maintain timestamp currently");
+                }
+                if valid.intersects(SetattrValid::MTIME | SetattrValid::MTIME_NOW) {
+                    debug!("Ignoring mtime change as authfs does not maintain timestamp currently");
+                }
+                Ok((new_attr, DEFAULT_METADATA_TIMEOUT))
+            }
+            _ => Err(io::Error::from_raw_os_error(libc::EBADF)),
+        }
+    }
 }
 
 /// Mount and start the FUSE instance. This requires CAP_SYS_ADMIN.