• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(meta, secretKey, decryptKey);
139         if (secretKey.area < 0) {
140             MetaDataManager::GetInstance().LoadMeta(key, secretKey, true);
141         }
142     }
143     auto backupPath = DirectoryManager::GetInstance().GetStoreBackupPath(meta);
144     std::string backupFullPath = backupPath + "/" + AUTO_BACKUP_NAME;
145 
146     KeepData(backupFullPath);
147     if (exporters_[meta.storeType] != nullptr) {
148         exporters_[meta.storeType](meta, backupFullPath + BACKUP_TMP_POSTFIX, result);
149     }
150     if (result) {
151         SaveData(backupFullPath, backupKey, secretKey);
152     } else {
153         CleanData(backupFullPath);
154     }
155     decryptKey.assign(decryptKey.size(), 0);
156 }
157 
CanBackup()158 bool BackupManager::CanBackup()
159 {
160     if (!BackupRuleManager::GetInstance().CanBackup()) {
161         return false;
162     }
163     int64_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
164     if (currentTime - backupSuccessTime_ < backupInternal_ * MICROSEC_TO_SEC && backupSuccessTime_ > 0) {
165         ZLOGE("no more than backup internal time since the last backup success.");
166         return false;
167     }
168     return true;
169 }
170 
KeepData(const std::string & path)171 void BackupManager::KeepData(const std::string &path)
172 {
173     auto backupPath = path + BACKUP_BK_POSTFIX;
174     CopyFile(path, backupPath, true);
175 }
176 
SaveData(const std::string & path,const std::string & key,const SecretKeyMetaData & secretKey)177 void BackupManager::SaveData(const std::string &path, const std::string &key, const SecretKeyMetaData &secretKey)
178 {
179     auto tmpPath = path + BACKUP_TMP_POSTFIX;
180     auto backupPath = path + BACKUP_BK_POSTFIX;
181     CopyFile(tmpPath, path);
182     RemoveFile(tmpPath.c_str());
183     if (secretKey.sKey.size() != 0) {
184         MetaDataManager::GetInstance().SaveMeta(key, secretKey, true);
185     }
186     RemoveFile(backupPath.c_str());
187 }
188 
RollBackData(const std::string & path)189 void BackupManager::RollBackData(const std::string &path)
190 {
191     auto tmpPath = path + BACKUP_TMP_POSTFIX;
192     auto backupPath = path + BACKUP_BK_POSTFIX;
193     CopyFile(backupPath, path);
194     RemoveFile(tmpPath.c_str());
195     RemoveFile(backupPath.c_str());
196 }
197 
CleanData(const std::string & path)198 void BackupManager::CleanData(const std::string &path)
199 {
200     auto backupPath = path + BACKUP_BK_POSTFIX;
201     auto tmpPath = path + BACKUP_TMP_POSTFIX;
202     RemoveFile(tmpPath.c_str());
203     RemoveFile(backupPath.c_str());
204 }
205 
206 /**
207  *  learning by watching blow table, we can konw :
208  *  as encrypt db, when backup's password same as db's password, need clean data,
209  *  others if .bk file or .tmp file exist, rollback data
210  *  as unencrypt db, tmp file exist, rollback, tmp file not exist, but .bk file exist, clean data
211  *
212  *  backup step (encrypt)   file status             key in meat         option          file num
213  *  1, backup old data      autoBachup.bak          autoBachup.key      rollback        .bk = 1
214  *                          autoBachup.bak.bk                                           .tmp = 0
215  *
216  *  2, do backup            autoBachup.bak          autoBachup.key      rollback        .bk = 1
217  *                          autoBachup.bak.bk                                           .tmp = 1
218  *                          autoBachup.bak.tmp
219  *
220  *  3, copy data            autoBachup.bak(new)     autoBachup.key      rollback        .bk = 1
221  *                          autoBachup.bak.bk                                           .tmp = 1
222  *                          autoBachup.bak.tmp
223  *
224  *  4, delet tmp data       autoBachup.bak(new)     autoBachup.key      rollback        .bk = 1
225  *                          autoBachup.bak.bk                                           .tmp = 0
226  *
227  *  5, save key             autoBachup.bak(new)     autoBachup.key(new) clean data      .bk = 1
228  *                          autoBachup.bak.bk                                           .tmp = 0
229  *
230  *  6, delet backup data    autoBachup.bak          autoBachup.key      do nothing      .bk = 0
231  *                          -                       -                                   .tmp = 0
232  *
233  *  backup step (unencrypt) file status                     option                      file num
234  *  1, backup old data      autoBachup.bak                  clean data                  .bk = 1
235  *                          autoBachup.bak.bk                                           .tmp = 0
236  *
237  *  2, do backup            autoBachup.bak                  rollback data               .bk = 1
238  *                          autoBachup.bak.bk,                                          .tmp = 1
239  *                          autoBachup.bak.tmp
240  *
241  *  3, copy data            autoBachup.bak(new)             rollback data               .bk = 1
242  *                          autoBachup.bak.bk,                                          .tmp = 1
243  *                          autoBachup.bak.tmp
244  *
245  *  4, delet tmp data       autoBachup.bak                  clean data                  .bk = 1
246  *                          autoBachup.bak.bk                                           .tmp = 0
247  *
248  *
249  *  5, delet backup data    autoBachup.bak                  do nothing                  .bk = 0
250  *                                                                                      .tmp =0
251  * */
GetClearType(const StoreMetaData & meta)252 BackupManager::ClearType BackupManager::GetClearType(const StoreMetaData &meta)
253 {
254     auto backupFile = DirectoryManager::GetInstance().GetStoreBackupPath(meta) + "/" + AUTO_BACKUP_NAME;
255     auto dbKey = meta.GetSecretKey();
256     auto backupKey = meta.GetBackupSecretKey();
257     auto bkFile = backupFile + BACKUP_BK_POSTFIX;
258 
259     SecretKeyMetaData dbPassword;
260     if (MetaDataManager::GetInstance().LoadMeta(dbKey, dbPassword, true)) {
261         SecretKeyMetaData backupPassword;
262         MetaDataManager::GetInstance().LoadMeta(backupKey, backupPassword, true);
263         if (dbPassword.sKey != backupPassword.sKey && IsFileExist(bkFile)) {
264             return ROLLBACK;
265         }
266         if (dbPassword.sKey == backupPassword.sKey && IsFileExist(bkFile)) {
267             return CLEAN_DATA;
268         }
269     } else {
270         auto tmpFile = backupFile + BACKUP_TMP_POSTFIX;
271         if (IsFileExist(tmpFile)) {
272             return ROLLBACK;
273         }
274         if (!IsFileExist(tmpFile) && IsFileExist(bkFile)) {
275             return CLEAN_DATA;
276         }
277     }
278     return DO_NOTHING;
279 }
280 
CopyFile(const std::string & oldPath,const std::string & newPath,bool isCreate)281 void BackupManager::CopyFile(const std::string &oldPath, const std::string &newPath, bool isCreate)
282 {
283     std::fstream fin, fout;
284     if (!IsFileExist(oldPath)) {
285         return;
286     }
287     fin.open(oldPath, std::ios_base::in);
288     if (isCreate) {
289         fout.open(newPath, std::ios_base::out | std::ios_base::ate);
290     } else {
291         fout.open(newPath, std::ios_base::out | std::ios_base::trunc);
292     }
293     char buf[COPY_SIZE] = { 0 };
294     while (fin.good()) {
295         fin.read(buf, COPY_SIZE);
296         fout.write(buf, fin.gcount());
297     }
298     fin.close();
299     fout.close();
300 }
301 
GetPassWord(const StoreMetaData & meta,std::vector<uint8_t> & password)302 bool BackupManager::GetPassWord(const StoreMetaData &meta, std::vector<uint8_t> &password)
303 {
304     SecretKeyMetaData secretKey;
305     if (!MetaDataManager::GetInstance().LoadMeta(meta.GetBackupSecretKey(), secretKey, true)) {
306         return false;
307     }
308     return CryptoManager::GetInstance().Decrypt(meta, secretKey, password);
309 }
310 
IsFileExist(const std::string & path)311 bool BackupManager::IsFileExist(const std::string &path)
312 {
313     if (path.empty()) {
314         return false;
315     }
316     if (access(path.c_str(), F_OK) != 0) {
317         return false;
318     }
319     return true;
320 }
321 
RemoveFile(const std::string & path)322 bool BackupManager::RemoveFile(const std::string &path)
323 {
324     if (access(path.c_str(), F_OK) != 0) {
325         return true;
326     }
327     if (remove(path.c_str()) != 0) {
328         ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str());
329         return false;
330     }
331     return true;
332 }
333 } // namespace OHOS::DistributedData