123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- //
- // Copyright (C) 2016 The Android Open Source Project
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- #include "update_engine/payload_generator/mapfile_filesystem.h"
- #include <algorithm>
- #include <map>
- #include <base/files/file_util.h>
- #include <base/logging.h>
- #include <base/memory/ptr_util.h>
- #include <base/strings/string_number_conversions.h>
- #include <base/strings/string_split.h>
- #include "update_engine/common/utils.h"
- #include "update_engine/payload_generator/extent_ranges.h"
- #include "update_engine/payload_generator/extent_utils.h"
- #include "update_engine/update_metadata.pb.h"
- using std::string;
- using std::vector;
- namespace {
- // The .map file is defined in terms of 4K blocks.
- size_t kMapfileBlockSize = 4096;
- } // namespace
- namespace chromeos_update_engine {
- std::unique_ptr<MapfileFilesystem> MapfileFilesystem::CreateFromFile(
- const string& filename, const string& mapfile_filename) {
- if (filename.empty() || mapfile_filename.empty())
- return nullptr;
- off_t file_size = utils::FileSize(filename);
- if (file_size < 0)
- return nullptr;
- if (file_size % kMapfileBlockSize) {
- LOG(ERROR) << "Image file " << filename << " has a size of " << file_size
- << " which is not multiple of " << kMapfileBlockSize;
- return nullptr;
- }
- off_t num_blocks = file_size / kMapfileBlockSize;
- if (!utils::FileExists(mapfile_filename.c_str())) {
- LOG(ERROR) << "File " << mapfile_filename << " doesn't exist";
- return nullptr;
- }
- return base::WrapUnique(new MapfileFilesystem(mapfile_filename, num_blocks));
- }
- MapfileFilesystem::MapfileFilesystem(const string& mapfile_filename,
- off_t num_blocks)
- : mapfile_filename_(mapfile_filename), num_blocks_(num_blocks) {}
- size_t MapfileFilesystem::GetBlockSize() const {
- return kMapfileBlockSize;
- }
- size_t MapfileFilesystem::GetBlockCount() const {
- return num_blocks_;
- }
- bool MapfileFilesystem::GetFiles(vector<File>* files) const {
- files->clear();
- string file_data;
- if (!base::ReadFileToString(base::FilePath(mapfile_filename_), &file_data)) {
- LOG(ERROR) << "Unable to read .map file: " << mapfile_filename_;
- return false;
- }
- // Iterate over all the lines in the file and generate one File entry per
- // line.
- vector<base::StringPiece> lines = base::SplitStringPiece(
- file_data, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
- for (const base::StringPiece& line : lines) {
- File mapped_file;
- mapped_file.extents = {};
- size_t delim, last_delim = line.size();
- while ((delim = line.rfind(' ', last_delim - 1)) != string::npos) {
- string blocks =
- line.substr(delim + 1, last_delim - (delim + 1)).as_string();
- size_t dash = blocks.find('-', 0);
- uint64_t block_start, block_end;
- if (dash == string::npos && base::StringToUint64(blocks, &block_start)) {
- mapped_file.extents.push_back(ExtentForRange(block_start, 1));
- } else if (dash != string::npos &&
- base::StringToUint64(blocks.substr(0, dash), &block_start) &&
- base::StringToUint64(blocks.substr(dash + 1), &block_end)) {
- if (block_end < block_start) {
- LOG(ERROR) << "End block " << block_end
- << " is smaller than start block " << block_start
- << std::endl
- << line;
- return false;
- }
- if (block_end > static_cast<uint64_t>(num_blocks_)) {
- LOG(ERROR) << "The end block " << block_end
- << " is past the end of the file of " << num_blocks_
- << " blocks" << std::endl
- << line;
- return false;
- }
- mapped_file.extents.push_back(
- ExtentForRange(block_start, block_end - block_start + 1));
- } else {
- // If we can't parse N or N-M, we assume the block is actually part of
- // the name of the file.
- break;
- }
- last_delim = delim;
- }
- // We parsed the blocks from the end of the line, so we need to reverse
- // the Extents in the file.
- std::reverse(mapped_file.extents.begin(), mapped_file.extents.end());
- if (last_delim == string::npos)
- continue;
- mapped_file.name = line.substr(0, last_delim).as_string();
- files->push_back(mapped_file);
- }
- return true;
- }
- bool MapfileFilesystem::LoadSettings(brillo::KeyValueStore* store) const {
- // Settings not supported in mapfile since the storage format is unknown.
- LOG(ERROR) << "mapfile doesn't support LoadSettings().";
- return false;
- }
- } // namespace chromeos_update_engine
|