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