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
16 #include "hi_audit.h"
17
18 #include <chrono>
19 #include <ctime>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <iomanip>
23 #include <sstream>
24 #include <sys/time.h>
25 #include <unistd.h>
26
27 #include "media_log.h"
28 #include "zip_util.h"
29
30 namespace OHOS::Media {
31 struct HiAuditConfig {
32 std::string logPath;
33 std::string logName;
34 uint32_t logSize;
35 uint32_t fileSize;
36 uint32_t fileCount;
37 };
38
39 const HiAuditConfig HIAUDIT_CONFIG = { "/data/storage/el2/log/audit/", "media_library", 2 * 1024, 3 * 1204 * 1024, 10 };
40 constexpr int8_t MILLISECONDS_LENGTH = 3;
41 constexpr int64_t SEC_TO_MILLISEC = 1000;
42 constexpr int MAX_TIME_BUFF = 64;
43 const std::string HIAUDIT_LOG_NAME = HIAUDIT_CONFIG.logPath + HIAUDIT_CONFIG.logName + "_audit.csv";
44
HiAudit()45 HiAudit::HiAudit()
46 {
47 Init();
48 }
49
~HiAudit()50 HiAudit::~HiAudit()
51 {
52 if (writeFd_ >= 0) {
53 close(writeFd_);
54 }
55 }
56
GetInstance()57 HiAudit& HiAudit::GetInstance()
58 {
59 static HiAudit hiAudit;
60 return hiAudit;
61 }
62
Init()63 void HiAudit::Init()
64 {
65 if (access(HIAUDIT_CONFIG.logPath.c_str(), F_OK) != 0) {
66 int ret = mkdir(HIAUDIT_CONFIG.logPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
67 if (ret != 0) {
68 MEDIA_ERR_LOG("Failed to create directory %{public}s.", HIAUDIT_CONFIG.logPath.c_str());
69 }
70 }
71 std::lock_guard<std::mutex> lock(mutex_);
72 writeFd_ = open(HIAUDIT_LOG_NAME.c_str(), O_CREAT | O_APPEND | O_RDWR,
73 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
74 if (writeFd_ < 0) {
75 MEDIA_ERR_LOG("writeFd_ open error errno: %{public}d", errno);
76 }
77 struct stat st;
78 writeLogSize_ = stat(HIAUDIT_LOG_NAME.c_str(), &st) ? 0 : static_cast<uint64_t>(st.st_size);
79 MEDIA_INFO_LOG("writeLogSize: %{public}u", writeLogSize_.load());
80 }
81
GetMilliseconds()82 uint64_t HiAudit::GetMilliseconds()
83 {
84 auto now = std::chrono::system_clock::now();
85 auto millisecs = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
86 return millisecs.count();
87 }
88
GetFormattedTimestamp(time_t timeStamp,const std::string & format)89 std::string HiAudit::GetFormattedTimestamp(time_t timeStamp, const std::string& format)
90 {
91 auto seconds = timeStamp / SEC_TO_MILLISEC;
92 char date[MAX_TIME_BUFF] = {0};
93 struct tm result {};
94 if (localtime_r(&seconds, &result) != nullptr) {
95 strftime(date, MAX_TIME_BUFF, format.c_str(), &result);
96 }
97 return std::string(date);
98 }
99
GetFormattedTimestampEndWithMilli()100 std::string HiAudit::GetFormattedTimestampEndWithMilli()
101 {
102 uint64_t milliSeconds = GetMilliseconds();
103 std::string formattedTimeStamp = GetFormattedTimestamp(milliSeconds, "%Y%m%d%H%M%S");
104 std::stringstream ss;
105 ss << formattedTimeStamp;
106 milliSeconds = milliSeconds % SEC_TO_MILLISEC;
107 ss << std::setfill('0') << std::setw(MILLISECONDS_LENGTH) << milliSeconds;
108 return ss.str();
109 }
110
Write(const AuditLog & auditLog)111 void HiAudit::Write(const AuditLog& auditLog)
112 {
113 MEDIA_INFO_LOG("write");
114 std::lock_guard<std::mutex> lock(mutex_);
115 if (writeLogSize_ == 0) {
116 WriteToFile(auditLog.TitleString() + "\n");
117 }
118 std::string writeLog = GetFormattedTimestampEndWithMilli() + ", " +
119 HIAUDIT_CONFIG.logName + ", NO, " + auditLog.ToString();
120 MEDIA_INFO_LOG("write %{public}s.", writeLog.c_str());
121 if (writeLog.length() > HIAUDIT_CONFIG.logSize) {
122 writeLog = writeLog.substr(0, HIAUDIT_CONFIG.logSize);
123 }
124 writeLog = writeLog + "\n";
125 WriteToFile(writeLog);
126 }
127
GetWriteFilePath()128 void HiAudit::GetWriteFilePath()
129 {
130 if (writeLogSize_ < HIAUDIT_CONFIG.fileSize) {
131 return;
132 }
133
134 close(writeFd_);
135 ZipAuditLog();
136 CleanOldAuditFile();
137
138 writeFd_ = open(HIAUDIT_LOG_NAME.c_str(), O_CREAT | O_TRUNC | O_RDWR,
139 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
140 if (writeFd_ < 0) {
141 MEDIA_ERR_LOG("fd open error errno: %{public}d", errno);
142 }
143
144 writeLogSize_ = 0;
145 }
146
CleanOldAuditFile()147 void HiAudit::CleanOldAuditFile()
148 {
149 uint32_t zipFileSize = 0;
150 std::string oldestAuditFile;
151 DIR* dir = opendir(HIAUDIT_CONFIG.logPath.c_str());
152 while (true) {
153 struct dirent* ptr = readdir(dir);
154 if (ptr == nullptr) {
155 break;
156 }
157 if (std::string(ptr->d_name).find(HIAUDIT_CONFIG.logName) != std::string::npos &&
158 std::string(ptr->d_name).find("zip") != std::string::npos) {
159 zipFileSize = zipFileSize + 1;
160 if (oldestAuditFile.empty()) {
161 oldestAuditFile = HIAUDIT_CONFIG.logPath + std::string(ptr->d_name);
162 continue;
163 }
164 struct stat st;
165 stat((HIAUDIT_CONFIG.logPath + std::string(ptr->d_name)).c_str(), &st);
166 struct stat oldestSt;
167 stat(oldestAuditFile.c_str(), &oldestSt);
168 if (st.st_mtime < oldestSt.st_mtime) {
169 oldestAuditFile = HIAUDIT_CONFIG.logPath + std::string(ptr->d_name);
170 }
171 }
172 }
173 closedir(dir);
174 if (zipFileSize > HIAUDIT_CONFIG.fileCount) {
175 remove(oldestAuditFile.c_str());
176 }
177 }
178
WriteToFile(const std::string & content)179 void HiAudit::WriteToFile(const std::string& content)
180 {
181 GetWriteFilePath();
182 if (writeFd_ < 0) {
183 MEDIA_ERR_LOG("fd invalid.");
184 return;
185 }
186 write(writeFd_, content.c_str(), content.length());
187 writeLogSize_ = writeLogSize_ + content.length();
188 }
189
ZipAuditLog()190 void HiAudit::ZipAuditLog()
191 {
192 std::string zipFileName = HIAUDIT_CONFIG.logPath + HIAUDIT_CONFIG.logName + "_audit_" +
193 GetFormattedTimestamp(GetMilliseconds(), "%Y%m%d%H%M%S");
194 std::rename(HIAUDIT_LOG_NAME.c_str(), (zipFileName + ".csv").c_str());
195 zipFile compressZip = Media::ZipUtil::CreateZipFile(zipFileName + ".zip");
196 if (compressZip == nullptr) {
197 MEDIA_WARN_LOG("open zip file failed.");
198 return;
199 }
200 if (Media::ZipUtil::AddFileInZip(compressZip, zipFileName + ".csv", Media::KEEP_NONE_PARENT_PATH) == 0) {
201 remove((zipFileName + ".csv").c_str());
202 }
203 Media::ZipUtil::CloseZipFile(compressZip);
204 }
205 }