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
22 #include "backuprule/backup_rule_manager.h"
23 #include "crypto_manager.h"
24 #include "device_manager_adapter.h"
25 #include "directory/directory_manager.h"
26 #include "log_print.h"
27 #include "metadata/meta_data_manager.h"
28 #include "types.h"
29 namespace OHOS::DistributedData {
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({DeviceManagerAdapter::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(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);
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(
175 const std::string &path, const std::string &key, const SecretKeyMetaData &secretKey)
176 {
177 auto tmpPath = path + BACKUP_TMP_POSTFIX;
178 auto backupPath = path + BACKUP_BK_POSTFIX;
179 CopyFile(tmpPath, path);
180 RemoveFile(tmpPath.c_str());
181 if (secretKey.sKey.size() != 0) {
182 MetaDataManager::GetInstance().SaveMeta(key, secretKey, true);
183 }
184 RemoveFile(backupPath.c_str());
185 }
186
RollBackData(const std::string & path)187 void BackupManager::RollBackData(const std::string &path)
188 {
189 auto tmpPath = path + BACKUP_TMP_POSTFIX;
190 auto backupPath = path + BACKUP_BK_POSTFIX;
191 CopyFile(backupPath, path);
192 RemoveFile(tmpPath.c_str());
193 RemoveFile(backupPath.c_str());
194 }
195
CleanData(const std::string & path)196 void BackupManager::CleanData(const std::string &path)
197 {
198 auto backupPath = path + BACKUP_BK_POSTFIX;
199 auto tmpPath = path + BACKUP_TMP_POSTFIX;
200 RemoveFile(tmpPath.c_str());
201 RemoveFile(backupPath.c_str());
202 }
203
204 /**
205 * learning by watching blow table, we can konw :
206 * as encrypt db, when backup's password same as db's password, need clean data,
207 * others if .bk file or .tmp file exist, rollback data
208 * as unencrypt db, tmp file exist, rollback, tmp file not exist, but .bk file exist, clean data
209 *
210 * backup step (encrypt) file status key in meat option file num
211 * 1, backup old data autoBachup.bak autoBachup.key rollback .bk = 1
212 * autoBachup.bak.bk .tmp = 0
213 *
214 * 2, do backup autoBachup.bak autoBachup.key rollback .bk = 1
215 * autoBachup.bak.bk .tmp = 1
216 * autoBachup.bak.tmp
217 *
218 * 3, copy data autoBachup.bak(new) autoBachup.key rollback .bk = 1
219 * autoBachup.bak.bk .tmp = 1
220 * autoBachup.bak.tmp
221 *
222 * 4, delet tmp data autoBachup.bak(new) autoBachup.key rollback .bk = 1
223 * autoBachup.bak.bk .tmp = 0
224 *
225 * 5, save key autoBachup.bak(new) autoBachup.key(new) clean data .bk = 1
226 * autoBachup.bak.bk .tmp = 0
227 *
228 * 6, delet backup data autoBachup.bak autoBachup.key do nothing .bk = 0
229 * - - .tmp = 0
230 *
231 * backup step (unencrypt) file status option file num
232 * 1, backup old data autoBachup.bak clean data .bk = 1
233 * autoBachup.bak.bk .tmp = 0
234 *
235 * 2, do backup autoBachup.bak rollback data .bk = 1
236 * autoBachup.bak.bk, .tmp = 1
237 * autoBachup.bak.tmp
238 *
239 * 3, copy data autoBachup.bak(new) rollback data .bk = 1
240 * autoBachup.bak.bk, .tmp = 1
241 * autoBachup.bak.tmp
242 *
243 * 4, delet tmp data autoBachup.bak clean data .bk = 1
244 * autoBachup.bak.bk .tmp = 0
245 *
246 *
247 * 5, delet backup data autoBachup.bak do nothing .bk = 0
248 * .tmp =0
249 * */
GetClearType(const StoreMetaData & meta)250 BackupManager::ClearType BackupManager::GetClearType(const StoreMetaData &meta)
251 {
252 auto backupFile =
253 DirectoryManager::GetInstance().GetStoreBackupPath(meta) + "/" + AUTO_BACKUP_NAME;
254 auto dbKey = meta.GetSecretKey();
255 auto backupKey = meta.GetBackupSecretKey();
256 auto bkFile = backupFile + BACKUP_BK_POSTFIX;
257
258 SecretKeyMetaData dbPassword;
259 if (MetaDataManager::GetInstance().LoadMeta(dbKey, dbPassword, true)) {
260 SecretKeyMetaData backupPassword;
261 MetaDataManager::GetInstance().LoadMeta(backupKey, backupPassword, true);
262 if (dbPassword.sKey != backupPassword.sKey && IsFileExist(bkFile)) {
263 return ROLLBACK;
264 }
265 if (dbPassword.sKey == backupPassword.sKey && IsFileExist(bkFile)) {
266 return CLEAN_DATA;
267 }
268 } else {
269 auto tmpFile = backupFile + BACKUP_TMP_POSTFIX;
270 if (IsFileExist(tmpFile)) {
271 return ROLLBACK;
272 }
273 if (!IsFileExist(tmpFile) && IsFileExist(bkFile)) {
274 return CLEAN_DATA;
275 }
276 }
277 return DO_NOTHING;
278 }
279
CopyFile(const std::string & oldPath,const std::string & newPath,bool isCreate)280 void BackupManager::CopyFile(const std::string &oldPath, const std::string &newPath, bool isCreate)
281 {
282 std::fstream fin, fout;
283 if (!IsFileExist(oldPath)) {
284 return;
285 }
286 fin.open(oldPath, std::ios_base::in);
287 if (isCreate) {
288 fout.open(newPath, std::ios_base::out | std::ios_base::ate);
289 } else {
290 fout.open(newPath, std::ios_base::out | std::ios_base::trunc);
291 }
292 char buf[COPY_SIZE] = {0};
293 while (fin.good()) {
294 fin.read(buf, COPY_SIZE);
295 fout.write(buf, fin.gcount());
296 }
297 fin.close();
298 fout.close();
299 }
300
GetPassWord(const StoreMetaData & meta,std::vector<uint8_t> & password)301 bool BackupManager::GetPassWord(const StoreMetaData &meta, std::vector<uint8_t> &password)
302 {
303 std::string key = meta.GetBackupSecretKey();
304 SecretKeyMetaData secretKey;
305 MetaDataManager::GetInstance().LoadMeta(key, secretKey, true);
306 return CryptoManager::GetInstance().Decrypt(secretKey.sKey, password);
307 }
308
IsFileExist(const std::string & path)309 bool BackupManager::IsFileExist(const std::string &path)
310 {
311 if (path.empty()) {
312 return false;
313 }
314 if (access(path.c_str(), F_OK) != 0) {
315 return false;
316 }
317 return true;
318 }
319
RemoveFile(const std::string & path)320 bool BackupManager::RemoveFile(const std::string &path)
321 {
322 if (access(path.c_str(), F_OK) != 0) {
323 return true;
324 }
325 if (remove(path.c_str()) != 0) {
326 ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str());
327 return false;
328 }
329 return true;
330 }
331 } // namespace OHOS::DistributedData