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_writer.h"
16 
17 #include "event_store_config.h"
18 #include "hiview_logger.h"
19 #include "parameter_ex.h"
20 #include "securec.h"
21 #include "sys_event_doc_reader.h"
22 
23 namespace OHOS {
24 namespace HiviewDFX {
25 namespace EventStore {
26 DEFINE_LOG_TAG("HiView-SysEventDocWriter");
27 namespace {
28 constexpr uint32_t RAW_DATA_OFFSET = BLOCK_SIZE + MAX_DOMAIN_LEN + MAX_EVENT_NAME_LEN;
29 }
SysEventDocWriter(const std::string & path)30 SysEventDocWriter::SysEventDocWriter(const std::string& path): EventDocWriter(path)
31 {
32     out_.open(path, std::ios::binary | std::ios::app);
33 }
34 
~SysEventDocWriter()35 SysEventDocWriter::~SysEventDocWriter()
36 {
37     if (out_.is_open()) {
38         out_.close();
39     }
40 }
41 
Write(const std::shared_ptr<SysEvent> & sysEvent)42 int SysEventDocWriter::Write(const std::shared_ptr<SysEvent>& sysEvent)
43 {
44     if (sysEvent == nullptr) {
45         HIVIEW_LOGE("event is null");
46         return DOC_STORE_ERROR_NULL;
47     }
48     if (!out_.is_open()) {
49         HIVIEW_LOGE("file=%{public}s is not open", docPath_.c_str());
50         return DOC_STORE_ERROR_IO;
51     }
52     uint32_t contentSize = 0;
53     if (int ret = GetContentSize(sysEvent, contentSize); ret != DOC_STORE_SUCCESS) {
54         return ret;
55     }
56     SysEventDocReader reader(docPath_);
57     int fileSize = reader.ReadFileSize();
58     if (fileSize < 0) {
59         HIVIEW_LOGE("failed to get the size of file=%{public}s", docPath_.c_str());
60         return DOC_STORE_ERROR_IO;
61     }
62 
63     // if file is empty, write header to the file first
64     if (fileSize == 0) {
65         if (auto ret = WriteHeader(sysEvent, contentSize); ret != DOC_STORE_SUCCESS) {
66             return ret;
67         }
68         return WriteContent(sysEvent, contentSize);
69     }
70 
71     DocHeader header;
72     HeadExtraInfo headExtra;
73     reader.ReadHeader(header, headExtra);
74     headerSize_ = header.blockSize + sizeof(header.magicNum); // for GetCurrPageRemainSize
75     if (header.version != EventStore::EVENT_DATA_FORMATE_VERSION::CURRENT ||
76         headExtra.sysVersion != Parameter::GetSysVersionStr() ||
77         headExtra.patchVersion != Parameter::GetPatchVersionStr()) {
78         return DOC_STORE_NEW_FILE;
79     }
80 
81     // if file is not empty, read the file header for writing
82     uint32_t pageSize = 0;
83     if (int ret = reader.ReadPageSize(pageSize); ret != DOC_STORE_SUCCESS) {
84         HIVIEW_LOGE("failed to get pageSize from the file=%{public}s", docPath_.c_str());
85         return ret;
86     }
87 
88     // if the current file is full, need to create a new file
89     if (pageSize == 0 || pageSize < contentSize) {
90         HIVIEW_LOGD("the current page is full, page=%{public}u, content=%{public}u", pageSize, contentSize);
91         return DOC_STORE_NEW_FILE;
92     }
93 
94     // if the current page is full, need to add zero
95     if (auto remainSize = GetCurrPageRemainSize(fileSize, pageSize); remainSize < contentSize) {
96         if (int ret = FillCurrPageWithZero(remainSize); ret != DOC_STORE_SUCCESS) {
97             return ret;
98         }
99     }
100     return WriteContent(sysEvent, contentSize);
101 }
102 
GetCurrPageRemainSize(int fileSize,uint32_t pageSize)103 uint32_t SysEventDocWriter::GetCurrPageRemainSize(int fileSize, uint32_t pageSize)
104 {
105     return (pageSize - ((static_cast<uint32_t>(fileSize) - headerSize_) % pageSize));
106 }
107 
FillCurrPageWithZero(uint32_t remainSize)108 int SysEventDocWriter::FillCurrPageWithZero(uint32_t remainSize)
109 {
110     if (remainSize == 0) {
111         return DOC_STORE_SUCCESS;
112     }
113     if (remainSize > MAX_NEW_SIZE) {
114         HIVIEW_LOGE("invalid new size=%{public}u", remainSize);
115         return DOC_STORE_ERROR_MEMORY;
116     }
117     uint8_t* fillData = new(std::nothrow) uint8_t[remainSize]{ 0x0 };
118     if (fillData == nullptr) {
119         HIVIEW_LOGE("failed to new memory for fillData, size=%{public}u", remainSize);
120         return DOC_STORE_ERROR_MEMORY;
121     }
122     out_.write(reinterpret_cast<char*>(fillData), remainSize);
123     delete[] fillData;
124     return DOC_STORE_SUCCESS;
125 }
126 
GetContentSize(const std::shared_ptr<SysEvent> & sysEvent,uint32_t & contentSize)127 int SysEventDocWriter::GetContentSize(const std::shared_ptr<SysEvent>& sysEvent, uint32_t& contentSize)
128 {
129     uint8_t* rawData = sysEvent->AsRawData();
130     if (rawData == nullptr) {
131         HIVIEW_LOGE("The raw data of event is null");
132         return DOC_STORE_ERROR_NULL;
133     }
134     uint32_t dataSize = *(reinterpret_cast<uint32_t*>(rawData));
135     if (dataSize < RAW_DATA_OFFSET || dataSize > MAX_NEW_SIZE) {
136         HIVIEW_LOGE("The length=%{public}u of raw data is invalid", dataSize);
137         return DOC_STORE_ERROR_INVALID;
138     }
139     contentSize = dataSize - RAW_DATA_OFFSET + BLOCK_SIZE + SEQ_SIZE + CRC_SIZE;
140     return DOC_STORE_SUCCESS;
141 }
142 
WriteHeader(const std::shared_ptr<SysEvent> & sysEvent,uint32_t contentSize)143 int SysEventDocWriter::WriteHeader(const std::shared_ptr<SysEvent>& sysEvent, uint32_t contentSize)
144 {
145     uint32_t pageSize = EventStoreConfig::GetInstance().GetPageSize(sysEvent->eventType_);
146     if (pageSize == 0) {
147         HIVIEW_LOGE("failed to get page size");
148         return DOC_STORE_ERROR_IO;
149     }
150     pageSize = contentSize > (pageSize * NUM_OF_BYTES_IN_KB) ? 0 : pageSize;
151 
152     DocHeader header = {
153         .magicNum = MAGIC_NUM,
154         .pageSize = pageSize,
155         .version = EventStore::EVENT_DATA_FORMATE_VERSION::CURRENT,
156     };
157     if (!sysEvent->GetTag().empty() && strcpy_s(header.tag, MAX_TAG_LEN, sysEvent->GetTag().c_str()) != EOK) {
158         HIVIEW_LOGW("failed to copy tag to event, tag=%{public}s", sysEvent->GetTag().c_str());
159     }
160     auto sysVersion = Parameter::GetSysVersionStr();
161     uint32_t sysVersionSize = sysVersion.length() + 1; // reserve one byte for '\0'
162     auto patchVersion = Parameter::GetPatchVersionStr();
163     uint32_t patchVersionSize = patchVersion.length() + 1; // reserve one byte for '\0'
164     header.blockSize = sizeof(DocHeader) - sizeof(header.magicNum)
165         + sizeof(sysVersionSize) + sysVersionSize
166         + sizeof(patchVersionSize) + patchVersionSize;
167     headerSize_ = header.blockSize + sizeof(header.magicNum);
168     out_.write(reinterpret_cast<char*>(&header), sizeof(DocHeader));
169     out_.write(reinterpret_cast<char*>(&sysVersionSize), sizeof(uint32_t)); // append size of system version string
170     out_.write(sysVersion.c_str(), sysVersionSize); // append system version
171     out_.write(reinterpret_cast<char*>(&patchVersionSize), sizeof(uint32_t)); // append size of patch version string
172     out_.write(patchVersion.c_str(), patchVersionSize); // append patch version
173     return DOC_STORE_SUCCESS;
174 }
175 
WriteContent(const std::shared_ptr<SysEvent> & sysEvent,uint32_t contentSize)176 int SysEventDocWriter::WriteContent(const std::shared_ptr<SysEvent>& sysEvent, uint32_t contentSize)
177 {
178     // move to the end
179     out_.seekp(0, std::ios::end);
180 
181     // content.blockSize
182     out_.write(reinterpret_cast<const char*>(&contentSize), sizeof(contentSize));
183 
184     // content.seq
185     const auto eventSeq = sysEvent->GetEventSeq();
186     out_.write(reinterpret_cast<const char*>(&eventSeq), sizeof(eventSeq));
187 
188     // content.rawData
189     uint8_t* rawData = sysEvent->AsRawData();
190     if (rawData == nullptr) {
191         HIVIEW_LOGE("The raw data of event is null");
192         return DOC_STORE_ERROR_NULL;
193     }
194     uint32_t dataSize = *(reinterpret_cast<uint32_t*>(rawData)) - RAW_DATA_OFFSET;
195     out_.write(reinterpret_cast<const char*>(rawData + RAW_DATA_OFFSET), dataSize);
196 
197     // content.crc
198     const uint32_t crcDefault = 0;
199     out_.write(reinterpret_cast<const char*>(&crcDefault), CRC_SIZE);
200 
201     // flush the file
202     out_.flush();
203 
204     HIVIEW_LOGD("write content size=%{public}u, seq=%{public}" PRId64 ", file=%{public}s", contentSize,
205         sysEvent->GetEventSeq(), docPath_.c_str());
206     return DOC_STORE_SUCCESS;
207 }
208 } // EventStore
209 } // HiviewDFX
210 } // OHOS
211