• 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 <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