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