Implement directory listing
Bug: 205715172
Test: AuthFsHostTest
Change-Id: I9ba4589636a7e1ef1261c7db14b5ecdea691e63c
diff --git a/authfs/src/file/dir.rs b/authfs/src/file/dir.rs
index 7f26fd7..f3cc6f8 100644
--- a/authfs/src/file/dir.rs
+++ b/authfs/src/file/dir.rs
@@ -17,18 +17,20 @@
use log::warn;
use nix::sys::stat::Mode;
use std::collections::{hash_map, HashMap};
+use std::ffi::{CString, OsString};
use std::io;
+use std::os::unix::ffi::OsStringExt;
use std::path::{Path, PathBuf};
use super::attr::Attr;
use super::remote_file::RemoteFileEditor;
use super::{validate_basename, VirtFdService, VirtFdServiceStatus};
use crate::fsverity::VerifiedFileEditor;
-use crate::fusefs::Inode;
+use crate::fusefs::{AuthFsDirEntry, Inode};
const MAX_ENTRIES: u16 = 100; // Arbitrary limit
-struct DirEntry {
+struct InodeInfo {
inode: Inode,
// This information is duplicated since it is also available in `AuthFs::inode_table` via the
@@ -58,7 +60,7 @@
/// Mapping of entry names to the corresponding inode. The actual file/directory is stored in
/// the global pool in fusefs.
- entries: HashMap<PathBuf, DirEntry>,
+ entries: HashMap<PathBuf, InodeInfo>,
}
impl RemoteDirEditor {
@@ -88,7 +90,7 @@
let new_remote_file =
VerifiedFileEditor::new(RemoteFileEditor::new(self.service.clone(), new_fd));
- self.entries.insert(basename.to_path_buf(), DirEntry { inode, is_dir: false });
+ self.entries.insert(basename.to_path_buf(), InodeInfo { inode, is_dir: false });
let new_attr = Attr::new_file_with_mode(self.service.clone(), new_fd, mode);
Ok((new_remote_file, new_attr))
}
@@ -110,7 +112,7 @@
.map_err(into_io_error)?;
let new_remote_dir = RemoteDirEditor::new(self.service.clone(), new_fd);
- self.entries.insert(basename.to_path_buf(), DirEntry { inode, is_dir: true });
+ self.entries.insert(basename.to_path_buf(), InodeInfo { inode, is_dir: true });
let new_attr = Attr::new_dir_with_mode(self.service.clone(), new_fd, mode);
Ok((new_remote_dir, new_attr))
}
@@ -156,6 +158,15 @@
self.entries.contains_key(name)
}
+ pub fn retrieve_entries(&self) -> io::Result<Vec<AuthFsDirEntry>> {
+ self.entries
+ .iter()
+ .map(|(name, InodeInfo { inode, is_dir })| {
+ Ok(AuthFsDirEntry { inode: *inode, name: path_to_cstring(name)?, is_dir: *is_dir })
+ })
+ .collect::<io::Result<Vec<_>>>()
+ }
+
fn force_delete_entry(&mut self, basename: &Path, expect_dir: bool) -> io::Result<Inode> {
// Kernel should only give us a basename.
debug_assert!(validate_basename(basename).is_ok());
@@ -192,7 +203,7 @@
}
/// An in-memory directory representation of a directory structure.
-pub struct InMemoryDir(HashMap<PathBuf, Inode>);
+pub struct InMemoryDir(HashMap<PathBuf, InodeInfo>);
impl InMemoryDir {
/// Creates an empty instance of `InMemoryDir`.
@@ -206,16 +217,26 @@
self.0.len() as u16 // limited to MAX_ENTRIES
}
- /// Adds an entry (name and the inode number) to the directory. Fails if already exists. The
+ /// Adds a directory name and its inode number to the directory. Fails if already exists. The
/// caller is responsible for ensure the inode uniqueness.
- pub fn add_entry(&mut self, basename: &Path, inode: Inode) -> io::Result<()> {
+ pub fn add_dir(&mut self, basename: &Path, inode: Inode) -> io::Result<()> {
+ self.add_entry(basename, InodeInfo { inode, is_dir: true })
+ }
+
+ /// Adds a file name and its inode number to the directory. Fails if already exists. The
+ /// caller is responsible for ensure the inode uniqueness.
+ pub fn add_file(&mut self, basename: &Path, inode: Inode) -> io::Result<()> {
+ self.add_entry(basename, InodeInfo { inode, is_dir: false })
+ }
+
+ fn add_entry(&mut self, basename: &Path, dir_entry: InodeInfo) -> io::Result<()> {
validate_basename(basename)?;
if self.0.len() >= MAX_ENTRIES.into() {
return Err(io::Error::from_raw_os_error(libc::EMLINK));
}
if let hash_map::Entry::Vacant(entry) = self.0.entry(basename.to_path_buf()) {
- entry.insert(inode);
+ entry.insert(dir_entry);
Ok(())
} else {
Err(io::Error::from_raw_os_error(libc::EEXIST))
@@ -224,8 +245,22 @@
/// Looks up an entry inode by name. `None` if not found.
pub fn lookup_inode(&self, basename: &Path) -> Option<Inode> {
- self.0.get(basename).copied()
+ self.0.get(basename).map(|entry| entry.inode)
}
+
+ pub fn retrieve_entries(&self) -> io::Result<Vec<AuthFsDirEntry>> {
+ self.0
+ .iter()
+ .map(|(name, InodeInfo { inode, is_dir })| {
+ Ok(AuthFsDirEntry { inode: *inode, name: path_to_cstring(name)?, is_dir: *is_dir })
+ })
+ .collect::<io::Result<Vec<_>>>()
+ }
+}
+
+fn path_to_cstring(path: &Path) -> io::Result<CString> {
+ let bytes = OsString::from(path).into_vec();
+ CString::new(bytes).map_err(|_| io::Error::from_raw_os_error(libc::EILSEQ))
}
fn into_io_error(e: VirtFdServiceStatus) -> io::Error {