| // Copyright 2021 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "oobe_config/pstore_storage.h" |
| |
| #include <sstream> |
| #include <string> |
| |
| #include <base/files/file_enumerator.h> |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/optional.h> |
| #include <base/strings/strcat.h> |
| #include <base/strings/string_number_conversions.h> |
| |
| #include "oobe_config/rollback_constants.h" |
| |
| namespace oobe_config { |
| namespace { |
| |
| const char kRollbackDataKey[] = "rollback_data"; |
| const char kRamoopsFilePattern[] = "pmsg-ramoops-*"; |
| |
| base::FilePath PrefixAbsolutePath(const base::FilePath& prefix, |
| const base::FilePath& file_path) { |
| if (prefix.empty()) |
| return file_path; |
| DCHECK(!file_path.empty()); |
| DCHECK_EQ('/', file_path.value()[0]); |
| return prefix.Append(file_path.value().substr(1)); |
| } |
| |
| base::FileEnumerator EnumerateRamoops(const base::FilePath& root_path) { |
| return base::FileEnumerator( |
| PrefixAbsolutePath(root_path, base::FilePath(kPstorePath)), |
| /*recursive=*/false, base::FileEnumerator::FILES, kRamoopsFilePattern); |
| } |
| |
| bool ExtractRollbackData(const base::FilePath& file, |
| std::string* rollback_data) { |
| std::string file_content; |
| base::ReadFileToString(file, &file_content); |
| std::stringstream file_stream(file_content); |
| std::string key; |
| while (file_stream && key != kRollbackDataKey) { |
| file_stream >> key; |
| } |
| if (file_stream && key == kRollbackDataKey) { |
| std::string hex_rollback_data; |
| file_stream >> hex_rollback_data; |
| *rollback_data = hex_rollback_data; |
| return true; // Data may be completely empty - that is valid as well. |
| } |
| return false; |
| } |
| |
| base::Optional<std::string> HexToBinary(const std::string& hex) { |
| std::string binary; |
| bool success = base::HexStringToString(hex, &binary); |
| |
| if (!success) { |
| LOG(ERROR) << "Could not decode rollback data."; |
| return base::nullopt; |
| } |
| return binary; |
| } |
| |
| } // namespace |
| |
| bool StageForPstore(const std::string& data, const base::FilePath& root_path) { |
| std::string hex_data_with_header = base::StrCat( |
| {kRollbackDataKey, " ", base::HexEncode(data.data(), data.size())}); |
| |
| int bytes_written = base::WriteFile( |
| PrefixAbsolutePath(root_path, base::FilePath(kRollbackDataForPmsgFile)), |
| hex_data_with_header.c_str(), hex_data_with_header.size()); |
| if (bytes_written != hex_data_with_header.size()) { |
| LOG(ERROR) << "Could not write " << kRollbackDataForPmsgFile; |
| return false; |
| } |
| return true; |
| } |
| |
| base::Optional<std::string> LoadFromPstore(const base::FilePath& root_path) { |
| base::FileEnumerator pmsg_ramoops_enumerator = EnumerateRamoops(root_path); |
| for (base::FilePath ramoops_file = pmsg_ramoops_enumerator.Next(); |
| !ramoops_file.empty(); ramoops_file = pmsg_ramoops_enumerator.Next()) { |
| LOG(INFO) << "Looking at file " << ramoops_file.value(); |
| std::string rollback_data; |
| if (ExtractRollbackData(ramoops_file, &rollback_data)) { |
| return HexToBinary(rollback_data); |
| } |
| LOG(INFO) << "No rollback data found in that file."; |
| } |
| LOG(ERROR) << "No rollback data found."; |
| return base::nullopt; |
| } |
| |
| } // namespace oobe_config |