1 /*
2  * Copyright (c) 2023-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 #include "sys_event_doc_reader.h"
16 
17 #include <cinttypes>
18 
19 #include "hiview_logger.h"
20 #include "securec.h"
21 #include "string_util.h"
22 #include "sys_event_query.h"
23 
24 namespace OHOS {
25 namespace HiviewDFX {
26 namespace EventStore {
27 DEFINE_LOG_TAG("HiView-SysEventDocReader");
28 using OHOS::HiviewDFX::EventRaw::RawData;
29 namespace {
30 template<typename T>
GetNegativeNum(T num)31 int32_t GetNegativeNum(T num)
32 {
33     return static_cast<int32_t>(~(num - 1)); // 1 for binary conversion
34 }
35 
36 template<typename T>
ReadValueAndReset(std::ifstream & in,T & value)37 void ReadValueAndReset(std::ifstream& in, T& value)
38 {
39     in.read(reinterpret_cast<char*>(&value), sizeof(T));
40     in.seekg(GetNegativeNum(sizeof(T)), std::ios::cur);
41 }
42 }
43 
SysEventDocReader(const std::string & path)44 SysEventDocReader::SysEventDocReader(const std::string& path): EventDocReader(path)
45 {
46     Init(path);
47 }
48 
~SysEventDocReader()49 SysEventDocReader::~SysEventDocReader()
50 {
51     if (in_.is_open()) {
52         in_.close();
53     }
54 }
55 
Init(const std::string & path)56 void SysEventDocReader::Init(const std::string& path)
57 {
58     in_.open(path, std::ios::binary);
59 
60     // get domain, name and level from file path
61     InitEventInfo(path);
62 
63     // get file size and data format version
64     if (in_.is_open()) {
65         auto curPos = in_.tellg();
66         in_.seekg(0, std::ios::end);
67         fileSize_ = in_.tellg();
68         in_.seekg(curPos, std::ios::beg);
69 
70         dataFmtVersion_ = ContentReader::ReadFmtVersion(in_);
71     }
72 }
73 
InitEventInfo(const std::string & path)74 void SysEventDocReader::InitEventInfo(const std::string& path)
75 {
76     std::vector<std::string> dirNames;
77     StringUtil::SplitStr(path, "/", dirNames);
78     constexpr size_t domainOffset = 2;
79     if (dirNames.size() < domainOffset) {
80         HIVIEW_LOGW("invalid size=%{public}zu of dir names", dirNames.size());
81         return;
82     }
83 
84     // init domain
85     const std::string domainStr = dirNames[dirNames.size() - domainOffset];
86     if (memcpy_s(info_.domain, MAX_DOMAIN_LEN, domainStr.c_str(), domainStr.length()) != EOK) {
87         HIVIEW_LOGE("failed to copy domain to EventInfo");
88         return;
89     }
90     std::string file = dirNames.back();
91     std::vector<std::string> fileNames;
92     StringUtil::SplitStr(file, "-", fileNames);
93     if (fileNames.size() != FILE_NAME_SPLIT_SIZE) {
94         HIVIEW_LOGW("invalid size=%{public}zu of file names", fileNames.size());
95         return;
96     }
97 
98     // init name
99     const std::string nameStr = fileNames[EVENT_NAME_INDEX];
100     if (memcpy_s(info_.name, MAX_EVENT_NAME_LEN, nameStr.c_str(), nameStr.length()) != EOK) {
101         HIVIEW_LOGE("failed to copy name to EventInfo");
102         return;
103     }
104 
105     // init level
106     info_.level = fileNames[EVENT_LEVEL_INDEX];
107 }
108 
Read(const DocQuery & query,EntryQueue & entries,int & num)109 int SysEventDocReader::Read(const DocQuery& query, EntryQueue& entries, int& num)
110 {
111     auto saveFunc = [this, &query, &entries, &num](uint8_t* content, uint32_t& contentSize) {
112         if (content == nullptr) {
113             return false;
114         }
115         TryToAddEntry(content, contentSize, query, entries, num);
116         return true;
117     };
118     return Read(saveFunc);
119 }
120 
Read(ReadCallback callback)121 int SysEventDocReader::Read(ReadCallback callback)
122 {
123     // read the header
124     DocHeader header;
125     if (auto ret = ReadHeader(header); ret != DOC_STORE_SUCCESS) {
126         return ret;
127     }
128 
129     if (!IsValidHeader(header)) {
130         return DOC_STORE_ERROR_INVALID;
131     }
132 
133     // set event tag if have
134     if (info_.tag.empty() && strlen(header.tag) != 0) {
135         info_.tag = header.tag;
136     }
137 
138     // set page size
139     pageSize_ = header.pageSize * NUM_OF_BYTES_IN_KB;
140 
141     // read the events
142     if (pageSize_ == 0) {
143         uint8_t* content = nullptr;
144         uint32_t contentSize = 0;
145         uint32_t pageIndex = 0;
146         if (auto ret = ReadContent(&content, contentSize, pageIndex); ret != DOC_STORE_SUCCESS) {
147             return ret;
148         }
149         callback(content, contentSize);
150         delete[] content;
151         return DOC_STORE_SUCCESS;
152     }
153     return ReadPages(callback);
154 }
155 
ReadHeader(DocHeader & header)156 int SysEventDocReader::ReadHeader(DocHeader& header)
157 {
158     auto reader = ContentReaderFactory::GetInstance().Get(dataFmtVersion_);
159     if (reader == nullptr) {
160         HIVIEW_LOGE("reader is nullptr, version:%{public}d", dataFmtVersion_);
161         return DOC_STORE_ERROR_IO;
162     }
163     return reader->ReadDocDetails(in_, header, docHeaderSize_, headExtra_);
164 }
165 
ReadHeader(DocHeader & header,HeadExtraInfo & headExtra)166 int SysEventDocReader::ReadHeader(DocHeader& header, HeadExtraInfo& headExtra)
167 {
168     ReadHeader(header);
169     headExtra = headExtra_;
170     return DOC_STORE_SUCCESS;
171 }
172 
ReadPages(ReadCallback callback)173 int SysEventDocReader::ReadPages(ReadCallback callback)
174 {
175     uint32_t pageIndex = 0;
176     while (!HasReadFileEnd()) {
177         uint8_t* content = nullptr;
178         uint32_t contentSize = 0;
179         if (ReadContent(&content, contentSize, pageIndex) != DOC_STORE_SUCCESS) {
180             pageIndex++;
181             if (SeekgPage(pageIndex) != DOC_STORE_SUCCESS) {
182                 HIVIEW_LOGD("end to seekg the next page index=%{public}" PRIu32 ", file=%{public}s",
183                     pageIndex, docPath_.c_str());
184                 break;
185             }
186             HIVIEW_LOGD("read the next page index=%{public}" PRIu32 ", file=%{public}s", pageIndex, docPath_.c_str());
187             continue;
188         }
189         callback(content, contentSize);
190         delete[] content;
191     }
192     return DOC_STORE_SUCCESS;
193 }
194 
HasReadFileEnd()195 bool SysEventDocReader::HasReadFileEnd()
196 {
197     if (!in_.is_open()) {
198         return true;
199     }
200     return (static_cast<int>(in_.tellg()) < 0) || in_.eof();
201 }
202 
HasReadPageEnd(uint32_t pageIndex)203 bool SysEventDocReader::HasReadPageEnd(uint32_t pageIndex)
204 {
205     if (HasReadFileEnd()) {
206         return true;
207     }
208     uint32_t curPos = static_cast<uint32_t>(in_.tellg());
209     if (curPos <= docHeaderSize_) {
210         return false;
211     }
212     if (curPos == docHeaderSize_ + pageSize_ * (pageIndex + 1)) {
213         /* if no byte of current page is filled with '\0' charactor,
214          * when position is at the end of current page,
215          * we should check whether page is end by page index increment.
216          */
217         return true;
218     }
219     return ((curPos - docHeaderSize_) % pageSize_ + BLOCK_SIZE) >= pageSize_;
220 }
221 
ReadContent(uint8_t ** content,uint32_t & contentSize,uint32_t pageIndex)222 int SysEventDocReader::ReadContent(uint8_t** content, uint32_t& contentSize, uint32_t pageIndex)
223 {
224     if (HasReadPageEnd(pageIndex)) {
225         HIVIEW_LOGD("end to read the page, file=%{public}s", docPath_.c_str());
226         return DOC_STORE_READ_EMPTY;
227     }
228     ReadValueAndReset(in_, contentSize);
229     constexpr uint32_t minContentSize = BLOCK_SIZE + sizeof(ContentHeader) + CRC_SIZE;
230     if (contentSize < minContentSize) {
231         HIVIEW_LOGD("invalid content size=%{public}u, file=%{public}s", contentSize, docPath_.c_str());
232         return DOC_STORE_READ_EMPTY;
233     }
234     if (contentSize > MAX_NEW_SIZE) {
235         HIVIEW_LOGE("invalid content size=%{public}u", contentSize);
236         return DOC_STORE_ERROR_MEMORY;
237     }
238     *content = new(std::nothrow) uint8_t[contentSize];
239     if (*content == nullptr) {
240         HIVIEW_LOGE("failed to new memory for content, size=%{public}u", contentSize);
241         return DOC_STORE_ERROR_MEMORY;
242     }
243     in_.read(reinterpret_cast<char*>(*content), contentSize);
244     return DOC_STORE_SUCCESS;
245 }
246 
ReadFileSize()247 int SysEventDocReader::ReadFileSize()
248 {
249     return fileSize_;
250 }
251 
ReadPageSize(uint32_t & pageSize)252 int SysEventDocReader::ReadPageSize(uint32_t& pageSize)
253 {
254     DocHeader header;
255     if (int ret = ReadHeader(header); ret != DOC_STORE_SUCCESS) {
256         return ret;
257     }
258     pageSize = header.pageSize * NUM_OF_BYTES_IN_KB;
259     return DOC_STORE_SUCCESS;
260 }
261 
IsValidHeader(const DocHeader & header)262 bool SysEventDocReader::IsValidHeader(const DocHeader& header)
263 {
264     auto reader = ContentReaderFactory::GetInstance().Get(dataFmtVersion_);
265     if (reader == nullptr) {
266         HIVIEW_LOGE("reader nullptr, version:%{public}d", dataFmtVersion_);
267         return false;
268     }
269     if (!reader->IsValidMagicNum(header.magicNum)) {
270         HIVIEW_LOGE("invalid magic number of file=%{public}s", docPath_.c_str());
271         return false;
272     }
273     return true;
274 }
275 
SeekgPage(uint32_t pageIndex)276 int SysEventDocReader::SeekgPage(uint32_t pageIndex)
277 {
278     if (HasReadFileEnd()) {
279         return DOC_STORE_ERROR_IO;
280     }
281     auto seekSize = docHeaderSize_ + pageSize_ * pageIndex;
282     if (static_cast<int>(seekSize) < ReadFileSize()) {
283         in_.seekg(seekSize, std::ios::beg);
284         return DOC_STORE_SUCCESS;
285     }
286     in_.setstate(std::ios::eofbit);
287     return DOC_STORE_ERROR_IO;
288 }
289 
BuildRawData(uint8_t * content,uint32_t contentSize)290 std::shared_ptr<RawData> SysEventDocReader::BuildRawData(uint8_t* content, uint32_t contentSize)
291 {
292     auto reader = ContentReaderFactory::GetInstance().Get(dataFmtVersion_);
293     if (reader == nullptr) {
294         HIVIEW_LOGE("reader nullptr, version:%{public}d", dataFmtVersion_);
295         return nullptr;
296     }
297     return reader->ReadRawData(info_, content, contentSize);
298 }
299 
TryToAddEntry(uint8_t * content,uint32_t contentSize,const DocQuery & query,EntryQueue & entries,int & num)300 void SysEventDocReader::TryToAddEntry(uint8_t* content, uint32_t contentSize, const DocQuery& query,
301     EntryQueue& entries, int& num)
302 {
303     if (!CheckEventInfo(content)) {
304         return;
305     }
306 
307     // check inner condition
308     if (!query.IsContainInnerConds(content)) {
309         return;
310     }
311     // build raw data
312     auto rawData = BuildRawData(content, contentSize);
313     if (rawData == nullptr) {
314         return;
315     }
316     // check extra condition
317     if (!query.IsContainExtraConds(rawData->GetData())) {
318         return;
319     }
320     // add to entry queue
321     num++;
322     entries.emplace(info_.seq, info_.timestamp, rawData, headExtra_.sysVersion, headExtra_.patchVersion);
323 }
324 
CheckEventInfo(uint8_t * content)325 bool SysEventDocReader::CheckEventInfo(uint8_t* content)
326 {
327     if (strlen(info_.domain) == 0 || strlen(info_.name) == 0 || info_.level.empty()) {
328         HIVIEW_LOGE("domain=%{public}s or name=%{public}s or level=%{public}s is empty",
329             info_.domain, info_.name, info_.level.c_str());
330         return false;
331     }
332 
333     int64_t seq = *(reinterpret_cast<int64_t*>(content + BLOCK_SIZE));
334     if (seq < 0) {
335         HIVIEW_LOGE("event seq is invalid, seq=%{public}" PRId64, seq);
336         return false;
337     }
338     info_.seq = seq;
339 
340     int64_t timestamp = *(reinterpret_cast<int64_t*>(content + BLOCK_SIZE + SEQ_SIZE));
341     if (timestamp < 0) {
342         HIVIEW_LOGE("event seq is invalid, timestamp=%{public}" PRId64, timestamp);
343         return false;
344     }
345     info_.timestamp = timestamp;
346 
347     return true;
348 }
349 } // EventStore
350 } // HiviewDFX
351 } // OHOS
352