AU: When applying delta locally, get source checksums

When applying a delta on the host, we need to calculate the original
checksums for the rootfs/kernel for the delta performer. This CL does
that.

Also:
- Log old/new checksums in performer
- Add base64 encode function to OmahaHashCalculator

BUG=8062
TEST=unittests; applied delta on host

Review URL: http://codereview.chromium.org/4042004

Change-Id: I953d7dd34cb65269e9b44e22c87a13a7f52e66d4
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index b447f11..03b59d9 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -611,9 +611,9 @@
   return true;
 }
 
-bool InitializePartitionInfo(bool is_kernel,
-                             const string& partition,
-                             PartitionInfo* info) {
+bool DeltaDiffGenerator::InitializePartitionInfo(bool is_kernel,
+                                                 const string& partition,
+                                                 PartitionInfo* info) {
   int64_t size = 0;
   if (is_kernel) {
     size = utils::FileSize(partition);
@@ -641,25 +641,25 @@
                               const string& new_rootfs,
                               DeltaArchiveManifest* manifest) {
   if (!old_kernel.empty()) {
-    TEST_AND_RETURN_FALSE(
-        InitializePartitionInfo(true,
-                                old_kernel,
-                                manifest->mutable_old_kernel_info()));
+    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
+        true,
+        old_kernel,
+        manifest->mutable_old_kernel_info()));
   }
-  TEST_AND_RETURN_FALSE(
-      InitializePartitionInfo(true,
-                              new_kernel,
-                              manifest->mutable_new_kernel_info()));
+  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
+      true,
+      new_kernel,
+      manifest->mutable_new_kernel_info()));
   if (!old_rootfs.empty()) {
-    TEST_AND_RETURN_FALSE(
-        InitializePartitionInfo(false,
-                                old_rootfs,
-                                manifest->mutable_old_rootfs_info()));
+    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
+        false,
+        old_rootfs,
+        manifest->mutable_old_rootfs_info()));
   }
-  TEST_AND_RETURN_FALSE(
-      InitializePartitionInfo(false,
-                              new_rootfs,
-                              manifest->mutable_new_rootfs_info()));
+  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
+      false,
+      new_rootfs,
+      manifest->mutable_new_rootfs_info()));
   return true;
 }
 
diff --git a/delta_diff_generator.h b/delta_diff_generator.h
index 9fbe0a5..3156fd6 100644
--- a/delta_diff_generator.h
+++ b/delta_diff_generator.h
@@ -215,6 +215,10 @@
   // (e.g., a move operation that copies blocks onto themselves).
   static bool IsNoopOperation(const DeltaArchiveManifest_InstallOperation& op);
 
+  static bool InitializePartitionInfo(bool is_kernel,
+                                      const std::string& partition,
+                                      PartitionInfo* info);
+
  private:
   // This should never be constructed
   DISALLOW_IMPLICIT_CONSTRUCTORS(DeltaDiffGenerator);
diff --git a/delta_performer.cc b/delta_performer.cc
index 134316e..e14ad4e 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -165,6 +165,33 @@
   return -err;
 }
 
+namespace {
+
+void LogPartitionInfoHash(const PartitionInfo& info, const string& tag) {
+  string sha256;
+  if (OmahaHashCalculator::Base64Encode(info.hash().data(),
+                                        info.hash().size(),
+                                        &sha256)) {
+    LOG(INFO) << "PartitionInfo " << tag << " sha256:" << sha256
+              << " length:" << tag.size();
+  } else {
+    LOG(ERROR) << "Base64Encode failed for tag: " << tag;
+  }
+}
+
+void LogPartitionInfo(const DeltaArchiveManifest& manifest) {
+  if (manifest.has_old_kernel_info())
+    LogPartitionInfoHash(manifest.old_kernel_info(), "old_kernel_info");
+  if (manifest.has_old_rootfs_info())
+    LogPartitionInfoHash(manifest.old_rootfs_info(), "old_rootfs_info");
+  if (manifest.has_new_kernel_info())
+    LogPartitionInfoHash(manifest.new_kernel_info(), "new_kernel_info");
+  if (manifest.has_new_rootfs_info())
+    LogPartitionInfoHash(manifest.new_rootfs_info(), "new_rootfs_info");
+}
+
+}  // namespace {}
+
 // Wrapper around write. Returns bytes written on success or
 // -errno on error.
 // This function performs as many actions as it can, given the amount of
@@ -207,6 +234,7 @@
                                       manifest_metadata_size_))
         << "Unable to save the manifest metadata size.";
     manifest_valid_ = true;
