authfs: Remote file editor over binder
The remote editor allows to read/write from/to a remote file. This
change:
- Adds new binder API `writeFile`.
- Update fd_server to serve a read/writable fd. Read operation is done
through the existing read API when applicable.
- Adds `RemoteFileEditor` as a binder client for both read and write.
Bug: 171279640
Test: adb shell exec 9<>/data/local/tmp/output fd_server --rw-fds 9
Test: with changes in fusefs.rs, saw file changed correctly (md5sum)
Change-Id: I78ef198ee8a3a0f2d99717dc0c00fccde757f3de
diff --git a/authfs/src/remote_file.rs b/authfs/src/remote_file.rs
index 01e803c..ed7381c 100644
--- a/authfs/src/remote_file.rs
+++ b/authfs/src/remote_file.rs
@@ -21,6 +21,7 @@
use crate::common::CHUNK_SIZE;
use crate::reader::ReadOnlyDataByChunk;
+use crate::writer::RandomWrite;
use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService;
use authfs_aidl_interface::binder::Strong;
@@ -36,6 +37,23 @@
}
}
+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 RemoteChunkedFileReader {
// This needs to have Sync trait to be used in fuse::worker::start_message_loop.
service: Arc<Mutex<VirtFdService>>,
@@ -49,17 +67,8 @@
}
impl ReadOnlyDataByChunk for RemoteChunkedFileReader {
- 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 service = Arc::clone(&self.service);
- let chunk = service
- .lock()
- .unwrap()
- .readFile(self.file_fd, offset, buf.len() as i32)
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
- buf.write(&chunk)
+ fn read_chunk(&self, chunk_index: u64, buf: &mut [u8]) -> io::Result<usize> {
+ remote_read_chunk(&self.service, self.file_fd, chunk_index, buf)
}
}
@@ -81,8 +90,8 @@
let offset = i64::try_from(chunk_index * CHUNK_SIZE)
.map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
- let service = Arc::clone(&self.service);
- let chunk = service
+ let chunk = self
+ .service
.lock()
.unwrap()
.readFsverityMerkleTree(self.file_fd, offset, buf.len() as i32)
@@ -90,3 +99,36 @@
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)
+ }
+}