add support for reading MTD partitions to applypatch

Allow an MTD partition so serve as a source "file" in applypatch,
using a magically-formatted 'filename' that specifies the partition
name, size of data to read, and expected hash.  Build incremental OTAs
that update the recovery image via a patch.
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index 364f751..cd063a1 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -322,9 +322,12 @@
                              for b in bootloaders]))
 
 
-def IncludeBinary(name, input_zip, output_zip):
+def IncludeBinary(name, input_zip, output_zip, input_path=None):
   try:
-    data = input_zip.read(os.path.join("OTA/bin", name))
+    if input_path is not None:
+      data = open(input_path).read()
+    else:
+      data = input_zip.read(os.path.join("OTA/bin", name))
     output_zip.writestr(name, data)
   except IOError:
     raise ExternalError('unable to include device binary "%s"' % (name,))
@@ -402,8 +405,11 @@
   return out
 
 
-def Difference(tf, sf):
-  """Return the patch (as a string of data) needed to turn sf into tf."""
+def Difference(tf, sf, diff_program):
+  """Return the patch (as a string of data) needed to turn sf into tf.
+  diff_program is the name of an external program (or list, if
+  additional arguments are desired) to run to generate the diff.
+  """
 
   ttemp = tf.WriteToTemp()
   stemp = sf.WriteToTemp()
@@ -412,10 +418,17 @@
 
   try:
     ptemp = tempfile.NamedTemporaryFile()
-    p = common.Run(["bsdiff", stemp.name, ttemp.name, ptemp.name])
+    if isinstance(diff_program, list):
+      cmd = copy.copy(diff_program)
+    else:
+      cmd = [diff_program]
+    cmd.append(stemp.name)
+    cmd.append(ttemp.name)
+    cmd.append(ptemp.name)
+    p = common.Run(cmd)
     _, err = p.communicate()
     if err:
-      raise ExternalError("failure running bsdiff:\n%s\n" % (err,))
+      raise ExternalError("failure running %s:\n%s\n" % (diff_program, err))
     diff = ptemp.read()
     ptemp.close()
   finally:
@@ -461,7 +474,10 @@
       verbatim_targets.append((fn, tf.size))
     elif tf.sha1 != sf.sha1:
       # File is different; consider sending as a patch
-      d = Difference(tf, sf)
+      diff_method = "bsdiff"
+      if tf.name.endswith(".gz"):
+        diff_method = "imgdiff"
+      d = Difference(tf, sf, diff_method)
       print fn, tf.size, len(d), (float(len(d)) / tf.size)
       if len(d) > tf.size * OPTIONS.patch_threshold:
         # patch is almost as big as the file; don't bother patching
@@ -493,11 +509,13 @@
       os.path.join(OPTIONS.target_tmp, "BOOT"))
   updating_boot = (source_boot != target_boot)
 
-  source_recovery = common.BuildBootableImage(
-      os.path.join(OPTIONS.source_tmp, "RECOVERY"))
-  target_recovery = common.BuildBootableImage(
-      os.path.join(OPTIONS.target_tmp, "RECOVERY"))
-  updating_recovery = (source_recovery != target_recovery)
+  source_recovery = File("system/recovery.img",
+                         common.BuildBootableImage(
+      os.path.join(OPTIONS.source_tmp, "RECOVERY")))
+  target_recovery = File("system/recovery.img",
+                         common.BuildBootableImage(
+      os.path.join(OPTIONS.target_tmp, "RECOVERY")))
+  updating_recovery = (source_recovery.data != target_recovery.data)
 
   source_radio = source_zip.read("RADIO/image")
   target_radio = target_zip.read("RADIO/image")
@@ -515,13 +533,13 @@
 
   pb_verify = progress_bar_total * 0.3 * \
               (total_patched_size /
-               float(total_patched_size+total_verbatim_size))
+               float(total_patched_size+total_verbatim_size+1))
 
   for i, (fn, tf, sf, size) in enumerate(patch_list):
     if i % 5 == 0:
       next_sizes = sum([i[3] for i in patch_list[i:i+5]])
       script.append("show_progress %f 1" %
-                    (next_sizes * pb_verify / total_patched_size,))
+                    (next_sizes * pb_verify / (total_patched_size+1),))
     script.append("run_program PACKAGE:applypatch -c /%s %s %s" %
                   (fn, tf.sha1, sf.sha1))
 
@@ -531,6 +549,19 @@
     script.append("copy_dir PACKAGE:patch CACHE:../tmp/patchtmp")
     IncludeBinary("applypatch", target_zip, output_zip)
 
+  if updating_recovery:
+    d = Difference(target_recovery, source_recovery, "imgdiff")
+    print "recovery  target: %d  source: %d  diff: %d" % (
+        target_recovery.size, source_recovery.size, len(d))
+
+    output_zip.writestr("patch/recovery.img.p", d)
+
+    script.append(("run_program PACKAGE:applypatch -c "
+                   "MTD:recovery:%d:%s:%d:%s") %
+                  (source_recovery.size, source_recovery.sha1,
+                   target_recovery.size, target_recovery.sha1))
+
+
   script.append("\n# ---- start making changes here\n")
 
   if OPTIONS.wipe_user_data:
@@ -546,7 +577,15 @@
     print "boot image unchanged; skipping."
 
   if updating_recovery:
-    output_zip.writestr("system/recovery.img", target_recovery)
+    # Produce /system/recovery.img by applying a patch to the current
+    # contents of the recovery partition.
+    script.append(("run_program PACKAGE:applypatch MTD:recovery:%d:%s:%d:%s "
+                   "/system/recovery.img %s %d %s:/tmp/patchtmp/recovery.img.p")
+                  % (source_recovery.size, source_recovery.sha1,
+                     target_recovery.size, target_recovery.sha1,
+                     target_recovery.sha1,
+                     target_recovery.size,
+                     source_recovery.sha1))
     print "recovery image changed; including."
   else:
     print "recovery image unchanged; skipping."
@@ -561,12 +600,12 @@
 
   pb_apply = progress_bar_total * 0.7 * \
              (total_patched_size /
-              float(total_patched_size+total_verbatim_size))
+              float(total_patched_size+total_verbatim_size+1))
   for i, (fn, tf, sf, size) in enumerate(patch_list):
     if i % 5 == 0:
       next_sizes = sum([i[3] for i in patch_list[i:i+5]])
       script.append("show_progress %f 1" %
-                    (next_sizes * pb_apply / total_patched_size,))
+                    (next_sizes * pb_apply / (total_patched_size+1),))
     script.append(("run_program PACKAGE:applypatch "
                    "/%s - %s %d %s:/tmp/patchtmp/%s.p") %
                   (fn, tf.sha1, tf.size, sf.sha1, fn))
@@ -594,7 +633,7 @@
   if verbatim_targets:
     pb_verbatim = progress_bar_total * \
                   (total_verbatim_size /
-                   float(total_patched_size+total_verbatim_size))
+                   float(total_patched_size+total_verbatim_size+1))
     script.append("show_progress %f 5" % (pb_verbatim,))
     script.append("copy_dir PACKAGE:system SYSTEM:")