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