AU: Verify source rootfs/kernel hashes before applying delta.

New style full updates will not send the old rootfs hash so no check takes
place.

BUG=7562
TEST=unit tests, gmerged on device and tested with good/bad source partition

Change-Id: I65b28bf57110e4d87472d4aea59121878cde24b0

Review URL: http://codereview.chromium.org/3712003
diff --git a/filesystem_copier_action.cc b/filesystem_copier_action.cc
index 5628ec3..1452b4d 100755
--- a/filesystem_copier_action.cc
+++ b/filesystem_copier_action.cc
@@ -79,6 +79,8 @@
     return;
   }
 
+  DetermineFilesystemSize(src_fd);
+
   src_stream_ = g_unix_input_stream_new(src_fd, TRUE);
   dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
 
@@ -89,7 +91,7 @@
 
   g_input_stream_read_async(src_stream_,
                             &buffer_[0],
-                            buffer_.size(),
+                            GetBytesToRead(),
                             G_PRIORITY_DEFAULT,
                             canceller_,
                             &FilesystemCopierAction::StaticAsyncReadyCallback,
@@ -137,9 +139,27 @@
 
     if (bytes_read == 0) {
       // We're done!
+      if (!hasher_.Finalize()) {
+        LOG(ERROR) << "Unable to finalize the hash.";
+        Cleanup(false, was_cancelled);
+        return;
+      }
+      LOG(INFO) << "hash: " << hasher_.hash();
+      if (copying_kernel_install_path_) {
+        install_plan_.current_kernel_hash = hasher_.raw_hash();
+      } else {
+        install_plan_.current_rootfs_hash = hasher_.raw_hash();
+      }
       Cleanup(true, was_cancelled);
       return;
     }
+    if (!hasher_.Update(buffer_.data(), bytes_read)) {
+      LOG(ERROR) << "Unable to update the hash.";
+      Cleanup(false, was_cancelled);
+      return;
+    }
+    filesystem_size_ -= bytes_read;
+
     // Kick off a write
     read_in_flight_ = false;
     buffer_valid_size_ = bytes_read;
@@ -175,11 +195,26 @@
   g_input_stream_read_async(
       src_stream_,
       &buffer_[0],
-      buffer_.size(),
+      GetBytesToRead(),
       G_PRIORITY_DEFAULT,
       canceller_,
       &FilesystemCopierAction::StaticAsyncReadyCallback,
       this);
 }
 
+void FilesystemCopierAction::DetermineFilesystemSize(int fd) {
+  filesystem_size_ = kint64max;
+  int block_count = 0, block_size = 0;
+  if (!copying_kernel_install_path_ &&
+      utils::GetFilesystemSizeFromFD(fd, &block_count, &block_size)) {
+    filesystem_size_ = static_cast<int64_t>(block_count) * block_size;
+    LOG(INFO) << "Filesystem size: " << filesystem_size_ << " bytes ("
+              << block_count << "x" << block_size << ").";
+  }
+}
+
+int64_t FilesystemCopierAction::GetBytesToRead() {
+  return std::min(static_cast<int64_t>(buffer_.size()), filesystem_size_);
+}
+
 }  // namespace chromeos_update_engine