mapfile_filesystem.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. #include "update_engine/payload_generator/mapfile_filesystem.h"
  17. #include <algorithm>
  18. #include <map>
  19. #include <base/files/file_util.h>
  20. #include <base/logging.h>
  21. #include <base/memory/ptr_util.h>
  22. #include <base/strings/string_number_conversions.h>
  23. #include <base/strings/string_split.h>
  24. #include "update_engine/common/utils.h"
  25. #include "update_engine/payload_generator/extent_ranges.h"
  26. #include "update_engine/payload_generator/extent_utils.h"
  27. #include "update_engine/update_metadata.pb.h"
  28. using std::string;
  29. using std::vector;
  30. namespace {
  31. // The .map file is defined in terms of 4K blocks.
  32. size_t kMapfileBlockSize = 4096;
  33. } // namespace
  34. namespace chromeos_update_engine {
  35. std::unique_ptr<MapfileFilesystem> MapfileFilesystem::CreateFromFile(
  36. const string& filename, const string& mapfile_filename) {
  37. if (filename.empty() || mapfile_filename.empty())
  38. return nullptr;
  39. off_t file_size = utils::FileSize(filename);
  40. if (file_size < 0)
  41. return nullptr;
  42. if (file_size % kMapfileBlockSize) {
  43. LOG(ERROR) << "Image file " << filename << " has a size of " << file_size
  44. << " which is not multiple of " << kMapfileBlockSize;
  45. return nullptr;
  46. }
  47. off_t num_blocks = file_size / kMapfileBlockSize;
  48. if (!utils::FileExists(mapfile_filename.c_str())) {
  49. LOG(ERROR) << "File " << mapfile_filename << " doesn't exist";
  50. return nullptr;
  51. }
  52. return base::WrapUnique(new MapfileFilesystem(mapfile_filename, num_blocks));
  53. }
  54. MapfileFilesystem::MapfileFilesystem(const string& mapfile_filename,
  55. off_t num_blocks)
  56. : mapfile_filename_(mapfile_filename), num_blocks_(num_blocks) {}
  57. size_t MapfileFilesystem::GetBlockSize() const {
  58. return kMapfileBlockSize;
  59. }
  60. size_t MapfileFilesystem::GetBlockCount() const {
  61. return num_blocks_;
  62. }
  63. bool MapfileFilesystem::GetFiles(vector<File>* files) const {
  64. files->clear();
  65. string file_data;
  66. if (!base::ReadFileToString(base::FilePath(mapfile_filename_), &file_data)) {
  67. LOG(ERROR) << "Unable to read .map file: " << mapfile_filename_;
  68. return false;
  69. }
  70. // Iterate over all the lines in the file and generate one File entry per
  71. // line.
  72. vector<base::StringPiece> lines = base::SplitStringPiece(
  73. file_data, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
  74. for (const base::StringPiece& line : lines) {
  75. File mapped_file;
  76. mapped_file.extents = {};
  77. size_t delim, last_delim = line.size();
  78. while ((delim = line.rfind(' ', last_delim - 1)) != string::npos) {
  79. string blocks =
  80. line.substr(delim + 1, last_delim - (delim + 1)).as_string();
  81. size_t dash = blocks.find('-', 0);
  82. uint64_t block_start, block_end;
  83. if (dash == string::npos && base::StringToUint64(blocks, &block_start)) {
  84. mapped_file.extents.push_back(ExtentForRange(block_start, 1));
  85. } else if (dash != string::npos &&
  86. base::StringToUint64(blocks.substr(0, dash), &block_start) &&
  87. base::StringToUint64(blocks.substr(dash + 1), &block_end)) {
  88. if (block_end < block_start) {
  89. LOG(ERROR) << "End block " << block_end
  90. << " is smaller than start block " << block_start
  91. << std::endl
  92. << line;
  93. return false;
  94. }
  95. if (block_end > static_cast<uint64_t>(num_blocks_)) {
  96. LOG(ERROR) << "The end block " << block_end
  97. << " is past the end of the file of " << num_blocks_
  98. << " blocks" << std::endl
  99. << line;
  100. return false;
  101. }
  102. mapped_file.extents.push_back(
  103. ExtentForRange(block_start, block_end - block_start + 1));
  104. } else {
  105. // If we can't parse N or N-M, we assume the block is actually part of
  106. // the name of the file.
  107. break;
  108. }
  109. last_delim = delim;
  110. }
  111. // We parsed the blocks from the end of the line, so we need to reverse
  112. // the Extents in the file.
  113. std::reverse(mapped_file.extents.begin(), mapped_file.extents.end());
  114. if (last_delim == string::npos)
  115. continue;
  116. mapped_file.name = line.substr(0, last_delim).as_string();
  117. files->push_back(mapped_file);
  118. }
  119. return true;
  120. }
  121. bool MapfileFilesystem::LoadSettings(brillo::KeyValueStore* store) const {
  122. // Settings not supported in mapfile since the storage format is unknown.
  123. LOG(ERROR) << "mapfile doesn't support LoadSettings().";
  124. return false;
  125. }
  126. } // namespace chromeos_update_engine