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