#include "common/recovery_file.h"
#include <boost/filesystem/operations.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/system/error_code.hpp>
+#include <manifest_parser/utils/logging.h>
+
#include <array>
#include <cstring>
+#include <string>
#include <map>
+#include <utility>
#include "common/installer_context.h"
-#include "common/utils/logging.h"
+#include "common/utils/file_util.h"
namespace bf = boost::filesystem;
namespace bs = boost::system;
+namespace bi = boost::iostreams;
namespace ci = common_installer;
namespace {
-const char kRecoveryNewInstallationString[] = "NEW";
-const char kRecoveryUpdateInstallationString[] = "UPDATE";
-const char kRecoveryUninstallationString[] = "UNINSTALLATION";
+const char kRecoveryInstallString[] = "NEW";
+const char kRecoveryUpdateString[] = "UPDATE";
+const char kRecoveryUninstallationString[] = "UNINSTALL";
const char kRecoveryRdsString[] = "RDS";
const char kRecoveryDeltaString[] = "DELTA";
+const char kRecoveryMountInstallString[] = "MOUNTINSTALL";
+const char kRecoveryMountUpdateString[] = "MOUNTUPDATE";
+const char kRecoveryReadonlyUpdateInstallString[] = "READONLYUPDATEINSTALL";
+const char kRecoveryReadonlyUpdateUninstallString[] = "READONLYUPDATEUNINSTALL";
const char kRecoveryUnknownString[] = "UNKNOWN";
const std::map<std::string, ci::RequestType> kStringToRequestMap = {
- {kRecoveryNewInstallationString, ci::RequestType::Install},
- {kRecoveryUpdateInstallationString, ci::RequestType::Update},
+ {kRecoveryInstallString, ci::RequestType::Install},
+ {kRecoveryUpdateString, ci::RequestType::Update},
{kRecoveryUninstallationString, ci::RequestType::Uninstall},
{kRecoveryRdsString, ci::RequestType::Reinstall},
- {kRecoveryDeltaString, ci::RequestType::Delta}
+ {kRecoveryDeltaString, ci::RequestType::Delta},
+ {kRecoveryMountInstallString, ci::RequestType::MountInstall},
+ {kRecoveryMountUpdateString, ci::RequestType::MountUpdate},
+ {kRecoveryReadonlyUpdateInstallString,
+ ci::RequestType::ReadonlyUpdateInstall},
+ {kRecoveryReadonlyUpdateUninstallString,
+ ci::RequestType::ReadonlyUpdateUninstall},
};
std::string TruncateNewLine(const char* data) {
namespace common_installer {
namespace recovery {
-std::unique_ptr<RecoveryFile> RecoveryFile::CreateRecoveryFileForPath(
- const boost::filesystem::path& path) {
+std::unique_ptr<RecoveryFile> RecoveryFile::CreateRecoveryFile(
+ const boost::filesystem::path& path, RequestType type) {
if (bf::exists(path)) {
LOG(ERROR) << "Recovery file already exists!";
return nullptr;
}
- std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, false));
+ std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, type, false));
if (file->is_detached()) {
LOG(ERROR) << "Failed to access file";
return nullptr;
return file;
}
-std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFileForPath(
+std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFile(
const boost::filesystem::path& path) {
if (!bf::exists(path)) {
LOG(ERROR) << "Cannot open recovery file";
return nullptr;
}
- std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, true));
+ std::unique_ptr<RecoveryFile> file(new RecoveryFile(path,
+ RequestType::Unknown, true));
if (file->is_detached()) {
LOG(ERROR) << "Failed to read recovery file";
return nullptr;
return file;
}
-RecoveryFile::RecoveryFile(const bf::path& path, bool load)
- : path_(path) {
+RecoveryFile::RecoveryFile(const bf::path& path, RequestType type, bool load)
+ : type_(type), path_(path), backup_done_(false), cleanup_(false),
+ security_operation_done_(false) {
+ backup_path_ = path_.string() + ".bck";
if (load) {
if (!ReadFileContent()) {
path_.clear();
}
} else {
// create file
- FILE* handle = fopen(path.c_str(), "w");
- if (!handle) {
+ if (!WriteAndCommitFileContent()) {
path_.clear();
return;
}
- fclose(handle);
LOG(DEBUG) << "Recovery file " << path_ << " created";
}
}
RecoveryFile::~RecoveryFile() {
- if (!path_.empty()) {
- bs::error_code error;
- bf::remove(path_, error);
+ if (Remove(path_))
LOG(DEBUG) << "Recovery file " << path_ << " removed";
- }
+ if (Remove(backup_path_))
+ LOG(DEBUG) << "Recovery file " << backup_path_ << " removed";
}
void RecoveryFile::Detach() {
}
void RecoveryFile::set_unpacked_dir(
- const boost::filesystem::path& unpacked_dir) {
- unpacked_dir_ = unpacked_dir;
+ boost::filesystem::path unpacked_dir) {
+ unpacked_dir_ = std::move(unpacked_dir);
+}
+
+void RecoveryFile::set_pkgid(std::string pkgid) {
+ pkgid_ = std::move(pkgid);
+}
+
+
+void RecoveryFile::set_backup_done(bool backup_done) {
+ backup_done_ = backup_done;
}
-void RecoveryFile::set_pkgid(const std::string& pkgid) {
- pkgid_ = pkgid;
+void RecoveryFile::set_cleanup(bool cleanup) {
+ cleanup_ = cleanup;
}
-void RecoveryFile::set_type(RequestType type) {
- type_ = type;
+void RecoveryFile::set_security_operation_done(bool security_operation_done) {
+ security_operation_done_ = security_operation_done;
}
const boost::filesystem::path& RecoveryFile::unpacked_dir() const {
return type_;
}
+bool RecoveryFile::backup_done() const {
+ return backup_done_;
+}
+
+bool RecoveryFile::cleanup() const {
+ return cleanup_;
+}
+
+bool RecoveryFile::security_operation_done() const {
+ return security_operation_done_;
+}
+
bool RecoveryFile::ReadFileContent() {
FILE* handle = fopen(path_.c_str(), "r");
if (!handle) {
return true;
}
pkgid_ = TruncateNewLine(data.data());
+ if (!fgets(data.data(), data.size(), handle)) {
+ fclose(handle);
+ return true;
+ }
+ std::string backup_flag = TruncateNewLine(data.data());
+ if (backup_flag == "true")
+ backup_done_ = true;
+ else
+ backup_done_ = false;
+ if (!fgets(data.data(), data.size(), handle)) {
+ fclose(handle);
+ return true;
+ }
+ std::string cleanup_flag = TruncateNewLine(data.data());
+ if (cleanup_flag == "cleanup")
+ cleanup_ = true;
+ else
+ cleanup_ = false;
+ if (!fgets(data.data(), data.size(), handle)) {
+ fclose(handle);
+ return true;
+ }
+ std::string security_operation_done_flag = TruncateNewLine(data.data());
+ if (security_operation_done_flag == "true")
+ security_operation_done_ = true;
+ else
+ security_operation_done_ = false;
fclose(handle);
return true;
}
bool RecoveryFile::WriteAndCommitFileContent() {
- FILE* handle = fopen(path_.c_str(), "w");
- if (!handle) {
+ if (bf::exists(path_)) {
+ bs::error_code error;
+ bf::rename(path_, backup_path_, error);
+ if (error) {
+ LOG(ERROR) << "Cannot backup recovery file:" << path_ <<
+ ", error: " << error;
+ return false;
+ }
+ }
+
+ bi::stream<bi::file_descriptor_sink> ofs(path_);
+ if (!ofs) {
LOG(ERROR) << "Cannot write recovery file";
return false;
}
+
switch (type_) {
case RequestType::Install:
- fputs(kRecoveryNewInstallationString, handle);
+ ofs << kRecoveryInstallString << std::endl;
break;
case RequestType::Update:
- fputs(kRecoveryUpdateInstallationString, handle);
+ ofs << kRecoveryUpdateString << std::endl;
break;
case RequestType::Uninstall:
- fputs(kRecoveryUninstallationString, handle);
+ ofs << kRecoveryUninstallationString << std::endl;
break;
case RequestType::Reinstall:
- fputs(kRecoveryRdsString, handle);
+ ofs << kRecoveryRdsString << std::endl;
break;
case RequestType::Delta:
- fputs(kRecoveryDeltaString, handle);
+ ofs << kRecoveryDeltaString << std::endl;
+ break;
+ case RequestType::MountInstall:
+ ofs << kRecoveryMountInstallString << std::endl;
+ break;
+ case RequestType::MountUpdate:
+ ofs << kRecoveryMountUpdateString << std::endl;
+ break;
+ case RequestType::ReadonlyUpdateInstall:
+ ofs << kRecoveryReadonlyUpdateInstallString << std::endl;
+ break;
+ case RequestType::ReadonlyUpdateUninstall:
+ ofs << kRecoveryReadonlyUpdateUninstallString << std::endl;
break;
default:
- fputs(kRecoveryUnknownString, handle);
+ ofs << kRecoveryUnknownString << std::endl;
break;
}
- fputs("\n", handle);
- fputs(unpacked_dir_.c_str(), handle);
- fputs("\n", handle);
- fputs(pkgid_.c_str(), handle);
- fputs("\n", handle);
- fclose(handle);
+ ofs << unpacked_dir_.c_str() << std::endl;
+ ofs << pkgid_ << std::endl;
+ ofs << (backup_done_ ? "true" : "false") << std::endl;
+ ofs << (cleanup_ ? "cleanup" : "rollback") << std::endl;
+ ofs << (security_operation_done_ ? "true" : "false") << std::endl;
+ ofs.flush();
+ ::fsync(ofs->handle());
+ ofs.close();
+
+ Remove(backup_path_);
return true;
}