update_engine: Add delta payload support for squashfs
This patch adds support for generating delta payloads for squashfs
images. This is needed to get delta payloads for DLC images.
In order to get the supported major and minor versions of the
update_engine that matches the squashfs image (either squashfs image
contains the entire rootfs, including the update_engine, or the image is
a DLC), we need to read /etc/update_engine inside the image.
We do this by calling unsquashfs and only unsquashing the target file
and later reading its content into a key-value store to be used for
delta payload generation.
BUG=chromium:926986
TEST=unittest
TEST=delta_generator --out_file=output --partition_names=dlc --new_partitions=dlc.img --old_partitions=dlc.img
Change-Id: Ib5599032c873223a5caca82918e138d8b4fcec43
Reviewed-on: https://chromium-review.googlesource.com/1446278
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Sen Jiang <senj@chromium.org>
diff --git a/payload_generator/squashfs_filesystem.cc b/payload_generator/squashfs_filesystem.cc
index 6c892f5..c423b69 100644
--- a/payload_generator/squashfs_filesystem.cc
+++ b/payload_generator/squashfs_filesystem.cc
@@ -23,6 +23,7 @@
#include <utility>
#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
@@ -36,6 +37,8 @@
#include "update_engine/payload_generator/extent_utils.h"
#include "update_engine/update_metadata.pb.h"
+using base::FilePath;
+using base::ScopedTempDir;
using std::string;
using std::unique_ptr;
using std::vector;
@@ -49,6 +52,8 @@
constexpr uint64_t kSquashfsCompressedBit = 1 << 24;
constexpr uint32_t kSquashfsZlibCompression = 1;
+constexpr char kUpdateEngineConf[] = "etc/update_engine.conf";
+
bool ReadSquashfsHeader(const brillo::Blob blob,
SquashfsFilesystem::SquashfsHeader* header) {
if (blob.size() < kSquashfsSuperBlockSize) {
@@ -88,6 +93,45 @@
return true;
}
+bool GetUpdateEngineConfig(const std::string& sqfs_path, string* config) {
+ ScopedTempDir unsquash_dir;
+ if (!unsquash_dir.CreateUniqueTempDir()) {
+ PLOG(ERROR) << "Failed to create a temporary directory.";
+ return false;
+ }
+
+ // Run unsquashfs to extract update_engine.conf
+ // -f: To force overriding if the target directory exists.
+ // -d: The directory to unsquash the files.
+ vector<string> cmd = {"unsquashfs",
+ "-f",
+ "-d",
+ unsquash_dir.GetPath().value(),
+ sqfs_path,
+ kUpdateEngineConf};
+ int exit_code;
+ if (!Subprocess::SynchronousExec(cmd, &exit_code, nullptr) ||
+ exit_code != 0) {
+ PLOG(ERROR) << "Failed to unsquashfs etc/update_engine.conf: ";
+ return false;
+ }
+
+ auto config_path = unsquash_dir.GetPath().Append(kUpdateEngineConf);
+ string config_content;
+ if (!utils::ReadFile(config_path.value(), &config_content)) {
+ PLOG(ERROR) << "Failed to read " << config_path.value();
+ return false;
+ }
+
+ if (config_content.empty()) {
+ LOG(ERROR) << "update_engine config file was empty!!";
+ return false;
+ }
+
+ *config = std::move(config_content);
+ return true;
+}
+
} // namespace
bool SquashfsFilesystem::Init(const string& map,
@@ -239,12 +283,12 @@
}
unique_ptr<SquashfsFilesystem> SquashfsFilesystem::CreateFromFile(
- const string& sqfs_path, bool extract_deflates) {
+ const string& sqfs_path, bool extract_deflates, bool load_settings) {
if (sqfs_path.empty())
return nullptr;
brillo::StreamPtr sqfs_file =
- brillo::FileStream::Open(base::FilePath(sqfs_path),
+ brillo::FileStream::Open(FilePath(sqfs_path),
brillo::Stream::AccessMode::READ,
brillo::FileStream::Disposition::OPEN_EXISTING,
nullptr);
@@ -278,6 +322,12 @@
return nullptr;
}
+ if (load_settings) {
+ if (!GetUpdateEngineConfig(sqfs_path, &sqfs->update_engine_config_)) {
+ return nullptr;
+ }
+ }
+
return sqfs;
}
@@ -311,9 +361,12 @@
}
bool SquashfsFilesystem::LoadSettings(brillo::KeyValueStore* store) const {
- // Settings not supported in squashfs.
- LOG(ERROR) << "squashfs doesn't support LoadSettings().";
- return false;
+ if (!store->LoadFromString(update_engine_config_)) {
+ LOG(ERROR) << "Failed to load the settings with config: "
+ << update_engine_config_;
+ return false;
+ }
+ return true;
}
bool SquashfsFilesystem::IsSquashfsImage(const brillo::Blob& blob) {