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