1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #define LOG_TAG "BackupManager"
16 #include "backup_manager.h"
17
18 #include <fstream>
19 #include <iostream>
20 #include <unistd.h>
21 #include "backuprule/backup_rule_manager.h"
22 #include "communication_provider.h"
23 #include "crypto_manager.h"
24 #include "directory_manager.h"
25 #include "log_print.h"
26 #include "metadata/meta_data_manager.h"
27 #include "types.h"
28 namespace OHOS::DistributedData {
29 using Commu = AppDistributedKv::CommunicationProvider;
30 namespace {
31 constexpr const int COPY_SIZE = 1024;
32 constexpr const int MICROSEC_TO_SEC = 1000;
33 constexpr const char *AUTO_BACKUP_NAME = "autoBackup.bak";
34 constexpr const char *BACKUP_BK_POSTFIX = ".bk";
35 constexpr const char *BACKUP_TMP_POSTFIX = ".tmp";
36 }
37
BackupManager()38 BackupManager::BackupManager()
39 {
40 }
41
~BackupManager()42 BackupManager::~BackupManager()
43 {
44 }
45
GetInstance()46 BackupManager &BackupManager::GetInstance()
47 {
48 static BackupManager instance;
49 return instance;
50 }
51
Init()52 void BackupManager::Init()
53 {
54 std::vector<StoreMetaData> metas;
55 MetaDataManager::GetInstance().LoadMeta(
56 StoreMetaData::GetPrefix({Commu::GetInstance().GetLocalDevice().uuid}), metas);
57 for (auto &meta : metas) {
58 if (!meta.isBackup || meta.isDirty) {
59 continue;
60 }
61 auto backupPath =
62 DirectoryManager::GetInstance().GetStoreBackupPath(meta) + "/" + AUTO_BACKUP_NAME;
63 switch (GetClearType(meta)) {
64 case ROLLBACK:
65 RollBackData(backupPath);
66 break;
67 case CLEAN_DATA:
68 CleanData(backupPath);
69 break;
70 case DO_NOTHING:
71 default:
72 break;
73 }
74 }
75 }
76
SetBackupParam(const BackupParam & backupParam)77 void BackupManager::SetBackupParam(const BackupParam &backupParam)
78 {
79 schedularDelay_ = backupParam.schedularDelay;
80 schedularInternal_ = backupParam.schedularInternal;
81 backupInternal_ = backupParam.backupInternal;
82 backupNumber_ = backupParam.backupNumber;
83 }
84
RegisterExporter(int32_t type,Exporter exporter)85 void BackupManager::RegisterExporter(int32_t type, Exporter exporter)
86 {
87 if (exporters_[type] == nullptr) {
88 exporters_[type] = exporter;
89 } else {
90 ZLOGI("Auto backup exporter has registed, type:%{public}d.", type);
91 }
92 }
93
BackSchedule()94 void BackupManager::BackSchedule()
95 {
96 std::chrono::duration<int> delay(schedularDelay_);
97 std::chrono::duration<int> internal(schedularInternal_);
98 ZLOGI("BackupManager Schedule start.");
99 scheduler_.Every(delay, internal, [this]() {
100 if (!CanBackup()) {
101 return;
102 }
103 std::vector<StoreMetaData> metas;
104 MetaDataManager::GetInstance().LoadMeta(
105 StoreMetaData::GetPrefix({Commu::GetInstance().GetLocalDevice().uuid}), metas);
106
107 int64_t end = std::min(startNum_ + backupNumber_, static_cast<int64_t>(metas.size()));
108 for (int64_t i = startNum_; i < end; startNum_++, i++) {
109 auto &meta = metas[i];
110 if (!meta.isBackup || meta.isDirty) {
111 continue;
112 }
113 DoBackup(meta);
114 }
115 if (startNum_ >= static_cast<int64_t>(metas.size())) {
116 startNum_ = 0;
117 }
118 sync();
119 backupSuccessTime_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
120 });
121 }
122
DoBackup(const StoreMetaData & meta)123 void BackupManager::DoBackup(const StoreMetaData &meta)
124 {
125 bool result = false;
126 auto key = meta.GetSecretKey();
127 auto backupKey = meta.GetBackupSecretKey();
128 std::vector<uint8_t> decryptKey;
129 SecretKeyMetaData secretKey;
130 if (MetaDataManager::GetInstance().LoadMeta(key, secretKey, true)) {
131 CryptoManager::GetInstance().Decrypt(secretKey.sKey, decryptKey);
132 }
133 auto backupPath = DirectoryManager::GetInstance().GetStoreBackupPath(meta);
134 std::string backupFullPath = backupPath + "/" + AUTO_BACKUP_NAME;
135
136 KeepData(backupFullPath);
137 if (exporters_[meta.storeType] != nullptr) {
138 exporters_[meta.storeType](meta, backupFullPath + BACKUP_TMP_POSTFIX, result);
139 }
140 if (result) {
141 SaveData(backupFullPath, backupKey, secretKey);
142 } else {
143 CleanData(backupFullPath);
144 }
145 decryptKey.assign(decryptKey.size(), 0);
146 }
147
CanBackup()148 bool BackupManager::CanBackup()
149 {
150 if (!BackupRuleManager::GetInstance().CanBackup()) {
151 return false;
152 }
153 int64_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
154 if (currentTime - backupSuccessTime_ < backupInternal_ * MICROSEC_TO_SEC && backupSuccessTime_ > 0) {
155 ZLOGE("no more than backup internal time since the last backup success.");
156 return false;
157 }
158 return true;
159 }
160
KeepData(const std::string & path)161 void BackupManager::KeepData(const std::string &path)
162 {
163 auto backupPath = path + BACKUP_BK_POSTFIX;
164 CopyFile(path, backupPath, true);
165 }
166
SaveData(const std::string & path,const std::string & key,const SecretKeyMetaData & secretKey)167 void BackupManager::SaveData(
168 const std::string &path, const std::string &key, const SecretKeyMetaData &secretKey)
169 {
170 auto tmpPath = path + BACKUP_TMP_POSTFIX;
171 auto backupPath = path + BACKUP_BK_POSTFIX;
172 CopyFile(tmpPath, path);
173 RemoveFile(tmpPath.c_str());
174 if (secretKey.sKey.size() != 0) {
175 MetaDataManager::GetInstance().SaveMeta(key, secretKey, true);
176 }
177 RemoveFile(backupPath.c_str());
178 }
179
RollBackData(const std::string & path)180 void BackupManager::RollBackData(const std::string &path)
181 {
182 auto tmpPath = path + BACKUP_TMP_POSTFIX;
183 auto backupPath = path + BACKUP_BK_POSTFIX;
184 CopyFile(backupPath, path);
185 RemoveFile(tmpPath.c_str());
186 RemoveFile(backupPath.c_str());
187 }
188
CleanData(const std::string & path)189 void BackupManager::CleanData(const std::string &path)
190 {
191 auto backupPath = path + BACKUP_BK_POSTFIX;
192 auto tmpPath = path + BACKUP_TMP_POSTFIX;
193 RemoveFile(tmpPath.c_str());
194 RemoveFile(backupPath.c_str());
195 }
196
197 /**
198 * learning by watching blow table, we can konw :
199 * as encrypt db, when backup's password same as db's password, need clean data,
200 * others if .bk file or .tmp file exist, rollback data
201 * as unencrypt db, tmp file exist, rollback, tmp file not exist, but .bk file exist, clean data
202 *
203 * backup step (encrypt) file status key in meat option file num
204 * 1, backup old data autoBachup.bak autoBachup.key rollback .bk = 1
205 * autoBachup.bak.bk .tmp = 0
206 *
207 * 2, do backup autoBachup.bak autoBachup.key rollback .bk = 1
208 * autoBachup.bak.bk .tmp = 1
209 * autoBachup.bak.tmp
210 *
211 * 3, copy data autoBachup.bak(new) autoBachup.key rollback .bk = 1
212 * autoBachup.bak.bk .tmp = 1
213 * autoBachup.bak.tmp
214 *
215 * 4, delet tmp data autoBachup.bak(new) autoBachup.key rollback .bk = 1
216 * autoBachup.bak.bk .tmp = 0
217 *
218 * 5, save key autoBachup.bak(new) autoBachup.key(new) clean data .bk = 1
219 * autoBachup.bak.bk .tmp = 0
220 *
221 * 6, delet backup data autoBachup.bak autoBachup.key do nothing .bk = 0
222 * - - .tmp = 0
223 *
224 * backup step (unencrypt) file status option file num
225 * 1, backup old data autoBachup.bak clean data .bk = 1
226 * autoBachup.bak.bk .tmp = 0
227 *
228 * 2, do backup autoBachup.bak rollback data .bk = 1
229 * autoBachup.bak.bk, .tmp = 1
230 * autoBachup.bak.tmp
231 *
232 * 3, copy data autoBachup.bak(new) rollback data .bk = 1
233 * autoBachup.bak.bk, .tmp = 1
234 * autoBachup.bak.tmp
235 *
236 * 4, delet tmp data autoBachup.bak clean data .bk = 1
237 * autoBachup.bak.bk .tmp = 0
238 *
239 *
240 * 5, delet backup data autoBachup.bak do nothing .bk = 0
241 * .tmp =0
242 * */
GetClearType(const StoreMetaData & meta)243 BackupManager::ClearType BackupManager::GetClearType(const StoreMetaData &meta)
244 {
245 auto backupFile =
246 DirectoryManager::GetInstance().GetStoreBackupPath(meta) + "/" + AUTO_BACKUP_NAME;
247 auto dbKey = meta.GetSecretKey();
248 auto backupKey = meta.GetBackupSecretKey();
249 auto bkFile = backupFile + BACKUP_BK_POSTFIX;
250
251 SecretKeyMetaData dbPassword;
252 if (MetaDataManager::GetInstance().LoadMeta(dbKey, dbPassword, true)) {
253 SecretKeyMetaData backupPassword;
254 MetaDataManager::GetInstance().LoadMeta(backupKey, backupPassword, true);
255 if (dbPassword.sKey != backupPassword.sKey && IsFileExist(bkFile)) {
256 return ROLLBACK;
257 }
258 if (dbPassword.sKey == backupPassword.sKey && IsFileExist(bkFile)) {
259 return CLEAN_DATA;
260 }
261 } else {
262 auto tmpFile = backupFile + BACKUP_TMP_POSTFIX;
263 if (IsFileExist(tmpFile)) {
264 return ROLLBACK;
265 }
266 if (!IsFileExist(tmpFile) && IsFileExist(bkFile)) {
267 return CLEAN_DATA;
268 }
269 }
270 return DO_NOTHING;
271 }
272
CopyFile(const std::string & oldPath,const std::string & newPath,bool isCreate)273 void BackupManager::CopyFile(const std::string &oldPath, const std::string &newPath, bool isCreate)
274 {
275 std::fstream fin, fout;
276 if (!IsFileExist(oldPath)) {
277 return;
278 }
279 fin.open(oldPath, std::ios_base::in);
280 if (isCreate) {
281 fout.open(newPath, std::ios_base::out | std::ios_base::ate);
282 } else {
283 fout.open(newPath, std::ios_base::out | std::ios_base::trunc);
284 }
285 char buf[COPY_SIZE] = {0};
286 while (!fin.eof()) {
287 fin.read(buf, COPY_SIZE);
288 fout.write(buf, fin.gcount());
289 }
290 fin.close();
291 fout.close();
292 }
293
GetPassWord(const StoreMetaData & meta,std::vector<uint8_t> & password)294 bool BackupManager::GetPassWord(const StoreMetaData &meta, std::vector<uint8_t> &password)
295 {
296 std::string key = meta.GetBackupSecretKey();
297 SecretKeyMetaData secretKey;
298 MetaDataManager::GetInstance().LoadMeta(key, secretKey, true);
299 return CryptoManager::GetInstance().Decrypt(secretKey.sKey, password);
300 }
301
IsFileExist(const std::string & path)302 bool BackupManager::IsFileExist(const std::string &path)
303 {
304 if (path.empty()) {
305 return false;
306 }
307 if (access(path.c_str(), F_OK) != 0) {
308 return false;
309 }
310 return true;
311 }
312
RemoveFile(const std::string & path)313 bool BackupManager::RemoveFile(const std::string &path)
314 {
315 if (access(path.c_str(), F_OK) != 0) {
316 return true;
317 }
318 if (remove(path.c_str()) != 0) {
319 ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str());
320 return false;
321 }
322 return true;
323 }
324 } // namespace OHOS::DistributedData