| // Copyright 2018 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "imageloader/dlc.h" |
| |
| #include <memory> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <chromeos/constants/imageloader.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <dlcservice/metadata/metadata_interface.h> |
| |
| #include "imageloader/component.h" |
| #include "imageloader/manifest.h" |
| |
| namespace imageloader { |
| |
| namespace { |
| |
| // The name of the image. |
| constexpr char kImageName[] = "dlc.img"; |
| constexpr char kSlotAName[] = "dlc_a"; |
| constexpr char kSlotBName[] = "dlc_b"; |
| constexpr char kManifestFileName[] = "imageloader.json"; |
| constexpr char kTableFileName[] = "table"; |
| constexpr char kRedactedImagePath[] = "<REDACTED_IMAGE_PATH>"; |
| |
| AOrB GetImageAOrB(const std::string& a_or_b) { |
| if (a_or_b == imageloader::kSlotNameA) { |
| return AOrB::kDlcA; |
| } else if (a_or_b == imageloader::kSlotNameB) { |
| return AOrB::kDlcB; |
| } else { |
| return AOrB::kUnknown; |
| } |
| } |
| |
| } // namespace |
| |
| Dlc::Dlc(const std::string& id, |
| const std::string& package, |
| const base::FilePath& mount_base, |
| std::shared_ptr<MetadataInterface> metadata) |
| : id_(id), |
| package_(package), |
| mount_base_(mount_base), |
| metadata_(metadata) {} |
| |
| base::FilePath Dlc::GetManifestPath() { |
| return base::FilePath(kDlcManifestRootpath) |
| .Append(id_) |
| .Append(package_) |
| .Append(kManifestFileName); |
| } |
| |
| base::FilePath Dlc::GetTablePath() { |
| return base::FilePath(kDlcManifestRootpath) |
| .Append(id_) |
| .Append(package_) |
| .Append(kTableFileName); |
| } |
| |
| base::FilePath Dlc::GetImagePath(const AOrB a_or_b) { |
| base::FilePath root = |
| base::FilePath(kDlcImageRootpath).Append(id_).Append(package_); |
| if (a_or_b == AOrB::kDlcA) { |
| return root.Append(kSlotAName).Append(kImageName); |
| } else if (a_or_b == AOrB::kDlcB) { |
| return root.Append(kSlotBName).Append(kImageName); |
| } else { |
| return base::FilePath(); |
| } |
| } |
| |
| // static |
| base::FilePath Dlc::GetMountPoint(const base::FilePath& mount_base, |
| const std::string& id, |
| const std::string& package) { |
| return mount_base.Append(id).Append(package); |
| } |
| |
| base::FilePath Dlc::GetMountPoint() { |
| return GetMountPoint(mount_base_, id_, package_); |
| } |
| |
| bool Dlc::Mount(HelperProcessProxy* proxy, const std::string& a_or_b_str) { |
| AOrB a_or_b = GetImageAOrB(a_or_b_str); |
| |
| if (a_or_b == AOrB::kUnknown) { |
| LOG(ERROR) << "Unknown image type: " << a_or_b_str; |
| return false; |
| } |
| |
| return Mount(proxy, GetImagePath(a_or_b)); |
| } |
| |
| bool Dlc::Mount(HelperProcessProxy* proxy, const base::FilePath& path) { |
| if (!metadata_) { |
| LOG(ERROR) << "The compressed metadata is not initialized, fallback to " |
| "uncompressed."; |
| return Mount(proxy, path, GetManifestPath(), GetTablePath(), |
| GetMountPoint()); |
| } |
| |
| const auto& entry = metadata_->Get(id_); |
| Manifest manifest; |
| if (!entry || !manifest.ParseManifest(entry->manifest)) { |
| LOG(ERROR) << "Could not get compressed metadata for DLC=" << id_ |
| << " fallback to uncompressed."; |
| return Mount(proxy, path, GetManifestPath(), GetTablePath(), |
| GetMountPoint()); |
| } |
| return MountInternal(proxy, path, GetMountPoint(), manifest, entry->table); |
| } |
| |
| bool Dlc::Mount(HelperProcessProxy* proxy, |
| const base::FilePath& image_path, |
| const base::FilePath& manifest_path, |
| const base::FilePath& table_path, |
| const base::FilePath& mount_point) { |
| std::string manifest_raw; |
| if (!base::ReadFileToStringWithMaxSize(manifest_path, &manifest_raw, |
| kMaximumFilesize)) { |
| LOG(ERROR) << "Could not read manifest file: " << manifest_path.value(); |
| return false; |
| } |
| Manifest manifest; |
| if (!manifest.ParseManifest(manifest_raw)) |
| return false; |
| |
| std::string table; |
| if (!base::ReadFileToStringWithMaxSize(table_path, &table, |
| kMaximumFilesize)) { |
| LOG(ERROR) << "Could not read table."; |
| return false; |
| } |
| return MountInternal(proxy, image_path, mount_point, manifest, table); |
| } |
| |
| bool Dlc::MountInternal(HelperProcessProxy* proxy, |
| const base::FilePath& image_path, |
| const base::FilePath& mount_point, |
| const Manifest& manifest, |
| const std::string& table) { |
| base::File image(image_path, base::File::FLAG_OPEN | base::File::FLAG_READ); |
| if (!image.IsValid()) { |
| LOG(ERROR) << "Could not open image file '" |
| << (manifest.user_tied() ? kRedactedImagePath |
| : image_path.value()) |
| << "': " << base::File::ErrorToString(image.error_details()); |
| return false; |
| } |
| base::ScopedFD image_fd(image.TakePlatformFile()); |
| |
| return proxy->SendMountCommand(image_fd.get(), mount_point.value(), |
| manifest.fs_type(), table); |
| } |
| |
| } // namespace imageloader |