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