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