Skip the security registration if it is unnecessary
[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 <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>
11
12 #include <manifest_parser/utils/logging.h>
13
14 #include <array>
15 #include <cstring>
16 #include <string>
17 #include <map>
18 #include <utility>
19
20 #include "common/installer_context.h"
21 #include "common/utils/file_util.h"
22
23 namespace bf = boost::filesystem;
24 namespace bs = boost::system;
25 namespace bi = boost::iostreams;
26 namespace ci = common_installer;
27
28 namespace {
29
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";
40
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},
53 };
54
55 std::string TruncateNewLine(const char* data) {
56   int length = strlen(data);
57   if (data[length - 1] == '\n')
58       --length;
59   return std::string(data, length);
60 }
61
62 }  // namespace
63
64 namespace common_installer {
65 namespace recovery {
66
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!";
71     return nullptr;
72   }
73   std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, type, false));
74   if (file->is_detached()) {
75     LOG(ERROR) << "Failed to access file";
76     return nullptr;
77   }
78   return file;
79 }
80
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";
85     return nullptr;
86   }
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";
91     return nullptr;
92   }
93   return file;
94 }
95
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";
100   if (load) {
101     if (!ReadFileContent()) {
102       path_.clear();
103       return;
104     }
105   } else {
106     // create file
107     if (!WriteAndCommitFileContent()) {
108       path_.clear();
109       return;
110     }
111     LOG(DEBUG) << "Recovery file " << path_ << " created";
112   }
113 }
114
115 RecoveryFile::~RecoveryFile() {
116   if (Remove(path_))
117     LOG(DEBUG) << "Recovery file " << path_ << " removed";
118   if (Remove(backup_path_))
119     LOG(DEBUG) << "Recovery file " << backup_path_ << " removed";
120 }
121
122 void RecoveryFile::Detach() {
123   path_.clear();
124 }
125
126 bool RecoveryFile::is_detached() const {
127   return path_.empty();
128 }
129
130 void RecoveryFile::set_unpacked_dir(
131     boost::filesystem::path unpacked_dir) {
132   unpacked_dir_ = std::move(unpacked_dir);
133 }
134
135 void RecoveryFile::set_pkgid(std::string pkgid) {
136   pkgid_ = std::move(pkgid);
137 }
138
139
140 void RecoveryFile::set_backup_done(bool backup_done) {
141   backup_done_ = backup_done;
142 }
143
144 void RecoveryFile::set_cleanup(bool cleanup) {
145   cleanup_ = cleanup;
146 }
147
148 void RecoveryFile::set_security_operation_done(bool security_operation_done) {
149   security_operation_done_ = security_operation_done;
150 }
151
152 const boost::filesystem::path& RecoveryFile::unpacked_dir() const {
153   return unpacked_dir_;
154 }
155
156 const std::string& RecoveryFile::pkgid() const {
157   return pkgid_;
158 }
159
160 RequestType RecoveryFile::type() const {
161   return type_;
162 }
163
164 bool RecoveryFile::backup_done() const {
165   return backup_done_;
166 }
167
168 bool RecoveryFile::cleanup() const {
169   return cleanup_;
170 }
171
172 bool RecoveryFile::security_operation_done() const {
173   return security_operation_done_;
174 }
175
176 bool RecoveryFile::ReadFileContent() {
177   FILE* handle = fopen(path_.c_str(), "r");
178   if (!handle) {
179     LOG(ERROR) << "Cannot read recovery file";
180     return false;
181   }
182   std::array<char, 200> data;
183   data[0] = '\0';
184   if (!fgets(data.data(), data.size(), handle)) {
185     type_ = RequestType::Unknown;
186     fclose(handle);
187     return true;
188   }
189   std::string mode(TruncateNewLine(data.data()));
190   auto iter = kStringToRequestMap.find(mode);
191   if (iter == kStringToRequestMap.end()) {
192     type_ = RequestType::Unknown;
193   } else {
194     type_ = iter->second;
195   }
196
197   if (!fgets(data.data(), data.size(), handle)) {
198     fclose(handle);
199     return true;
200   }
201   unpacked_dir_ = TruncateNewLine(data.data());
202   if (!fgets(data.data(), data.size(), handle)) {
203     fclose(handle);
204     return true;
205   }
206   pkgid_ = TruncateNewLine(data.data());
207   if (!fgets(data.data(), data.size(), handle)) {
208     fclose(handle);
209     return true;
210   }
211   std::string backup_flag = TruncateNewLine(data.data());
212   if (backup_flag == "true")
213     backup_done_ = true;
214   else
215     backup_done_ = false;
216   if (!fgets(data.data(), data.size(), handle)) {
217     fclose(handle);
218     return true;
219   }
220   std::string cleanup_flag = TruncateNewLine(data.data());
221   if (cleanup_flag == "cleanup")
222     cleanup_ = true;
223   else
224     cleanup_ = false;
225   if (!fgets(data.data(), data.size(), handle)) {
226     fclose(handle);
227     return true;
228   }
229   std::string security_operation_done_flag = TruncateNewLine(data.data());
230   if (security_operation_done_flag == "true")
231     security_operation_done_ = true;
232   else
233     security_operation_done_ = false;
234   fclose(handle);
235   return true;
236 }
237
238 bool RecoveryFile::WriteAndCommitFileContent() {
239   if (bf::exists(path_))  {
240     bs::error_code error;
241     bf::rename(path_, backup_path_, error);
242     if (error) {
243       LOG(ERROR) << "Cannot backup recovery file:" << path_ <<
244           ", error: " << error;
245       return false;
246     }
247   }
248
249   bi::stream<bi::file_descriptor_sink> ofs(path_);
250   if (!ofs) {
251     LOG(ERROR) << "Cannot write recovery file";
252     return false;
253   }
254
255   switch (type_) {
256   case RequestType::Install:
257     ofs << kRecoveryInstallString << std::endl;
258     break;
259   case RequestType::Update:
260     ofs << kRecoveryUpdateString << std::endl;
261     break;
262   case RequestType::Uninstall:
263     ofs << kRecoveryUninstallationString << std::endl;
264     break;
265   case RequestType::Reinstall:
266     ofs << kRecoveryRdsString << std::endl;
267     break;
268   case RequestType::Delta:
269     ofs << kRecoveryDeltaString << std::endl;
270     break;
271   case RequestType::MountInstall:
272     ofs << kRecoveryMountInstallString << std::endl;
273     break;
274   case RequestType::MountUpdate:
275     ofs << kRecoveryMountUpdateString << std::endl;
276     break;
277   case RequestType::ReadonlyUpdateInstall:
278     ofs << kRecoveryReadonlyUpdateInstallString << std::endl;
279     break;
280   case RequestType::ReadonlyUpdateUninstall:
281     ofs << kRecoveryReadonlyUpdateUninstallString << std::endl;
282     break;
283   default:
284     ofs << kRecoveryUnknownString << std::endl;
285     break;
286   }
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;
292   ofs.flush();
293   ::fsync(ofs->handle());
294   ofs.close();
295
296   Remove(backup_path_);
297   return true;
298 }
299
300 }  // namespace recovery
301 }  // namespace common_installer
302