Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / recovery_file.cc
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.
4
5 #include "common/recovery_file.h"
6
7 #include <manifest_parser/utils/logging.h>
8
9 #include <array>
10 #include <cstring>
11 #include <fstream>
12 #include <string>
13 #include <system_error>
14 #include <map>
15 #include <utility>
16
17 #include "common/installer_context.h"
18 #include "common/utils/file_util.h"
19
20 namespace ci = common_installer;
21 namespace fs = std::filesystem;
22
23 namespace {
24
25 const char kRecoveryInstallString[] = "NEW";
26 const char kRecoveryUpdateString[] = "UPDATE";
27 const char kRecoveryUninstallationString[] = "UNINSTALL";
28 const char kRecoveryRdsString[] = "RDS";
29 const char kRecoveryDeltaString[] = "DELTA";
30 const char kRecoveryMountInstallString[] = "MOUNTINSTALL";
31 const char kRecoveryMountUpdateString[] = "MOUNTUPDATE";
32 const char kRecoveryReadonlyUpdateInstallString[] = "READONLYUPDATEINSTALL";
33 const char kRecoveryReadonlyUpdateUninstallString[] = "READONLYUPDATEUNINSTALL";
34 const char kRecoveryUnknownString[] = "UNKNOWN";
35
36 const std::map<std::string, ci::RequestType> kStringToRequestMap = {
37   {kRecoveryInstallString, ci::RequestType::Install},
38   {kRecoveryUpdateString, ci::RequestType::Update},
39   {kRecoveryUninstallationString, ci::RequestType::Uninstall},
40   {kRecoveryRdsString, ci::RequestType::Reinstall},
41   {kRecoveryDeltaString, ci::RequestType::Delta},
42   {kRecoveryMountInstallString, ci::RequestType::MountInstall},
43   {kRecoveryMountUpdateString, ci::RequestType::MountUpdate},
44   {kRecoveryReadonlyUpdateInstallString,
45       ci::RequestType::ReadonlyUpdateInstall},
46   {kRecoveryReadonlyUpdateUninstallString,
47       ci::RequestType::ReadonlyUpdateUninstall},
48 };
49
50 std::string TruncateNewLine(const char* data) {
51   int length = strlen(data);
52   if (data[length - 1] == '\n')
53       --length;
54   return std::string(data, length);
55 }
56
57 }  // namespace
58
59 namespace common_installer {
60 namespace recovery {
61
62 std::unique_ptr<RecoveryFile> RecoveryFile::CreateRecoveryFile(
63     const std::filesystem::path& path, RequestType type) {
64   if (fs::exists(path)) {
65     LOG(ERROR) << "Recovery file already exists!";
66     return nullptr;
67   }
68   std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, type, false));
69   if (file->is_detached()) {
70     LOG(ERROR) << "Failed to access file";
71     return nullptr;
72   }
73   return file;
74 }
75
76 std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFile(
77     const std::filesystem::path& path) {
78   if (!fs::exists(path)) {
79     LOG(ERROR) << "Cannot open recovery file";
80     return nullptr;
81   }
82   std::unique_ptr<RecoveryFile> file(new RecoveryFile(path,
83       RequestType::Unknown, true));
84   if (file->is_detached()) {
85     LOG(ERROR) << "Failed to read recovery file";
86     return nullptr;
87   }
88   return file;
89 }
90
91 RecoveryFile::RecoveryFile(const fs::path& path, RequestType type, bool load)
92     : type_(type), path_(path), backup_done_(false), cleanup_(false),
93       security_operation_done_(false) {
94   backup_path_ = path_.string() + ".bck";
95   if (load) {
96     if (!ReadFileContent()) {
97       path_.clear();
98       return;
99     }
100   } else {
101     // create file
102     if (!WriteAndCommitFileContent()) {
103       path_.clear();
104       return;
105     }
106     LOG(DEBUG) << "Recovery file " << path_ << " created";
107   }
108 }
109
110 RecoveryFile::~RecoveryFile() {
111   if (Remove(path_))
112     LOG(DEBUG) << "Recovery file " << path_ << " removed";
113   if (Remove(backup_path_))
114     LOG(DEBUG) << "Recovery file " << backup_path_ << " removed";
115 }
116
117 void RecoveryFile::Detach() {
118   path_.clear();
119 }
120
121 bool RecoveryFile::is_detached() const {
122   return path_.empty();
123 }
124
125 void RecoveryFile::set_unpacked_dir(
126     std::filesystem::path unpacked_dir) {
127   unpacked_dir_ = std::move(unpacked_dir);
128 }
129
130 void RecoveryFile::set_pkgid(std::string pkgid) {
131   pkgid_ = std::move(pkgid);
132 }
133
134
135 void RecoveryFile::set_backup_done(bool backup_done) {
136   backup_done_ = backup_done;
137 }
138
139 void RecoveryFile::set_cleanup(bool cleanup) {
140   cleanup_ = cleanup;
141 }
142
143 void RecoveryFile::set_security_operation_done(bool security_operation_done) {
144   security_operation_done_ = security_operation_done;
145 }
146
147 const std::filesystem::path& RecoveryFile::unpacked_dir() const {
148   return unpacked_dir_;
149 }
150
151 const std::string& RecoveryFile::pkgid() const {
152   return pkgid_;
153 }
154
155 RequestType RecoveryFile::type() const {
156   return type_;
157 }
158
159 bool RecoveryFile::backup_done() const {
160   return backup_done_;
161 }
162
163 bool RecoveryFile::cleanup() const {
164   return cleanup_;
165 }
166
167 bool RecoveryFile::security_operation_done() const {
168   return security_operation_done_;
169 }
170
171 bool RecoveryFile::ReadFileContent() {
172   FILE* handle = fopen(path_.c_str(), "r");
173   if (!handle) {
174     LOG(ERROR) << "Cannot read recovery file";
175     return false;
176   }
177   std::array<char, 200> data;
178   data[0] = '\0';
179   if (!fgets(data.data(), data.size(), handle)) {
180     type_ = RequestType::Unknown;
181     fclose(handle);
182     return true;
183   }
184   std::string mode(TruncateNewLine(data.data()));
185   auto iter = kStringToRequestMap.find(mode);
186   if (iter == kStringToRequestMap.end()) {
187     type_ = RequestType::Unknown;
188   } else {
189     type_ = iter->second;
190   }
191
192   if (!fgets(data.data(), data.size(), handle)) {
193     fclose(handle);
194     return true;
195   }
196   unpacked_dir_ = TruncateNewLine(data.data());
197   if (!fgets(data.data(), data.size(), handle)) {
198     fclose(handle);
199     return true;
200   }
201   pkgid_ = TruncateNewLine(data.data());
202   if (!fgets(data.data(), data.size(), handle)) {
203     fclose(handle);
204     return true;
205   }
206   std::string backup_flag = TruncateNewLine(data.data());
207   if (backup_flag == "true")
208     backup_done_ = true;
209   else
210     backup_done_ = false;
211   if (!fgets(data.data(), data.size(), handle)) {
212     fclose(handle);
213     return true;
214   }
215   std::string cleanup_flag = TruncateNewLine(data.data());
216   if (cleanup_flag == "cleanup")
217     cleanup_ = true;
218   else
219     cleanup_ = false;
220   if (!fgets(data.data(), data.size(), handle)) {
221     fclose(handle);
222     return true;
223   }
224   std::string security_operation_done_flag = TruncateNewLine(data.data());
225   if (security_operation_done_flag == "true")
226     security_operation_done_ = true;
227   else
228     security_operation_done_ = false;
229   fclose(handle);
230   return true;
231 }
232
233 bool RecoveryFile::WriteAndCommitFileContent() {
234   if (fs::exists(path_))  {
235     std::error_code error;
236     fs::rename(path_, backup_path_, error);
237     if (error) {
238       LOG(ERROR) << "Cannot backup recovery file:" << path_ <<
239           ", error: " << error;
240       return false;
241     }
242   }
243
244   std::ofstream ofs(path_);
245   if (!ofs) {
246     LOG(ERROR) << "Cannot write recovery file";
247     return false;
248   }
249
250   switch (type_) {
251   case RequestType::Install:
252     ofs << kRecoveryInstallString << std::endl;
253     break;
254   case RequestType::Update:
255     ofs << kRecoveryUpdateString << std::endl;
256     break;
257   case RequestType::Uninstall:
258     ofs << kRecoveryUninstallationString << std::endl;
259     break;
260   case RequestType::Reinstall:
261     ofs << kRecoveryRdsString << std::endl;
262     break;
263   case RequestType::Delta:
264     ofs << kRecoveryDeltaString << std::endl;
265     break;
266   case RequestType::MountInstall:
267     ofs << kRecoveryMountInstallString << std::endl;
268     break;
269   case RequestType::MountUpdate:
270     ofs << kRecoveryMountUpdateString << std::endl;
271     break;
272   case RequestType::ReadonlyUpdateInstall:
273     ofs << kRecoveryReadonlyUpdateInstallString << std::endl;
274     break;
275   case RequestType::ReadonlyUpdateUninstall:
276     ofs << kRecoveryReadonlyUpdateUninstallString << std::endl;
277     break;
278   default:
279     ofs << kRecoveryUnknownString << std::endl;
280     break;
281   }
282   ofs << unpacked_dir_.c_str() << std::endl;
283   ofs << pkgid_ << std::endl;
284   ofs << (backup_done_ ? "true" : "false") << std::endl;
285   ofs << (cleanup_ ? "cleanup" : "rollback") << std::endl;
286   ofs << (security_operation_done_ ? "true" : "false") << std::endl;
287   ofs.flush();
288   ofs.close();
289   SyncFile(path_);
290
291   Remove(backup_path_);
292   return true;
293 }
294
295 }  // namespace recovery
296 }  // namespace common_installer