1 // 2 // Copyright (C) 2016 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/payload_generator/mapfile_filesystem.h" 18 19 #include <unistd.h> 20 21 #include <map> 22 #include <string> 23 #include <vector> 24 25 #include <base/format_macros.h> 26 #include <base/logging.h> 27 #include <base/strings/string_number_conversions.h> 28 #include <base/strings/string_util.h> 29 #include <base/strings/stringprintf.h> 30 #include <gtest/gtest.h> 31 32 #include "update_engine/common/test_utils.h" 33 #include "update_engine/common/utils.h" 34 #include "update_engine/payload_generator/extent_ranges.h" 35 #include "update_engine/payload_generator/extent_utils.h" 36 37 using std::map; 38 using std::string; 39 using std::unique_ptr; 40 using std::vector; 41 42 namespace chromeos_update_engine { 43 44 namespace { 45 46 // Checks that all the blocks in |extents| are in the range [0, total_blocks). 47 void ExpectBlocksInRange(const vector<Extent>& extents, uint64_t total_blocks) { 48 for (const Extent& extent : extents) { 49 EXPECT_LE(0U, extent.start_block()); 50 EXPECT_LE(extent.start_block() + extent.num_blocks(), total_blocks); 51 } 52 } 53 54 } // namespace 55 56 class MapfileFilesystemTest : public ::testing::Test { 57 protected: 58 test_utils::ScopedTempFile temp_file_{"mapfile_file.XXXXXX"}; 59 test_utils::ScopedTempFile temp_mapfile_{"mapfile_mapfile.XXXXXX"}; 60 }; 61 62 TEST_F(MapfileFilesystemTest, EmptyFilesystem) { 63 unique_ptr<MapfileFilesystem> fs = MapfileFilesystem::CreateFromFile( 64 temp_file_.path(), temp_mapfile_.path()); 65 ASSERT_NE(nullptr, fs.get()); 66 67 EXPECT_EQ(0U, fs->GetBlockCount()); 68 // .map files are always 4KiB blocks. 69 EXPECT_EQ(4096U, fs->GetBlockSize()); 70 } 71 72 TEST_F(MapfileFilesystemTest, SeveralFileFormatTest) { 73 string text = 74 "/fileA 1\n" 75 "/fileB 2-4\n" 76 "/fileC 5-6 9 11-12\n" 77 "/file with spaces 14 19\n" 78 "/1234 7\n"; 79 test_utils::WriteFileString(temp_mapfile_.path(), text); 80 EXPECT_EQ(0, HANDLE_EINTR(truncate(temp_file_.path().c_str(), 4096 * 20))); 81 82 unique_ptr<MapfileFilesystem> fs = MapfileFilesystem::CreateFromFile( 83 temp_file_.path(), temp_mapfile_.path()); 84 ASSERT_NE(nullptr, fs.get()); 85 86 vector<FilesystemInterface::File> files; 87 EXPECT_TRUE(fs->GetFiles(&files)); 88 89 map<string, FilesystemInterface::File> map_files; 90 for (const auto& file : files) { 91 EXPECT_EQ(map_files.end(), map_files.find(file.name)) 92 << "File " << file.name << " repeated in the list."; 93 map_files[file.name] = file; 94 ExpectBlocksInRange(file.extents, fs->GetBlockCount()); 95 } 96 97 EXPECT_EQ(map_files["/fileA"].extents, 98 (vector<Extent>{ExtentForRange(1, 1)})); 99 EXPECT_EQ(map_files["/fileB"].extents, 100 (vector<Extent>{ExtentForRange(2, 3)})); 101 EXPECT_EQ( 102 map_files["/fileC"].extents, 103 (vector<Extent>{ 104 ExtentForRange(5, 2), ExtentForRange(9, 1), ExtentForRange(11, 2)})); 105 EXPECT_EQ(map_files["/file with spaces"].extents, 106 (vector<Extent>{ExtentForRange(14, 1), ExtentForRange(19, 1)})); 107 EXPECT_EQ(map_files["/1234"].extents, (vector<Extent>{ExtentForRange(7, 1)})); 108 } 109 110 TEST_F(MapfileFilesystemTest, BlockNumberTooBigTest) { 111 test_utils::WriteFileString(temp_mapfile_.path(), "/some/file 1-4\n"); 112 EXPECT_EQ(0, HANDLE_EINTR(truncate(temp_file_.path().c_str(), 4096 * 3))); 113 114 unique_ptr<MapfileFilesystem> fs = MapfileFilesystem::CreateFromFile( 115 temp_file_.path(), temp_mapfile_.path()); 116 ASSERT_NE(nullptr, fs.get()); 117 118 vector<FilesystemInterface::File> files; 119 EXPECT_FALSE(fs->GetFiles(&files)); 120 } 121 122 TEST_F(MapfileFilesystemTest, EndBeforeStartTest) { 123 test_utils::WriteFileString(temp_mapfile_.path(), "/some/file 2-1\n"); 124 EXPECT_EQ(0, HANDLE_EINTR(truncate(temp_file_.path().c_str(), 4096 * 3))); 125 126 unique_ptr<MapfileFilesystem> fs = MapfileFilesystem::CreateFromFile( 127 temp_file_.path(), temp_mapfile_.path()); 128 ASSERT_NE(nullptr, fs.get()); 129 130 vector<FilesystemInterface::File> files; 131 EXPECT_FALSE(fs->GetFiles(&files)); 132 } 133 134 } // namespace chromeos_update_engine 135