Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
update_agent_file.cc
1 #include "update_agent_file.h"
2 #include <fstream>
3 #include "crypto/crypto.h"
4 #include "logging/logging.h"
5 #include "uptane/manifest.h"
6 
7 // TODO(OTA-4939): Unify this with the check in
8 // SotaUptaneClient::getNewTargets() and make it more generic.
9 bool FileUpdateAgent::isTargetSupported(const Uptane::Target& target) const { return target.type() != "OSTREE"; }
10 
11 bool FileUpdateAgent::getInstalledImageInfo(Uptane::InstalledImageInfo& installed_image_info) const {
12  if (boost::filesystem::exists(target_filepath_)) {
13  auto file_content = Utils::readFile(target_filepath_);
14 
15  installed_image_info.name = current_target_name_;
16  installed_image_info.len = file_content.size();
17  installed_image_info.hash = Uptane::ManifestIssuer::generateVersionHashStr(file_content);
18  } else {
19  // mimic the Primary's fake package manager behavior
20  auto unknown_target = Uptane::Target::Unknown();
21  installed_image_info.name = unknown_target.filename();
22  installed_image_info.len = unknown_target.length();
23  installed_image_info.hash = unknown_target.sha256Hash();
24  }
25 
26  return true;
27 }
28 
29 data::InstallationResult FileUpdateAgent::install(const Uptane::Target& target) {
30  if (!boost::filesystem::exists(new_target_filepath_)) {
31  LOG_ERROR << "The target image has not been received";
33  "The target image has not been received");
34  }
35 
36  auto received_target_image_size = boost::filesystem::file_size(new_target_filepath_);
37  if (received_target_image_size != target.length()) {
38  LOG_ERROR << "Received image size does not match the size specified in Target metadata: "
39  << received_target_image_size << " != " << target.length();
40  boost::filesystem::remove(new_target_filepath_);
42  "Received image size does not match the size specified in Target metadata: " +
43  std::to_string(received_target_image_size) +
44  " != " + std::to_string(target.length()));
45  }
46 
47  if (!target.MatchHash(new_target_hasher_->getHash())) {
48  LOG_ERROR << "The received image's hash does not match the hash specified in Target metadata: "
49  << new_target_hasher_->getHash() << " != " << getTargetHash(target).HashString();
51  "The received image's hash does not match the hash specified in Target metadata: " +
52  new_target_hasher_->getHash().HashString() +
53  " != " + getTargetHash(target).HashString());
54  }
55 
56  boost::filesystem::rename(new_target_filepath_, target_filepath_);
57 
58  if (boost::filesystem::exists(new_target_filepath_)) {
60  "The target image has not been installed");
61  }
62 
63  if (!boost::filesystem::exists(target_filepath_)) {
65  "The target image has not been installed");
66  }
67 
68  current_target_name_ = target.filename();
69  new_target_hasher_.reset();
70  return data::InstallationResult(data::ResultCode::Numeric::kOk, "");
71 }
72 
73 void FileUpdateAgent::completeInstall() {}
74 
75 data::InstallationResult FileUpdateAgent::applyPendingInstall(const Uptane::Target& target) {
76  (void)target;
78  "Applying pending updates is not supported by the file update agent");
79 }
80 
81 data::InstallationResult FileUpdateAgent::receiveData(const Uptane::Target& target, const uint8_t* data, size_t size) {
82  std::ofstream target_file(new_target_filepath_.c_str(),
83  std::ofstream::out | std::ofstream::binary | std::ofstream::app);
84 
85  if (!target_file.good()) {
86  LOG_ERROR << "Failed to open a new target image file";
88  "Failed to open a new target image file");
89  }
90 
91  auto current_new_image_size = target_file.tellp();
92  if (-1 == current_new_image_size) {
93  LOG_ERROR << "Failed to obtain a size of the new target image that is being uploaded";
94  target_file.close();
96  "Failed to obtain a size of the new target image that is being uploaded");
97  }
98 
99  if (static_cast<uint64_t>(current_new_image_size) >= target.length()) {
100  LOG_ERROR << "The size of the received image data exceeds the expected Target image size: "
101  << current_new_image_size << " != " << target.length();
102  target_file.close();
104  "The size of the received image data exceeds the expected Target image size: " +
105  std::to_string(current_new_image_size) +
106  " != " + std::to_string(target.length()));
107  }
108 
109  if (current_new_image_size == 0) {
110  new_target_hasher_ = MultiPartHasher::create(getTargetHash(target).type());
111  }
112 
113  target_file.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
114  auto written_data_size = target_file.tellp() - current_new_image_size;
115 
116  if (written_data_size < 0 || static_cast<size_t>(written_data_size) != size) {
117  LOG_ERROR << "The size of data written is not equal to the received data size: " << written_data_size
118  << " != " << size;
119  target_file.close();
121  "The size of data written is not equal to the received data size: " +
122  std::to_string(written_data_size) + " != " + std::to_string(size));
123  }
124 
125  target_file.close();
126 
127  auto total_size = current_new_image_size + written_data_size;
128  LOG_DEBUG << "Received and stored data of a new target image."
129  " Received in this request (bytes): "
130  << size << "; total received so far: " << total_size << "; expected total: " << target.length();
131  if (static_cast<uint64_t>(total_size) == target.length()) {
132  LOG_INFO << "Successfully received and stored new target image of " << total_size << " bytes.";
133  }
134 
135  new_target_hasher_->update(data, size);
136 
137  return data::InstallationResult(data::ResultCode::Numeric::kOk, "");
138 }
139 
140 Hash FileUpdateAgent::getTargetHash(const Uptane::Target& target) {
141  // TODO(OTA-4831): check target.hashes() size.
142  return target.hashes()[0];
143 }
Hash
The Hash class The hash of a file or Uptane metadata.
Definition: types.h:159
data::InstallationResult
Definition: types.h:277
data
General data structures.
Definition: types.h:217
Uptane::InstalledImageInfo
Definition: types.h:306
data::ResultCode::Numeric::kInternalError
@ kInternalError
SWM Internal integrity error.
Uptane::Target
Definition: types.h:379
data::ResultCode::Numeric::kDownloadFailed
@ kDownloadFailed
Package download failed.
data::ResultCode::Numeric::kInstallFailed
@ kInstallFailed
Package installation failed.