authfs: Support write config/operation in fuse

Bug: 171279640
Test: atest
Test: tools/device-test.sh

Change-Id: Ic611f72d51a5522d9ec6e6fdc82c115b5782c4ac
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index 39482e3..a4b0d40 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -43,8 +43,8 @@
 mod fusefs;
 
 use auth::FakeAuthenticator;
-use file::{LocalFileReader, RemoteFileReader, RemoteMerkleTreeReader};
-use fsverity::VerifiedFileReader;
+use file::{LocalFileReader, RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
+use fsverity::{VerifiedFileEditor, VerifiedFileReader};
 use fusefs::{FileConfig, Inode};
 
 #[derive(StructOpt)]
@@ -68,6 +68,13 @@
     #[structopt(long, parse(try_from_str = parse_remote_ro_file_unverified_option))]
     remote_ro_file_unverified: Vec<OptionRemoteRoFileUnverified>,
 
+    /// A new read-writable remote file with integrity check. Can be multiple.
+    ///
+    /// For example, `--remote-new-verified-file 12:34` tells the filesystem to associate entry 12
+    /// with a remote file 34.
+    #[structopt(long, parse(try_from_str = parse_remote_new_rw_file_option))]
+    remote_new_rw_file: Vec<OptionRemoteRwFile>,
+
     /// Debug only. A read-only local file with integrity check. Can be multiple.
     #[structopt(long, parse(try_from_str = parse_local_file_ro_option))]
     local_ro_file: Vec<OptionLocalFileRo>,
@@ -102,6 +109,13 @@
     file_size: u64,
 }
 
+struct OptionRemoteRwFile {
+    ino: Inode,
+
+    /// ID to refer to the remote file.
+    remote_id: i32,
+}
+
 struct OptionLocalFileRo {
     ino: Inode,
 
@@ -151,6 +165,17 @@
     })
 }
 
+fn parse_remote_new_rw_file_option(option: &str) -> Result<OptionRemoteRwFile> {
+    let strs: Vec<&str> = option.split(':').collect();
+    if strs.len() != 2 {
+        bail!("Invalid option: {}", option);
+    }
+    Ok(OptionRemoteRwFile {
+        ino: strs[0].parse::<Inode>().unwrap(),
+        remote_id: strs[1].parse::<i32>().unwrap(),
+    })
+}
+
 fn parse_local_file_ro_option(option: &str) -> Result<OptionLocalFileRo> {
     let strs: Vec<&str> = option.split(':').collect();
     if strs.len() != 5 {
@@ -223,6 +248,12 @@
     Ok(FileConfig::LocalUnverifiedReadonlyFile(file_reader, file_size))
 }
 
+fn new_config_remote_new_verified_file(remote_id: i32) -> Result<FileConfig> {
+    let remote_file =
+        RemoteFileEditor::new(Arc::new(Mutex::new(file::get_local_binder())), remote_id);
+    Ok(FileConfig::RemoteVerifiedNewFile(VerifiedFileEditor::new(remote_file)))
+}
+
 fn prepare_file_pool(args: &Args) -> Result<BTreeMap<Inode, FileConfig>> {
     let mut file_pool = BTreeMap::new();
 
@@ -240,6 +271,10 @@
         );
     }
 
+    for config in &args.remote_new_rw_file {
+        file_pool.insert(config.ino, new_config_remote_new_verified_file(config.remote_id)?);
+    }
+
     for config in &args.local_ro_file {
         file_pool.insert(
             config.ino,