1 /*
2 * Copyright (c) 2021-2025 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 "file_util.h"
17
18 #include <cstdint>
19 #include <cstdio>
20 #include <cstring>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <fstream>
24 #include <istream>
25 #include <sys/sendfile.h>
26 #include <sys/stat.h>
27 #include <sys/statfs.h>
28 #include <sys/xattr.h>
29 #include <unistd.h>
30 #include <vector>
31
32 #include "common_utils.h"
33 #include "directory_ex.h"
34 #include "file_ex.h"
35
36 #define FDSAN_FILEUTIL_TAG 0xD002D10 // hiview domainid
37
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace FileUtil {
41 using namespace std;
42 namespace {
43 constexpr int VALUE_MOD = 200000;
44
CheckAndCreateDirectory(const std::string & tmpDirPath)45 bool CheckAndCreateDirectory(const std::string &tmpDirPath)
46 {
47 if (!FileExists(tmpDirPath)) {
48 return ForceCreateDirectory(tmpDirPath, FILE_PERM_775);
49 }
50 return true;
51 }
52 }
53
LoadStringFromFile(const std::string & filePath,std::string & content)54 bool LoadStringFromFile(const std::string& filePath, std::string& content)
55 {
56 return OHOS::LoadStringFromFile(filePath, content);
57 }
58
LoadLinesFromFile(const std::string & filePath,std::vector<std::string> & lines)59 bool LoadLinesFromFile(const std::string& filePath, std::vector<std::string>& lines)
60 {
61 std::ifstream file(filePath);
62 if (file.is_open()) {
63 std::string line;
64 while (std::getline(file, line)) {
65 lines.emplace_back(line);
66 }
67 file.close();
68 return true;
69 }
70 return false;
71 }
72
LoadStringFromFd(int fd,std::string & content)73 bool LoadStringFromFd(int fd, std::string& content)
74 {
75 return OHOS::LoadStringFromFd(fd, content);
76 }
77
SaveStringToFile(const std::string & filePath,const std::string & content,bool truncated)78 bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated)
79 {
80 return OHOS::SaveStringToFile(filePath, content, truncated);
81 }
82
SaveStringToFd(int fd,const std::string & content)83 bool SaveStringToFd(int fd, const std::string& content)
84 {
85 return OHOS::SaveStringToFd(fd, content);
86 }
87
LoadBufferFromFile(const std::string & filePath,std::vector<char> & content)88 bool LoadBufferFromFile(const std::string& filePath, std::vector<char>& content)
89 {
90 return OHOS::LoadBufferFromFile(filePath, content);
91 }
92
SaveBufferToFile(const std::string & filePath,const std::vector<char> & content,bool truncated)93 bool SaveBufferToFile(const std::string& filePath, const std::vector<char>& content, bool truncated)
94 {
95 return OHOS::SaveBufferToFile(filePath, content, truncated);
96 }
97
FileExists(const std::string & fileName)98 bool FileExists(const std::string& fileName)
99 {
100 return OHOS::FileExists(fileName);
101 }
102
ExtractFilePath(const std::string & fileFullName)103 std::string ExtractFilePath(const std::string& fileFullName)
104 {
105 return OHOS::ExtractFilePath(fileFullName);
106 }
107
ExtractFileName(const std::string & fileFullName)108 std::string ExtractFileName(const std::string& fileFullName)
109 {
110 return OHOS::ExtractFileName(fileFullName);
111 }
112
ExtractFileExt(const std::string & fileName)113 std::string ExtractFileExt(const std::string& fileName)
114 {
115 return OHOS::ExtractFileExt(fileName);
116 }
117
IncludeTrailingPathDelimiter(const std::string & path)118 std::string IncludeTrailingPathDelimiter(const std::string& path)
119 {
120 return OHOS::IncludeTrailingPathDelimiter(path);
121 }
122
ExcludeTrailingPathDelimiter(const std::string & path)123 std::string ExcludeTrailingPathDelimiter(const std::string& path)
124 {
125 return OHOS::ExcludeTrailingPathDelimiter(path);
126 }
127
GetDirFiles(const std::string & path,std::vector<std::string> & files,bool isRecursive)128 void GetDirFiles(const std::string& path, std::vector<std::string>& files, bool isRecursive)
129 {
130 DIR* dir = opendir(path.c_str());
131 if (dir == nullptr) {
132 return;
133 }
134
135 while (true) {
136 struct dirent* ptr = readdir(dir);
137 if (ptr == nullptr) {
138 break;
139 }
140
141 // current dir or parent dir
142 if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
143 continue;
144 } else if (ptr->d_type == DT_DIR && isRecursive) {
145 std::string pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
146 GetDirFiles(pathStringWithDelimiter, files);
147 } else {
148 files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
149 }
150 }
151 closedir(dir);
152 }
153
GetDirDirs(const std::string & path,std::vector<std::string> & dirs)154 void GetDirDirs(const std::string& path, std::vector<std::string>& dirs)
155 {
156 DIR* dir = opendir(path.c_str());
157 if (dir == nullptr) {
158 return;
159 }
160
161 while (true) {
162 struct dirent *ptr = readdir(dir);
163 if (ptr == nullptr) {
164 break;
165 }
166 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
167 continue;
168 } else if (ptr->d_type == DT_DIR) {
169 dirs.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
170 }
171 }
172 closedir(dir);
173 }
174
ForceCreateDirectory(const std::string & path)175 bool ForceCreateDirectory(const std::string& path)
176 {
177 return OHOS::ForceCreateDirectory(path);
178 }
179
ForceCreateDirectory(const string & path,mode_t mode)180 bool ForceCreateDirectory(const string& path, mode_t mode)
181 {
182 string::size_type index = 0;
183 do {
184 index = path.find('/', index + 1);
185 string subPath = (index == string::npos) ? path : path.substr(0, index);
186 if (access(subPath.c_str(), F_OK) != 0) {
187 if (mkdir(subPath.c_str(), mode) != 0) {
188 return false;
189 }
190 }
191 } while (index != string::npos);
192 return access(path.c_str(), F_OK) == 0;
193 }
194
ForceRemoveDirectory(const std::string & path,bool isNeedDeleteGivenDirSelf)195 bool ForceRemoveDirectory(const std::string& path, bool isNeedDeleteGivenDirSelf)
196 {
197 return OHOS::ForceRemoveDirectory(path);
198 }
199
GetFileSize(const std::string & path)200 uint64_t GetFileSize(const std::string& path)
201 {
202 struct stat st;
203 return stat(path.c_str(), &st) ? 0 : static_cast<uint64_t>(st.st_size);
204 }
205
RemoveFile(const std::string & fileName)206 bool RemoveFile(const std::string& fileName)
207 {
208 return OHOS::RemoveFile(fileName);
209 }
210
GetFolderSize(const std::string & path)211 uint64_t GetFolderSize(const std::string& path)
212 {
213 return OHOS::GetFolderSize(path);
214 }
215
GetDeviceValidSize(const std::string & partitionName)216 double GetDeviceValidSize(const std::string& partitionName)
217 {
218 struct statfs stat;
219 int err = statfs(partitionName.c_str(), &stat);
220 if (err != 0) {
221 return 0;
222 }
223 return static_cast<double>(stat.f_bfree) * static_cast<double>(stat.f_bsize);
224 }
225
226 // inner function, and param is legitimate
ChangeMode(const string & fileName,const mode_t & mode)227 bool ChangeMode(const string& fileName, const mode_t& mode)
228 {
229 return (chmod(fileName.c_str(), mode) == 0);
230 }
231
ChangeModeFile(const string & fileName,const mode_t & mode)232 bool ChangeModeFile(const string& fileName, const mode_t& mode)
233 {
234 if (access(fileName.c_str(), F_OK) != 0) {
235 return false;
236 }
237
238 return ChangeMode(fileName, mode);
239 }
240
ChangeModeDirectory(const std::string & path,const mode_t & mode)241 bool ChangeModeDirectory(const std::string& path, const mode_t& mode)
242 {
243 return OHOS::ChangeModeDirectory(path, mode);
244 }
245
PathToRealPath(const std::string & path,std::string & realPath)246 bool PathToRealPath(const std::string& path, std::string& realPath)
247 {
248 return OHOS::PathToRealPath(path, realPath);
249 }
250
Umask(const mode_t & mode)251 mode_t Umask(const mode_t& mode)
252 {
253 return umask(mode);
254 }
255
Open(const std::string & path,const int flags,const mode_t mode)256 int Open(const std::string& path, const int flags, const mode_t mode)
257 {
258 return open(path.c_str(), flags, mode);
259 }
260
CreateDirWithDefaultPerm(const std::string & path,uid_t aidRoot,uid_t aidSystem)261 void CreateDirWithDefaultPerm(const std::string& path, uid_t aidRoot, uid_t aidSystem)
262 {
263 FileUtil::ForceCreateDirectory(path);
264 chown(path.c_str(), aidRoot, aidSystem);
265 }
266
FormatPath2UnixStyle(std::string & path)267 void FormatPath2UnixStyle(std::string &path)
268 {
269 // unimplemented
270 }
271
RemoveFolderBeginWith(const std::string & path,const std::string & folderName)272 void RemoveFolderBeginWith(const std::string &path, const std::string &folderName)
273 {
274 // unimplemented
275 }
276
WriteBufferToFd(int fd,const char * buffer,size_t size)277 bool WriteBufferToFd(int fd, const char* buffer, size_t size)
278 {
279 if (fd < 0) {
280 return false;
281 }
282
283 if (buffer == nullptr) {
284 return false;
285 }
286
287 ssize_t writeSize = size;
288 if (writeSize != TEMP_FAILURE_RETRY(write(fd, buffer, size))) {
289 return false;
290 }
291
292 return true;
293 }
294
CreateFile(const std::string & path,mode_t mode)295 int CreateFile(const std::string &path, mode_t mode)
296 {
297 if (FileExists(path)) {
298 return 0;
299 } else {
300 std::ofstream fout(path);
301 if (!fout.is_open()) {
302 return -1;
303 }
304 fout.flush();
305 fout.close();
306 if (!ChangeMode(path, mode)) {
307 return -1;
308 }
309 }
310 return 0;
311 }
312
CopyFile(const std::string & src,const std::string & des)313 int CopyFile(const std::string &src, const std::string &des)
314 {
315 std::ifstream fin(src, ios::binary);
316 std::ofstream fout(des, ios::binary);
317 if (!fin.is_open()) {
318 return -1;
319 }
320 if (!fout.is_open()) {
321 return -1;
322 }
323 fout << fin.rdbuf();
324 if (fout.fail()) {
325 fout.clear();
326 }
327 fout.flush();
328 return 0;
329 }
330
CopyFileFast(const std::string & src,const std::string & des,uint32_t truncatedFileSize)331 int CopyFileFast(const std::string &src, const std::string &des, uint32_t truncatedFileSize)
332 {
333 int fdIn = open(src.c_str(), O_RDONLY);
334 if (fdIn < 0) {
335 return -1;
336 }
337 fdsan_exchange_owner_tag(fdIn, 0, FDSAN_FILEUTIL_TAG);
338 int fdOut = open(des.c_str(), O_CREAT | O_RDWR, 0664);
339 if (fdOut < 0) {
340 fdsan_close_with_tag(fdIn, FDSAN_FILEUTIL_TAG);
341 return -1;
342 }
343 fdsan_exchange_owner_tag(fdOut, 0, FDSAN_FILEUTIL_TAG);
344 struct stat st;
345 uint64_t totalLen = stat(src.c_str(), &st) ? 0 : static_cast<uint64_t>(st.st_size);
346 std::string truncateMsg = "";
347 if (truncatedFileSize != 0 && totalLen > truncatedFileSize) {
348 totalLen = truncatedFileSize;
349 truncateMsg = "\n[truncated]";
350 }
351 uint64_t copyTotalLen = 0;
352 while (copyTotalLen < totalLen) {
353 ssize_t copyLen = sendfile(fdOut, fdIn, nullptr, totalLen - copyTotalLen);
354 if (copyLen <= 0) {
355 break;
356 }
357 copyTotalLen += static_cast<uint64_t>(copyLen);
358 }
359 if (!truncateMsg.empty()) {
360 SaveStringToFd(fdOut, truncateMsg);
361 }
362 fdsan_close_with_tag(fdIn, FDSAN_FILEUTIL_TAG);
363 fdsan_close_with_tag(fdOut, FDSAN_FILEUTIL_TAG);
364 return copyTotalLen == totalLen ? 0 : -1;
365 }
366
IsDirectory(const std::string & path)367 bool IsDirectory(const std::string &path)
368 {
369 struct stat statBuffer;
370 if (stat(path.c_str(), &statBuffer) == 0 && S_ISDIR(statBuffer.st_mode)) {
371 return true;
372 }
373 return false;
374 }
375
GetLastLine(std::istream & fin,std::string & line,uint32_t maxLen)376 bool GetLastLine(std::istream &fin, std::string &line, uint32_t maxLen)
377 {
378 if (fin.tellg() <= 0) {
379 return false;
380 } else {
381 fin.seekg(-1, fin.cur);
382 }
383 uint32_t count = 0;
384 while (fin.good() && fin.peek() == fin.widen('\n') && fin.tellg() > 0 && count < maxLen) {
385 fin.seekg(-1, fin.cur);
386 count++;
387 }
388 if (!fin.good() || count >= maxLen) {
389 return false;
390 }
391 if (fin.tellg() == 0) {
392 return true;
393 }
394 count = 0;
395 while (fin.good() && fin.peek() != fin.widen('\n') && fin.tellg() > 0 && count < maxLen) {
396 fin.seekg(-1, fin.cur);
397 count++;
398 }
399 if (!fin.good() || count >= maxLen) {
400 return false;
401 }
402 if (fin.tellg() != 0) {
403 fin.seekg(1, fin.cur);
404 }
405 auto oldPos = fin.tellg();
406 getline(fin, line);
407 fin.seekg(oldPos);
408 return true;
409 }
410
GetFirstLine(const std::string & path)411 std::string GetFirstLine(const std::string& path)
412 {
413 std::ifstream inFile(path.c_str());
414 if (!inFile) {
415 return "";
416 }
417 std::string firstLine;
418 getline(inFile, firstLine);
419 inFile.close();
420 return firstLine;
421 }
422
GetParentDir(const std::string & path)423 std::string GetParentDir(const std::string &path)
424 {
425 string str = ExtractFilePath(path);
426 if (str.empty()) {
427 return "";
428 }
429 return str.substr(0, str.size() - 1);
430 }
431
IsLegalPath(const std::string & path)432 bool IsLegalPath(const std::string& path)
433 {
434 if (path.find("./") != std::string::npos ||
435 path.find("../") != std::string::npos) {
436 return false;
437 }
438 return true;
439 }
440
RenameFile(const std::string & src,const std::string & dest)441 bool RenameFile(const std::string& src, const std::string& dest)
442 {
443 if (std::rename(src.c_str(), dest.c_str()) == 0) {
444 return true;
445 }
446 return false;
447 }
448
GetDirXattr(const std::string & dir,const std::string & name,std::string & value)449 bool GetDirXattr(const std::string& dir, const std::string& name, std::string& value)
450 {
451 char buf[BUF_SIZE_256] = {0};
452 if (getxattr(dir.c_str(), name.c_str(), buf, BUF_SIZE_256) == -1) {
453 return false;
454 }
455 value = buf;
456 return true;
457 }
458
GetLastModifiedTimeStamp(const std::string & filePath)459 int64_t GetLastModifiedTimeStamp(const std::string& filePath)
460 {
461 struct stat fileInfo {0};
462 if (stat(filePath.c_str(), &fileInfo) != ERR_OK) {
463 return 0;
464 }
465 return fileInfo.st_mtime;
466 }
467
GetUserId(int32_t uid)468 int GetUserId(int32_t uid)
469 {
470 return uid / VALUE_MOD;
471 }
472
GetSandBoxLogPath(int32_t uid,const std::string & pathHolder,const std::string & subPath)473 std::string GetSandBoxLogPath(int32_t uid, const std::string& pathHolder, const std::string& subPath)
474 {
475 int userId = GetUserId(uid);
476 if (pathHolder.empty()) {
477 return "";
478 }
479 return "/data/app/el2/" + std::to_string(userId) + "/log/" + pathHolder + "/" + subPath;
480 }
481
GetSandBoxBasePath(int32_t uid,const std::string & pathHolder)482 std::string GetSandBoxBasePath(int32_t uid, const std::string& pathHolder)
483 {
484 int userId = GetUserId(uid);
485 if (pathHolder.empty()) {
486 return "";
487 }
488 return "/data/app/el2/" + std::to_string(userId) + "/base/" + pathHolder + "/cache/hiappevent";
489 }
490
CreateMultiDirectory(const std::string & dirPath)491 bool CreateMultiDirectory(const std::string &dirPath)
492 {
493 uint32_t dirPathLen = dirPath.length();
494 if (dirPathLen > PATH_MAX) {
495 return false;
496 }
497 char tmpDirPath[PATH_MAX] = { 0 };
498 for (uint32_t i = 0; i < dirPathLen; ++i) {
499 tmpDirPath[i] = dirPath[i];
500 if (tmpDirPath[i] == '/') {
501 if (!CheckAndCreateDirectory(tmpDirPath)) {
502 return false;
503 }
504 }
505 }
506 return true;
507 }
508 } // namespace FileUtil
509 } // namespace HiviewDFX
510 } // namespace OHOS
511