AU: Class to perform delta updates.

A class to perform delta updates and the associated unittests. Also,
change the delta diff generator executable to be able to apply a
delta, which is handy for debugging.

TEST=Attached unit test, hand-tested on real build images
BUG=552

Review URL: http://codereview.chromium.org/1718001
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index 2f21b2a..a996fb8 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -5,14 +5,17 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <set>
 #include <string>
+#include <vector>
 #include <gflags/gflags.h>
 #include <glib.h>
 #include "base/command_line.h"
 #include "chromeos/obsolete_logging.h"
 #include "update_engine/delta_diff_generator.h"
+#include "update_engine/delta_performer.h"
 #include "update_engine/subprocess.h"
 #include "update_engine/update_metadata.pb.h"
 #include "update_engine/utils.h"
@@ -24,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(apply_delta, "",
+              "If set, apply delta over old_image. (For debugging.)");
 
 // This file contains a simple program that takes an old path, a new path,
 // and an output file as arguments and the path to an output file and
@@ -31,6 +36,7 @@
 
 using std::set;
 using std::string;
+using std::vector;
 
 namespace chromeos_update_engine {
 
@@ -51,6 +57,27 @@
                        logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
                        logging::DONT_LOCK_LOG_FILE,
                        logging::APPEND_TO_OLD_LOG_FILE);
+  if (!FLAGS_apply_delta.empty()) {
+    if (FLAGS_old_image.empty()) {
+      LOG(FATAL) << "Must pass --old_image with --apply_delta.";
+    }
+    DeltaPerformer performer;
+    CHECK_EQ(performer.Open(FLAGS_old_image.c_str(), 0, 0), 0);
+    vector<char> buf(1024 * 1024);
+    int fd = open(FLAGS_apply_delta.c_str(), O_RDONLY, 0);
+    CHECK_GE(fd, 0);
+    ScopedFdCloser fd_closer(&fd);
+    for (off_t offset = 0;; offset += buf.size()) {
+      ssize_t bytes_read;
+      CHECK(utils::PReadAll(fd, &buf[0], buf.size(), offset, &bytes_read));
+      if (bytes_read == 0)
+        break;
+      CHECK_EQ(performer.Write(&buf[0], bytes_read), bytes_read);
+    }
+    CHECK_EQ(performer.Close(), 0);
+    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()) {