// // Copyright (C) 2018 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/boot_img_filesystem.h" #include <base/logging.h> #include <brillo/secure_blob.h> #include <puffin/utils.h> #include "update_engine/common/utils.h" #include "update_engine/payload_generator/delta_diff_generator.h" #include "update_engine/payload_generator/extent_ranges.h" using std::string; using std::unique_ptr; using std::vector; namespace chromeos_update_engine { unique_ptr<BootImgFilesystem> BootImgFilesystem::CreateFromFile( const string& filename) { if (filename.empty()) return nullptr; brillo::Blob header; if (!utils::ReadFileChunk(filename, 0, sizeof(boot_img_hdr), &header) || header.size() != sizeof(boot_img_hdr) || memcmp(header.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) { return nullptr; } unique_ptr<BootImgFilesystem> result(new BootImgFilesystem()); result->filename_ = filename; memcpy(&result->hdr_, header.data(), header.size()); return result; } size_t BootImgFilesystem::GetBlockSize() const { // Page size may not be 4K, but we currently only support 4K block size. return kBlockSize; } size_t BootImgFilesystem::GetBlockCount() const { return utils::DivRoundUp(utils::FileSize(filename_), kBlockSize); } FilesystemInterface::File BootImgFilesystem::GetFile(const string& name, uint64_t offset, uint64_t size) const { File file; file.name = name; file.extents = {ExtentForBytes(kBlockSize, offset, size)}; brillo::Blob data; if (utils::ReadFileChunk(filename_, offset, size, &data)) { constexpr size_t kGZipHeaderSize = 10; // Check GZip header magic. if (data.size() > kGZipHeaderSize && data[0] == 0x1F && data[1] == 0x8B) { if (!puffin::LocateDeflatesInGzip(data, &file.deflates)) { LOG(ERROR) << "Error occurred parsing gzip " << name << " at offset " << offset << " of " << filename_ << ", found " << file.deflates.size() << " deflates."; return file; } for (auto& deflate : file.deflates) { deflate.offset += offset * 8; } } } return file; } bool BootImgFilesystem::GetFiles(vector<File>* files) const { files->clear(); const uint64_t file_size = utils::FileSize(filename_); // The first page is header. uint64_t offset = hdr_.page_size; if (hdr_.kernel_size > 0 && offset + hdr_.kernel_size <= file_size) { files->emplace_back(GetFile("<kernel>", offset, hdr_.kernel_size)); } offset += utils::RoundUp(hdr_.kernel_size, hdr_.page_size); if (hdr_.ramdisk_size > 0 && offset + hdr_.ramdisk_size <= file_size) { files->emplace_back(GetFile("<ramdisk>", offset, hdr_.ramdisk_size)); } return true; } bool BootImgFilesystem::LoadSettings(brillo::KeyValueStore* store) const { return false; } } // namespace chromeos_update_engine