blob: f6d407406f95badebefb347d508b25a36098368b [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.
#![deny(missing_docs)]
//! Typesafe wrappers around an "update" package.
mod board;
mod epoch;
mod hash;
mod image;
mod images;
mod name;
mod packages;
mod update_mode;
mod version;
pub use crate::{
board::VerifyBoardError,
epoch::ParseEpochError,
hash::HashError,
image::{Image, ImageClass, ImageType, OpenImageError},
images::{ImageList, ResolveImagesError, UnverifiedImageList},
name::VerifyNameError,
packages::ParsePackageError,
update_mode::{ParseUpdateModeError, UpdateMode},
version::{ReadVersionError, SystemVersion},
};
use {fidl_fuchsia_io::DirectoryProxy, fuchsia_hash::Hash, fuchsia_url::pkg_url::PkgUrl};
/// An open handle to an "update" package.
#[derive(Debug)]
pub struct UpdatePackage {
proxy: DirectoryProxy,
}
impl UpdatePackage {
/// Creates a new [`UpdatePackage`] with the given proxy.
pub fn new(proxy: DirectoryProxy) -> Self {
Self { proxy }
}
/// Verifies that the package's name/variant is "update/0".
pub async fn verify_name(&self) -> Result<(), VerifyNameError> {
name::verify(&self.proxy).await
}
/// Searches for the requested images in the update package, returning the resolved sequence of
/// images in the same order as the requests.
///
/// If a request ends in `[_type]`, that request is expanded to all found images with the
/// prefix of the request, sorted alphabetically.
pub async fn resolve_images(
&self,
requests: &[ImageType],
) -> Result<UnverifiedImageList, ResolveImagesError> {
images::resolve_images(&self.proxy, requests).await
}
/// Opens the given `image` as a resizable VMO buffer.
pub async fn open_image(
&self,
image: &Image,
) -> Result<fidl_fuchsia_mem::Buffer, OpenImageError> {
image::open(&self.proxy, image).await
}
/// Verifies the board file has the given `contents`.
pub async fn verify_board(&self, contents: &str) -> Result<(), VerifyBoardError> {
board::verify_board(&self.proxy, contents).await
}
/// Parses the update-mode file to obtain update mode. Returns `Ok(None)` if the update-mode
/// file is not present in the update package.
pub async fn update_mode(&self) -> Result<Option<UpdateMode>, ParseUpdateModeError> {
update_mode::update_mode(&self.proxy).await
}
/// Returns the list of package urls that go in the universe of this update package.
pub async fn packages(&self) -> Result<Vec<PkgUrl>, ParsePackageError> {
packages::packages(&self.proxy).await
}
/// Returns the package hash of this update package.
pub async fn hash(&self) -> Result<Hash, HashError> {
hash::hash(&self.proxy).await
}
/// Returns the version of this update package.
pub async fn version(&self) -> Result<SystemVersion, ReadVersionError> {
version::read_version(&self.proxy).await
}
/// Parses the epoch.json file to obtain the epoch. Returns `Ok(None)` if the epoch.json file
/// is not present in the update package.
pub async fn epoch(&self) -> Result<Option<u64>, ParseEpochError> {
epoch::epoch(&self.proxy).await
}
}
#[cfg(test)]
struct TestUpdatePackage {
update_pkg: UpdatePackage,
temp_dir: tempfile::TempDir,
}
#[cfg(test)]
impl TestUpdatePackage {
fn new() -> Self {
let temp_dir = tempfile::tempdir().expect("/tmp to exist");
let update_pkg_proxy = io_util::directory::open_in_namespace(
temp_dir.path().to_str().unwrap(),
io_util::OPEN_RIGHT_READABLE,
)
.expect("temp dir to open");
Self { temp_dir, update_pkg: UpdatePackage::new(update_pkg_proxy) }
}
fn proxy(&self) -> &DirectoryProxy {
&self.update_pkg.proxy
}
async fn add_file(self, path: impl AsRef<std::path::Path>, contents: impl AsRef<[u8]>) -> Self {
let path = path.as_ref();
match path.parent() {
Some(empty) if empty == std::path::Path::new("") => {}
None => {}
Some(parent) => std::fs::create_dir_all(self.temp_dir.path().join(parent)).unwrap(),
}
io_util::file::write_in_namespace(
self.temp_dir.path().join(path).to_str().unwrap(),
contents,
)
.await
.expect("create test update package file");
self
}
}
#[cfg(test)]
impl std::ops::Deref for TestUpdatePackage {
type Target = UpdatePackage;
fn deref(&self) -> &Self::Target {
&self.update_pkg
}
}
#[cfg(test)]
mod tests {
use {super::*, fidl_fuchsia_io::DirectoryMarker};
#[fuchsia_async::run_singlethreaded(test)]
async fn lifecycle() {
let (proxy, _server_end) = fidl::endpoints::create_proxy::<DirectoryMarker>().unwrap();
UpdatePackage::new(proxy);
}
}