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 <unistd.h>
19
20 #include <fstream>
21 #include <iostream>
22
23 #include "backuprule/backup_rule_manager.h"
24 #include "crypto_manager.h"
25 #include "device_manager_adapter.h"
26 #include "directory/directory_manager.h"
27 #include "log_print.h"
28 #include "metadata/meta_data_manager.h"
29 #include "types.h"
30 namespace OHOS::DistributedData {
31 namespace {
32 constexpr const int COPY_SIZE = 1024;
33 constexpr const int MICROSEC_TO_SEC = 1000;
34 constexpr const char *AUTO_BACKUP_NAME = "autoBackup.bak";
35 constexpr const char *BACKUP_BK_POSTFIX = ".bk";
36 constexpr const char *BACKUP_TMP_POSTFIX = ".tmp";
37 }
38
BackupManager()39 BackupManager::BackupManager()
40 {
41 }
42
~BackupManager()43 BackupManager::~BackupManager()
44 {
45 }
46
GetInstance()47 BackupManager &BackupManager::GetInstance()
48 {
49 static BackupManager instance;
50 return instance;
51 }
52
Init()53 void BackupManager::Init()
54 {
55 std::vector<StoreMetaData> metas;
56 MetaDataManager::GetInstance().LoadMeta(
57 StoreMetaData::GetPrefix({ DeviceManagerAdapter::GetInstance().GetLocalDevice().uuid }), metas, true);
58 for (auto &meta : metas) {
59 if (!meta.isBackup || meta.isDirty) {
60 continue;
61 }
62 auto backupPath = 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(std::shared_ptr<ExecutorPool> executors)94 void BackupManager::BackSchedule(std::shared_ptr<ExecutorPool> executors)
95 {
96 if (!executors_) {
97 executors_ = std::move(executors);
98 }
99 std::chrono::duration<int> delay(schedularDelay_);
100 std::chrono::duration<int> internal(schedularInternal_);
101 ZLOGI("BackupManager Schedule start.");
102 executors_->Schedule(
103 [this]() {
104 if (!CanBackup()) {
105 return;
106 }
107
108 ZLOGI("start automatic backup.");
109 std::vector<StoreMetaData> metas;
110 MetaDataManager::GetInstance().LoadMeta(
111 StoreMetaData::GetPrefix({ DeviceManagerAdapter::GetInstance().GetLocalDevice().uuid }), metas, true);
112
113 int64_t end = std::min(startNum_ + backupNumber_, static_cast<int64_t>(metas.size()));
114 for (int64_t i = startNum_; i < end; startNum_++, i++) {
115 auto &meta = metas[i];
116 if (!meta.isBackup || meta.isDirty) {
117 continue;
118 }
119 DoBackup(meta);
120 }
121 if (startNum_ >= static_cast<int64_t>(metas.size())) {
122 startNum_ = 0;
123 }
124 sync();
125 backupSuccessTime_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
126 },
127 delay, internal);
128 }
129
DoBackup(const StoreMetaData & meta)130 void BackupManager::DoBackup(const StoreMetaData &meta)
131 {
132 bool result = false;
133 auto key = meta.GetSecretKey();
134 auto backupKey = meta.GetBackupSecretKey();
135 std::vector<uint8_t> decryptKey;
136 SecretKeyMetaData secretKey;
137 if (MetaDataManager::GetInstance().LoadMeta(key, secretKey, true)) {
138 CryptoManager::GetInstance().Decrypt(secretKey.sKey, decryptKey);
139 }
140 auto backupPath = DirectoryManager::GetInstance().GetStoreBackupPath(meta);
141 std::string backupFullPath = backupPath + "/" + AUTO_BACKUP_NAME;
142
143 KeepData(backupFullPath);
144 if (exporters_[meta.storeType] != nullptr) {
145 exporters_[meta.storeType](meta, backupFullPath + BACKUP_TMP_POSTFIX, result);
146 }
147 if (result) {
148 SaveData(backupFullPath, backupKey, secretKey);
149 } else {
150 CleanData(backupFullPath);
151 }
152 decryptKey.assign(decryptKey.size(), 0);
153 }
154
CanBackup()155 bool BackupManager::CanBackup()
156 {
157 if (!BackupRuleManager::GetInstance().CanBackup()) {
158 return false;
159 }
160 int64_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
161 if (currentTime - backupSuccessTime_ < backupInternal_ * MICROSEC_TO_SEC && backupSuccessTime_ > 0) {
162 ZLOGE("no more than backup internal time since the last backup success.");
163 return false;
164 }
165 return true;
166 }
167
KeepData(const std::string & path)168 void BackupManager::KeepData(const std::string &path)
169 {
170 auto backupPath = path + BACKUP_BK_POSTFIX;
171 CopyFile(path, backupPath, true);
172 }
173
SaveData(const std::string & path,const std::string & key,const SecretKeyMetaData & secretKey)174 void BackupManager::SaveData(const std::string &path, const std::string &key, const SecretKeyMetaData &secretKey)
175 {
176 auto tmpPath = path + BACKUP_TMP_POSTFIX;
177 auto backupPath = path + BACKUP_BK_POSTFIX;
178 CopyFile(tmpPath, path);
179 RemoveFile(tmpPath.c_str());
180 if (secretKey.sKey.size() != 0) {
181 MetaDataManager::GetInstance().SaveMeta(key, secretKey, true);
182 }
183 RemoveFile(backupPath.c_str());
184 }
185
RollBackData(const std::string & path)186 void BackupManager::RollBackData(const std::string &path)
187 {
188 auto tmpPath = path + BACKUP_TMP_POSTFIX;
189 auto backupPath = path + BACKUP_BK_POSTFIX;
190 CopyFile(backupPath, path);
191 RemoveFile(tmpPath.c_str());
192 RemoveFile(backupPath.c_str());
193 }
194
CleanData(const std::string & path)195 void BackupManager::CleanData(const std::string &path)
196 {
197 auto backupPath = path + BACKUP_BK_POSTFIX;
198 auto tmpPath = path + BACKUP_TMP_POSTFIX;
199 RemoveFile(tmpPath.c_str());
200 RemoveFile(backupPath.c_str());
201 }
202
203 /**
204 * learning by watching blow table, we can konw :
205 * as encrypt db, when backup's password same as db's password, need clean data,
206 * others if .bk file or .tmp file exist, rollback data
207 * as unencrypt db, tmp file exist, rollback, tmp file not exist, but .bk file exist, clean data
208 *
209 * backup step (encrypt) file status key in meat option file num
210 * 1, backup old data autoBachup.bak autoBachup.key rollback .bk = 1
211 * autoBachup.bak.bk .tmp = 0
212 *
213 * 2, do backup autoBachup.bak autoBachup.key rollback .bk = 1
214 * autoBachup.bak.bk .tmp = 1
215 * autoBachup.bak.tmp
216 *
217 * 3, copy data autoBachup.bak(new) autoBachup.key rollback .bk = 1
218 * autoBachup.bak.bk .tmp = 1
219 * autoBachup.bak.tmp
220 *
221 * 4, delet tmp data autoBachup.bak(new) autoBachup.key rollback .bk = 1
222 * autoBachup.bak.bk .tmp = 0
223 *
224 * 5, save key autoBachup.bak(new) autoBachup.key(new) clean data .bk = 1
225 * autoBachup.bak.bk .tmp = 0
226 *
227 * 6, delet backup data autoBachup.bak autoBachup.key do nothing .bk = 0
228 * - - .tmp = 0
229 *
230 * backup step (unencrypt) file status option file num
231 * 1, backup old data autoBachup.bak clean data .bk = 1
232 * autoBachup.bak.bk .tmp = 0
233 *
234 * 2, do backup autoBachup.bak rollback data .bk = 1
235 * autoBachup.bak.bk, .tmp = 1
236 * autoBachup.bak.tmp
237 *
238 * 3, copy data autoBachup.bak(new) rollback data .bk = 1
239 * autoBachup.bak.bk, .tmp = 1
240 * autoBachup.bak.tmp
241 *
242 * 4, delet tmp data autoBachup.bak clean data .bk = 1
243 * autoBachup.bak.bk .tmp = 0
244 *
245 *
246 * 5, delet backup data autoBachup.bak do nothing .bk = 0
247 * .tmp =0
248 * */
GetClearType(const StoreMetaData & meta)249 BackupManager::ClearType BackupManager::GetClearType(const StoreMetaData &meta)
250 {
251 auto backupFile = DirectoryManager::GetInstance().GetStoreBackupPath(meta) + "/" + AUTO_BACKUP_NAME;
252 auto dbKey = meta.GetSecretKey();
253 auto backupKey = meta.GetBackupSecretKey();
254 auto bkFile = backupFile + BACKUP_BK_POSTFIX;
255
256 SecretKeyMetaData dbPassword;
257 if (MetaDataManager::GetInstance().LoadMeta(dbKey, dbPassword, true)) {
258 SecretKeyMetaData backupPassword;
259 MetaDataManager::GetInstance().LoadMeta(backupKey, backupPassword, true);
260 if (dbPassword.sKey != backupPassword.sKey && IsFileExist(bkFile)) {
261 return ROLLBACK;
262 }
263 if (dbPassword.sKey == backupPassword.sKey && IsFileExist(bkFile)) {
264 return CLEAN_DATA;
265 }
266 } else {
267 auto tmpFile = backupFile + BACKUP_TMP_POSTFIX;
268 if (IsFileExist(tmpFile)) {
269 return ROLLBACK;
270 }
271 if (!IsFileExist(tmpFile) && IsFileExist(bkFile)) {
272 return CLEAN_DATA;
273 }
274 }
275 return DO_NOTHING;
276 }
277
CopyFile(const std::string & oldPath,const std::string & newPath,bool isCreate)278 void BackupManager::CopyFile(const std::string &oldPath, const std::string &newPath, bool isCreate)
279 {
280 std::fstream fin, fout;
281 if (!IsFileExist(oldPath)) {
282 return;
283 }
284 fin.open(oldPath, std::ios_base::in);
285 if (isCreate) {
286 fout.open(newPath, std::ios_base::out | std::ios_base::ate);
287 } else {
288 fout.open(newPath, std::ios_base::out | std::ios_base::trunc);
289 }
290 char buf[COPY_SIZE] = { 0 };
291 while (fin.good()) {
292 fin.read(buf, COPY_SIZE);
293 fout.write(buf, fin.gcount());
294 }
295 fin.close();
296 fout.close();
297 }
298
GetPassWord(const StoreMetaData & meta,std::vector<uint8_t> & password)299 bool BackupManager::GetPassWord(const StoreMetaData &meta, std::vector<uint8_t> &password)
300 {
301 std::string key = meta.GetBackupSecretKey();
302 SecretKeyMetaData secretKey;
303 MetaDataManager::GetInstance().LoadMeta(key, secretKey, true);
304 return CryptoManager::GetInstance().Decrypt(secretKey.sKey, password);
305 }
306
IsFileExist(const std::string & path)307 bool BackupManager::IsFileExist(const std::string &path)
308 {
309 if (path.empty()) {
310 return false;
311 }
312 if (access(path.c_str(), F_OK) != 0) {
313 return false;
314 }
315 return true;
316 }
317
RemoveFile(const std::string & path)318 bool BackupManager::RemoveFile(const std::string &path)
319 {
320 if (access(path.c_str(), F_OK) != 0) {
321 return true;
322 }
323 if (remove(path.c_str()) != 0) {
324 ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str());
325 return false;
326 }
327 return true;
328 }
329 } // namespace OHOS::DistributedData