Revert "update_engine: Remove sparse hole extents."

Speculatively reverting commit 96b659d794be39762e8e7fd9f72fe6f723e21ec8 due to crbug.com/474497.

Change-Id: I17fd91c8568b30eafea9e70c9f2255ac2dc459a6
Reviewed-on: https://chromium-review.googlesource.com/264306
Reviewed-by: Shawn N <shawnn@chromium.org>
Commit-Queue: Shawn N <shawnn@chromium.org>
Tested-by: Shawn N <shawnn@chromium.org>
diff --git a/delta_performer.cc b/delta_performer.cc
index 0544e12..e6441fe 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -486,6 +486,7 @@
   return kMetadataParseSuccess;
 }
 
+
 // Wrapper around write. Returns true if all requested bytes
 // were written, or false on any error, regardless of progress
 // and stores an action exit code in |error|.
@@ -733,12 +734,16 @@
     ssize_t bytes_read_this_iteration = 0;
     const Extent& extent = operation.src_extents(i);
     const size_t bytes = extent.num_blocks() * block_size_;
-    TEST_AND_RETURN_FALSE(extent.start_block() != kSparseHole);
-    TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
-                                          &buf[bytes_read],
-                                          bytes,
-                                          extent.start_block() * block_size_,
-                                          &bytes_read_this_iteration));
+    if (extent.start_block() == kSparseHole) {
+      bytes_read_this_iteration = bytes;
+      memset(&buf[bytes_read], 0, bytes);
+    } else {
+      TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
+                                            &buf[bytes_read],
+                                            bytes,
+                                            extent.start_block() * block_size_,
+                                            &bytes_read_this_iteration));
+    }
     TEST_AND_RETURN_FALSE(
         bytes_read_this_iteration == static_cast<ssize_t>(bytes));
     bytes_read += bytes_read_this_iteration;
@@ -757,11 +762,18 @@
   for (int i = 0; i < operation.dst_extents_size(); i++) {
     const Extent& extent = operation.dst_extents(i);
     const size_t bytes = extent.num_blocks() * block_size_;
-    TEST_AND_RETURN_FALSE(extent.start_block() != kSparseHole);
-    TEST_AND_RETURN_FALSE(utils::PWriteAll(fd,
-                                           &buf[bytes_written],
-                                           bytes,
-                                           extent.start_block() * block_size_));
+    if (extent.start_block() == kSparseHole) {
+      DCHECK(buf.begin() + bytes_written ==
+             std::search_n(buf.begin() + bytes_written,
+                           buf.begin() + bytes_written + bytes,
+                           bytes, 0));
+    } else {
+      TEST_AND_RETURN_FALSE(
+          utils::PWriteAll(fd,
+                           &buf[bytes_written],
+                           bytes,
+                           extent.start_block() * block_size_));
+    }
     bytes_written += bytes;
   }
   DCHECK_EQ(bytes_written, bytes_read);
@@ -778,9 +790,13 @@
   uint64_t length = 0;
   for (int i = 0; i < extents.size(); i++) {
     Extent extent = extents.Get(i);
-    int64_t start = extent.start_block() * block_size;
+    int64_t start = extent.start_block();
     uint64_t this_length = min(full_length - length,
                                extent.num_blocks() * block_size);
+    if (start == static_cast<int64_t>(kSparseHole))
+      start = -1;
+    else
+      start *= block_size;
     ret += base::StringPrintf("%" PRIi64 ":%" PRIu64 ",", start, this_length);
     length += this_length;
   }