1 /*
2  * Copyright (c) 2024 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 #include "hiview_db_util.h"
16 
17 #include <algorithm>
18 
19 #include "file_util.h"
20 #include "hiview_logger.h"
21 #include "time_util.h"
22 
23 namespace OHOS {
24 namespace HiviewDFX {
25 namespace HiviewDbUtil {
26 DEFINE_LOG_TAG("HiviewDbUtil");
27 namespace {
IsDbFile(const std::string & dbPath)28 bool IsDbFile(const std::string& dbPath)
29 {
30     std::string dbFileName = FileUtil::ExtractFileName(dbPath);
31     std::string dbFileExt = FileUtil::ExtractFileExt(dbFileName);
32     return dbFileExt == "db";
33 }
34 
ClearDbFilesByTimestampOrder(const std::vector<std::string> & dbFiles,uint32_t maxFileNum)35 void ClearDbFilesByTimestampOrder(const std::vector<std::string>& dbFiles, uint32_t maxFileNum)
36 {
37     uint32_t numOfCleanFiles = dbFiles.size() - maxFileNum;
38     for (size_t i = 0; i < numOfCleanFiles; i++) {
39         HIVIEW_LOGI("start to clear db file=%{public}s", dbFiles[i].c_str());
40         if (!FileUtil::RemoveFile(dbFiles[i])) {
41             HIVIEW_LOGW("failed to delete db file=%{public}s", dbFiles[i].c_str());
42         }
43     }
44 }
45 }
46 
CreateFileNameByDate(const std::string & prefix)47 std::string CreateFileNameByDate(const std::string& prefix)
48 {
49     // xxx_yyyymmdd.db
50     std::string dbFileName;
51     std::string dateStr = TimeUtil::TimestampFormatToDate(TimeUtil::GetSeconds(), "%Y%m%d");
52     dbFileName.append(prefix).append(dateStr).append(".db");
53     return dbFileName;
54 }
55 
GetDateFromDbFile(const std::string & dbPath)56 std::string GetDateFromDbFile(const std::string& dbPath)
57 {
58     // /data/../xxx_yyyymmdd.db
59     if (dbPath.empty()) {
60         return "";
61     }
62 
63     std::string dbFileName = FileUtil::ExtractFileName(dbPath);
64     size_t startPos = dbFileName.find("_");
65     if (startPos == std::string::npos) {
66         return "";
67     }
68     size_t endPos = dbFileName.rfind(".");
69     if (endPos == std::string::npos) {
70         return "";
71     }
72     return startPos < endPos ? dbFileName.substr(startPos + 1, endPos - startPos - 1) : "";
73 }
74 
InitDbUploadPath(const std::string & dbPath,std::string & uploadPath)75 bool InitDbUploadPath(const std::string& dbPath, std::string& uploadPath)
76 {
77     if (!uploadPath.empty()) {
78         return true;
79     }
80 
81     if (dbPath.empty()) {
82         HIVIEW_LOGE("db path is empty");
83         return false;
84     }
85 
86     const std::string uploadDirName = "upload";
87     std::string tmpUploadPath = FileUtil::IncludeTrailingPathDelimiter(
88         FileUtil::ExtractFilePath(dbPath)).append(uploadDirName);
89     if (!FileUtil::IsDirectory(tmpUploadPath) && !FileUtil::ForceCreateDirectory(tmpUploadPath)) {
90         HIVIEW_LOGE("failed to create upload dir=%{public}s", tmpUploadPath.c_str());
91         return false;
92     }
93     uploadPath = tmpUploadPath;
94     HIVIEW_LOGI("init db upload path=%{public}s", uploadPath.c_str());
95     return true;
96 }
97 
MoveDbFilesToUploadDir(const std::string & dbPath,const std::string & uploadPath)98 void MoveDbFilesToUploadDir(const std::string& dbPath, const std::string& uploadPath)
99 {
100     std::vector<std::string> dbFiles;
101     FileUtil::GetDirFiles(FileUtil::ExtractFilePath(dbPath), dbFiles, false);
102     for (auto& dbFile : dbFiles) {
103         // upload only xxx.db, and delete xxx.db-shm/xxx.db-wal
104         if (IsDbFile(dbFile)) {
105             MoveDbFileToUploadDir(dbFile, uploadPath);
106             continue;
107         }
108         // skip upload dir
109         if (dbFile.find("/upload") != std::string::npos) {
110             continue;
111         }
112         if (!FileUtil::RemoveFile(dbFile)) {
113             HIVIEW_LOGW("failed to remove db file=%{public}s", dbFile.c_str());
114             continue;
115         }
116         HIVIEW_LOGI("succ to remove db file=%{public}s", dbFile.c_str());
117     }
118 }
119 
MoveDbFileToUploadDir(const std::string & dbPath,const std::string & uploadPath)120 void MoveDbFileToUploadDir(const std::string& dbPath, const std::string& uploadPath)
121 {
122     std::string uploadFilePath = FileUtil::IncludeTrailingPathDelimiter(uploadPath)
123         .append(FileUtil::ExtractFileName(dbPath));
124     HIVIEW_LOGI("start to move db file, src=%{public}s, dst=%{public}s", dbPath.c_str(), uploadFilePath.c_str());
125     if (FileUtil::CopyFile(dbPath, uploadFilePath) != 0) {
126         HIVIEW_LOGW("failed to copy db file=%{public}s", dbPath.c_str());
127         return;
128     }
129     if (!FileUtil::RemoveFile(dbPath)) {
130         HIVIEW_LOGW("failed to delete db file=%{public}s", dbPath.c_str());
131     }
132 }
133 
TryToAgeUploadDbFiles(const std::string & uploadPath,uint32_t maxFileNum)134 void TryToAgeUploadDbFiles(const std::string& uploadPath, uint32_t maxFileNum)
135 {
136     std::vector<std::string> dbFiles;
137     FileUtil::GetDirFiles(uploadPath, dbFiles);
138     if (dbFiles.size() <= maxFileNum) {
139         return;
140     }
141     HIVIEW_LOGI("start to clean db files, size=%{public}zu", dbFiles.size());
142     std::sort(dbFiles.begin(), dbFiles.end());
143     ClearDbFilesByTimestampOrder(dbFiles, maxFileNum);
144 }
145 } // namespace HiviewDbUtil
146 } // namespace HiviewDFX
147 } // namespace OHOS
148