1 /*
2 * Copyright (C) 2025 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
16 #include "file_system_store_helper.h"
17
18 #include <iostream>
19 #include <fstream>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 #include <chrono>
24 #include <iomanip>
25 #include <dirent.h>
26 #include <zlib.h>
27 #include <sys/stat.h>
28 #include <algorithm>
29 #include "bigdata.h"
30 #include "security_guard_log.h"
31 #include "security_guard_utils.h"
32 #include "security_guard_define.h"
33
34 namespace OHOS::Security::SecurityGuard {
GetInstance()35 FileSystemStoreHelper& FileSystemStoreHelper::GetInstance()
36 {
37 static FileSystemStoreHelper instance;
38 return instance;
39 }
40
GetFileSize(const std::string & filepath)41 size_t FileSystemStoreHelper::GetFileSize(const std::string& filepath)
42 {
43 struct stat stat_buf;
44 int rc = stat(filepath.c_str(), &stat_buf);
45 return rc == 0 ? stat_buf.st_size : 0;
46 }
47
48 // 获取最新的未写满的日志文件
GetLatestStoreFile()49 std::string FileSystemStoreHelper::GetLatestStoreFile()
50 {
51 SGLOGI("Enter FileSystemStoreHelper GetLatestStoreFile");
52 std::vector<std::string> storeFiles;
53 if (GetStoreFileList(storeFiles) != SUCCESS) {
54 return "";
55 }
56 if (storeFiles.empty()) {
57 return "";
58 }
59 std::sort(storeFiles.begin(), storeFiles.end(), std::greater<std::string>());
60 for (const auto& filename : storeFiles) {
61 std::string filepath = STORE_FILE_FOLDER_PATH + filename;
62 if (GetFileSize(filepath) < SINGLE_FILE_SIZE) {
63 return filepath;
64 }
65 std::string fileTime = GetTimestampFromFileName(filepath);
66 size_t startPos = fileTime.find("_");
67 if (startPos == std::string::npos) {
68 RenameStoreFile(filepath, fileTime, SecurityGuardUtils::GetDate());
69 }
70 return "";
71 }
72 return "";
73 }
74
CreateNewStoreFile(const std::string & startTime)75 std::string FileSystemStoreHelper::CreateNewStoreFile(const std::string& startTime)
76 {
77 std::string filename = STORE_FILE_FOLDER_PATH + STORE_FILE_NAME_PREFIX + startTime + STORE_FILE_NAME_SUFFIX;
78 return filename;
79 }
80
GetShortFileName(const std::string & filename)81 std::string FileSystemStoreHelper::GetShortFileName(const std::string& filename)
82 {
83 if (filename.empty()) {
84 return "";
85 }
86 size_t startPos = filename.find(STORE_FILE_NAME_PREFIX);
87 if (startPos == std::string::npos) {
88 return "";
89 }
90 return filename.substr(startPos, filename.size() - startPos);
91 }
92
WriteEventToGzFile(const std::string & filepath,const std::string & data)93 void FileSystemStoreHelper::WriteEventToGzFile(const std::string& filepath, const std::string& data)
94 {
95 gzFile file = gzopen(filepath.c_str(), "ab");
96 if (!file) {
97 std::string mesg = strerror(errno);
98 SGLOGE("Failed to open file::%{public}s, error msg:%{public}s",
99 GetShortFileName(filepath).c_str(), mesg.c_str());
100 BigData::ReportFileSystemStoreEvent({"write", GetShortFileName(filepath), mesg});
101 return;
102 }
103 gzprintf(file, "%s\n", data.c_str());
104 gzclose(file);
105 }
106
RenameStoreFile(const std::string & oldFilepath,const std::string & startTime,const std::string & endTime)107 void FileSystemStoreHelper::RenameStoreFile(const std::string& oldFilepath, const std::string& startTime,
108 const std::string& endTime)
109 {
110 std::string newFilepath = STORE_FILE_FOLDER_PATH + STORE_FILE_NAME_PREFIX + startTime + "_" + endTime +
111 STORE_FILE_NAME_SUFFIX;
112 if (rename(oldFilepath.c_str(), newFilepath.c_str()) != 0) {
113 std::string mesg = strerror(errno);
114 SGLOGE("Failed to rename file:%{public}s, error msg:%{public}s",
115 GetShortFileName(oldFilepath).c_str(), mesg.c_str());
116 BigData::ReportFileSystemStoreEvent({"rename", GetShortFileName(oldFilepath), mesg});
117 }
118 }
119
GetStoreFileList(std::vector<std::string> & storeFiles)120 int32_t FileSystemStoreHelper::GetStoreFileList(std::vector<std::string>& storeFiles)
121 {
122 DIR* dir = opendir(STORE_FILE_FOLDER_PATH.c_str());
123 if (nullptr == dir) {
124 SGLOGE("Store file dir is not exist!");
125 return FILE_ERR;
126 }
127 dirent* ent;
128 while ((ent = readdir(dir)) != nullptr) {
129 std::string filename(ent->d_name);
130 if (IsGzFile(filename)) {
131 storeFiles.push_back(filename);
132 }
133 }
134 closedir(dir);
135 return SUCCESS;
136 }
137
138 // LCOV_EXCL_START
DeleteOldestStoreFile()139 void FileSystemStoreHelper::DeleteOldestStoreFile()
140 {
141 SGLOGI("Enter FileSystemStoreHelper DeleteOldestStoreFile");
142 std::vector<std::string> storeFiles;
143 if (GetStoreFileList(storeFiles) != SUCCESS) {
144 return;
145 }
146 if (storeFiles.empty() || storeFiles.size() < MAX_STORE_FILE_COUNT) {
147 SGLOGI("No need to delete oldest store file");
148 return;
149 }
150 std::sort(storeFiles.begin(), storeFiles.end());
151 std::string oldestFile = STORE_FILE_FOLDER_PATH + storeFiles[0];
152 if (remove(oldestFile.c_str())) {
153 std::string mesg = strerror(errno);
154 SGLOGE("Failed to delete file:%{public}s, error msg:%{public}s",
155 GetShortFileName(oldestFile).c_str(), mesg.c_str());
156 BigData::ReportFileSystemStoreEvent({"delete", GetShortFileName(oldestFile), mesg});
157 } else {
158 SGLOGI("Deleted oldest log file:%{public}s", GetShortFileName(oldestFile).c_str());
159 }
160 }
161 // LCOV_EXCL_STOP
162
InsertEvent(const SecEvent & event)163 int32_t FileSystemStoreHelper::InsertEvent(const SecEvent& event)
164 {
165 SGLOGD("Enter FileSystemStoreHelper InsertEvent");
166 static std::string currentEventFile;
167 static std::string eventStartTime;
168 std::string date = event.date;
169 if (date.empty()) {
170 date = SecurityGuardUtils::GetDate();
171 }
172 std::string data = std::to_string(event.eventId) + "|" + date + "||" + std::to_string(event.userId) + "|||"
173 + event.content;
174 // 检查文件是否存在,如果不存在则创建
175 SGLOGD("CurrentEventFile:%{public}s", GetShortFileName(currentEventFile).c_str());
176 // 如果当前日志文件为空,尝试加载最新的未写满的文件
177 std::lock_guard<ffrt::mutex> lock(mutex_);
178 if (currentEventFile.empty()) {
179 currentEventFile = GetLatestStoreFile();
180 if (!currentEventFile.empty()) {
181 // 从文件名中提取起始时间
182 eventStartTime = GetTimestampFromFileName(currentEventFile);
183 } else {
184 // 没有未写满的文件,创建新文件
185 eventStartTime = SecurityGuardUtils::GetDate();
186 currentEventFile = CreateNewStoreFile(eventStartTime);
187 }
188 }
189 // 如果当前文件大小超过限制,创建新文件
190 if (GetFileSize(currentEventFile) >= SINGLE_FILE_SIZE) {
191 std::string endTime = SecurityGuardUtils::GetDate();
192 RenameStoreFile(currentEventFile, eventStartTime, endTime);
193 DeleteOldestStoreFile();
194 eventStartTime = SecurityGuardUtils::GetDate();
195 currentEventFile = CreateNewStoreFile(eventStartTime);
196 }
197 WriteEventToGzFile(currentEventFile, data);
198 SGLOGD("Insert file done");
199 return SUCCESS;
200 }
201
IsGzFile(const std::string & filename)202 bool FileSystemStoreHelper::IsGzFile(const std::string& filename)
203 {
204 return filename.size() >= STORE_FILE_NAME_SUFFIX.length() &&
205 filename.substr(filename.size() - STORE_FILE_NAME_SUFFIX.length()) == STORE_FILE_NAME_SUFFIX;
206 }
207
GetTimestampFromFileName(const std::string & filename)208 std::string FileSystemStoreHelper::GetTimestampFromFileName(const std::string& filename)
209 {
210 if (filename.empty()) {
211 return "";
212 }
213 size_t startPos = filename.find(STORE_FILE_NAME_PREFIX) + STORE_FILE_NAME_PREFIX.length();
214 size_t endPos = filename.find(STORE_FILE_NAME_SUFFIX);
215 if (startPos == std::string::npos || endPos == std::string::npos) {
216 return "";
217 }
218 return filename.substr(startPos, endPos - startPos);
219 }
220
GetEndTimeFromFileName(const std::string & fileTime)221 std::string FileSystemStoreHelper::GetEndTimeFromFileName(const std::string& fileTime)
222 {
223 size_t startPos = fileTime.find("_");
224 if (startPos == std::string::npos) {
225 return SecurityGuardUtils::GetDate();
226 }
227 return fileTime.substr(startPos);
228 }
229
230 // LCOV_EXCL_START
IsWantDate(const std::string & fileEvent,int64_t eventid,std::string startTime,std::string endTime)231 SecurityCollector::SecurityEvent FileSystemStoreHelper::IsWantDate(const std::string& fileEvent, int64_t eventid,
232 std::string startTime, std::string endTime)
233 {
234 size_t firstPos = fileEvent.find(STORE_FILE_EVENT_FIRST_DELIMITER);
235 size_t secondPos = fileEvent.find(STORE_FILE_EVENT_SECOND_DELIMITER);
236 size_t thirdPos = fileEvent.find(STORE_FILE_EVENT_THRID_DELIMITER);
237 if (firstPos == std::string::npos || secondPos == std::string::npos || thirdPos == std::string::npos) {
238 return {};
239 }
240 std::string fileEventid = fileEvent.substr(0, firstPos);
241 if (fileEventid != std::to_string(eventid)) {
242 return {};
243 }
244 std::string fileEventTime = fileEvent.substr(firstPos + STORE_FILE_EVENT_FIRST_DELIMITER.length(), secondPos);
245 if ((fileEventTime < startTime) || (fileEventTime > endTime)) {
246 return {};
247 }
248 std::string userId = fileEvent.substr(secondPos + STORE_FILE_EVENT_SECOND_DELIMITER.length(), thirdPos);
249 std::string fileEventContent = fileEvent.substr(thirdPos + STORE_FILE_EVENT_THRID_DELIMITER.length());
250 return {eventid, "1.0", fileEventContent, fileEventTime, atoi(userId.c_str())};
251 }
252 // LCOV_EXCL_STOP
253
GetQueryStoreFileList(std::vector<std::string> & storeFiles,const std::string & startTime,const std::string & endTime)254 int32_t FileSystemStoreHelper::GetQueryStoreFileList(std::vector<std::string>& storeFiles,
255 const std::string& startTime, const std::string& endTime)
256 {
257 DIR* dir = opendir(STORE_FILE_FOLDER_PATH.c_str());
258 if (nullptr == dir) {
259 SGLOGE("Store file dir is not exist!");
260 return FILE_ERR;
261 }
262 struct dirent* ent;
263 while ((ent = readdir(dir)) != nullptr) {
264 std::string filename(ent->d_name);
265 if (IsGzFile(filename)) {
266 std::string fileBeginTime = GetTimestampFromFileName(filename);
267 std::string fileEndTime = GetEndTimeFromFileName(fileBeginTime);
268 if (fileBeginTime == "" || fileEndTime < startTime || fileBeginTime > endTime) {
269 continue;
270 }
271 SGLOGD("QuerySecurityEvent add file:%{public}s", GetShortFileName(filename).c_str());
272 storeFiles.push_back(filename);
273 }
274 }
275 closedir(dir);
276 return SUCCESS;
277 }
278
QuerySecurityEventCallBack(sptr<ISecurityEventQueryCallback> proxy,std::vector<SecurityCollector::SecurityEvent> events)279 void FileSystemStoreHelper::QuerySecurityEventCallBack(sptr<ISecurityEventQueryCallback> proxy,
280 std::vector<SecurityCollector::SecurityEvent> events)
281 {
282 int32_t step = MAX_ON_QUERY_SIZE;
283 if (events.size() > 0 && events.size() <= static_cast<size_t>(MAX_ON_QUERY_SIZE)) {
284 proxy->OnQuery(events);
285 } else if (events.size() > static_cast<size_t>(MAX_ON_QUERY_SIZE)) {
286 std::vector<SecurityCollector::SecurityEvent>::iterator curPtr = events.begin();
287 std::vector<SecurityCollector::SecurityEvent>::iterator endPtr = events.end();
288 std::vector<SecurityCollector::SecurityEvent>::iterator end;
289 while (curPtr < endPtr) {
290 end = endPtr - curPtr > step ? step + curPtr : endPtr;
291 step = endPtr - curPtr > step ? step : endPtr - curPtr;
292 proxy->OnQuery(std::vector<SecurityCollector::SecurityEvent>(curPtr, end));
293 curPtr += step;
294 }
295 }
296 }
297
298
QuerySecurityEvent(const SecurityCollector::SecurityEventRuler ruler,sptr<ISecurityEventQueryCallback> proxy)299 int32_t FileSystemStoreHelper::QuerySecurityEvent(const SecurityCollector::SecurityEventRuler ruler,
300 sptr<ISecurityEventQueryCallback> proxy)
301 {
302 SGLOGI("Enter FileSystemStoreHelper QuerySecurityEvent");
303 std::string startTime = ruler.GetBeginTime();
304 std::string endTime = ruler.GetEndTime();
305 int64_t eventid = ruler.GetEventId();
306 if (ruler.GetBeginTime().empty()) {
307 startTime = MIN_START_TIME;
308 }
309 if (ruler.GetEndTime().empty()) {
310 endTime = SecurityGuardUtils::GetDate();
311 }
312 std::vector<std::string> storeFiles;
313 if (GetQueryStoreFileList(storeFiles, startTime, endTime) != SUCCESS) {
314 return FILE_ERR;
315 }
316 std::sort(storeFiles.begin(), storeFiles.end(), [this](const std::string& a, const std::string& b) {
317 return GetTimestampFromFileName(a) < GetTimestampFromFileName(b);
318 });
319 std::vector<SecurityCollector::SecurityEvent> events;
320 for (const auto& filename : storeFiles) {
321 std::string filepath = STORE_FILE_FOLDER_PATH + filename;
322 SGLOGD("Found store file:%{public}s", GetShortFileName(filepath).c_str());
323 gzFile file = gzopen(filepath.c_str(), "rb");
324 if (!file) {
325 std::string mesg = strerror(errno);
326 SGLOGE("Failed to open store file:%{public}s, error msg:%{public}s",
327 GetShortFileName(filepath).c_str(), mesg.c_str());
328 BigData::ReportFileSystemStoreEvent({"open", GetShortFileName(filepath), mesg});
329 continue;
330 }
331 char buffer[BUF_LEN];
332 while (gzgets(file, buffer, sizeof(buffer))) {
333 SecurityCollector::SecurityEvent event = IsWantDate(std::string(buffer), eventid, startTime, endTime);
334 if (event.GetEventId() == 0) {
335 continue;
336 }
337 events.push_back(event);
338 }
339 gzclose(file);
340 if (events.size() > MAX_QUERY_EVENTS_SIZE) {
341 break;
342 }
343 }
344 QuerySecurityEventCallBack(proxy, events);
345 return SUCCESS;
346 }
347 } // namespace OHOS::Security::SecurityGuard