+    LogPartitionInfo(manifest_);
     if (!PrimeUpdateState()) {
       LOG(ERROR) << "Unable to prime the update state.";
       return -EINVAL;
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index efeeb3b..39a0e08 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -76,7 +76,22 @@
     LOG(INFO) << "Setting up preferences under: " << FLAGS_prefs_dir;
     LOG_IF(ERROR, !prefs.Init(FilePath(FLAGS_prefs_dir)))
         << "Failed to initialize preferences.";
+    // Get original checksums
+    LOG(INFO) << "Calculating original checksums";
+    PartitionInfo kern_info, root_info;
+    CHECK(DeltaDiffGenerator::InitializePartitionInfo(true,  // is_kernel
+                                                      FLAGS_old_kernel,
+                                                      &kern_info));
+    CHECK(DeltaDiffGenerator::InitializePartitionInfo(false,  // is_kernel
+                                                      FLAGS_old_image,
+                                                      &root_info));
+    vector<char> kern_hash(kern_info.hash().begin(),
+                           kern_info.hash().end());
+    vector<char> root_hash(root_info.hash().begin(),
+                           root_info.hash().end());
     DeltaPerformer performer(&prefs);
+    performer.set_current_kernel_hash(&kern_hash);
+    performer.set_current_rootfs_hash(&root_hash);
     CHECK_EQ(performer.Open(FLAGS_old_image.c_str(), 0, 0), 0);
     CHECK(performer.OpenKernel(FLAGS_old_kernel.c_str()));
     vector<char> buf(1024 * 1024);
diff --git a/omaha_hash_calculator.cc b/omaha_hash_calculator.cc
index ac4edf4..cf583a9 100644
--- a/omaha_hash_calculator.cc
+++ b/omaha_hash_calculator.cc
@@ -63,18 +63,10 @@
   return bytes_processed;
 }
 
-// Call Finalize() when all data has been passed in. This mostly just
-// calls OpenSSL's SHA256_Final() and then base64 encodes the hash.
-bool OmahaHashCalculator::Finalize() {
+bool OmahaHashCalculator::Base64Encode(const void* data,
+                                       size_t size,
+                                       string* out) {
   bool success = true;
-  TEST_AND_RETURN_FALSE(hash_.empty());
-  TEST_AND_RETURN_FALSE(raw_hash_.empty());
-  raw_hash_.resize(SHA256_DIGEST_LENGTH);
-  TEST_AND_RETURN_FALSE(
-      SHA256_Final(reinterpret_cast<unsigned char*>(&raw_hash_[0]),
-                   &ctx_) == 1);
-
-  // Convert raw_hash_ to base64 encoding and store it in hash_.
   BIO *b64 = BIO_new(BIO_f_base64());
   if (!b64)
     LOG(INFO) << "BIO_new(BIO_f_base64()) failed";
@@ -84,14 +76,13 @@
   if (b64 && bmem) {
     b64 = BIO_push(b64, bmem);
     success =
-        (BIO_write(b64, &raw_hash_[0], raw_hash_.size()) ==
-         static_cast<int>(raw_hash_.size()));
+        (BIO_write(b64, data, size) == static_cast<int>(size));
     if (success)
       success = (BIO_flush(b64) == 1);
 
     BUF_MEM *bptr = NULL;
     BIO_get_mem_ptr(b64, &bptr);
-    hash_.assign(bptr->data, bptr->length - 1);
+    out->assign(bptr->data, bptr->length - 1);
   }
   if (b64) {
     BIO_free_all(b64);
@@ -100,6 +91,20 @@
   return success;
 }
 
+// Call Finalize() when all data has been passed in. This mostly just
+// calls OpenSSL's SHA256_Final() and then base64 encodes the hash.
+bool OmahaHashCalculator::Finalize() {
+  TEST_AND_RETURN_FALSE(hash_.empty());
+  TEST_AND_RETURN_FALSE(raw_hash_.empty());
+  raw_hash_.resize(SHA256_DIGEST_LENGTH);
+  TEST_AND_RETURN_FALSE(
+      SHA256_Final(reinterpret_cast<unsigned char*>(&raw_hash_[0]),
+                   &ctx_) == 1);
+
+  // Convert raw_hash_ to base64 encoding and store it in hash_.
+  return Base64Encode(&raw_hash_[0], raw_hash_.size(), &hash_);;
+}
+
 bool OmahaHashCalculator::RawHashOfData(const vector<char>& data,
                                         vector<char>* out_hash) {
   OmahaHashCalculator calc;
diff --git a/omaha_hash_calculator.h b/omaha_hash_calculator.h
index dc9fe4e..762b8d4 100644
--- a/omaha_hash_calculator.h
+++ b/omaha_hash_calculator.h
@@ -70,6 +70,8 @@
   static std::string OmahaHashOfString(const std::string& str);
   static std::string OmahaHashOfData(const std::vector<char>& data);
 
+  static bool Base64Encode(const void* data, size_t size, std::string* out);
+
  private:
   // If non-empty, the final base64 encoded hash and the raw hash. Will only be
   // set to non-empty when Finalize is called.