AU: Delta Diff Generator

Adds a class that can take two root filesystem image and generate a
delta between them. Currently it's not very well tested, but this will
improve once the diff applicator is written.

Also, an executable to run the generator.

Other changes:
- Stop leaking loop devices in unittests
- extent mapper: support sparse files, ability to get FS block size
- AppendBlockToExtents support sparse files
- subprocess more verbose on errors
- add WriteAll to utils (WriteAll avoids short-write() returns)
- mkstemp wrapper for ease of use
- VectorIndexOf, finds index of an element in a vector

Review URL: http://codereview.chromium.org/891002
diff --git a/extent_mapper_unittest.cc b/extent_mapper_unittest.cc
index 6962004..dc69437 100644
--- a/extent_mapper_unittest.cc
+++ b/extent_mapper_unittest.cc
@@ -11,6 +11,7 @@
 #include <gtest/gtest.h>
 #include "base/basictypes.h"
 #include "update_engine/extent_mapper.h"
+#include "update_engine/graph_types.h"
 #include "update_engine/utils.h"
 
 using std::set;
@@ -27,8 +28,11 @@
   // In lieu of this, we do a weak test: make sure the extents of the unittest
   // executable are consistent and they match with the size of the file.
   const string kFilename = "/proc/self/exe";
-  const off_t kBlockSize = 4096;
   
+  uint32 block_size = 0;
+  EXPECT_TRUE(extent_mapper::GetFilesystemBlockSize(kFilename, &block_size));
+  EXPECT_GT(block_size, 0);
+    
   vector<Extent> extents;
   
   ASSERT_TRUE(extent_mapper::ExtentsForFileFibmap(kFilename, &extents));
@@ -48,7 +52,41 @@
   
   struct stat stbuf;
   EXPECT_EQ(0, stat(kFilename.c_str(), &stbuf));
-  EXPECT_EQ(blocks.size(), (stbuf.st_size + kBlockSize - 1)/kBlockSize);
+  EXPECT_EQ(blocks.size(), (stbuf.st_size + block_size - 1)/block_size);
+}
+
+TEST(ExtentMapperTest, RunAsRootSparseFileTest) {
+  // Create sparse file with one real block, then two sparse ones, then a real
+  // block at the end.
+  const char tmp_name_template[] =
+      "/tmp/ExtentMapperTest.RunAsRootSparseFileTest.XXXXXX";
+  char buf[sizeof(tmp_name_template)];
+  strncpy(buf, tmp_name_template, sizeof(buf));
+  COMPILE_ASSERT(sizeof(buf) > 8, buf_size_incorrect);
+  ASSERT_EQ('\0', buf[sizeof(buf) - 1]);
+
+  int fd = mkstemp(buf);
+  ASSERT_GE(fd, 0);
+
+  uint32 block_size = 0;
+  EXPECT_TRUE(extent_mapper::GetFilesystemBlockSize(buf, &block_size));
+  EXPECT_GT(block_size, 0);
+  
+  EXPECT_EQ(1, pwrite(fd, "x", 1, 0));
+  EXPECT_EQ(1, pwrite(fd, "x", 1, 3 * block_size));
+  close(fd);
+  
+  vector<Extent> extents;
+  EXPECT_TRUE(extent_mapper::ExtentsForFileFibmap(buf, &extents));
+  unlink(buf);
+  EXPECT_EQ(3, extents.size());
+  EXPECT_EQ(1, extents[0].num_blocks());
+  EXPECT_EQ(2, extents[1].num_blocks());
+  EXPECT_EQ(1, extents[2].num_blocks());
+  EXPECT_NE(kSparseHole, extents[0].start_block());
+  EXPECT_EQ(kSparseHole, extents[1].start_block());
+  EXPECT_NE(kSparseHole, extents[2].start_block());
+  EXPECT_NE(extents[2].start_block(), extents[0].start_block());
 }
 
 }  // namespace chromeos_update_engine