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 "utils.h"
17
18 #include <algorithm>
19 #include <cmath>
20 #include <cstdlib>
21 #include <cstring>
22 #include <dirent.h>
23 #include <fstream>
24 #include <iomanip>
25 #include <random>
26 #include <sstream>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <vector>
31
32 #include "log.h"
33
34 namespace OHOS {
35 namespace AppPackingTool {
36 namespace {
37 const int BUFFER_SIZE = 1024;
38 const int HEX_WIDTH = 2;
39 const char PATH_DELIMITER = '/';
40 const long FILE_LENGTH_1M = 1024 * 1024L;
41 const double FILE_SIZE_OFFSET_DOUBLE = 0.01;
42 const int FILE_SIZE_DECIMAL_PRECISION = 2;
43 const int MAX_UUID_LENGTH = 32;
44 const int RANGE_MIN = 0;
45 const int RANGE_MAX = 15;
46 const int TEN = 10;
47 }
48
GetFileContent(const std::string filePath)49 std::string Utils::GetFileContent(const std::string filePath)
50 {
51 std::string realFilePath;
52 if (!Utils::GetRealPath(filePath, realFilePath)) {
53 LOGE("get real file path failed! filePath=%s", filePath.c_str());
54 return nullptr;
55 }
56 std::ifstream inFile(realFilePath, std::ios::in);
57 if (!inFile.is_open()) {
58 LOGE("open file path failed![filePath=%s][realFilePath=%s]", filePath.c_str(), realFilePath.c_str());
59 return nullptr;
60 }
61 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
62 inFile.close();
63 return fileContent;
64 }
65
ListToString(const std::list<std::string> & lst)66 std::string Utils::ListToString(const std::list<std::string>& lst)
67 {
68 std::stringstream ss;
69 for (auto str : lst) {
70 ss << str;
71 }
72 return ss.str();
73 }
74
CopyListToSet(const std::list<std::string> & lst,std::set<std::string> & st)75 void Utils::CopyListToSet(const std::list<std::string>& lst, std::set<std::string>& st)
76 {
77 for (auto& em : lst) {
78 st.insert(em);
79 }
80 }
81
ReplaceAll(std::string str,const std::string & from,const std::string & to)82 std::string Utils::ReplaceAll(std::string str, const std::string& from, const std::string& to)
83 {
84 size_t startPos = 0;
85 while ((startPos = str.find(from, startPos)) != std::string::npos) {
86 str.replace(startPos, from.length(), to);
87 startPos += to.length();
88 }
89 return str;
90 }
91
GetFileLength(const std::string filePath)92 int64_t Utils::GetFileLength(const std::string filePath)
93 {
94 struct stat statbuf = { 0 };
95 if (stat(filePath.c_str(), &statbuf) != 0) {
96 LOGE("file stat failed! filePath=%s", filePath.c_str());
97 return -1;
98 }
99 return statbuf.st_size;
100 }
101
EndsWith(const std::string & str,const std::string & suffix)102 bool Utils::EndsWith(const std::string& str, const std::string& suffix)
103 {
104 if (str.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), str.rbegin())) {
105 return true;
106 }
107 return false;
108 }
109
110 // If there is no same element then returns true, else then returns false
CheckDisjoint(const std::list<std::string> & list1,const std::list<std::string> & list2)111 bool Utils::CheckDisjoint(const std::list<std::string>& list1, const std::list<std::string>& list2)
112 {
113 for (const std::string& str1 : list1) {
114 for (const std::string& str2 : list2) {
115 if (str1.compare(str2) == 0) {
116 return false;
117 }
118 }
119 }
120 return true;
121 }
122
123 // If list1 contains all elements in list2, returns true, else returns false
CheckContainsAll(const std::list<std::string> & list1,const std::list<std::string> & list2)124 bool Utils::CheckContainsAll(const std::list<std::string>& list1, const std::list<std::string>& list2)
125 {
126 bool isFind = false;
127 for (const std::string& str2 : list2) {
128 isFind = false;
129 for (const std::string& str1 : list1) {
130 if (str2.compare(str1) == 0) {
131 isFind = true;
132 break;
133 }
134 }
135 if (!isFind) {
136 return false;
137 }
138 }
139 return true;
140 }
141
CheckListContain(const std::list<std::string> & lst,const std::string & value)142 bool Utils::CheckListContain(const std::list<std::string>& lst, const std::string& value)
143 {
144 return std::find(lst.begin(), lst.end(), value) != lst.end();
145 }
146
GetListDistinctCount(const std::list<std::string> & lst)147 long Utils::GetListDistinctCount(const std::list<std::string>& lst)
148 {
149 std::set<std::string> st;
150 std::copy(lst.begin(), lst.end(), std::inserter(st, st.end()));
151 return st.size();
152 }
153
GetSha256Str(const std::string & str)154 std::string Utils::GetSha256Str(const std::string &str)
155 {
156 unsigned char hash[SHA256_DIGEST_LENGTH];
157 SHA256_CTX ctx;
158 SHA256_Init(&ctx);
159 SHA256_Update(&ctx, str.c_str(), str.length());
160 SHA256_Final(hash, &ctx);
161
162 // Convert hash to hex string
163 std::stringstream ss;
164 for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
165 ss << std::hex << std::setw(HEX_WIDTH) << std::setfill('0') << static_cast<uint32_t>(hash[i]);
166 }
167 return ss.str();
168 }
169
GetSha256File(const std::string & filePath)170 std::string Utils::GetSha256File(const std::string &filePath)
171 {
172 std::string realFilePath;
173 if (!GetRealPath(filePath, realFilePath)) {
174 LOGE("get real file path failed! jsonFile=%s", filePath.c_str());
175 return "";
176 }
177 std::ifstream file(realFilePath, std::ios::binary);
178 if (!file) {
179 return "";
180 }
181 SHA256_CTX ctx;
182 SHA256_Init(&ctx);
183 std::vector<char> buffer(BUFFER_SIZE);
184 while (!file.eof()) {
185 file.read(buffer.data(), BUFFER_SIZE);
186 SHA256_Update(&ctx, buffer.data(), file.gcount());
187 }
188 unsigned char hash[SHA256_DIGEST_LENGTH];
189 SHA256_Final(hash, &ctx);
190
191 // Convert hash to hex string
192 std::stringstream ss;
193 for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
194 ss << std::hex << std::setw(HEX_WIDTH) << std::setfill('0') << static_cast<uint32_t>(hash[i]);
195 }
196 return ss.str();
197 }
198
GetSha256Folder(const std::string & filePath)199 std::string Utils::GetSha256Folder(const std::string &filePath)
200 {
201 SHA256_CTX ctx;
202 SHA256_Init(&ctx);
203 for (const auto& entry : fs::recursive_directory_iterator(filePath)) {
204 if (fs::is_regular_file(entry)) {
205 std::ifstream file(entry, std::ios::binary);
206 if (!file.is_open()) {
207 LOGE("file open failed! filePath=%s", entry.path().string().c_str());
208 return "";
209 }
210 std::vector<char> buffer((std::istreambuf_iterator<char>(file)),
211 std::istreambuf_iterator<char>());
212 SHA256_Update(&ctx, buffer.data(), buffer.size());
213 }
214 }
215 unsigned char hash[SHA256_DIGEST_LENGTH];
216 SHA256_Final(hash, &ctx);
217
218 // Convert hash to hex string
219 std::stringstream ss;
220 for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
221 ss << std::hex << std::setw(HEX_WIDTH) << std::setfill('0') << static_cast<uint32_t>(hash[i]);
222 }
223 return ss.str();
224 }
225
IsFileExists(const std::string & file)226 bool Utils::IsFileExists(const std::string& file)
227 {
228 return access(file.c_str(), F_OK) == 0;
229 }
230
IsFile(const std::string & file)231 bool Utils::IsFile(const std::string& file)
232 {
233 struct stat statBuf {};
234 return lstat(file.c_str(), &statBuf) == 0 ? S_ISREG(statBuf.st_mode) : false;
235 }
236
IsDirectory(const std::string & dir)237 bool Utils::IsDirectory(const std::string& dir)
238 {
239 struct stat statBuf {};
240 return lstat(dir.c_str(), &statBuf) == 0 ? S_ISDIR(statBuf.st_mode) : false;
241 }
242
RemoveFile(const std::string & file)243 bool Utils::RemoveFile(const std::string& file)
244 {
245 return !IsFileExists(file) || (remove(file.c_str()) == 0);
246 }
247
RemoveDirectory(const std::string & dir)248 bool Utils::RemoveDirectory(const std::string& dir)
249 {
250 return !IsFileExists(dir) || (rmdir(dir.c_str()) == 0);
251 }
252
GetFilePathByDir(const std::string & dir,const std::string & fileName)253 std::string Utils::GetFilePathByDir(const std::string& dir, const std::string& fileName)
254 {
255 if (dir.empty()) {
256 return fileName;
257 }
258 std::string filePath = dir;
259 if (filePath.back() != '/') {
260 filePath.push_back(PATH_DELIMITER);
261 }
262 filePath.append(fileName);
263 return filePath;
264 }
265
ForceCreateDirectory(const std::string & dir)266 bool Utils::ForceCreateDirectory(const std::string& dir)
267 {
268 std::string::size_type index = 0;
269 do {
270 std::string subPath;
271 index = dir.find('/', index + 1); // (index + 1) means the next char traversed
272 if (index == std::string::npos) {
273 subPath = dir;
274 } else {
275 subPath = dir.substr(0, index);
276 }
277
278 if (!IsFileExists(subPath) && mkdir(subPath.c_str(), S_IRWXU) != 0) {
279 return false;
280 }
281 } while (index != std::string::npos);
282 return IsFileExists(dir);
283 }
284
ForceRemoveDirectory(const std::string & dir,bool isDeleteSelf)285 bool Utils::ForceRemoveDirectory(const std::string& dir, bool isDeleteSelf)
286 {
287 if (IsFile(dir)) {
288 return RemoveFile(dir);
289 } else if (IsDirectory(dir)) {
290 DIR* dirPtr = opendir(dir.c_str());
291 if (dirPtr == nullptr) {
292 return false;
293 }
294 struct dirent* dirInfo = nullptr;
295 while ((dirInfo = readdir(dirPtr)) != nullptr) {
296 // do not process the special dir
297 if (strcmp(dirInfo->d_name, ".") == 0 || strcmp(dirInfo->d_name, "..") == 0) {
298 continue;
299 }
300 std::string filePath = GetFilePathByDir(dir, dirInfo->d_name);
301 if (!ForceRemoveDirectory(filePath)) {
302 closedir(dirPtr);
303 return false;
304 }
305 }
306 closedir(dirPtr);
307 if (isDeleteSelf && !RemoveDirectory(dir)) {
308 return false;
309 }
310 } else {
311 return false;
312 }
313 return true;
314 }
315
GetCeilFileSize(long fileSize,int sizeLimit)316 double Utils::GetCeilFileSize(long fileSize, int sizeLimit)
317 {
318 double threshold = static_cast<double>(sizeLimit) + FILE_SIZE_OFFSET_DOUBLE;
319 double size = static_cast<double>(fileSize) / FILE_LENGTH_1M;
320 size = std::round(size * std::pow(TEN, FILE_SIZE_DECIMAL_PRECISION)) / std::pow(TEN, FILE_SIZE_DECIMAL_PRECISION);
321 if (size < threshold && size >= sizeLimit) {
322 size = threshold;
323 }
324 return size;
325 }
326
IsPositiveInteger(const std::string & str,int min,int max)327 bool Utils::IsPositiveInteger(const std::string& str, int min, int max)
328 {
329 if (str.empty()) {
330 return false;
331 }
332 for (char c : str) {
333 if (!std::isdigit(c)) {
334 return false;
335 }
336 }
337 try {
338 int number = std::stoi(str);
339 return number > 0 && number >= min && number <= max;
340 } catch (const std::out_of_range& e) {
341 LOGE("Number %s is Out of Range!", str.c_str());
342 return false;
343 }
344 return true;
345 }
346
CheckFileName(const std::string & filePath,const std::string & fileName)347 bool Utils::CheckFileName(const std::string& filePath, const std::string& fileName)
348 {
349 fs::path fsFilePath(filePath);
350 if (fs::is_regular_file(fsFilePath) && fsFilePath.filename().compare(fileName) == 0) {
351 return true;
352 }
353 return false;
354 }
355
CheckFileSuffix(const std::string & filePath,const std::string & suffix)356 bool Utils::CheckFileSuffix(const std::string& filePath, const std::string& suffix)
357 {
358 fs::path fsFilePath(filePath);
359 if (fs::is_regular_file(fsFilePath) && EndsWith(fsFilePath.filename(), suffix)) {
360 return true;
361 }
362 return false;
363 }
364
GenerateUUID()365 std::string Utils::GenerateUUID()
366 {
367 static const char* hexDigits = "0123456789abcdef";
368 std::random_device rd;
369 std::mt19937 gen(rd());
370 std::uniform_int_distribution<> dis(RANGE_MIN, RANGE_MAX);
371
372 std::stringstream ss;
373 std::vector<int> format = {8, 4, 4, 4, 12};
374 int flag = 1;
375 for (int i = 0; i < MAX_UUID_LENGTH; ++i) {
376 ss << hexDigits[dis(gen)];
377 if ((i + 1) == format[0] && i != MAX_UUID_LENGTH - 1) {
378 ss << "-";
379 format[0] += format[flag];
380 flag++;
381 }
382 }
383 return ss.str();
384 }
385
CopyFile(const std::string & srcPath,const std::string & dstPath)386 bool Utils::CopyFile(const std::string& srcPath, const std::string& dstPath)
387 {
388 std::string realSrcPath;
389 std::string realDstPath;
390 if (!GetRealPath(srcPath, realSrcPath)) {
391 LOGE("get real src path failed! srcPath=%s", srcPath.c_str());
392 return false;
393 }
394 fs::path fsDstPath(dstPath);
395 std::string parentOfDstPath = fsDstPath.parent_path().string();
396 std::string dstFileName = fsDstPath.filename();
397 if (!GetRealPathOfNoneExistFile(parentOfDstPath, realDstPath)) {
398 LOGE("get real dst path failed! dstPath=%s", dstPath.c_str());
399 return false;
400 }
401 realDstPath += fs::path::preferred_separator + dstFileName;
402 std::ifstream srcFile(realSrcPath, std::ios::binary);
403 std::ofstream dstFile(realDstPath, std::ios::binary);
404 if (!srcFile.is_open()) {
405 LOGE("Open srcPath failed![srcPath=%s][realSrcPath=%s]", srcPath.c_str(), realSrcPath.c_str());
406 return false;
407 }
408 if (!dstFile.is_open()) {
409 LOGE("Open dstPath failed![dstPath=%s][realDstPath=%s]", dstPath.c_str(), realDstPath.c_str());
410 return false;
411 }
412 dstFile << srcFile.rdbuf();
413 srcFile.close();
414 dstFile.close();
415 return true;
416 }
417
GetFormattedPath(const std::string & path,std::string & formattedPath)418 bool Utils::GetFormattedPath(const std::string& path, std::string& formattedPath)
419 {
420 if (path.empty()) {
421 formattedPath = "";
422 return true;
423 }
424 try {
425 formattedPath = fs::canonical(path).string();
426 } catch (const fs::filesystem_error& err) {
427 LOGE("GetFormattedPath exception: ", err.what());
428 return false;
429 }
430 return true;
431 }
432
GetRealPath(const std::string & path,std::string & realPath)433 bool Utils::GetRealPath(const std::string& path, std::string& realPath)
434 {
435 if (path.length() >= PATH_MAX) {
436 return false;
437 }
438 char buffer[PATH_MAX] = {0};
439 if (realpath(path.c_str(), buffer) == nullptr) {
440 return false;
441 }
442 realPath = std::string(buffer);
443 return true;
444 }
445
GetRealPathOfNoneExistFile(const std::string & path,std::string & realPath)446 bool Utils::GetRealPathOfNoneExistFile(const std::string& path, std::string& realPath)
447 {
448 fs::path fsPath = fs::path(path);
449 std::string filePath = fsPath.parent_path().string();
450 std::string fileName = fsPath.filename().string();
451 if (path.length() >= PATH_MAX) {
452 return false;
453 }
454 char buffer[PATH_MAX] = {0};
455 if (realpath(filePath.c_str(), buffer) == nullptr) {
456 return false;
457 }
458 realPath = std::string(buffer) + fs::path::preferred_separator + fileName;
459 return true;
460 }
461 } // namespace AppPackingTool
462 } // namespace OHOS
463