blob: 1b40e037775309993fabc32e47da24f17668eab3 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
anyhow::Error,
fidl_fuchsia_io::*,
files_async::*,
fuchsia_async::{DurationExt, TimeoutExt},
fuchsia_zircon as zx,
futures::FutureExt,
io_util::{directory::*, file::*},
std::path::PathBuf,
};
// A convenience wrapper over a FIDL FileProxy.
// Functions of this struct do not tolerate errors and will panic when they encounter them.
struct File {
proxy: FileProxy,
}
impl File {
async fn read_string(&self) -> String {
read_to_string(&self.proxy).await.unwrap()
}
async fn close(self) {
io_util::file::close(self.proxy).await.unwrap();
}
}
// A convenience wrapper over a FIDL DirectoryProxy.
// Functions of this struct do not tolerate errors and will panic when they encounter them.
pub struct Directory {
proxy: DirectoryProxy,
}
// Time to wait before giving up on opening a directory
static DIR_OPEN_TIMEOUT: zx::Duration = zx::Duration::from_seconds(1);
impl Directory {
// Create a Directory object from a path in the namespace
pub fn from_namespace(path: PathBuf) -> Result<Directory, Error> {
let path_str = path.into_os_string().into_string().unwrap();
let proxy = io_util::directory::open_in_namespace(
&path_str,
OPEN_RIGHT_WRITABLE | OPEN_RIGHT_READABLE,
)?;
Ok(Directory { proxy })
}
// Open a file that already exists in the directory with the given |filename|.
async fn open_file(&self, filename: &str) -> Result<File, Error> {
let proxy = open_file(&self.proxy, filename, OPEN_RIGHT_READABLE).await?;
Ok(File { proxy })
}
// Open a directory that already exists in the directory with the given |filename|.
pub async fn open_dir(&self, filename: &str) -> Directory {
let proxy = open_directory(&self.proxy, filename, OPEN_RIGHT_READABLE).await.unwrap();
Directory { proxy }
}
// Open a directory with a timeout. If the directory could not be opened in time,
// None is returned.
pub async fn open_dir_timeout(&self, filename: &str) -> Option<Directory> {
self.open_dir(filename)
.map(|d| Some(d))
.on_timeout(DIR_OPEN_TIMEOUT.after_now(), || None)
.await
}
// Returns the contents of a file in this directory as a string
pub async fn read_file(&self, filename: &str) -> Result<String, Error> {
let file = self.open_file(filename).await?;
let data = file.read_string().await;
file.close().await;
Ok(data)
}
// Checks if a file exists in this directory.
// Function is not recursive. Does not check subdirectories.
pub async fn exists(&self, filename: &str) -> bool {
self.entries().await.iter().any(|s| s == filename)
}
// Return a list of filenames in the directory
pub async fn entries(&self) -> Vec<String> {
readdir(&self.proxy).await.unwrap().iter().map(|entry| entry.name.clone()).collect()
}
}