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