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 37using std::map; 38using std::string; 39using std::unique_ptr; 40using std::vector; 41 42namespace chromeos_update_engine { 43 44namespace { 45 46// Checks that all the blocks in |extents| are in the range [0, total_blocks). 47void 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 56class 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 62TEST_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 72TEST_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 110TEST_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 122TEST_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