1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
5 #include "common/recovery_file.h"
7 #include <boost/filesystem/operations.hpp>
8 #include <boost/iostreams/stream.hpp>
9 #include <boost/iostreams/device/file_descriptor.hpp>
10 #include <boost/system/error_code.hpp>
12 #include <manifest_parser/utils/logging.h>
20 #include "common/installer_context.h"
21 #include "common/utils/file_util.h"
23 namespace bf = boost::filesystem;
24 namespace bs = boost::system;
25 namespace bi = boost::iostreams;
26 namespace ci = common_installer;
30 const char kRecoveryInstallString[] = "NEW";
31 const char kRecoveryUpdateString[] = "UPDATE";
32 const char kRecoveryUninstallationString[] = "UNINSTALL";
33 const char kRecoveryRdsString[] = "RDS";
34 const char kRecoveryDeltaString[] = "DELTA";
35 const char kRecoveryMountInstallString[] = "MOUNTINSTALL";
36 const char kRecoveryMountUpdateString[] = "MOUNTUPDATE";
37 const char kRecoveryReadonlyUpdateInstallString[] = "READONLYUPDATEINSTALL";
38 const char kRecoveryReadonlyUpdateUninstallString[] = "READONLYUPDATEUNINSTALL";
39 const char kRecoveryUnknownString[] = "UNKNOWN";
41 const std::map<std::string, ci::RequestType> kStringToRequestMap = {
42 {kRecoveryInstallString, ci::RequestType::Install},
43 {kRecoveryUpdateString, ci::RequestType::Update},
44 {kRecoveryUninstallationString, ci::RequestType::Uninstall},
45 {kRecoveryRdsString, ci::RequestType::Reinstall},
46 {kRecoveryDeltaString, ci::RequestType::Delta},
47 {kRecoveryMountInstallString, ci::RequestType::MountInstall},
48 {kRecoveryMountUpdateString, ci::RequestType::MountUpdate},
49 {kRecoveryReadonlyUpdateInstallString,
50 ci::RequestType::ReadonlyUpdateInstall},
51 {kRecoveryReadonlyUpdateUninstallString,
52 ci::RequestType::ReadonlyUpdateUninstall},
55 std::string TruncateNewLine(const char* data) {
56 int length = strlen(data);
57 if (data[length - 1] == '\n')
59 return std::string(data, length);
64 namespace common_installer {
67 std::unique_ptr<RecoveryFile> RecoveryFile::CreateRecoveryFile(
68 const boost::filesystem::path& path, RequestType type) {
69 if (bf::exists(path)) {
70 LOG(ERROR) << "Recovery file already exists!";
73 std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, type, false));
74 if (file->is_detached()) {
75 LOG(ERROR) << "Failed to access file";
81 std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFile(
82 const boost::filesystem::path& path) {
83 if (!bf::exists(path)) {
84 LOG(ERROR) << "Cannot open recovery file";
87 std::unique_ptr<RecoveryFile> file(new RecoveryFile(path,
88 RequestType::Unknown, true));
89 if (file->is_detached()) {
90 LOG(ERROR) << "Failed to read recovery file";
96 RecoveryFile::RecoveryFile(const bf::path& path, RequestType type, bool load)
97 : type_(type), path_(path), backup_done_(false), cleanup_(false),
98 security_operation_done_(false) {
99 backup_path_ = path_.string() + ".bck";
101 if (!ReadFileContent()) {
107 if (!WriteAndCommitFileContent()) {
111 LOG(DEBUG) << "Recovery file " << path_ << " created";
115 RecoveryFile::~RecoveryFile() {
117 LOG(DEBUG) << "Recovery file " << path_ << " removed";
118 if (Remove(backup_path_))
119 LOG(DEBUG) << "Recovery file " << backup_path_ << " removed";
122 void RecoveryFile::Detach() {
126 bool RecoveryFile::is_detached() const {
127 return path_.empty();
130 void RecoveryFile::set_unpacked_dir(
131 boost::filesystem::path unpacked_dir) {
132 unpacked_dir_ = std::move(unpacked_dir);
135 void RecoveryFile::set_pkgid(std::string pkgid) {
136 pkgid_ = std::move(pkgid);
140 void RecoveryFile::set_backup_done(bool backup_done) {
141 backup_done_ = backup_done;
144 void RecoveryFile::set_cleanup(bool cleanup) {
148 void RecoveryFile::set_security_operation_done(bool security_operation_done) {
149 security_operation_done_ = security_operation_done;
152 const boost::filesystem::path& RecoveryFile::unpacked_dir() const {
153 return unpacked_dir_;
156 const std::string& RecoveryFile::pkgid() const {
160 RequestType RecoveryFile::type() const {
164 bool RecoveryFile::backup_done() const {
168 bool RecoveryFile::cleanup() const {
172 bool RecoveryFile::security_operation_done() const {
173 return security_operation_done_;
176 bool RecoveryFile::ReadFileContent() {
177 FILE* handle = fopen(path_.c_str(), "r");
179 LOG(ERROR) << "Cannot read recovery file";
182 std::array<char, 200> data;
184 if (!fgets(data.data(), data.size(), handle)) {
185 type_ = RequestType::Unknown;
189 std::string mode(TruncateNewLine(data.data()));
190 auto iter = kStringToRequestMap.find(mode);
191 if (iter == kStringToRequestMap.end()) {
192 type_ = RequestType::Unknown;
194 type_ = iter->second;
197 if (!fgets(data.data(), data.size(), handle)) {
201 unpacked_dir_ = TruncateNewLine(data.data());
202 if (!fgets(data.data(), data.size(), handle)) {
206 pkgid_ = TruncateNewLine(data.data());
207 if (!fgets(data.data(), data.size(), handle)) {
211 std::string backup_flag = TruncateNewLine(data.data());
212 if (backup_flag == "true")
215 backup_done_ = false;
216 if (!fgets(data.data(), data.size(), handle)) {
220 std::string cleanup_flag = TruncateNewLine(data.data());
221 if (cleanup_flag == "cleanup")
225 if (!fgets(data.data(), data.size(), handle)) {
229 std::string security_operation_done_flag = TruncateNewLine(data.data());
230 if (security_operation_done_flag == "true")
231 security_operation_done_ = true;
233 security_operation_done_ = false;
238 bool RecoveryFile::WriteAndCommitFileContent() {
239 if (bf::exists(path_)) {
240 bs::error_code error;
241 bf::rename(path_, backup_path_, error);
243 LOG(ERROR) << "Cannot backup recovery file:" << path_ <<
244 ", error: " << error;
249 bi::stream<bi::file_descriptor_sink> ofs(path_);
251 LOG(ERROR) << "Cannot write recovery file";
256 case RequestType::Install:
257 ofs << kRecoveryInstallString << std::endl;
259 case RequestType::Update:
260 ofs << kRecoveryUpdateString << std::endl;
262 case RequestType::Uninstall:
263 ofs << kRecoveryUninstallationString << std::endl;
265 case RequestType::Reinstall:
266 ofs << kRecoveryRdsString << std::endl;
268 case RequestType::Delta:
269 ofs << kRecoveryDeltaString << std::endl;
271 case RequestType::MountInstall:
272 ofs << kRecoveryMountInstallString << std::endl;
274 case RequestType::MountUpdate:
275 ofs << kRecoveryMountUpdateString << std::endl;
277 case RequestType::ReadonlyUpdateInstall:
278 ofs << kRecoveryReadonlyUpdateInstallString << std::endl;
280 case RequestType::ReadonlyUpdateUninstall:
281 ofs << kRecoveryReadonlyUpdateUninstallString << std::endl;
284 ofs << kRecoveryUnknownString << std::endl;
287 ofs << unpacked_dir_.c_str() << std::endl;
288 ofs << pkgid_ << std::endl;
289 ofs << (backup_done_ ? "true" : "false") << std::endl;
290 ofs << (cleanup_ ? "cleanup" : "rollback") << std::endl;
291 ofs << (security_operation_done_ ? "true" : "false") << std::endl;
293 ::fsync(ofs->handle());
296 Remove(backup_path_);
300 } // namespace recovery
301 } // namespace common_installer