Recovery mode for mount install and mount update
[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/system/error_code.hpp>
9
10 #include <manifest_parser/utils/logging.h>
11
12 #include <array>
13 #include <cstring>
14 #include <map>
15 #include <utility>
16
17 #include "common/installer_context.h"
18
19 namespace bf = boost::filesystem;
20 namespace bs = boost::system;
21 namespace ci = common_installer;
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 kRecoveryUnknownString[] = "UNKNOWN";
33
34 const std::map<std::string, ci::RequestType> kStringToRequestMap = {
35   {kRecoveryInstallString, ci::RequestType::Install},
36   {kRecoveryUpdateString, ci::RequestType::Update},
37   {kRecoveryUninstallationString, ci::RequestType::Uninstall},
38   {kRecoveryRdsString, ci::RequestType::Reinstall},
39   {kRecoveryDeltaString, ci::RequestType::Delta},
40   {kRecoveryMountInstallString, ci::RequestType::MountInstall},
41   {kRecoveryMountUpdateString, ci::RequestType::MountUpdate},
42 };
43
44 std::string TruncateNewLine(const char* data) {
45   int length = strlen(data);
46   if (data[length - 1] == '\n')
47       --length;
48   return std::string(data, length);
49 }
50
51 }  // namespace
52
53 namespace common_installer {
54 namespace recovery {
55
56 std::unique_ptr<RecoveryFile> RecoveryFile::CreateRecoveryFileForPath(
57     const boost::filesystem::path& path) {
58   if (bf::exists(path)) {
59     LOG(ERROR) << "Recovery file already exists!";
60     return nullptr;
61   }
62   std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, false));
63   if (file->is_detached()) {
64     LOG(ERROR) << "Failed to access file";
65     return nullptr;
66   }
67   return file;
68 }
69
70 std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFileForPath(
71     const boost::filesystem::path& path) {
72   if (!bf::exists(path)) {
73     LOG(ERROR) << "Cannot open recovery file";
74     return nullptr;
75   }
76   std::unique_ptr<RecoveryFile> file(new RecoveryFile(path, true));
77   if (file->is_detached()) {
78     LOG(ERROR) << "Failed to read recovery file";
79     return nullptr;
80   }
81   return file;
82 }
83
84 RecoveryFile::RecoveryFile(const bf::path& path, bool load)
85     : path_(path) {
86   if (load) {
87     if (!ReadFileContent()) {
88       path_.clear();
89       return;
90     }
91   } else {
92     // create file
93     FILE* handle = fopen(path.c_str(), "w");
94     if (!handle) {
95       path_.clear();
96       return;
97     }
98     fclose(handle);
99     LOG(DEBUG) << "Recovery file " << path_ << " created";
100   }
101 }
102
103 RecoveryFile::~RecoveryFile() {
104   if (!path_.empty()) {
105     bs::error_code error;
106     bf::remove(path_, error);
107     LOG(DEBUG) << "Recovery file " << path_ << " removed";
108   }
109 }
110
111 void RecoveryFile::Detach() {
112   path_.clear();
113 }
114
115 bool RecoveryFile::is_detached() const {
116   return path_.empty();
117 }
118
119 void RecoveryFile::set_unpacked_dir(
120     boost::filesystem::path unpacked_dir) {
121   unpacked_dir_ = std::move(unpacked_dir);
122 }
123
124 void RecoveryFile::set_pkgid(std::string pkgid) {
125   pkgid_ = std::move(pkgid);
126 }
127
128 void RecoveryFile::set_type(RequestType type) {
129   type_ = type;
130 }
131
132 const boost::filesystem::path& RecoveryFile::unpacked_dir() const {
133   return unpacked_dir_;
134 }
135
136 const std::string& RecoveryFile::pkgid() const {
137   return pkgid_;
138 }
139
140 RequestType RecoveryFile::type() const {
141   return type_;
142 }
143
144 bool RecoveryFile::ReadFileContent() {
145   FILE* handle = fopen(path_.c_str(), "r");
146   if (!handle) {
147     LOG(ERROR) << "Cannot read recovery file";
148     return false;
149   }
150   std::array<char, 200> data;
151   data[0] = '\0';
152   if (!fgets(data.data(), data.size(), handle)) {
153     type_ = RequestType::Unknown;
154     fclose(handle);
155     return true;
156   }
157   std::string mode(TruncateNewLine(data.data()));
158   auto iter = kStringToRequestMap.find(mode);
159   if (iter == kStringToRequestMap.end()) {
160     type_ = RequestType::Unknown;
161   } else {
162     type_ = iter->second;
163   }
164
165   if (!fgets(data.data(), data.size(), handle)) {
166     fclose(handle);
167     return true;
168   }
169   unpacked_dir_ = TruncateNewLine(data.data());
170   if (!fgets(data.data(), data.size(), handle)) {
171     fclose(handle);
172     return true;
173   }
174   pkgid_ = TruncateNewLine(data.data());
175   fclose(handle);
176   return true;
177 }
178
179 bool RecoveryFile::WriteAndCommitFileContent() {
180   FILE* handle = fopen(path_.c_str(), "w");
181   if (!handle) {
182     LOG(ERROR) << "Cannot write recovery file";
183     return false;
184   }
185   switch (type_) {
186   case RequestType::Install:
187     fputs(kRecoveryInstallString, handle);
188     break;
189   case RequestType::Update:
190     fputs(kRecoveryUpdateString, handle);
191     break;
192   case RequestType::Uninstall:
193     fputs(kRecoveryUninstallationString, handle);
194     break;
195   case RequestType::Reinstall:
196     fputs(kRecoveryRdsString, handle);
197     break;
198   case RequestType::Delta:
199     fputs(kRecoveryDeltaString, handle);
200     break;
201   case RequestType::MountInstall:
202     fputs(kRecoveryMountInstallString, handle);
203     break;
204   case RequestType::MountUpdate:
205     fputs(kRecoveryMountUpdateString, handle);
206     break;
207   default:
208     fputs(kRecoveryUnknownString, handle);
209     break;
210   }
211   fputs("\n", handle);
212   fputs(unpacked_dir_.c_str(), handle);
213   fputs("\n", handle);
214   fputs(pkgid_.c_str(), handle);
215   fputs("\n", handle);
216   fclose(handle);
217   return true;
218 }
219
220 }  // namespace recovery
221 }  // namespace common_installer
222