blob: 28b7eebea31b03361719444c2849579e64370a1e [file] [log] [blame]
// Copyright 2016 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.
#include "garnet/lib/loader/package_loader.h"
#include <fcntl.h>
#include <trace/event.h>
#include <zircon/status.h>
#include <utility>
#include "lib/fidl/cpp/optional.h"
#include "lib/fsl/io/fd.h"
#include "lib/fsl/vmo/file.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/strings/substitute.h"
#include "lib/pkg_url/url_resolver.h"
namespace component {
PackageLoader::PackageLoader() = default;
PackageLoader::~PackageLoader() = default;
void PackageLoader::LoadUrl(std::string url, LoadUrlCallback callback) {
TRACE_DURATION("appmgr", "PackageLoader::LoadUrl", "url", url);
// package is our result. We're going to build it up iteratively.
fuchsia::sys::Package package;
// First we are going to resolve the package directory, if it is present. We
// can't handle resources yet, because we may not have enough URL to do so.
FuchsiaPkgUrl fuchsia_url;
bool parsed = false;
if (FuchsiaPkgUrl::IsFuchsiaPkgScheme(url)) {
parsed = fuchsia_url.Parse(url);
} else {
parsed =
fuchsia_url.Parse("fuchsia-pkg://fuchsia.com/" + GetPathFromURL(url));
}
// If the url isn't valid after our attempt at fix-up, bail.
if (!parsed) {
FXL_LOG(ERROR) << "Cannot load " << url << " because the URL is not valid.";
callback(nullptr);
return;
}
package.resolved_url = fuchsia_url.ToString();
fxl::UniqueFD package_dir(
open(fuchsia_url.pkgfs_dir_path().c_str(), O_DIRECTORY | O_RDONLY));
if (!package_dir.is_valid()) {
FXL_LOG(ERROR) << "Could not open directory "
<< fuchsia_url.pkgfs_dir_path() << " " << strerror(errno);
callback(nullptr);
return;
}
// Why does this method have un-reportable error conditions?
zx::channel directory =
fsl::CloneChannelFromFileDescriptor(package_dir.get());
if (!directory) {
FXL_LOG(ERROR) << "Could not clone directory "
<< fuchsia_url.pkgfs_dir_path();
callback(nullptr);
return;
}
package.directory = std::move(directory);
if (!fuchsia_url.resource_path().empty()) {
if (!LoadResource(package_dir, fuchsia_url.resource_path(), package)) {
FXL_LOG(ERROR) << "Could not load package resource "
<< fuchsia_url.resource_path() << " from " << url;
callback(nullptr);
return;
}
}
callback(fidl::MakeOptional(std::move(package)));
}
void PackageLoader::AddBinding(
fidl::InterfaceRequest<fuchsia::sys::Loader> request) {
bindings_.AddBinding(this, std::move(request));
}
bool PackageLoader::LoadResource(const fxl::UniqueFD& dir,
const std::string path,
fuchsia::sys::Package& package) {
fsl::SizedVmo resource;
if (!fsl::VmoFromFilenameAt(dir.get(), path, &resource)) {
return false;
}
resource.vmo().set_property(ZX_PROP_NAME, path.c_str(), path.length());
package.data = fidl::MakeOptional(std::move(resource).ToTransport());
return true;
}
} // namespace component