• 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 #include "backuprule/backup_rule_manager.h"
22 #include "communication_provider.h"
23 #include "crypto_manager.h"
24 #include "directory_manager.h"
25 #include "log_print.h"
26 #include "metadata/meta_data_manager.h"
27 #include "types.h"
28 namespace OHOS::DistributedData {
29 using Commu = AppDistributedKv::CommunicationProvider;
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({Commu::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()94 void BackupManager::BackSchedule()
95 {
96     std::chrono::duration<int> delay(schedularDelay_);
97     std::chrono::duration<int> internal(schedularInternal_);
98     ZLOGI("BackupManager Schedule start.");
99     scheduler_.Every(delay, internal, [this]() {
100         if (!CanBackup()) {
101             return;
102         }
103         std::vector<StoreMetaData> metas;
104         MetaDataManager::GetInstance().LoadMeta(
105             StoreMetaData::GetPrefix({Commu::GetInstance().GetLocalDevice().uuid}), metas);
106 
107         int64_t end = std::min(startNum_ + backupNumber_, static_cast<int64_t>(metas.size()));
108         for (int64_t i = startNum_; i < end; startNum_++, i++) {
109             auto &meta = metas[i];
110             if (!meta.isBackup || meta.isDirty) {
111                 continue;
112             }
113             DoBackup(meta);
114         }
115         if (startNum_ >= static_cast<int64_t>(metas.size())) {
116             startNum_ = 0;
117         }
118         sync();
119         backupSuccessTime_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
120     });
121 }
122 
DoBackup(const StoreMetaData & meta)123 void BackupManager::DoBackup(const StoreMetaData &meta)
124 {
125     bool result = false;
126     auto key = meta.GetSecretKey();
127     auto backupKey = meta.GetBackupSecretKey();
128     std::vector<uint8_t> decryptKey;
129     SecretKeyMetaData secretKey;
130     if (MetaDataManager::GetInstance().LoadMeta(key, secretKey, true)) {
131         CryptoManager::GetInstance().Decrypt(secretKey.sKey, decryptKey);
132     }
133     auto backupPath = DirectoryManager::GetInstance().GetStoreBackupPath(meta);
134     std::string backupFullPath = backupPath + "/" + AUTO_BACKUP_NAME;
135 
136     KeepData(backupFullPath);
137     if (exporters_[meta.storeType] != nullptr) {
138         exporters_[meta.storeType](meta, backupFullPath + BACKUP_TMP_POSTFIX, result);
139     }
140     if (result) {
141         SaveData(backupFullPath, backupKey, secretKey);
142     } else {
143         CleanData(backupFullPath);
144     }
145     decryptKey.assign(decryptKey.size(), 0);
146 }
147 
CanBackup()148 bool BackupManager::CanBackup()
149 {
150     if (!BackupRuleManager::GetInstance().CanBackup()) {
151         return false;
152     }
153     int64_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
154     if (currentTime - backupSuccessTime_ < backupInternal_ * MICROSEC_TO_SEC && backupSuccessTime_ > 0) {
155         ZLOGE("no more than backup internal time since the last backup success.");
156         return false;
157     }
158     return true;
159 }
160 
KeepData(const std::string & path)161 void BackupManager::KeepData(const std::string &path)
162 {
163     auto backupPath = path + BACKUP_BK_POSTFIX;
164     CopyFile(path, backupPath, true);
165 }
166 
SaveData(const std::string & path,const std::string & key,const SecretKeyMetaData & secretKey)167 void BackupManager::SaveData(
168     const std::string &path, const std::string &key, const SecretKeyMetaData &secretKey)
169 {
170     auto tmpPath = path + BACKUP_TMP_POSTFIX;
171     auto backupPath = path + BACKUP_BK_POSTFIX;
172     CopyFile(tmpPath, path);
173     RemoveFile(tmpPath.c_str());
174     if (secretKey.sKey.size() != 0) {
175         MetaDataManager::GetInstance().SaveMeta(key, secretKey, true);
176     }
177     RemoveFile(backupPath.c_str());
178 }
179 
RollBackData(const std::string & path)180 void BackupManager::RollBackData(const std::string &path)
181 {
182     auto tmpPath = path + BACKUP_TMP_POSTFIX;
183     auto backupPath = path + BACKUP_BK_POSTFIX;
184     CopyFile(backupPath, path);
185     RemoveFile(tmpPath.c_str());
186     RemoveFile(backupPath.c_str());
187 }
188 
CleanData(const std::string & path)189 void BackupManager::CleanData(const std::string &path)
190 {
191     auto backupPath = path + BACKUP_BK_POSTFIX;
192     auto tmpPath = path + BACKUP_TMP_POSTFIX;
193     RemoveFile(tmpPath.c_str());
194     RemoveFile(backupPath.c_str());
195 }
196 
197 /**
198  *  learning by watching blow table, we can konw :
199  *  as encrypt db, when backup's password same as db's password, need clean data,
200  *  others if .bk file or .tmp file exist, rollback data
201  *  as unencrypt db, tmp file exist, rollback, tmp file not exist, but .bk file exist, clean data
202  *
203  *  backup step (encrypt)   file status             key in meat         option          file num
204  *  1, backup old data      autoBachup.bak          autoBachup.key      rollback        .bk = 1
205  *                          autoBachup.bak.bk                                           .tmp = 0
206  *
207  *  2, do backup            autoBachup.bak          autoBachup.key      rollback        .bk = 1
208  *                          autoBachup.bak.bk                                           .tmp = 1
209  *                          autoBachup.bak.tmp
210  *
211  *  3, copy data            autoBachup.bak(new)     autoBachup.key      rollback        .bk = 1
212  *                          autoBachup.bak.bk                                           .tmp = 1
213  *                          autoBachup.bak.tmp
214  *
215  *  4, delet tmp data       autoBachup.bak(new)     autoBachup.key      rollback        .bk = 1
216  *                          autoBachup.bak.bk                                           .tmp = 0
217  *
218  *  5, save key             autoBachup.bak(new)     autoBachup.key(new) clean data      .bk = 1
219  *                          autoBachup.bak.bk                                           .tmp = 0
220  *
221  *  6, delet backup data    autoBachup.bak          autoBachup.key      do nothing      .bk = 0
222  *                          -                       -                                   .tmp = 0
223  *
224  *  backup step (unencrypt) file status                     option                      file num
225  *  1, backup old data      autoBachup.bak                  clean data                  .bk = 1
226  *                          autoBachup.bak.bk                                           .tmp = 0
227  *
228  *  2, do backup            autoBachup.bak                  rollback data               .bk = 1
229  *                          autoBachup.bak.bk,                                          .tmp = 1
230  *                          autoBachup.bak.tmp
231  *
232  *  3, copy data            autoBachup.bak(new)             rollback data               .bk = 1
233  *                          autoBachup.bak.bk,                                          .tmp = 1
234  *                          autoBachup.bak.tmp
235  *
236  *  4, delet tmp data       autoBachup.bak                  clean data                  .bk = 1
237  *                          autoBachup.bak.bk                                           .tmp = 0
238  *
239  *
240  *  5, delet backup data    autoBachup.bak                  do nothing                  .bk = 0
241  *                                                                                      .tmp =0
242  * */
GetClearType(const StoreMetaData & meta)243 BackupManager::ClearType BackupManager::GetClearType(const StoreMetaData &meta)
244 {
245     auto backupFile =
246         DirectoryManager::GetInstance().GetStoreBackupPath(meta) + "/" + AUTO_BACKUP_NAME;
247     auto dbKey = meta.GetSecretKey();
248     auto backupKey = meta.GetBackupSecretKey();
249     auto bkFile = backupFile + BACKUP_BK_POSTFIX;
250 
251     SecretKeyMetaData dbPassword;
252     if (MetaDataManager::GetInstance().LoadMeta(dbKey, dbPassword, true)) {
253         SecretKeyMetaData backupPassword;
254         MetaDataManager::GetInstance().LoadMeta(backupKey, backupPassword, true);
255         if (dbPassword.sKey != backupPassword.sKey && IsFileExist(bkFile)) {
256             return ROLLBACK;
257         }
258         if (dbPassword.sKey == backupPassword.sKey && IsFileExist(bkFile)) {
259             return CLEAN_DATA;
260         }
261     } else {
262         auto tmpFile = backupFile + BACKUP_TMP_POSTFIX;
263         if (IsFileExist(tmpFile)) {
264             return ROLLBACK;
265         }
266         if (!IsFileExist(tmpFile) && IsFileExist(bkFile)) {
267             return CLEAN_DATA;
268         }
269     }
270     return DO_NOTHING;
271 }
272 
CopyFile(const std::string & oldPath,const std::string & newPath,bool isCreate)273 void BackupManager::CopyFile(const std::string &oldPath, const std::string &newPath, bool isCreate)
274 {
275     std::fstream fin, fout;
276     if (!IsFileExist(oldPath)) {
277         return;
278     }
279     fin.open(oldPath, std::ios_base::in);
280     if (isCreate) {
281         fout.open(newPath, std::ios_base::out | std::ios_base::ate);
282     } else {
283         fout.open(newPath, std::ios_base::out | std::ios_base::trunc);
284     }
285     char buf[COPY_SIZE] = {0};
286     while (!fin.eof()) {
287         fin.read(buf, COPY_SIZE);
288         fout.write(buf, fin.gcount());
289     }
290     fin.close();
291     fout.close();
292 }
293 
GetPassWord(const StoreMetaData & meta,std::vector<uint8_t> & password)294 bool BackupManager::GetPassWord(const StoreMetaData &meta, std::vector<uint8_t> &password)
295 {
296     std::string key = meta.GetBackupSecretKey();
297     SecretKeyMetaData secretKey;
298     MetaDataManager::GetInstance().LoadMeta(key, secretKey, true);
299     return CryptoManager::GetInstance().Decrypt(secretKey.sKey, password);
300 }
301 
IsFileExist(const std::string & path)302 bool BackupManager::IsFileExist(const std::string &path)
303 {
304     if (path.empty()) {
305         return false;
306     }
307     if (access(path.c_str(), F_OK) != 0) {
308         return false;
309     }
310     return true;
311 }
312 
RemoveFile(const std::string & path)313 bool BackupManager::RemoveFile(const std::string &path)
314 {
315     if (access(path.c_str(), F_OK) != 0) {
316         return true;
317     }
318     if (remove(path.c_str()) != 0) {
319         ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str());
320         return false;
321     }
322     return true;
323 }
324 } // namespace OHOS::DistributedData