1 /*
2 * Copyright (c) 2023-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 "untar_file.h"
17
18 #include <utime.h>
19
20 #include "b_anony/b_anony.h"
21 #include "b_filesystem/b_dir.h"
22 #include "directory_ex.h"
23 #include "filemgmt_libhilog.h"
24 #include "securec.h"
25
26 namespace OHOS::FileManagement::Backup {
27 using namespace std;
28 const int32_t PATH_MAX_LEN = 4096;
29 const int32_t OCTAL = 8;
30 const int DEFAULT_ERR = -1;
31
IsEmptyBlock(const char * p)32 static bool IsEmptyBlock(const char *p)
33 {
34 if (p != nullptr) {
35 return (p[0] == '\0');
36 }
37 return true;
38 }
39
40 // 八进制字符串转十进制数字
ParseOctalStr(const string & octalStr,size_t destLen)41 static off_t ParseOctalStr(const string &octalStr, size_t destLen)
42 {
43 off_t ret = 0;
44 string::const_iterator it = octalStr.begin();
45
46 while (it != octalStr.end() && (*it < '0' || *it > '7') && destLen > 0) {
47 ++it;
48 --destLen;
49 }
50
51 while (it != octalStr.end() && *it >= '0' && *it <= '7' && destLen > 0) {
52 ret *= OCTAL;
53 ret += *it - '0';
54 ++it;
55 --destLen;
56 }
57
58 return ret;
59 }
60
ForceCreateDirectoryWithMode(const string & path,mode_t mode)61 static bool ForceCreateDirectoryWithMode(const string& path, mode_t mode)
62 {
63 string::size_type index = 0;
64 do {
65 index = path.find('/', index + 1);
66 string subPath = (index == string::npos) ? path : path.substr(0, index);
67 if (access(subPath.c_str(), F_OK) != 0) {
68 if (mkdir(subPath.c_str(), mode) != 0) {
69 return false;
70 }
71 }
72 } while (index != string::npos);
73 return access(path.c_str(), F_OK) == 0;
74 }
75
RTrimNull(std::string & s)76 static void RTrimNull(std::string &s)
77 {
78 auto iter = std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return ch != '\0'; });
79 s.erase(iter.base(), s.end());
80 }
81
ReadLongName(FileStatInfo & info)82 std::tuple<int, ErrFileInfo> UntarFile::ReadLongName(FileStatInfo &info)
83 {
84 size_t nameLen = static_cast<size_t>(tarFileSize_);
85 int ret = 0;
86 if (nameLen <= PATH_MAX_LEN) {
87 string tempName("");
88 tempName.resize(nameLen);
89 size_t read = fread(&(tempName[0]), sizeof(char), nameLen, tarFilePtr_);
90 if (read < nameLen) {
91 HILOGE("Failed to fread longName of %{private}s", info.fullPath.c_str());
92 ret = -1;
93 }
94 info.longName = tempName;
95 } else {
96 HILOGE("longName of %{private}s exceed PATH_MAX_LEN", info.fullPath.c_str());
97 ret = -1;
98 }
99 ErrFileInfo errFileInfo;
100 if (ret != 0) {
101 errFileInfo[info.fullPath].push_back(ret);
102 return {-1, errFileInfo};
103 }
104 if (fseeko(tarFilePtr_, pos_ + tarFileBlockCnt_ * BLOCK_SIZE, SEEK_SET) != 0) {
105 HILOGE("Failed to fseeko of %{private}s, err = %{public}d", info.fullPath.c_str(), errno);
106 errFileInfo[info.fullPath].push_back(errno);
107 return {-1, errFileInfo};
108 }
109 return {0, errFileInfo};
110 }
111
GetInstance()112 UntarFile &UntarFile::GetInstance()
113 {
114 static UntarFile instance;
115 return instance;
116 }
117
UnPacket(const std::string & tarFile,const std::string & rootPath)118 std::tuple<int, EndFileInfo, ErrFileInfo> UntarFile::UnPacket(
119 const std::string &tarFile, const std::string &rootPath)
120 {
121 tarFilePtr_ = fopen(tarFile.c_str(), "rb");
122 if (tarFilePtr_ == nullptr) {
123 HILOGE("Failed to open tar file %{public}s, err = %{public}d", tarFile.c_str(), errno);
124 return {errno, {}, {}};
125 }
126
127 auto [ret, fileInfos, errInfos] = ParseTarFile(rootPath);
128 if (ret != 0) {
129 HILOGE("Failed to parse tar file");
130 }
131
132 fclose(tarFilePtr_);
133 tarFilePtr_ = nullptr;
134
135 return {0, fileInfos, errInfos};
136 }
137
IncrementalUnPacket(const string & tarFile,const string & rootPath,const unordered_map<string,struct ReportFileInfo> & includes)138 std::tuple<int, EndFileInfo, ErrFileInfo> UntarFile::IncrementalUnPacket(
139 const string &tarFile, const string &rootPath, const unordered_map<string, struct ReportFileInfo> &includes)
140 {
141 includes_ = includes;
142 tarFilePtr_ = fopen(tarFile.c_str(), "rb");
143 if (tarFilePtr_ == nullptr) {
144 HILOGE("Failed to open tar file %{public}s, err = %{public}d", tarFile.c_str(), errno);
145 return {errno, {}, {}};
146 }
147
148 auto [ret, fileInfos, errFileInfos] = ParseIncrementalTarFile(rootPath);
149 if (ret != 0) {
150 HILOGE("Failed to parse tar file");
151 }
152
153 fclose(tarFilePtr_);
154 tarFilePtr_ = nullptr;
155
156 return {0, fileInfos, errFileInfos};
157 }
158
HandleTarBuffer(const string & buff,const string & name,FileStatInfo & info)159 off_t UntarFile::HandleTarBuffer(const string &buff, const string &name, FileStatInfo &info)
160 {
161 info.mode = static_cast<mode_t>(ParseOctalStr(&buff[0] + TMODE_BASE, TMODE_LEN));
162 info.uid = static_cast<uid_t>(ParseOctalStr(&buff[0] + TUID_BASE, TUID_LEN));
163 info.gid = static_cast<gid_t>(ParseOctalStr(&buff[0] + TGID_BASE, TGID_LEN));
164 info.mtime = ParseOctalStr(&buff[0] + TMTIME_BASE, MTIME_LEN);
165
166 tarFileSize_ = ParseOctalStr(&buff[0] + TSIZE_BASE, TSIZE_LEN);
167 tarFileBlockCnt_ = (tarFileSize_ + BLOCK_SIZE - 1) / BLOCK_SIZE;
168 pos_ = ftello(tarFilePtr_);
169
170 string realName = name;
171 if (!info.longName.empty()) {
172 realName = info.longName;
173 info.longName.clear();
174 }
175 if (realName.length() > 0 && realName[0] == '/') {
176 info.fullPath = realName.substr(1, realName.length() - 1);
177 return tarFileSize_;
178 }
179 info.fullPath = realName;
180 return tarFileSize_;
181 }
182
CheckAndFillTarSize()183 int UntarFile::CheckAndFillTarSize()
184 {
185 // tarFileSize
186 int ret = fseeko(tarFilePtr_, 0L, SEEK_END);
187 if (ret != 0) {
188 HILOGE("Failed to fseeko tarFileSize SEEK_SET, err = %{public}d", errno);
189 return ret;
190 }
191 tarFileSize_ = ftello(tarFilePtr_);
192 // reback file to begin
193 ret = fseeko(tarFilePtr_, 0L, SEEK_SET);
194 if (ret != 0) {
195 HILOGE("Failed to fseeko reback SEEK_SET, err = %{public}d", errno);
196 return ret;
197 }
198 return ret;
199 }
200
DealParseTarFileResult(const std::tuple<int,bool,ErrFileInfo> & result,const off_t fileSize,const std::string & fileName,EndFileInfo & fileInfos,ErrFileInfo & errInfos)201 int UntarFile::DealParseTarFileResult(const std::tuple<int, bool, ErrFileInfo> &result,
202 const off_t fileSize, const std::string &fileName, EndFileInfo &fileInfos, ErrFileInfo &errInfos)
203 {
204 auto [ret, isFilter, subErrInfos] = result;
205 if (ret != 0) {
206 HILOGE("Failed to parse incremental file by type flag");
207 return ret;
208 }
209 if (!isFilter) {
210 fileInfos[fileName] = fileSize;
211 }
212 if (!errInfos.empty()) {
213 errInfos.merge(subErrInfos);
214 }
215 return 0;
216 }
217
CheckIfTarBlockValid(char * buff,size_t buffLen,TarHeader * header,int & ret)218 bool UntarFile::CheckIfTarBlockValid(char *buff, size_t buffLen, TarHeader *header, int &ret)
219 {
220 // two empty continuous block indicate end of file
221 if (buff == nullptr || buffLen != BLOCK_SIZE || header == nullptr) {
222 return false;
223 }
224 if (IsEmptyBlock(buff) && header->typeFlag != GNUTYPE_LONGNAME) {
225 char tailBuff[BLOCK_SIZE] = {0};
226 size_t tailRead = fread(tailBuff, 1, BLOCK_SIZE, tarFilePtr_);
227 if (tailRead == BLOCK_SIZE && IsEmptyBlock(tailBuff)) {
228 HILOGE("Parsing tar file completed, tailBuff is empty.");
229 ret = 0;
230 return false;
231 }
232 }
233 // check header
234 if (!IsValidTarBlock(*header)) {
235 // when split unpack, ftell size is over than file really size [0,READ_BUFF_SIZE]
236 if (ftello(tarFilePtr_) > (tarFileSize_ + READ_BUFF_SIZE) || !IsEmptyBlock(buff)) {
237 HILOGE("Invalid tar file format");
238 ret = ERR_FORMAT;
239 }
240 HILOGE("invalid tar block header");
241 return false;
242 }
243 return true;
244 }
245
ParseTarFile(const string & rootPath)246 std::tuple<int, EndFileInfo, ErrFileInfo> UntarFile::ParseTarFile(const string &rootPath)
247 {
248 // re-parse tar header
249 rootPath_ = rootPath;
250 char buff[BLOCK_SIZE] = {0};
251 FileStatInfo info {};
252 int ret = 0;
253 if ((ret = CheckAndFillTarSize()) != 0) {
254 return {ret, {}, {}};
255 }
256 EndFileInfo fileInfos;
257 ErrFileInfo errInfos;
258 while (1) {
259 readCnt_ = fread(buff, 1, BLOCK_SIZE, tarFilePtr_);
260 if (readCnt_ < BLOCK_SIZE) {
261 HILOGE("Parsing tar file completed, read data count is less then block size.");
262 return {0, fileInfos, errInfos};
263 }
264 TarHeader *header = reinterpret_cast<TarHeader *>(buff);
265 bool isValid = CheckIfTarBlockValid(buff, sizeof(buff), header, ret);
266 if (!isValid) {
267 return {ret, fileInfos, errInfos};
268 }
269 off_t fileSize = HandleTarBuffer(string(buff, BLOCK_SIZE), header->name, info);
270 auto result = ParseFileByTypeFlag(header->typeFlag, info);
271 if ((ret = DealParseTarFileResult(result, fileSize, info.fullPath, fileInfos, errInfos)) != 0) {
272 return {ret, fileInfos, errInfos};
273 }
274 }
275
276 return {ret, fileInfos, errInfos};
277 }
278
DealIncreParseTarFileResult(const std::tuple<int,bool,ErrFileInfo> & result,const off_t fileSize,const std::string & fileName,EndFileInfo & fileInfos,ErrFileInfo & errInfos)279 int UntarFile::DealIncreParseTarFileResult(const std::tuple<int, bool, ErrFileInfo> &result,
280 const off_t fileSize, const std::string &fileName, EndFileInfo &fileInfos, ErrFileInfo &errInfos)
281 {
282 auto [ret, isFilter, subErrInfo] = result;
283 if (ret != 0) {
284 HILOGE("Failed to parse incremental file by type flag");
285 return ret;
286 }
287 if (!isFilter) {
288 fileInfos[fileName] = fileSize;
289 }
290 if (!subErrInfo.empty()) {
291 errInfos.merge(subErrInfo);
292 }
293 return 0;
294 }
295
ParseIncrementalTarFile(const string & rootPath)296 std::tuple<int, EndFileInfo, ErrFileInfo> UntarFile::ParseIncrementalTarFile(const string &rootPath)
297 {
298 // re-parse tar header
299 rootPath_ = rootPath;
300 char buff[BLOCK_SIZE] = {0};
301 FileStatInfo info {};
302 int ret = 0;
303 if ((ret = CheckAndFillTarSize()) != 0) {
304 return {ret, {}, {}};
305 }
306 EndFileInfo fileInfos;
307 ErrFileInfo errFileInfo;
308 do {
309 readCnt_ = fread(buff, 1, BLOCK_SIZE, tarFilePtr_);
310 if (readCnt_ < BLOCK_SIZE) {
311 HILOGE("Parsing tar file completed, read data count is less then block size.");
312 return {0, fileInfos, errFileInfo};
313 }
314 TarHeader *header = reinterpret_cast<TarHeader *>(buff);
315 bool isValid = CheckIfTarBlockValid(buff, sizeof(buff), header, ret);
316 if (!isValid) {
317 return {ret, fileInfos, errFileInfo};
318 }
319 off_t fileSize = HandleTarBuffer(string(buff, BLOCK_SIZE), header->name, info);
320 auto result = ParseIncrementalFileByTypeFlag(header->typeFlag, info);
321 ret = DealIncreParseTarFileResult(result, fileSize, info.fullPath, fileInfos, errFileInfo);
322 if (ret != 0) {
323 return {ret, fileInfos, errFileInfo};
324 }
325 } while (readCnt_ >= BLOCK_SIZE);
326
327 return {ret, fileInfos, errFileInfo};
328 }
329
ParseFileByTypeFlag(char typeFlag,FileStatInfo & info)330 tuple<int, bool, ErrFileInfo> UntarFile::ParseFileByTypeFlag(char typeFlag, FileStatInfo &info)
331 {
332 HILOGD("untar file: %{public}s, rootPath: %{public}s", GetAnonyPath(info.fullPath).c_str(), rootPath_.c_str());
333 bool isFilter = true;
334 ErrFileInfo errFileInfo;
335 switch (typeFlag) {
336 case REGTYPE:
337 case AREGTYPE:
338 info.fullPath = GenRealPath(rootPath_, info.fullPath);
339 if (BDir::CheckFilePathInvalid(info.fullPath)) {
340 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
341 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
342 }
343 errFileInfo = ParseRegularFile(info);
344 isFilter = false;
345 break;
346 case SYMTYPE:
347 break;
348 case DIRTYPE:
349 info.fullPath = GenRealPath(rootPath_, info.fullPath);
350 if (BDir::CheckFilePathInvalid(info.fullPath)) {
351 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
352 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
353 }
354 errFileInfo = CreateDir(info.fullPath, info.mode);
355 isFilter = false;
356 break;
357 case GNUTYPE_LONGNAME: {
358 auto result = ReadLongName(info);
359 if (BDir::CheckFilePathInvalid(info.fullPath) || BDir::CheckFilePathInvalid(info.longName)) {
360 HILOGE("Check file path : %{public}s or long name : %{public}s err, path is forbidden",
361 GetAnonyPath(info.fullPath).c_str(), GetAnonyPath(info.longName).c_str());
362 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
363 }
364 errFileInfo = std::get<SECOND_PARAM>(result);
365 return {std::get<FIRST_PARAM>(result), isFilter, errFileInfo};
366 break;
367 }
368 default: {
369 if (fseeko(tarFilePtr_, tarFileBlockCnt_ * BLOCK_SIZE, SEEK_CUR) != 0) {
370 HILOGE("Failed to fseeko of %{private}s, err = %{public}d", info.fullPath.c_str(), errno);
371 return {-1, true, errFileInfo};
372 }
373 break;
374 }
375 }
376 return {0, isFilter, errFileInfo};
377 }
378
DealFileTag(ErrFileInfo & errFileInfo,FileStatInfo & info,bool & isFilter,const std::string & tmpFullPath)379 bool UntarFile::DealFileTag(ErrFileInfo &errFileInfo,
380 FileStatInfo &info, bool &isFilter, const std::string &tmpFullPath)
381 {
382 if (!includes_.empty() && includes_.find(tmpFullPath) == includes_.end()) { // not in includes
383 if (fseeko(tarFilePtr_, pos_ + tarFileBlockCnt_ * BLOCK_SIZE, SEEK_SET) != 0) {
384 HILOGE("Failed to fseeko of %{private}s, err = %{public}d", info.fullPath.c_str(), errno);
385 errFileInfo[info.fullPath].push_back(DEFAULT_ERR);
386 return false;
387 }
388 return true;
389 }
390 info.fullPath = GenRealPath(rootPath_, info.fullPath);
391 if (BDir::CheckFilePathInvalid(info.fullPath)) {
392 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
393 errFileInfo[info.fullPath].push_back(DEFAULT_ERR);
394 return false;
395 }
396 errFileInfo = ParseRegularFile(info);
397 isFilter = false;
398 return true;
399 }
400
401
ParseIncrementalFileByTypeFlag(char typeFlag,FileStatInfo & info)402 std::tuple<int, bool, ErrFileInfo> UntarFile::ParseIncrementalFileByTypeFlag(char typeFlag, FileStatInfo &info)
403 {
404 HILOGD("untar file: %{public}s, rootPath: %{public}s", GetAnonyPath(info.fullPath).c_str(), rootPath_.c_str());
405 string tmpFullPath = info.fullPath;
406 bool isFilter = true;
407 ErrFileInfo errFileInfo;
408 RTrimNull(tmpFullPath);
409 switch (typeFlag) {
410 case REGTYPE:
411 case AREGTYPE: {
412 if (!DealFileTag(errFileInfo, info, isFilter, tmpFullPath)) {
413 return {DEFAULT_ERR, true, errFileInfo};
414 }
415 break;
416 }
417 case SYMTYPE:
418 break;
419 case DIRTYPE:
420 info.fullPath = GenRealPath(rootPath_, info.fullPath);
421 if (BDir::CheckFilePathInvalid(info.fullPath)) {
422 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
423 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
424 }
425 errFileInfo = CreateDir(info.fullPath, info.mode);
426 isFilter = false;
427 break;
428 case GNUTYPE_LONGNAME: {
429 auto result = ReadLongName(info);
430 if (BDir::CheckFilePathInvalid(info.fullPath)) {
431 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
432 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
433 }
434 return {std::get<FIRST_PARAM>(result), isFilter, std::get<SECOND_PARAM>(result)};
435 break;
436 }
437 default: {
438 if (fseeko(tarFilePtr_, tarFileBlockCnt_ * BLOCK_SIZE, SEEK_CUR) != 0) {
439 HILOGE("Failed to fseeko of %{private}s, err = %{public}d", info.fullPath.c_str(), errno);
440 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
441 }
442 break;
443 }
444 }
445
446 return {0, isFilter, errFileInfo};
447 }
448
ParseRegularFile(FileStatInfo & info)449 ErrFileInfo UntarFile::ParseRegularFile(FileStatInfo &info)
450 {
451 ErrFileInfo errFileInfo;
452 FILE *destFile = CreateFile(info.fullPath);
453 if (destFile != nullptr) {
454 string destStr("");
455 destStr.resize(READ_BUFF_SIZE);
456 size_t remainSize = static_cast<size_t>(tarFileSize_);
457 size_t readBuffSize = READ_BUFF_SIZE;
458 while (remainSize > 0) {
459 if (remainSize < READ_BUFF_SIZE) {
460 readBuffSize = remainSize;
461 }
462 fread(&destStr[0], sizeof(char), readBuffSize, tarFilePtr_);
463 fwrite(&destStr[0], sizeof(char), readBuffSize, destFile);
464 remainSize -= readBuffSize;
465 }
466 fclose(destFile);
467 if (chmod(info.fullPath.data(), info.mode) != 0) {
468 HILOGE("Failed to chmod of %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
469 errFileInfo[info.fullPath].push_back(errno);
470 }
471 struct utimbuf times;
472 struct stat attr;
473 if (stat(info.fullPath.c_str(), &attr) != 0) {
474 errFileInfo[info.fullPath].push_back(errno);
475 HILOGE("Failed to get stat of %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
476 times.actime = info.mtime;
477 } else {
478 times.actime = attr.st_atime;
479 }
480 times.modtime = info.mtime;
481 if (info.mtime != 0 && utime(info.fullPath.c_str(), ×) != 0) {
482 errFileInfo[info.fullPath].push_back(errno);
483 HILOGE("Failed to set mtime of %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
484 }
485 // anyway, go to correct
486 fseeko(tarFilePtr_, pos_ + tarFileBlockCnt_ * BLOCK_SIZE, SEEK_SET);
487 } else {
488 HILOGE("Failed to create file %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
489 errFileInfo[info.fullPath].push_back(errno);
490 fseeko(tarFilePtr_, tarFileBlockCnt_ * BLOCK_SIZE, SEEK_CUR);
491 }
492 return errFileInfo;
493 }
494
VerifyChecksum(TarHeader & header)495 bool UntarFile::VerifyChecksum(TarHeader &header)
496 {
497 vector<uint8_t> buffer {};
498 buffer.resize(sizeof(header));
499 buffer.assign(reinterpret_cast<uint8_t *>(&header), reinterpret_cast<uint8_t *>(&header) + sizeof(header));
500 int sum = 0;
501 for (uint32_t index = 0; index < BLOCK_SIZE; ++index) {
502 if (index < CHKSUM_BASE || index > CHKSUM_BASE + CHKSUM_LEN - 1) {
503 // Standard tar checksum adds unsigned bytes.
504 sum += (buffer[index] & 0xFF);
505 } else {
506 sum += BLANK_SPACE;
507 }
508 }
509 string strChksum;
510 strChksum.assign(buffer.begin(), buffer.end());
511 return (sum == ParseOctalStr(&strChksum[0] + CHKSUM_BASE, CHKSUM_LEN));
512 }
513
IsValidTarBlock(TarHeader & header)514 bool UntarFile::IsValidTarBlock(TarHeader &header)
515 {
516 // check magic && checksum
517 if (strncmp(header.magic, TMAGIC.c_str(), TMAGIC_LEN - 1) == 0 && VerifyChecksum(header)) {
518 return true;
519 }
520 HILOGE("Invalid tar block");
521 return false;
522 }
523
GenRealPath(const string & rootPath,const string & realName)524 string UntarFile::GenRealPath(const string &rootPath, const string &realName)
525 {
526 if (rootPath.empty() || realName.empty()) {
527 return "";
528 }
529 string realPath(rootPath);
530 size_t len = realPath.length();
531 if (realPath[len - 1] == '/') {
532 realPath = realPath.substr(0, len - 1);
533 }
534 realPath.append((realName[0] == '/') ? realName : ("/" + realName));
535 if (realPath[0] == '/') {
536 realPath = realPath.substr(1, realPath.length());
537 }
538 return realPath;
539 }
540
CreateDir(string & path,mode_t mode)541 ErrFileInfo UntarFile::CreateDir(string &path, mode_t mode)
542 {
543 ErrFileInfo errFileInfo;
544 if (path.empty()) {
545 return errFileInfo;
546 }
547 size_t len = path.length();
548 if (path[len - 1] == '/') {
549 path[len - 1] = '\0';
550 }
551 if (access(path.c_str(), F_OK) != 0) {
552 HILOGE("directory does not exist, path:%{public}s, err = %{public}d", path.c_str(), errno);
553 if (!ForceCreateDirectoryWithMode(path, mode)) {
554 HILOGE("Failed to force create directory %{public}s, err = %{public}d", path.c_str(), errno);
555 errFileInfo[path].push_back(errno);
556 }
557 }
558 return errFileInfo;
559 }
560
CreateFile(string & filePath)561 FILE *UntarFile::CreateFile(string &filePath)
562 {
563 FILE *f = fopen(filePath.c_str(), "wb+");
564 if (f != nullptr) {
565 return f;
566 }
567
568 uint32_t len = filePath.length();
569 HILOGE("Failed to open file %{public}d, %{public}s, err = %{public}d", len,
570 GetAnonyPath(filePath).c_str(), errno);
571 size_t pos = filePath.rfind('/');
572 if (pos == string::npos) {
573 return nullptr;
574 }
575
576 string path = filePath.substr(0, pos);
577 if (ForceCreateDirectory(path)) {
578 f = fopen(filePath.c_str(), "wb+");
579 if (f == nullptr) {
580 HILOGE("Failed to open file %{public}s, err = %{public}d", GetAnonyPath(filePath).c_str(), errno);
581 }
582 }
583
584 return f;
585 }
586
587 } // namespace OHOS::FileManagement::Backup