• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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