1 /*
2  * Copyright (C) 2021 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 "executor/zip_output.h"
16 #include <unistd.h>
17 #include "securec.h"
18 #include "dump_utils.h"
19 #include "util/file_utils.h"
20 #include "common/dumper_constant.h"
21 namespace OHOS {
22 namespace HiviewDFX {
ZipOutput()23 ZipOutput::ZipOutput() : fd_(-1)
24 {
25 }
26 
~ZipOutput()27 ZipOutput::~ZipOutput()
28 {
29     if (fd_ >= 0) {
30         close(fd_);
31     }
32 }
33 
PreExecute(const std::shared_ptr<DumperParameter> & parameter,StringMatrix dumpDatas)34 DumpStatus ZipOutput::PreExecute(const std::shared_ptr<DumperParameter>& parameter,
35     StringMatrix dumpDatas)
36 {
37     mDumpDatas_ = dumpDatas;
38     if (mDumpDatas_.get() == nullptr) {
39         return DumpStatus::DUMP_FAIL;
40     }
41 
42     // init myself once
43     if (mFilePath_.empty()) {
44         mFilePath_ =  parameter->GetOpts().path_;
45         srcBuffer_ = std::make_shared<CompressBuffer>();
46         destBuffer_ = std::make_shared<CompressBuffer>();
47         ClearBuffer();
48         fd_= DumpUtils::FdToWrite(mFilePath_);
49         if (fd_ < 0) {
50             return DumpStatus::DUMP_FAIL;
51         }
52     }
53 
54     return DumpStatus::DUMP_OK;
55 }
56 
Execute()57 DumpStatus ZipOutput::Execute()
58 {
59     DUMPER_HILOGI(MODULE_COMMON, "info|ZipOutput Execute");
60     if (!mDumpDatas_.get() || (fd_ < 0)) {
61         return DumpStatus::DUMP_FAIL;
62     }
63     CompressBuffer* srcBuffer = srcBuffer_.get();
64     CompressBuffer* destBuffer = destBuffer_.get();
65     if (!srcBuffer || !destBuffer) {
66         return DumpStatus::DUMP_FAIL;
67     }
68     DumpCompressor compressor;
69     for (auto v_line : *(mDumpDatas_.get())) {
70         // whole line
71         std::string line;
72         for (auto v_content : v_line)  {
73             line.append(v_content);
74         }
75         const char* content = line.c_str();
76         uint16_t content_size = strlen(content);
77         uint16_t size = strlen(content) + 1; // include \n
78         // buffer is full
79         if ((srcBuffer->offset + size) > MAX_COMPRESS_BUFFER_SIZE) {
80             // compress and write to file
81             CompressAndWriteToFd();
82         }
83         // Process big line.
84         if (size > MAX_COMPRESS_BUFFER_SIZE) {
85             CompressAndWriteToFd(); // clear buffer
86             CompressBigLine(content, size);
87             continue;
88         }
89         // Add to buffer end with \n
90         if (memcpy_s(srcBuffer->content + srcBuffer->offset,
91             MAX_COMPRESS_BUFFER_SIZE - srcBuffer->offset, content, content_size) != EOK) {
92             LOG_DEBUG("ZipOutput::Execute() memcpy_s failed!\n");
93             return DumpStatus::DUMP_FAIL;
94         }
95         srcBuffer->offset = srcBuffer->offset + content_size;
96         srcBuffer->content[srcBuffer->offset] = '\n';
97         srcBuffer->offset = srcBuffer->offset + 1;
98     }
99     // compress and write to file
100     CompressAndWriteToFd();
101     // clear dump data.
102     mDumpDatas_->clear();
103     DUMPER_HILOGI(MODULE_COMMON, "info|ZipOutput Execute end");
104     return DumpStatus::DUMP_OK;
105 }
106 
CompressAndWriteToFd()107 DumpStatus ZipOutput::CompressAndWriteToFd()
108 {
109     CompressBuffer* srcBuffer = srcBuffer_.get();
110     CompressBuffer* destBuffer = destBuffer_.get();
111     if (!srcBuffer || !destBuffer) {
112         return DumpStatus::DUMP_FAIL;
113     }
114     DumpStatus ret = DumpStatus::DUMP_OK;
115     if (srcBuffer->offset > 0) {
116         ret = compressor_.Compress(srcBuffer, destBuffer);
117         if (ret == DumpStatus::DUMP_OK) {
118             if (write(fd_, destBuffer->content, destBuffer->offset) < 0) {
119                 ret = DumpStatus::DUMP_FAIL;
120                 LOG_DEBUG("ZipOutput::CompressAndWriteToFd() Write to FD failed!\n");
121             }
122         } else {
123             ret = DumpStatus::DUMP_FAIL;
124             LOG_DEBUG("ZipOutput::CompressAndWriteToFd() Compress failed!\n");
125         }
126         ClearBuffer();
127     }
128 
129     return ret;
130 }
131 
CompressBigLine(const char * content,uint16_t size)132 DumpStatus ZipOutput::CompressBigLine(const char* content, uint16_t size)
133 {
134     if (!content) {
135         return DumpStatus::DUMP_FAIL;
136     }
137     CompressBuffer* srcBuffer = srcBuffer_.get();
138     CompressBuffer* destBuffer = destBuffer_.get();
139     if (!srcBuffer || !destBuffer) {
140         return DumpStatus::DUMP_FAIL;
141     }
142     DumpStatus ret = DumpStatus::DUMP_OK;
143     uint16_t remain_size = size - 1; // size include \n
144     uint16_t complete_size = 0;
145     while (remain_size > 0) {
146         uint16_t process_size = remain_size;
147         if ((srcBuffer->offset + remain_size) > MAX_COMPRESS_BUFFER_SIZE) {
148             process_size = MAX_COMPRESS_BUFFER_SIZE - srcBuffer->offset;
149         }
150         if (memcpy_s(srcBuffer->content + srcBuffer->offset,
151             MAX_COMPRESS_BUFFER_SIZE - srcBuffer->offset,
152             content + complete_size, process_size) != EOK) {
153             LOG_DEBUG("ZipOutput::CompressBigLine() memcpy_s failed!\n");
154             return DumpStatus::DUMP_FAIL;
155         }
156         srcBuffer->offset = srcBuffer->offset + process_size;
157         complete_size += process_size;
158         remain_size -= process_size;
159         CompressAndWriteToFd();
160     }
161     // process \n
162     srcBuffer->content[srcBuffer->offset] = '\n';
163     srcBuffer->offset = srcBuffer->offset + 1;
164     CompressAndWriteToFd();
165     return ret;
166 }
167 
168 
AfterExecute()169 DumpStatus ZipOutput::AfterExecute()
170 {
171     return DumpStatus::DUMP_OK;
172 }
173 
ClearBuffer()174 void ZipOutput::ClearBuffer()
175 {
176     if (srcBuffer_.get()) {
177         (void)memset_s(srcBuffer_.get(), sizeof(CompressBuffer), 0, sizeof(CompressBuffer));
178     }
179     if (destBuffer_.get()) {
180         (void)memset_s(destBuffer_.get(), sizeof(CompressBuffer), 0, sizeof(CompressBuffer));
181     }
182 }
183 } // namespace HiviewDFX
184 } // namespace OHOS
185