1 /*
2 * Copyright (c) 2022-2023 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 <directory_ex.h>
17 #include <map>
18 #include <string>
19 #include <tuple>
20 #include <vector>
21
22 #include "b_error/b_error.h"
23 #include "b_error/b_excep_utils.h"
24 #include "b_json/b_json_entity_ext_manage.h"
25 #include "b_resources/b_constants.h"
26 #include "filemgmt_libhilog.h"
27 #include "json/value.h"
28
29 namespace OHOS::FileManagement::Backup {
30 using namespace std;
31 namespace {
32 const int32_t DEFAULT_MODE = 0100660; // 0660
33 }
34
CheckBigFile(struct stat sta)35 static bool CheckBigFile(struct stat sta)
36 {
37 if (sta.st_size > BConstants::BIG_FILE_BOUNDARY) {
38 return true;
39 }
40 return false;
41 }
42
43 /**
44 * @brief 判断是否属于自身打包的文件
45 *
46 * @param fileName
47 */
CheckOwnPackTar(const string & fileName)48 static bool CheckOwnPackTar(const string &fileName)
49 {
50 if (ExtractFileExt(fileName) != "tar") {
51 return false;
52 }
53 // 如果不是在默认路径下的文件包,不属于自身打包的tar文件
54 string defaultBackupPath = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_BACKUP);
55 string absPath;
56 try {
57 absPath = IncludeTrailingPathDelimiter(BExcepUltils::Canonicalize(ExtractFilePath(fileName)));
58 } catch (const BError &e) {
59 HILOGE("file is not backup path");
60 return false;
61 } catch (...) {
62 return false;
63 }
64
65 string::size_type pathPos = absPath.find(defaultBackupPath);
66 if (pathPos == string::npos || pathPos != 0) {
67 return false;
68 }
69 // 获取tar包名称
70 string tarFile = ExtractFileName(fileName);
71 string::size_type pos = tarFile.find(".");
72 if (pos == string::npos) {
73 return false;
74 }
75
76 string firstName = string(tarFile).substr(0, pos);
77 // 判断文件名是否包含part (兼容增量)
78 string::size_type partPos = firstName.find("part");
79 if (partPos == string::npos) {
80 return false;
81 }
82
83 return true;
84 }
85
CheckUserTar(const string & fileName,struct stat sta)86 static bool CheckUserTar(const string &fileName, struct stat sta)
87 {
88 if (access(fileName.c_str(), F_OK) != 0) {
89 HILOGI("file does not exists");
90 return false;
91 }
92 return (ExtractFileExt(fileName) == "tar") && CheckBigFile(sta);
93 }
94
Stat2JsonValue(struct stat sta)95 Json::Value Stat2JsonValue(struct stat sta)
96 {
97 Json::Value value;
98 value["st_size"] = static_cast<int64_t>(sta.st_size);
99 value["st_mode"] = static_cast<int32_t>(sta.st_mode);
100 value["st_atim"]["tv_sec"] = static_cast<int64_t>(sta.st_atim.tv_sec);
101 value["st_atim"]["tv_nsec"] = static_cast<int64_t>(sta.st_atim.tv_nsec);
102 value["st_mtim"]["tv_sec"] = static_cast<int64_t>(sta.st_mtim.tv_sec);
103 value["st_mtim"]["tv_nsec"] = static_cast<int64_t>(sta.st_mtim.tv_nsec);
104 return value;
105 }
106
JsonValue2Stat(const Json::Value & value)107 struct stat JsonValue2Stat(const Json::Value &value)
108 {
109 struct stat sta = {};
110
111 if (!value.isObject()) {
112 return sta;
113 }
114
115 sta.st_size = value.isMember("st_size") && value["st_size"].isInt64() ? value["st_size"].asInt64() : 0;
116 auto mode = value.isMember("st_mode") && value["st_mode"].isInt() ? value["st_mode"].asInt() : DEFAULT_MODE;
117 sta.st_mode = static_cast<mode_t>(mode);
118 if (value.isMember("st_atim")) {
119 sta.st_atim.tv_sec = value["st_atim"].isMember("tv_sec") && value["st_atim"]["tv_sec"].isInt64()
120 ? value["st_atim"]["tv_sec"].asInt64()
121 : 0;
122 sta.st_atim.tv_nsec = value["st_atim"].isMember("tv_nsec") && value["st_atim"]["tv_nsec"].isInt64()
123 ? value["st_atim"]["tv_nsec"].asInt64()
124 : 0;
125 }
126 if (value.isMember("st_mtim")) {
127 sta.st_mtim.tv_sec = value["st_mtim"].isMember("tv_sec") && value["st_mtim"]["tv_sec"].isInt64()
128 ? value["st_mtim"]["tv_sec"].asInt64()
129 : 0;
130 sta.st_mtim.tv_nsec = value["st_mtim"].isMember("tv_nsec") && value["st_mtim"]["tv_nsec"].isInt64()
131 ? value["st_mtim"]["tv_nsec"].asInt64()
132 : 0;
133 }
134
135 return sta;
136 }
137
SetExtManageForClone(const map<string,tuple<string,struct stat,bool,bool>> & info) const138 void BJsonEntityExtManage::SetExtManageForClone(const map<string, tuple<string, struct stat, bool, bool>> &info) const
139 {
140 obj_.clear();
141
142 unsigned long index = 0;
143 for (auto item = info.begin(); item != info.end(); ++item, ++index) {
144 Json::Value value;
145 value["fileName"] = item->first;
146 auto [path, sta, isBigFile, isUserTar] = item->second;
147 value["information"]["path"] = path;
148 value["information"]["stat"] = Stat2JsonValue(sta);
149 value["isUserTar"] = isUserTar;
150 value["isBigFile"] = isBigFile;
151
152 obj_.append(value);
153 }
154 }
155
SetExtManage(const map<string,tuple<string,struct stat,bool>> & info) const156 void BJsonEntityExtManage::SetExtManage(const map<string, tuple<string, struct stat, bool>> &info) const
157 {
158 obj_.clear();
159
160 for (auto item = info.begin(); item != info.end(); ++item) {
161 Json::Value value;
162 value["fileName"] = item->first;
163 auto [path, sta, isBeforeTar] = item->second;
164 value["information"]["path"] = path;
165 value["information"]["stat"] = Stat2JsonValue(sta);
166 value["isUserTar"] = isBeforeTar && CheckUserTar(path, sta);
167 value["isBigFile"] = !CheckOwnPackTar(path) && CheckBigFile(sta);
168
169 obj_.append(value);
170 }
171 }
172
GetExtManage() const173 set<string> BJsonEntityExtManage::GetExtManage() const
174 {
175 if (!obj_) {
176 HILOGE("Uninitialized JSon Object reference");
177 return {};
178 }
179 if (!obj_.isArray()) {
180 HILOGE("json object isn't an array");
181 return {};
182 }
183
184 set<string> info;
185 for (Json::Value &item : obj_) {
186 string fileName = item.isObject() && item.isMember("fileName") && item["fileName"].isString()
187 ? item["fileName"].asString()
188 : "";
189 info.emplace(fileName);
190 }
191 return info;
192 }
193
GetExtManageInfo() const194 std::vector<ExtManageInfo> BJsonEntityExtManage::GetExtManageInfo() const
195 {
196 if (!obj_) {
197 HILOGE("Uninitialized JSon Object reference");
198 return {};
199 }
200 if (!obj_.isArray()) {
201 HILOGE("json object isn't an array");
202 return {};
203 }
204
205 std::vector<ExtManageInfo> infos {};
206 for (const Json::Value &item : obj_) {
207 if (!(item.isObject() && item.isMember("information"))) {
208 continue;
209 }
210
211 struct stat sta = {};
212 string path = item["information"].isMember("path") && item["information"]["path"].isString()
213 ? item["information"]["path"].asString()
214 : "";
215 if (item["information"].isMember("stat")) {
216 sta = JsonValue2Stat(item["information"]["stat"]);
217 }
218 string fileName = item.isMember("fileName") && item["fileName"].isString() ? item["fileName"].asString() : "";
219 bool isUserTar = item.isMember("isUserTar") && item["isUserTar"].isBool() ? item["isUserTar"].asBool() : false;
220 bool isBigFile = item.isMember("isBigFile") && item["isBigFile"].isBool() ? item["isBigFile"].asBool() : false;
221 // 兼容旧版本没有isBigFile属性时,增加判断是否为bigFile
222 if (!item.isMember("isBigFile") && fileName != "" && ExtractFileExt(fileName) != "tar") {
223 isBigFile = true;
224 }
225 HILOGD("GetExtManageInfo, fileName:%{public}s, isUserTar:%{public}d, isBigFile:%{public}d", fileName.data(),
226 isUserTar, isBigFile);
227 if (!fileName.empty()) {
228 ExtManageInfo info = {
229 .hashName = fileName, .fileName = path, .sta = sta, .isUserTar = isUserTar, .isBigFile = isBigFile};
230 infos.emplace_back(info);
231 }
232 }
233
234 return infos;
235 }
236 } // namespace OHOS::FileManagement::Backup