• 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 
17 #include "backup_manager.h"
18 #include "kvdb_service_client.h"
19 #include "log_print.h"
20 #include "task_executor.h"
21 namespace OHOS::DistributedKv {
22 namespace {
23 constexpr const char *BACKUP_POSTFIX = ".bak";
24 constexpr const int BACKUP_POSTFIX_SIZE = 4;
25 constexpr const char *BACKUP_TMP_POSTFIX = ".bk";
26 constexpr const int BACKUP_TMP_POSTFIX_SIZE = 3;
27 constexpr const char *BACKUP_KEY_POSTFIX = ".key";
28 constexpr const char *BACKUP_KEY_PREFIX = "Prefix_backup_";
29 constexpr const char *AUTO_BACKUP_NAME = "autoBackup";
30 constexpr const char *BACKUP_TOP_PATH = "/kvdb/backup";
31 constexpr const char *KEY_PATH = "/key";
32 }
33 
GetInstance()34 BackupManager &BackupManager::GetInstance()
35 {
36     static BackupManager instance;
37     return instance;
38 }
39 
BackupManager()40 BackupManager::BackupManager()
41 {
42 }
43 
~BackupManager()44 BackupManager::~BackupManager()
45 {
46 }
47 
Init(const std::string & baseDir)48 void BackupManager::Init(const std::string &baseDir)
49 {
50     TaskScheduler::Task task = [this, baseDir]() {
51         auto topPath = baseDir + BACKUP_TOP_PATH;
52         auto keyPath = baseDir + KEY_PATH;
53         auto storeIds = StoreUtil::GetSubPath(topPath);
54         auto keyFiles = StoreUtil::GetFiles(keyPath);
55         for (auto &storeId : storeIds) {
56             if (storeId == "." || storeId == "..") {
57                 continue;
58             }
59             auto backupPath = topPath + "/" + storeId;
60             auto backupFiles = StoreUtil::GetFiles(backupPath);
61             if (HaveResidueFile(backupFiles) || HaveResidueKey(keyFiles, storeId)) {
62                 auto ResidueInfo = BuildResidueInfo(backupFiles, keyFiles, storeId);
63                 ClearResidueFile(ResidueInfo, baseDir, storeId);
64             }
65         }
66     };
67     TaskExecutor::GetInstance().Execute(std::move(task));
68 }
69 
Prepare(const std::string & path,const std::string & storeId)70 void BackupManager::Prepare(const std::string &path, const std::string &storeId)
71 {
72     std::string topPath = path + BACKUP_TOP_PATH;
73     std::string storePath = topPath + "/" + storeId;
74     std::string autoBackupName = storePath + "/" + AUTO_BACKUP_NAME + BACKUP_POSTFIX;
75     (void)StoreUtil::InitPath(topPath);
76     (void)StoreUtil::InitPath(storePath);
77     (void)StoreUtil::CreateFile(autoBackupName);
78 }
79 
KeepData(const std::string & name,bool isCreated)80 void BackupManager::KeepData(const std::string &name, bool isCreated)
81 {
82     auto tmpName = name + BACKUP_TMP_POSTFIX;
83     if (isCreated) {
84         StoreUtil::CreateFile(tmpName);
85     } else {
86         StoreUtil::Rename(name, tmpName);
87     }
88 }
89 
RollBackData(const std::string & name,bool isCreated)90 void BackupManager::RollBackData(const std::string &name, bool isCreated)
91 {
92     auto tmpName = name + BACKUP_TMP_POSTFIX;
93     if (isCreated) {
94         StoreUtil::Remove(name);
95         StoreUtil::Remove(tmpName);
96     } else {
97         StoreUtil::Remove(name);
98         StoreUtil::Rename(tmpName, name);
99     }
100 }
101 
CleanTmpData(const std::string & name)102 void BackupManager::CleanTmpData(const std::string &name)
103 {
104     auto tmpName = name + BACKUP_TMP_POSTFIX;
105     StoreUtil::Remove(tmpName);
106 }
107 
Backup(const std::string & name,const std::string & baseDir,const std::string & storeId,std::shared_ptr<DBStore> dbStore)108 Status BackupManager::Backup(const std::string &name, const std::string &baseDir, const std::string &storeId,
109     std::shared_ptr<DBStore> dbStore)
110 {
111     if (dbStore == nullptr) {
112         return ALREADY_CLOSED;
113     }
114     if (name.size() == 0 || baseDir.size() == 0 || storeId.size() == 0 || name == AUTO_BACKUP_NAME) {
115         return INVALID_ARGUMENT;
116     }
117     std::string topPath = baseDir + BACKUP_TOP_PATH;
118     std::string storePath = topPath + "/" + storeId;
119     std::string backupFullName = storePath + "/"+ name + BACKUP_POSTFIX;
120     std::string keyName = BACKUP_KEY_PREFIX + storeId + "_" + name;
121     std::string keyFullName = baseDir + KEY_PATH + "/" + keyName + BACKUP_KEY_POSTFIX;
122 
123     bool isCreate = !StoreUtil::IsFileExist(backupFullName);
124     if ((StoreUtil::GetFiles(storePath).size() >= MAX_BACKUP_NUM) && isCreate) {
125         return ERROR;
126     }
127     (void)StoreUtil::InitPath(topPath);
128     (void)StoreUtil::InitPath(storePath);
129     KeepData(backupFullName, isCreate);
130     auto password = SecurityManager::GetInstance().GetDBPassword(storeId, baseDir);
131     if (password.GetSize() != 0) {
132         KeepData(keyFullName, isCreate);
133     }
134 
135     auto dbStatus = dbStore->Export(backupFullName, password);
136     auto status = StoreUtil::ConvertStatus(dbStatus);
137     if (status == SUCCESS) {
138         if (password.GetSize() != 0) {
139             SecurityManager::GetInstance().SaveDBPassword(keyName, baseDir, password);
140             CleanTmpData(keyFullName);
141         }
142         CleanTmpData(backupFullName);
143     } else {
144         RollBackData(backupFullName, isCreate);
145         if (password.GetSize() != 0) {
146             RollBackData(keyFullName, isCreate);
147         }
148     }
149     StoreUtil::Flush();
150     return status;
151 }
152 
GetBackupFileInfo(const std::string & name,const std::string & baseDir,const std::string & storeId)153 StoreUtil::FileInfo BackupManager::GetBackupFileInfo(
154     const std::string &name, const std::string &baseDir, const std::string &storeId)
155 {
156     StoreUtil::FileInfo backupFile;
157     std::string path = baseDir + BACKUP_TOP_PATH + "/" + storeId;
158     std::string backupName = name + BACKUP_POSTFIX;
159 
160     auto files = StoreUtil::GetFiles(path);
161     time_t modifyTime = 0;
162     for (auto &file : files) {
163         if (file.name == backupName) {
164             backupFile = file;
165             break;
166         }
167         if ((file.modifyTime > modifyTime) && (file.size != 0)) {
168             modifyTime = file.modifyTime;
169             backupFile = file;
170         }
171     }
172     return backupFile;
173 }
174 
Restore(const std::string & name,const std::string & baseDir,const std::string & appId,const std::string & storeId,std::shared_ptr<DBStore> dbStore)175 Status BackupManager::Restore(const std::string &name, const std::string &baseDir, const std::string &appId,
176     const std::string &storeId, std::shared_ptr<DBStore> dbStore)
177 {
178     if (dbStore == nullptr) {
179         return ALREADY_CLOSED;
180     }
181     if (storeId.size() == 0 || baseDir.size() == 0) {
182         return INVALID_ARGUMENT;
183     }
184     auto backupFile = GetBackupFileInfo(name, baseDir, storeId);
185     if (backupFile.name.size() == 0) {
186         return INVALID_ARGUMENT;
187     }
188     auto fullName = baseDir + BACKUP_TOP_PATH + "/" + storeId + "/" + backupFile.name;
189     auto password = GetRestorePassword(backupFile.name, baseDir, appId, storeId);
190     auto dbStatus = dbStore->Import(fullName, password);
191     auto status = StoreUtil::ConvertStatus(dbStatus);
192     return status;
193 }
194 
GetRestorePassword(const std::string & name,const std::string & baseDir,const std::string & appId,const std::string & storeId)195 SecurityManager::DBPassword BackupManager::GetRestorePassword(const std::string &name, const std::string &baseDir,
196     const std::string &appId, const std::string &storeId)
197 {
198     auto backupName = name.substr(0, name.length() - BACKUP_POSTFIX_SIZE);
199     auto keyName = BACKUP_KEY_PREFIX + storeId + "_" + backupName;
200     SecurityManager::DBPassword password;
201     if (backupName == AUTO_BACKUP_NAME) {
202         auto service = KVDBServiceClient::GetInstance();
203         if (service == nullptr) {
204             return SecurityManager::DBPassword();
205         }
206         std::vector<uint8_t> pwd;
207         service->GetBackupPassword({ appId }, { storeId }, pwd);
208         password.SetValue(pwd.data(), pwd.size());
209         pwd.assign(pwd.size(), 0);
210     } else {
211         password =  SecurityManager::GetInstance().GetDBPassword(keyName, baseDir);
212     }
213     return password;
214 }
215 
DeleteBackup(std::map<std::string,Status> & deleteList,const std::string & baseDir,const std::string & storeId)216 Status BackupManager::DeleteBackup(std::map<std::string, Status> &deleteList, const std::string &baseDir,
217     const std::string &storeId)
218 {
219     if (deleteList.empty() || baseDir.size() == 0 || storeId.size() == 0) {
220         return INVALID_ARGUMENT;
221     }
222 
223     std::string path = baseDir + BACKUP_TOP_PATH + "/" + storeId;
224     auto fileInfos = StoreUtil::GetFiles(path);
225     for (auto &info : fileInfos) {
226         auto it = deleteList.find(info.name.substr(0, info.name.length() - BACKUP_POSTFIX_SIZE));
227         if (it == deleteList.end()) {
228             continue;
229         }
230         auto backupName = info.name.substr(0, info.name.length() - BACKUP_POSTFIX_SIZE);
231         if (backupName ==  AUTO_BACKUP_NAME) {
232             it->second = INVALID_ARGUMENT;
233             continue;
234         }
235         std::string keyName = BACKUP_KEY_PREFIX + storeId + "_" + backupName;
236         SecurityManager::GetInstance().DelDBPassword(keyName, baseDir);
237         it->second = (StoreUtil::Remove(path + "/" + info.name)) ?  SUCCESS : ERROR;
238     }
239     return SUCCESS;
240 }
241 
HaveResidueFile(const std::vector<StoreUtil::FileInfo> & files)242 bool BackupManager::HaveResidueFile(const std::vector<StoreUtil::FileInfo> &files)
243 {
244     for (auto &file : files) {
245         if (IsEndWith(file.name, BACKUP_TMP_POSTFIX)) {
246             return true;
247         }
248     }
249     return false;
250 }
251 
HaveResidueKey(const std::vector<StoreUtil::FileInfo> & files,std::string storeId)252 bool BackupManager::HaveResidueKey(const std::vector<StoreUtil::FileInfo> &files, std::string storeId)
253 {
254     for (auto &file : files) {
255         auto prefix = BACKUP_KEY_PREFIX + storeId;
256         if (IsBeginWith(file.name, prefix) && IsEndWith(file.name, BACKUP_TMP_POSTFIX)) {
257             return true;
258         }
259     }
260     return false;
261 }
262 
GetBackupName(const std::string & fileName)263 std::string BackupManager::GetBackupName(const std::string &fileName)
264 {
265     int postFixLen = IsEndWith(fileName, BACKUP_TMP_POSTFIX) ?
266         BACKUP_POSTFIX_SIZE + BACKUP_TMP_POSTFIX_SIZE : BACKUP_POSTFIX_SIZE;
267     return fileName.substr(0, fileName.length() - postFixLen);
268 }
269 
SetResidueInfo(BackupManager::ResidueInfo & residueInfo,const std::vector<StoreUtil::FileInfo> & files,const std::string & name,const std::string & postFix)270 void BackupManager::SetResidueInfo(BackupManager::ResidueInfo &residueInfo,
271     const std::vector<StoreUtil::FileInfo> &files, const std::string &name, const std::string &postFix)
272 {
273     for (auto &file : files) {
274         auto fullName = name + postFix;
275         auto fullTmpName = fullName + BACKUP_TMP_POSTFIX;
276         if ((file.name == fullTmpName) && (postFix == BACKUP_POSTFIX)) {
277             residueInfo.hasTmpBackup = true;
278             residueInfo.tmpBackupSize = file.size;
279         }
280         if ((file.name == fullName) && (postFix == BACKUP_POSTFIX)) {
281             residueInfo.hasRawBackup = true;
282         }
283         if ((file.name == fullTmpName) && (postFix == BACKUP_KEY_POSTFIX)) {
284             residueInfo.hasTmpKey = true;
285             residueInfo.tmpKeySize = file.size;
286         }
287         if ((file.name == fullName) && (postFix == BACKUP_KEY_POSTFIX)) {
288             residueInfo.hasRawKey = true;
289         }
290     }
291 }
292 
BuildResidueInfo(const std::vector<StoreUtil::FileInfo> & files,const std::vector<StoreUtil::FileInfo> & keys,const std::string & storeId)293 std::map<std::string, BackupManager::ResidueInfo> BackupManager::BuildResidueInfo(
294     const std::vector<StoreUtil::FileInfo> &files,
295     const std::vector<StoreUtil::FileInfo> &keys, const std::string &storeId)
296 {
297     std::map<std::string, ResidueInfo> residueInfoList;
298     for (auto &file : files) {
299         auto backupName = GetBackupName(file.name);
300         if (backupName == AUTO_BACKUP_NAME) {
301             continue;
302         }
303         auto it = residueInfoList.find(backupName);
304         if (it == residueInfoList.end()) {
305             ResidueInfo residueInfo = { 0, 0, false, false, false, false };
306             SetResidueInfo(residueInfo, files, backupName, BACKUP_POSTFIX);
307             SetResidueInfo(residueInfo, keys, BACKUP_KEY_PREFIX + storeId + "_" + backupName, BACKUP_KEY_POSTFIX);
308             residueInfoList.emplace(backupName, residueInfo);
309         }
310     }
311     return residueInfoList;
312 }
313 
314 /**
315  *  in function NeedRollBack, use the number of tmp and raw file to charge who to do when start,
316  *  learning by watching blow table,
317  *  we can konw when the num of tmp file greater than or equal raw, interrupt happend druing backup
318  *
319  *  backup step (encrypt)   file status                         option          file num
320  *  1, backup old data      -               storeId.key         rollback data   raw = 1
321  *                          storeId.bak.bk  -                                   tmp = 1
322  *
323  *  2, backup old key       -               -                   rollback        raw = 0
324  *                          storeId.bak.bk, storeId.key.bk                      tmp = 2
325  *
326  *  3, do backup            storeId.bak     -                   rollback        raw = 1
327  *                          storeId.bak.bk, storeId.key.bk                      tmp = 2
328  *
329  *  4, store key            storeId.bak     storeId.key         rollback        raw = 2
330  *                          storeId.bak.bk, storeId.key.bk                      tmp = 2
331  *
332  *  5, delet tmp key        storeId.bak     storeId.key         clean data      raw = 2
333  *                          storeId.bak.bk  -                                   tmp = 1
334  *
335  *  6, delet tmp data       storeId.bak     storeId.key         do nothing      raw = 2
336  *                          -               -                                   tmp = 0
337  *
338  *  if step3 has failed, do as 7 ~ 8
339  *
340  *  7, rollback  data       storeId.bak     -                   rollback key    raw = 1
341  *                          -               storeId.key.bk                      tmp = 1
342  *
343  *  8, rollback  data       storeId.bak     storeId.key         do nothing      raw = 2
344  *                          -               -                                   tmp = 0
345  *
346  *  backup step (unencrypt) file status                         option          file num
347  *  1, backup old data      -                                   rollback data   raw = 0
348  *                          storeId.bak.bk  -                                   tmp = 1
349  *
350  *  2, do backup            storeId.bak     -                   rollback data   raw = 1
351  *                          storeId.bak.bk, -                                   tmp = 1
352  *
353  *  6, delet tmp data       storeId.bak     -                   do nothing      raw = 1
354  *                          -               -                                   tmp = 0
355  *
356  * */
GetClearType(const BackupManager::ResidueInfo & residueInfo)357 BackupManager::ClearType BackupManager::GetClearType(const BackupManager::ResidueInfo &residueInfo)
358 {
359     int rawFile = 0;
360     int tmpFile = 0;
361     if (residueInfo.hasRawBackup) {
362         rawFile++;
363     }
364     if (residueInfo.hasRawKey) {
365         rawFile++;
366     }
367     if (residueInfo.hasTmpBackup) {
368         tmpFile++;
369     }
370     if (residueInfo.hasTmpKey) {
371         tmpFile++;
372     }
373     if (tmpFile == 0) {
374         return DO_NOTHING;
375     }
376     if ((tmpFile >= rawFile) && (tmpFile == 1) && residueInfo.hasTmpBackup) {
377         return ROLLBACK_DATA;
378     }
379     if ((tmpFile >= rawFile) && (tmpFile == 1) && residueInfo.hasTmpKey) {
380         return ROLLBACK_KEY;
381     }
382     return (tmpFile >= rawFile) ? ROLLBACK : CLEAN_TMP;
383 }
384 
ClearResidueFile(std::map<std::string,ResidueInfo> residueInfo,const std::string & baseDir,const std::string & storeId)385 void BackupManager::ClearResidueFile(std::map<std::string, ResidueInfo> residueInfo,
386     const std::string &baseDir, const std::string &storeId)
387 {
388     for (auto &info : residueInfo) {
389         auto backupFullName = baseDir + BACKUP_TOP_PATH + "/" + storeId + "/" + info.first + BACKUP_POSTFIX;
390         auto keyFullName =
391             baseDir + KEY_PATH + "/" + BACKUP_KEY_PREFIX + storeId + "_" + info.first + BACKUP_KEY_POSTFIX;
392         switch (GetClearType(info.second)) {
393             case ROLLBACK_DATA:
394                 RollBackData(backupFullName, (info.second.tmpBackupSize == 0));
395                 break;
396             case ROLLBACK_KEY:
397                 RollBackData(keyFullName, (info.second.tmpKeySize == 0));
398                 break;
399             case ROLLBACK:
400                 RollBackData(backupFullName, (info.second.tmpBackupSize == 0));
401                 RollBackData(keyFullName, (info.second.tmpKeySize == 0));
402                 break;
403             case CLEAN_TMP:
404                 CleanTmpData(backupFullName);
405                 CleanTmpData(keyFullName);
406                 break;
407             case DO_NOTHING:
408             default:
409                 break;
410         }
411     }
412 }
413 
IsEndWith(const std::string & fullString,const std::string & end)414 bool BackupManager::IsEndWith(const std::string &fullString, const std::string &end)
415 {
416     if (fullString.length() >= end.length()) {
417         return (fullString.compare(fullString.length() - end.length(), end.length(), end) == 0);
418     } else {
419         return false;
420     }
421 }
422 
IsBeginWith(const std::string & fullString,const std::string & begin)423 bool BackupManager::IsBeginWith(const std::string &fullString, const std::string &begin)
424 {
425     if (fullString.length() >= begin.length()) {
426         return (fullString.compare(0, begin.length(), begin) == 0);
427     } else {
428         return false;
429     }
430 }
431 } // namespace OHOS::DistributedKv