AU: delta compress the kernel partition
Add kernel partition to proto buf. Change delta generator to compress
the kernel partition and the delta performer to perform operations to
update the kernel partition. Update unittests to test it.
Also, remove checksums from the protobuf while we're at it, since the
partitions themselves will contains checksums.
BUG=None
TEST=Attached unittest
Review URL: http://codereview.chromium.org/1819002
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index 6b880cd..23c5fc8 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -390,6 +390,7 @@
void InstallOperationsToManifest(
const Graph& graph,
const vector<Vertex::Index>& order,
+ const vector<DeltaArchiveManifest_InstallOperation>& kernel_ops,
DeltaArchiveManifest* out_manifest) {
for (vector<Vertex::Index>::const_iterator it = order.begin();
it != order.end(); ++it) {
@@ -397,6 +398,12 @@
out_manifest->add_install_operations();
*op = graph[*it].op;
}
+ for (vector<DeltaArchiveManifest_InstallOperation>::const_iterator it =
+ kernel_ops.begin(); it != kernel_ops.end(); ++it) {
+ DeltaArchiveManifest_InstallOperation* op =
+ out_manifest->add_kernel_install_operations();
+ *op = *it;
+ }
}
void CheckGraph(const Graph& graph) {
@@ -405,6 +412,55 @@
}
}
+// Delta compresses a kernel partition new_kernel_part with knowledge of
+// the old kernel partition old_kernel_part.
+bool DeltaCompressKernelPartition(
+ const string& old_kernel_part,
+ const string& new_kernel_part,
+ vector<DeltaArchiveManifest_InstallOperation>* ops,
+ int blobs_fd,
+ off_t* blobs_length) {
+ // For now, just bsdiff the kernel partition as a whole.
+ // TODO(adlr): Use knowledge of how the kernel partition is laid out
+ // to more efficiently compress it.
+
+ LOG(INFO) << "Delta compressing kernel partition...";
+
+ // Add a new install operation
+ ops->resize(1);
+ DeltaArchiveManifest_InstallOperation* op = &(*ops)[0];
+ op->set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
+ op->set_data_offset(*blobs_length);
+
+ // Do the actual compression
+ vector<char> data;
+ TEST_AND_RETURN_FALSE(BsdiffFiles(old_kernel_part, new_kernel_part, &data));
+ TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, &data[0], data.size()));
+ *blobs_length += data.size();
+
+ off_t old_part_size = utils::FileSize(old_kernel_part);
+ TEST_AND_RETURN_FALSE(old_part_size >= 0);
+ off_t new_part_size = utils::FileSize(new_kernel_part);
+ TEST_AND_RETURN_FALSE(new_part_size >= 0);
+
+ op->set_data_length(data.size());
+
+ op->set_src_length(old_part_size);
+ op->set_dst_length(new_part_size);
+
+ // Theres a single src/dest extent for each
+ Extent* src_extent = op->add_src_extents();
+ src_extent->set_start_block(0);
+ src_extent->set_num_blocks((old_part_size + kBlockSize - 1) / kBlockSize);
+
+ Extent* dst_extent = op->add_dst_extents();
+ dst_extent->set_start_block(0);
+ dst_extent->set_num_blocks((new_part_size + kBlockSize - 1) / kBlockSize);
+
+ LOG(INFO) << "Done delta compressing kernel partition.";
+ return true;
+}
+
} // namespace {}
bool DeltaDiffGenerator::ReadFileToDiff(
@@ -653,9 +709,15 @@
ScopedFileWriterCloser writer_closer(&writer);
uint64_t out_file_size = 0;
- for (int i = 0; i < manifest->install_operations_size(); i++) {
- DeltaArchiveManifest_InstallOperation* op =
- manifest->mutable_install_operations(i);
+ for (int i = 0; i < (manifest->install_operations_size() +
+ manifest->kernel_install_operations_size()); i++) {
+ DeltaArchiveManifest_InstallOperation* op = NULL;
+ if (i < manifest->install_operations_size()) {
+ op = manifest->mutable_install_operations(i);
+ } else {
+ op = manifest->mutable_kernel_install_operations(
+ i - manifest->install_operations_size());
+ }
if (!op->has_data_offset())
continue;
CHECK(op->has_data_length());
@@ -671,11 +733,14 @@
return true;
}
-bool DeltaDiffGenerator::GenerateDeltaUpdateFile(const string& old_root,
- const string& old_image,
- const string& new_root,
- const string& new_image,
- const string& output_path) {
+bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
+ const string& old_root,
+ const string& old_image,
+ const string& new_root,
+ const string& new_image,
+ const std::string& old_kernel_part,
+ const std::string& new_kernel_part,
+ const string& output_path) {
struct stat old_image_stbuf;
TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0);
struct stat new_image_stbuf;
@@ -687,6 +752,10 @@
LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize)
<< "Old image not a multiple of block size " << kBlockSize;
+ // Sanity check kernel partition args
+ TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0);
+ TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0);
+
vector<Block> blocks(min(old_image_stbuf.st_size / kBlockSize,
new_image_stbuf.st_size / kBlockSize));
LOG(INFO) << "invalid: " << Vertex::kInvalidIndex;
@@ -704,6 +773,8 @@
LOG(INFO) << "Reading files...";
+ vector<DeltaArchiveManifest_InstallOperation> kernel_ops;
+
DeltaArchiveManifest_InstallOperation final_op;
{
int fd;
@@ -720,12 +791,18 @@
&data_file_size));
CheckGraph(graph);
- // TODO(adlr): read all the rest of the blocks in
TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks,
fd,
&data_file_size,
new_image,
&final_op));
+
+ // Read kernel partition
+ TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part,
+ new_kernel_part,
+ &kernel_ops,
+ fd,
+ &data_file_size));
}
CheckGraph(graph);
@@ -753,7 +830,7 @@
// Convert to protobuf Manifest object
DeltaArchiveManifest manifest;
CheckGraph(graph);
- InstallOperationsToManifest(graph, final_order, &manifest);
+ InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest);
{
// Write final operation
DeltaArchiveManifest_InstallOperation* op =
@@ -762,9 +839,9 @@
CHECK(op->has_type());
LOG(INFO) << "final op length: " << op->data_length();
}
+
CheckGraph(graph);
manifest.set_block_size(kBlockSize);
- // TODO(adlr): set checksums
// Reorder the data blobs with the newly ordered manifest
string ordered_blobs_path;
@@ -780,9 +857,13 @@
{
vector<uint32_t> written_count(blocks.size(), 0);
uint64_t next_blob_offset = 0;
- for (int i = 0; i < manifest.install_operations_size(); i++) {
+ for (int i = 0; i < (manifest.install_operations_size() +
+ manifest.kernel_install_operations_size()); i++) {
const DeltaArchiveManifest_InstallOperation& op =
- manifest.install_operations(i);
+ i < manifest.install_operations_size() ?
+ manifest.install_operations(i) :
+ manifest.kernel_install_operations(
+ i - manifest.install_operations_size());
for (int j = 0; j < op.dst_extents_size(); j++) {
const Extent& extent = op.dst_extents(j);
for (uint64_t block = extent.start_block();
diff --git a/delta_diff_generator.h b/delta_diff_generator.h
index bbaa473..efc4747 100644
--- a/delta_diff_generator.h
+++ b/delta_diff_generator.h
@@ -40,12 +40,16 @@
// This is the only function that external users of the class should call.
// old_image and new_image are paths to two image files. They should be
// mounted read-only at paths old_root and new_root respectively.
+ // {old,new}_kernel_part are paths to the old and new kernel partition
+ // images, respectively.
// output_path is the filename where the delta update should be written.
// Returns true on success.
static bool GenerateDeltaUpdateFile(const std::string& old_root,
const std::string& old_image,
const std::string& new_root,
const std::string& new_image,
+ const std::string& old_kernel_part,
+ const std::string& new_kernel_part,
const std::string& output_path);
// These functions are public so that the unit tests can access them:
diff --git a/delta_performer.cc b/delta_performer.cc
index 765fc1e..1f8d8e4 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -59,12 +59,18 @@
// LOGs a DeltaArchiveManifest object. Useful for debugging.
void DumpUpdateProto(const DeltaArchiveManifest& manifest) {
LOG(INFO) << "Update Proto:";
- LOG(INFO) << " src_checksum: " << manifest.src_checksum();
- LOG(INFO) << " dst_checksum: " << manifest.dst_checksum();
LOG(INFO) << " block_size: " << manifest.block_size();
- for (int i = 0; i < manifest.install_operations_size(); i++) {
+ for (int i = 0; i < (manifest.install_operations_size() +
+ manifest.kernel_install_operations_size()); i++) {
const DeltaArchiveManifest_InstallOperation& op =
- manifest.install_operations(i);
+ i < manifest.install_operations_size() ?
+ manifest.install_operations(i) :
+ manifest.kernel_install_operations(
+ i - manifest.install_operations_size());
+ if (i == 0)
+ LOG(INFO) << " Rootfs ops:";
+ else if (i == manifest.install_operations_size())
+ LOG(INFO) << " Kernel ops:";
LOG(INFO) << " operation(" << i << ")";
LOG(INFO) << " type: "
<< DeltaArchiveManifest_InstallOperation_Type_Name(op.type());
@@ -80,18 +86,40 @@
LOG(INFO) << " dst_length: " << op.dst_length();
}
}
+
+// Opens path for read/write, put the fd into *fd. On success returns true
+// and sets *err to 0. On failure, returns false and sets *err to errno.
+bool OpenFile(const char* path, int* fd, int* err) {
+ if (*fd != -1) {
+ LOG(ERROR) << "Can't open(" << path << "), *fd != -1 (it's " << *fd << ")";
+ *err = EINVAL;
+ return false;
+ }
+ *fd = open(path, O_RDWR, 000);
+ if (*fd < 0) {
+ *err = errno;
+ PLOG(ERROR) << "Unable to open file " << path;
+ return false;
+ }
+ *err = 0;
+ return true;
+}
+
} // namespace {}
int DeltaPerformer::Open(const char* path, int flags, mode_t mode) {
- if (fd_ != -1) {
- LOG(ERROR) << "Can't Open(), fd_ != -1 (it's " << fd_ << ")";
- return -EINVAL;
- }
- path_ = path;
- fd_ = open(path, O_RDWR, 000);
- if (fd_ < 0)
- return -errno;
- return 0;
+ int err;
+ if (OpenFile(path, &fd_, &err))
+ path_ = path;
+ return -err;
+}
+
+bool DeltaPerformer::OpenKernel(const char* kernel_path) {
+ int err;
+ bool success = OpenFile(kernel_path, &kernel_fd_, &err);
+ if (success)
+ kernel_path_ = kernel_path;
+ return success;
}
int DeltaPerformer::Close() {
@@ -99,11 +127,18 @@
LOG(ERROR) << "Called Close() while buffer not empty!";
return -1;
}
- if (close(fd_) == -1)
- return -errno;
+ int err = 0;
+ if (close(kernel_fd_) == -1) {
+ err = errno;
+ PLOG(ERROR) << "Unable to close kernel fd:";
+ }
+ if (close(fd_) == -1) {
+ err = errno;
+ PLOG(ERROR) << "Unable to close rootfs fd:";
+ }
fd_ = -2; // Set so that isn't not valid AND calls to Open() will fail.
path_ = "";
- return 0;
+ return -err;
}
// Wrapper around write. Returns bytes written on success or
@@ -148,29 +183,39 @@
manifest_valid_ = true;
block_size_ = manifest_.block_size();
}
- while (next_operation_ < manifest_.install_operations_size() &&
- CanPerformInstallOperation(
- manifest_.install_operations(next_operation_))) {
+ ssize_t total_operations = manifest_.install_operations_size() +
+ manifest_.kernel_install_operations_size();
+ while (next_operation_num_ < total_operations) {
const DeltaArchiveManifest_InstallOperation &op =
- manifest_.install_operations(next_operation_);
+ next_operation_num_ < manifest_.install_operations_size() ?
+ manifest_.install_operations(next_operation_num_) :
+ manifest_.kernel_install_operations(
+ next_operation_num_ - manifest_.install_operations_size());
+ if (!CanPerformInstallOperation(op))
+ break;
+ bool is_kernel_partition =
+ (next_operation_num_ >= manifest_.install_operations_size());
if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
- if (!PerformReplaceOperation(op)) {
- LOG(ERROR) << "Failed to perform replace operation " << next_operation_;
+ if (!PerformReplaceOperation(op, is_kernel_partition)) {
+ LOG(ERROR) << "Failed to perform replace operation "
+ << next_operation_num_;
return -EINVAL;
}
} else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
- if (!PerformMoveOperation(op)) {
- LOG(ERROR) << "Failed to perform move operation " << next_operation_;
+ if (!PerformMoveOperation(op, is_kernel_partition)) {
+ LOG(ERROR) << "Failed to perform move operation "
+ << next_operation_num_;
return -EINVAL;
}
} else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
- if (!PerformBsdiffOperation(op)) {
- LOG(ERROR) << "Failed to perform bsdiff operation " << next_operation_;
+ if (!PerformBsdiffOperation(op, is_kernel_partition)) {
+ LOG(ERROR) << "Failed to perform bsdiff operation "
+ << next_operation_num_;
return -EINVAL;
}
}
- next_operation_++;
+ next_operation_num_++;
}
return count;
}
@@ -194,7 +239,8 @@
}
bool DeltaPerformer::PerformReplaceOperation(
- const DeltaArchiveManifest_InstallOperation& operation) {
+ const DeltaArchiveManifest_InstallOperation& operation,
+ bool is_kernel_partition) {
CHECK(operation.type() == \
DeltaArchiveManifest_InstallOperation_Type_REPLACE || \
operation.type() == \
@@ -228,7 +274,9 @@
extents.push_back(operation.dst_extents(i));
}
- TEST_AND_RETURN_FALSE(writer->Init(fd_, extents, block_size_));
+ int fd = is_kernel_partition ? kernel_fd_ : fd_;
+
+ TEST_AND_RETURN_FALSE(writer->Init(fd, extents, block_size_));
TEST_AND_RETURN_FALSE(writer->Write(&buffer_[0], operation.data_length()));
TEST_AND_RETURN_FALSE(writer->End());
@@ -239,7 +287,8 @@
}
bool DeltaPerformer::PerformMoveOperation(
- const DeltaArchiveManifest_InstallOperation& operation) {
+ const DeltaArchiveManifest_InstallOperation& operation,
+ bool is_kernel_partition) {
// Calculate buffer size. Note, this function doesn't do a sliding
// window to copy in case the source and destination blocks overlap.
// If we wanted to do a sliding window, we could program the server
@@ -255,13 +304,15 @@
DCHECK_EQ(blocks_to_write, blocks_to_read);
vector<char> buf(blocks_to_write * block_size_);
-
+
+ int fd = is_kernel_partition ? kernel_fd_ : fd_;
+
// Read in bytes.
ssize_t bytes_read = 0;
for (int i = 0; i < operation.src_extents_size(); i++) {
ssize_t bytes_read_this_iteration = 0;
const Extent& extent = operation.src_extents(i);
- TEST_AND_RETURN_FALSE(utils::PReadAll(fd_,
+ TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
&buf[bytes_read],
extent.num_blocks() * block_size_,
extent.start_block() * block_size_,
@@ -276,7 +327,7 @@
ssize_t bytes_written = 0;
for (int i = 0; i < operation.dst_extents_size(); i++) {
const Extent& extent = operation.dst_extents(i);
- TEST_AND_RETURN_FALSE(utils::PWriteAll(fd_,
+ TEST_AND_RETURN_FALSE(utils::PWriteAll(fd,
&buf[bytes_written],
extent.num_blocks() * block_size_,
extent.start_block() * block_size_));
@@ -314,7 +365,8 @@
}
bool DeltaPerformer::PerformBsdiffOperation(
- const DeltaArchiveManifest_InstallOperation& operation) {
+ const DeltaArchiveManifest_InstallOperation& operation,
+ bool is_kernel_partition) {
// Since we delete data off the beginning of the buffer as we use it,
// the data we need should be exactly at the beginning of the buffer.
CHECK_EQ(buffer_offset_, operation.data_offset());
@@ -342,10 +394,14 @@
TEST_AND_RETURN_FALSE(
utils::WriteAll(fd, &buffer_[0], operation.data_length()));
}
+
+ int fd = is_kernel_partition ? kernel_fd_ : fd_;
+ const string& path = is_kernel_partition ? kernel_path_ : path_;
+
vector<string> cmd;
cmd.push_back(kBspatchPath);
- cmd.push_back(path_);
- cmd.push_back(path_);
+ cmd.push_back(path);
+ cmd.push_back(path);
cmd.push_back(temp_filename);
cmd.push_back(input_positions);
cmd.push_back(output_positions);
@@ -364,7 +420,7 @@
end_byte - (block_size_ - operation.dst_length() % block_size_);
vector<char> zeros(end_byte - begin_byte);
TEST_AND_RETURN_FALSE(
- utils::PWriteAll(fd_, &zeros[0], end_byte - begin_byte, begin_byte));
+ utils::PWriteAll(fd, &zeros[0], end_byte - begin_byte, begin_byte));
}
// Update buffer.
diff --git a/delta_performer.h b/delta_performer.h
index 4a096c2..cf75a67 100644
--- a/delta_performer.h
+++ b/delta_performer.h
@@ -20,10 +20,16 @@
public:
DeltaPerformer()
: fd_(-1),
+ kernel_fd_(-1),
manifest_valid_(false),
- next_operation_(0),
+ next_operation_num_(0),
buffer_offset_(0),
block_size_(0) {}
+
+ // Opens the kernel. Should be called before or after Open(), but before
+ // Write(). The kernel file will be close()d when Close() is called.
+ bool OpenKernel(const char* kernel_path);
+
// flags and mode ignored. Once Close()d, a DeltaPerformer can't be
// Open()ed again.
int Open(const char* path, int flags, mode_t mode);
@@ -33,6 +39,7 @@
ssize_t Write(const void* bytes, size_t count);
// Wrapper around close. Returns 0 on success or -errno on error.
+ // Closes both 'path' given to Open() and the kernel path.
int Close();
// Converts an ordered collection of Extent objects which contain data of
@@ -62,22 +69,29 @@
// These perform a specific type of operation and return true on success.
bool PerformReplaceOperation(
- const DeltaArchiveManifest_InstallOperation& operation);
+ const DeltaArchiveManifest_InstallOperation& operation,
+ bool is_kernel_partition);
bool PerformMoveOperation(
- const DeltaArchiveManifest_InstallOperation& operation);
+ const DeltaArchiveManifest_InstallOperation& operation,
+ bool is_kernel_partition);
bool PerformBsdiffOperation(
- const DeltaArchiveManifest_InstallOperation& operation);
+ const DeltaArchiveManifest_InstallOperation& operation,
+ bool is_kernel_partition);
// File descriptor of open device.
int fd_;
- std::string path_; // Path that fd_ refers to
+ // File descriptor of the kernel device
+ int kernel_fd_;
+
+ std::string path_; // Path that fd_ refers to.
+ std::string kernel_path_; // Path that kernel_fd_ refers to.
DeltaArchiveManifest manifest_;
bool manifest_valid_;
// Index of the next operation to perform in the manifest.
- int next_operation_;
+ int next_operation_num_;
// buffer_ is a window of the data that's been downloaded. At first,
// it contains the beginning of the download, but after the protobuf
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index 7ce2cf0..fb9aabc 100755
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -154,6 +154,29 @@
sizeof(kRandomString)));
}
+ string old_kernel;
+ EXPECT_TRUE(utils::MakeTempFile("/tmp/old_kernel.XXXXXX", &old_kernel, NULL));
+ ScopedPathUnlinker old_kernel_unlinker(old_kernel);
+
+ string new_kernel;
+ EXPECT_TRUE(utils::MakeTempFile("/tmp/new_kernel.XXXXXX", &new_kernel, NULL));
+ ScopedPathUnlinker new_kernel_unlinker(new_kernel);
+
+ vector<char> old_kernel_data(4096); // Something small for a test
+ vector<char> new_kernel_data(old_kernel_data.size());
+ FillWithData(&old_kernel_data);
+ FillWithData(&new_kernel_data);
+
+ // change the new kernel data
+ const char* new_data_string = "This is new data.";
+ strcpy(&new_kernel_data[0], new_data_string);
+
+ // Write kernels to disk
+ EXPECT_TRUE(utils::WriteFile(
+ old_kernel.c_str(), &old_kernel_data[0], old_kernel_data.size()));
+ EXPECT_TRUE(utils::WriteFile(
+ new_kernel.c_str(), &new_kernel_data[0], new_kernel_data.size()));
+
string delta_path;
EXPECT_TRUE(utils::MakeTempFile("/tmp/delta.XXXXXX", &delta_path, NULL));
ScopedPathUnlinker delta_path_unlinker(delta_path);
@@ -166,6 +189,8 @@
a_img,
b_mnt,
b_img,
+ old_kernel,
+ new_kernel,
delta_path));
}
@@ -177,6 +202,7 @@
DeltaPerformer performer;
EXPECT_EQ(0, performer.Open(a_img.c_str(), 0, 0));
+ EXPECT_TRUE(performer.OpenKernel(old_kernel.c_str()));
// Write at some number of bytes per operation. Arbitrarily chose 5.
const size_t kBytesPerWrite = 5;
@@ -189,6 +215,12 @@
EXPECT_EQ(0, performer.Close());
CompareFilesByBlock("/tmp/a_ref", "/tmp/b_ref");
+ CompareFilesByBlock(old_kernel, new_kernel);
+
+ vector<char> updated_kernel_partition;
+ EXPECT_TRUE(utils::ReadFile(old_kernel, &updated_kernel_partition));
+ EXPECT_EQ(0, strncmp(&updated_kernel_partition[0], new_data_string,
+ strlen(new_data_string)));
}
} // namespace chromeos_update_engine
diff --git a/download_action_unittest.cc b/download_action_unittest.cc
index 014d3b7..d2c5cb1 100644
--- a/download_action_unittest.cc
+++ b/download_action_unittest.cc
@@ -174,7 +174,7 @@
}
// 1 or 0 chunks should have come through
- const off_t resulting_file_size(FileSize(path));
+ const off_t resulting_file_size(utils::FileSize(path));
if (resulting_file_size != 0)
EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
}
diff --git a/extent_writer_unittest.cc b/extent_writer_unittest.cc
index 484d069..f0f5f7a 100644
--- a/extent_writer_unittest.cc
+++ b/extent_writer_unittest.cc
@@ -237,7 +237,7 @@
EXPECT_TRUE(direct_writer.End());
// check file size, then data inside
- ASSERT_EQ(2 * kBlockSize, FileSize(path()));
+ ASSERT_EQ(2 * kBlockSize, utils::FileSize(path()));
vector<char> resultant_data;
EXPECT_TRUE(utils::ReadFile(path(), &resultant_data));
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index a996fb8..32b3923 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -27,6 +27,8 @@
DEFINE_string(old_image, "", "Path to the old rootfs");
DEFINE_string(new_image, "", "Path to the new rootfs");
DEFINE_string(out_file, "", "Path to output file");
+DEFINE_string(old_kernel, "", "Path to the old kernel partition image");
+DEFINE_string(new_kernel, "", "Path to the new kernel partition image");
DEFINE_string(apply_delta, "",
"If set, apply delta over old_image. (For debugging.)");
@@ -78,11 +80,13 @@
LOG(INFO) << "done applying delta.";
return 0;
}
- if (FLAGS_old_dir.empty() || FLAGS_new_dir.empty() ||
- FLAGS_old_image.empty() || FLAGS_new_image.empty() ||
- FLAGS_out_file.empty()) {
- LOG(FATAL) << "Missing required argument(s)";
- }
+ CHECK(!FLAGS_old_dir.empty());
+ CHECK(!FLAGS_new_dir.empty());
+ CHECK(!FLAGS_old_image.empty());
+ CHECK(!FLAGS_new_image.empty());
+ CHECK(!FLAGS_out_file.empty());
+ CHECK(!FLAGS_old_kernel.empty());
+ CHECK(!FLAGS_new_kernel.empty());
if ((!IsDir(FLAGS_old_dir.c_str())) || (!IsDir(FLAGS_new_dir.c_str()))) {
LOG(FATAL) << "old_dir or new_dir not directory";
}
@@ -91,6 +95,8 @@
FLAGS_old_image,
FLAGS_new_dir,
FLAGS_new_image,
+ FLAGS_old_kernel,
+ FLAGS_new_kernel,
FLAGS_out_file);
return 0;
diff --git a/test_utils.cc b/test_utils.cc
index 851e45d..a075c2d 100644
--- a/test_utils.cc
+++ b/test_utils.cc
@@ -35,15 +35,6 @@
return utils::WriteFile(path.c_str(), data.data(), data.size());
}
-off_t FileSize(const string& path) {
- struct stat stbuf;
- int rc = stat(path.c_str(), &stbuf);
- CHECK_EQ(rc, 0);
- if (rc < 0)
- return rc;
- return stbuf.st_size;
-}
-
std::string Readlink(const std::string& path) {
vector<char> buf(PATH_MAX + 1);
ssize_t r = readlink(path.c_str(), &buf[0], buf.size());
diff --git a/test_utils.h b/test_utils.h
index 2a87f49..4bc107e 100644
--- a/test_utils.h
+++ b/test_utils.h
@@ -21,10 +21,6 @@
bool WriteFileVector(const std::string& path, const std::vector<char>& data);
bool WriteFileString(const std::string& path, const std::string& data);
-// Returns the size of the file at path. If the file doesn't exist or some
-// error occurrs, -1 is returned.
-off_t FileSize(const std::string& path);
-
// Reads a symlink from disk. Returns empty string on failure.
std::string Readlink(const std::string& path);
diff --git a/update_metadata.proto b/update_metadata.proto
index 115d513..2fa8392 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -90,10 +90,8 @@
optional uint64 dst_length = 7;
}
repeated InstallOperation install_operations = 1;
- // The checksums of the install device before and after the install process.
- optional string src_checksum = 2;
- optional string dst_checksum = 3;
+ repeated InstallOperation kernel_install_operations = 2;
// (At time of writing) usually 4096
- optional uint32 block_size = 5 [default = 4096];
+ optional uint32 block_size = 3 [default = 4096];
}
diff --git a/utils.cc b/utils.cc
index 724a4ba..85d9e7d 100644
--- a/utils.cc
+++ b/utils.cc
@@ -105,6 +105,15 @@
return true;
}
+off_t FileSize(const string& path) {
+ struct stat stbuf;
+ int rc = stat(path.c_str(), &stbuf);
+ CHECK_EQ(rc, 0);
+ if (rc < 0)
+ return rc;
+ return stbuf.st_size;
+}
+
void HexDumpArray(const unsigned char* const arr, const size_t length) {
const unsigned char* const char_arr =
reinterpret_cast<const unsigned char* const>(arr);
diff --git a/utils.h b/utils.h
index 7b6fc10..7983eec 100644
--- a/utils.h
+++ b/utils.h
@@ -36,6 +36,10 @@
bool ReadFile(const std::string& path, std::vector<char>* out);
bool ReadFileToString(const std::string& path, std::string* out);
+// Returns the size of the file at path. If the file doesn't exist or some
+// error occurrs, -1 is returned.
+off_t FileSize(const std::string& path);
+
std::string ErrnoNumberAsString(int err);
// Strips duplicate slashes, and optionally removes all trailing slashes.