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 "b_json/b_report_entity.h"
17
18 #include <map>
19 #include <sstream>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23
24 #include "b_error/b_error.h"
25 #include "filemgmt_libhilog.h"
26 #include "sandbox_helper.h"
27 #include "unique_fd.h"
28
29 namespace OHOS::FileManagement::Backup {
30 using namespace std;
31 namespace {
32 const char ATTR_SEP = ';';
33 const char LINE_SEP = '\n';
34 const char LINE_WRAP = '\r';
35 const int64_t HASH_BUFFER_SIZE = 4096; // 每次读取的size
36 const int INFO_ALIGN_NUM = 2;
37 const size_t ENCODE_FLAG_VERSION = 7; // 7: "path", "mode", "dir", "size", "mtime", "hash", "isIncremental"
38 const std::string DEFAULT_VALUE = "1";
39 const std::vector<std::string> Data_Header = {
40 "path", "mode", "dir", "size", "mtime", "hash", "isIncremental", "encodeFlag"
41 };
42
43 } // namespace
44
SplitStringByChar(const string & str,const char & sep,vector<string> & splits)45 static void SplitStringByChar(const string &str, const char &sep, vector<string>& splits)
46 {
47 string newStr = str;
48 if (str.empty()) {
49 return;
50 }
51 if (str.rfind(sep) == str.size() - 1) {
52 newStr += sep;
53 }
54 stringstream ss(newStr);
55 string res;
56 while (getline(ss, res, sep)) {
57 splits.emplace_back(res);
58 }
59 }
60
ParseReportInfo(struct ReportFileInfo & fileStat,const vector<string> & splits,const size_t keyLen)61 static ErrCode ParseReportInfo(struct ReportFileInfo &fileStat,
62 const vector<string> &splits,
63 const size_t keyLen)
64 {
65 // 根据数据拼接结构体
66 // 处理path路径
67 try {
68 // 识别path字段与其他字段
69 size_t dataLen = splits.size();
70 if (dataLen != keyLen || dataLen < ENCODE_FLAG_VERSION) {
71 HILOGE("Error data size");
72 return EPERM;
73 }
74 string path = splits[static_cast<size_t>(KeyType::PATH)] + ATTR_SEP;
75 if (dataLen == ENCODE_FLAG_VERSION) {
76 fileStat.encodeFlag = false;
77 } else {
78 fileStat.encodeFlag = splits[static_cast<size_t>(KeyType::ENCODE_FLAG)] == DEFAULT_VALUE;
79 }
80 path = (path.length() > 0 && path[0] == '/') ? path.substr(1, path.length() - 1) : path;
81 auto fileRawPath = (path.length() > 0) ? path.substr(0, path.length() - 1) : path;
82 fileStat.filePath = BReportEntity::DecodeReportItem(fileRawPath, fileStat.encodeFlag);
83 HILOGD("Briefings file %{public}s", fileStat.filePath.c_str());
84 fileStat.mode = splits[static_cast<size_t>(KeyType::MODE)];
85 fileStat.isDir = splits[static_cast<size_t>(KeyType::DIR)] == DEFAULT_VALUE;
86
87 stringstream sizeStream(splits[static_cast<size_t>(KeyType::SIZE)]);
88 off_t size = 0;
89 if (!(sizeStream >> size)) {
90 HILOGE("Transfer size err");
91 }
92 fileStat.size = size;
93
94 stringstream mtimeStream(splits[static_cast<size_t>(KeyType::MTIME)]);
95 off_t mtime = 0;
96 if (!(mtimeStream >> mtime)) {
97 HILOGE("Transfer mtime err");
98 }
99 fileStat.mtime = mtime;
100 fileStat.hash = splits[static_cast<size_t>(KeyType::HASH)];
101 fileStat.isIncremental = splits[static_cast<size_t>(KeyType::IS_INCREMENTAL)] == DEFAULT_VALUE;
102 return ERR_OK;
103 } catch (...) {
104 HILOGE("Failed to ParseReportInfo");
105 return EPERM;
106 }
107 }
108
DealLine(vector<std::string> & keys,int & num,const string & line,unordered_map<string,struct ReportFileInfo> & infos)109 static void DealLine(vector<std::string> &keys,
110 int &num,
111 const string &line,
112 unordered_map<string, struct ReportFileInfo> &infos)
113 {
114 if (line.empty()) {
115 return;
116 }
117
118 string currentLine = line;
119 if (currentLine[currentLine.length() - 1] == LINE_WRAP) {
120 currentLine.pop_back();
121 }
122 vector<string> splits;
123 SplitStringByChar(currentLine, ATTR_SEP, splits);
124 if (num < INFO_ALIGN_NUM) {
125 if (num == 1) {
126 keys = splits;
127 if (keys != Data_Header) {
128 HILOGE("File halder check err");
129 }
130 }
131 num++;
132 } else {
133 struct ReportFileInfo fileState;
134 auto code = ParseReportInfo(fileState, splits, keys.size());
135 if (code != ERR_OK) {
136 HILOGE("ParseReportInfo err:%{public}d, %{public}s", code, currentLine.c_str());
137 } else {
138 infos.try_emplace(fileState.filePath, fileState);
139 }
140 }
141 }
142
GetReportInfos(unordered_map<string,struct ReportFileInfo> & infos) const143 void BReportEntity::GetReportInfos(unordered_map<string, struct ReportFileInfo> &infos) const
144 {
145 char buffer[HASH_BUFFER_SIZE];
146 ssize_t bytesRead;
147 string currentLine;
148 vector<std::string> keys;
149
150 int num = 0;
151 while ((bytesRead = read(srcFile_, buffer, sizeof(buffer))) > 0) {
152 for (ssize_t i = 0; i < bytesRead; i++) {
153 if (buffer[i] == LINE_SEP) {
154 DealLine(keys, num, currentLine, infos);
155 currentLine.clear();
156 } else {
157 currentLine += buffer[i];
158 }
159 }
160 }
161
162 // 处理文件中的最后一行
163 if (!currentLine.empty()) {
164 DealLine(keys, num, currentLine, infos);
165 }
166 }
167
GetStorageReportInfos(std::unordered_map<string,struct ReportFileInfo> & infos)168 bool BReportEntity::GetStorageReportInfos(std::unordered_map<string, struct ReportFileInfo> &infos)
169 {
170 char buffer[HASH_BUFFER_SIZE];
171 ssize_t bytesRead = 0;
172
173 if ((bytesRead = read(srcFile_, buffer, sizeof(buffer))) > 0) {
174 for (ssize_t i = 0; i < bytesRead; i++) {
175 if (buffer[i] == LINE_SEP) {
176 DealLine(keys_, currLineNum_, currLineInfo_, infos);
177 currLineInfo_.clear();
178 } else {
179 currLineInfo_ += buffer[i];
180 }
181 }
182 } else {
183 if (currLineInfo_.empty()) {
184 return false;
185 }
186 DealLine(keys_, currLineNum_, currLineInfo_, infos);
187 currLineInfo_.clear();
188 }
189 return true;
190 }
191
CheckAndUpdateIfReportLineEncoded(std::string & path)192 void BReportEntity::CheckAndUpdateIfReportLineEncoded(std::string &path)
193 {
194 if (path.empty()) {
195 return;
196 }
197
198 unordered_map<string, struct ReportFileInfo> infos;
199 GetReportInfos(infos);
200 constexpr int BIG_FILE_REPORT_INFO_NUM = 1;
201 if (infos.size() == BIG_FILE_REPORT_INFO_NUM) {
202 auto info = infos.begin();
203 path = info->first;
204 } else {
205 HILOGE("Invalid item sizes in report, current is %{public}zu", infos.size());
206 }
207 }
208
EncodeReportItem(const string & reportItem,bool enableEncode)209 string BReportEntity::EncodeReportItem(const string &reportItem, bool enableEncode)
210 {
211 string encodeItem;
212 if (enableEncode) {
213 encodeItem = AppFileService::SandboxHelper::Encode(reportItem);
214 } else {
215 encodeItem = reportItem;
216 }
217 return encodeItem;
218 }
219
DecodeReportItem(const string & reportItem,bool enableEncode)220 string BReportEntity::DecodeReportItem(const string &reportItem, bool enableEncode)
221 {
222 string decodeItem;
223 if (enableEncode) {
224 decodeItem = AppFileService::SandboxHelper::Decode(reportItem);
225 } else {
226 decodeItem = reportItem;
227 }
228 return decodeItem;
229 }
230 } // namespace OHOS::FileManagement::Backup