• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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