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.cc b/extent_mapper.cc
index ed528fd..4af5f5d 100755
--- a/extent_mapper.cc
+++ b/extent_mapper.cc
@@ -16,6 +16,8 @@
 
 #include <linux/fs.h>
 
+#include "update_engine/graph_types.h"
+#include "update_engine/graph_utils.h"
 #include "update_engine/utils.h"
 
 using std::string;
@@ -31,7 +33,6 @@
 
 bool ExtentsForFileFibmap(const std::string& path, std::vector<Extent>* out) {
   CHECK(out);
-  // TODO(adlr): verify path is a file
   struct stat stbuf;
   int rc = stat(path.c_str(), &stbuf);
   TEST_AND_RETURN_FALSE_ERRNO(rc == 0);
@@ -53,32 +54,23 @@
   current.set_num_blocks(0);
 
   for (int i = 0; i < block_count; i++) {
-    unsigned int block = i;
-    rc = ioctl(fd, FIBMAP, &block);
+    unsigned int block32 = i;
+    rc = ioctl(fd, FIBMAP, &block32);
     TEST_AND_RETURN_FALSE_ERRNO(rc == 0);
     
-    // Add next block to extents
-    if (current.num_blocks() == 0) {
-      // We're starting a new extent
-      current.set_start_block(block);
-      current.set_num_blocks(1);
-      continue;
-    }
-    if ((current.start_block() + current.num_blocks()) == block) {
-      // We're continuing the last extent
-      current.set_num_blocks(current.num_blocks() + 1);
-      continue;
-    }
-    // We're starting a new extent and keeping the current one
-    out->push_back(current);
-    current.set_start_block(block);
-    current.set_num_blocks(1);
-    continue;
+    const uint64 block = (block32 == 0 ? kSparseHole : block32);
+    
+    graph_utils::AppendBlockToExtents(out, block);
   }
-  
-  if (current.num_blocks() > 0)
-    out->push_back(current);
+  return true;
+}
 
+bool GetFilesystemBlockSize(const std::string& path, uint32* out_blocksize) {
+  int fd = open(path.c_str(), O_RDONLY, 0);
+  TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
+  ScopedFdCloser fd_closer(&fd);
+  int rc = ioctl(fd, FIGETBSZ, out_blocksize);
+  TEST_AND_RETURN_FALSE_ERRNO(rc != -1);
   return true;
 }