| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include <base/strings/string_util.h> |
| #include <base/strings/stringprintf.h> |
| #include <gtest/gtest.h> |
| |
| #include "update_engine/graph_types.h" |
| #include "update_engine/delta_diff_generator.h" |
| #include "update_engine/metadata.h" |
| #include "update_engine/test_utils.h" |
| #include "update_engine/utils.h" |
| |
| using std::string; |
| using std::vector; |
| |
| namespace chromeos_update_engine { |
| |
| typedef DeltaDiffGenerator::Block Block; |
| |
| class MetadataTest : public ::testing::Test { |
| }; |
| |
| TEST_F(MetadataTest, RunAsRootReadMetadataDissimilarFileSystems) { |
| string a_img, b_img; |
| EXPECT_TRUE(utils::MakeTempFile("a_img.XXXXXX", &a_img, NULL)); |
| ScopedPathUnlinker a_img_unlinker(a_img); |
| EXPECT_TRUE(utils::MakeTempFile("b_img.XXXXXX", &b_img, NULL)); |
| ScopedPathUnlinker b_img_unlinker(b_img); |
| |
| CreateEmptyExtImageAtPath(a_img, 10485759, 4096); |
| CreateEmptyExtImageAtPath(b_img, 11534336, 4096); |
| |
| Graph graph; |
| vector<Block> blocks; |
| EXPECT_TRUE(Metadata::DeltaReadMetadata(&graph, |
| &blocks, |
| a_img, |
| b_img, |
| 0, |
| NULL)); |
| EXPECT_EQ(graph.size(), 0); |
| |
| CreateEmptyExtImageAtPath(a_img, 10485759, 4096); |
| CreateEmptyExtImageAtPath(b_img, 10485759, 8192); |
| |
| graph.clear(); |
| blocks.clear(); |
| EXPECT_TRUE(Metadata::DeltaReadMetadata(&graph, |
| &blocks, |
| a_img, |
| b_img, |
| 0, |
| NULL)); |
| EXPECT_EQ(graph.size(), 0); |
| } |
| |
| TEST_F(MetadataTest, RunAsRootReadMetadata) { |
| string a_img, b_img, data_file; |
| EXPECT_TRUE(utils::MakeTempFile("a_img.XXXXXX", &a_img, NULL)); |
| ScopedPathUnlinker a_img_unlinker(a_img); |
| EXPECT_TRUE(utils::MakeTempFile("b_img.XXXXXX", &b_img, NULL)); |
| ScopedPathUnlinker b_img_unlinker(b_img); |
| EXPECT_TRUE(utils::MakeTempFile("data_file.XXXXXX", &data_file, NULL)); |
| ScopedPathUnlinker data_file_unlinker(data_file); |
| |
| const size_t image_size = (256 * 1024 * 1024); // Enough for 2 block groups |
| const int block_size = 4096; |
| CreateEmptyExtImageAtPath(a_img, image_size, block_size); |
| |
| // Create a file large enough to create an indirect block |
| { |
| string a_img_mnt; |
| ScopedLoopMounter a_img_mount(a_img, &a_img_mnt, 0); |
| System(base::StringPrintf("dd if=/dev/zero of=%s/test_file bs=%d count=%d", |
| a_img_mnt.c_str(), block_size, |
| EXT2_NDIR_BLOCKS + 1)); |
| } |
| |
| System(base::StringPrintf("cp %s %s", a_img.c_str(), b_img.c_str())); |
| |
| int fd = open(data_file.c_str(), O_RDWR | O_CREAT, S_IRWXU); |
| EXPECT_NE(fd, -1); |
| ScopedFdCloser fd_closer(&fd); |
| |
| Graph graph; |
| vector<Block> blocks(image_size / block_size); |
| off_t data_file_size; |
| EXPECT_TRUE(Metadata::DeltaReadMetadata(&graph, |
| &blocks, |
| a_img, |
| b_img, |
| fd, |
| &data_file_size)); |
| |
| // There are 12 metadata that we look for: |
| // - Block group 0 metadata (superblock, group descriptor, bitmaps, etc) |
| // - Chunk 0, 1, 2, 3 |
| // - Block group 1 metadata |
| // - Chunk 0, 1, 2, 3 |
| // - Root directory (inode 2) |
| // - Journal (inode 8) |
| // - lost+found directory (inode 11) |
| // - test_file indirect block (inode 12) |
| struct { |
| string metadata_name; |
| off_t start_block; // Set to -1 to skip start block verification |
| off_t num_blocks; // Set to -1 to skip num blocks verification |
| } exp_results[] = |
| {{"<rootfs-bg-0-0-metadata>", 0, 104}, |
| {"<rootfs-bg-0-1-metadata>", 104, 104}, |
| {"<rootfs-bg-0-2-metadata>", 208, 104}, |
| {"<rootfs-bg-0-3-metadata>", 312, 104}, |
| {"<rootfs-bg-0-4-metadata>", 416, 104}, |
| {"<rootfs-bg-0-5-metadata>", 520, 104}, |
| {"<rootfs-bg-0-6-metadata>", 624, 104}, |
| {"<rootfs-bg-0-7-metadata>", 728, 104}, |
| {"<rootfs-bg-0-8-metadata>", 832, 104}, |
| {"<rootfs-bg-0-9-metadata>", 936, 107}, |
| {"<rootfs-bg-1-0-metadata>", 32768, 104}, |
| {"<rootfs-bg-1-1-metadata>", 32872, 104}, |
| {"<rootfs-bg-1-2-metadata>", 32976, 104}, |
| {"<rootfs-bg-1-3-metadata>", 33080, 104}, |
| {"<rootfs-bg-1-4-metadata>", 33184, 104}, |
| {"<rootfs-bg-1-5-metadata>", 33288, 104}, |
| {"<rootfs-bg-1-6-metadata>", 33392, 104}, |
| {"<rootfs-bg-1-7-metadata>", 33496, 104}, |
| {"<rootfs-bg-1-8-metadata>", 33600, 104}, |
| {"<rootfs-bg-1-9-metadata>", 33704, 107}, |
| {"<rootfs-inode-2-metadata>", -1, 1}, |
| {"<rootfs-inode-8-metadata>", -1, 4101}, |
| {"<rootfs-inode-11-metadata>", -1, 4}, |
| {"<rootfs-inode-12-metadata>", -1, 1}}; |
| |
| int num_exp_results = sizeof(exp_results) / sizeof(exp_results[0]); |
| EXPECT_EQ(graph.size(), num_exp_results); |
| |
| for (int i = 0; i < num_exp_results; i++) { |
| Vertex& vertex = graph[i]; |
| DeltaArchiveManifest_InstallOperation& op = vertex.op; |
| |
| EXPECT_STRCASEEQ(vertex.file_name.c_str(), |
| exp_results[i].metadata_name.c_str()); |
| |
| EXPECT_EQ(op.src_extents().size(), op.dst_extents().size()); |
| for (int e = 0; e < op.src_extents().size(); e++) { |
| EXPECT_EQ(op.src_extents(e).start_block(), |
| op.dst_extents(e).start_block()); |
| EXPECT_EQ(op.src_extents(e).num_blocks(), |
| op.dst_extents(e).num_blocks()); |
| } |
| |
| if (exp_results[i].start_block != -1) { |
| EXPECT_EQ(op.src_extents(0).start_block(), exp_results[i].start_block); |
| } |
| |
| if (exp_results[i].num_blocks != -1) { |
| EXPECT_EQ(op.src_extents(0).num_blocks(), exp_results[i].num_blocks); |
| } |
| } |
| } |
| |
| } // namespace chromeos_update_engine |