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