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