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 }
387 return false;
388 }
389 info.fullPath = GenRealPath(rootPath_, info.fullPath);
390 if (BDir::CheckFilePathInvalid(info.fullPath)) {
391 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
392 errFileInfo[info.fullPath].push_back(DEFAULT_ERR);
393 return false;
394 }
395 errFileInfo = ParseRegularFile(info);
396 isFilter = false;
397 return true;
398 }
399
400
ParseIncrementalFileByTypeFlag(char typeFlag,FileStatInfo & info)401 std::tuple<int, bool, ErrFileInfo> UntarFile::ParseIncrementalFileByTypeFlag(char typeFlag, FileStatInfo &info)
402 {
403 HILOGD("untar file: %{public}s, rootPath: %{public}s", GetAnonyPath(info.fullPath).c_str(), rootPath_.c_str());
404 string tmpFullPath = info.fullPath;
405 bool isFilter = true;
406 ErrFileInfo errFileInfo;
407 RTrimNull(tmpFullPath);
408 switch (typeFlag) {
409 case REGTYPE:
410 case AREGTYPE: {
411 if (!DealFileTag(errFileInfo, info, isFilter, tmpFullPath)) {
412 return {DEFAULT_ERR, true, errFileInfo};
413 }
414 break;
415 }
416 case SYMTYPE:
417 break;
418 case DIRTYPE:
419 info.fullPath = GenRealPath(rootPath_, info.fullPath);
420 if (BDir::CheckFilePathInvalid(info.fullPath)) {
421 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
422 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
423 }
424 errFileInfo = CreateDir(info.fullPath, info.mode);
425 isFilter = false;
426 break;
427 case GNUTYPE_LONGNAME: {
428 auto result = ReadLongName(info);
429 if (BDir::CheckFilePathInvalid(info.fullPath)) {
430 HILOGE("Check file path : %{public}s err, path is forbidden", GetAnonyPath(info.fullPath).c_str());
431 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
432 }
433 return {std::get<FIRST_PARAM>(result), isFilter, std::get<SECOND_PARAM>(result)};
434 break;
435 }
436 default: {
437 if (fseeko(tarFilePtr_, tarFileBlockCnt_ * BLOCK_SIZE, SEEK_CUR) != 0) {
438 HILOGE("Failed to fseeko of %{private}s, err = %{public}d", info.fullPath.c_str(), errno);
439 return {DEFAULT_ERR, true, {{info.fullPath, {DEFAULT_ERR}}}};
440 }
441 break;
442 }
443 }
444
445 return {0, isFilter, errFileInfo};
446 }
447
ParseRegularFile(FileStatInfo & info)448 ErrFileInfo UntarFile::ParseRegularFile(FileStatInfo &info)
449 {
450 ErrFileInfo errFileInfo;
451 FILE *destFile = CreateFile(info.fullPath);
452 if (destFile != nullptr) {
453 string destStr("");
454 destStr.resize(READ_BUFF_SIZE);
455 size_t remainSize = static_cast<size_t>(tarFileSize_);
456 size_t readBuffSize = READ_BUFF_SIZE;
457 while (remainSize > 0) {
458 if (remainSize < READ_BUFF_SIZE) {
459 readBuffSize = remainSize;
460 }
461 fread(&destStr[0], sizeof(char), readBuffSize, tarFilePtr_);
462 fwrite(&destStr[0], sizeof(char), readBuffSize, destFile);
463 remainSize -= readBuffSize;
464 }
465 fclose(destFile);
466 if (chmod(info.fullPath.data(), info.mode) != 0) {
467 HILOGE("Failed to chmod of %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
468 errFileInfo[info.fullPath].push_back(errno);
469 }
470 struct utimbuf times;
471 struct stat attr;
472 if (stat(info.fullPath.c_str(), &attr) != 0) {
473 errFileInfo[info.fullPath].push_back(errno);
474 HILOGE("Failed to get stat of %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
475 times.actime = info.mtime;
476 } else {
477 times.actime = attr.st_atime;
478 }
479 times.modtime = info.mtime;
480 if (info.mtime != 0 && utime(info.fullPath.c_str(), ×) != 0) {
481 errFileInfo[info.fullPath].push_back(errno);
482 HILOGE("Failed to set mtime of %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
483 }
484 // anyway, go to correct
485 fseeko(tarFilePtr_, pos_ + tarFileBlockCnt_ * BLOCK_SIZE, SEEK_SET);
486 } else {
487 HILOGE("Failed to create file %{public}s, err = %{public}d", GetAnonyPath(info.fullPath).c_str(), errno);
488 errFileInfo[info.fullPath].push_back(errno);
489 fseeko(tarFilePtr_, tarFileBlockCnt_ * BLOCK_SIZE, SEEK_CUR);
490 }
491 return errFileInfo;
492 }
493
VerifyChecksum(TarHeader & header)494 bool UntarFile::VerifyChecksum(TarHeader &header)
495 {
496 vector<uint8_t> buffer {};
497 buffer.resize(sizeof(header));
498 buffer.assign(reinterpret_cast<uint8_t *>(&header), reinterpret_cast<uint8_t *>(&header) + sizeof(header));
499 int sum = 0;
500 for (uint32_t index = 0; index < BLOCK_SIZE; ++index) {
501 if (index < CHKSUM_BASE || index > CHKSUM_BASE + CHKSUM_LEN - 1) {
502 // Standard tar checksum adds unsigned bytes.
503 sum += (buffer[index] & 0xFF);
504 } else {
505 sum += BLANK_SPACE;
506 }
507 }
508 string strChksum;
509 strChksum.assign(buffer.begin(), buffer.end());
510 return (sum == ParseOctalStr(&strChksum[0] + CHKSUM_BASE, CHKSUM_LEN));
511 }
512
IsValidTarBlock(TarHeader & header)513 bool UntarFile::IsValidTarBlock(TarHeader &header)
514 {
515 // check magic && checksum
516 if (strncmp(header.magic, TMAGIC.c_str(), TMAGIC_LEN - 1) == 0 && VerifyChecksum(header)) {
517 return true;
518 }
519 HILOGE("Invalid tar block");
520 return false;
521 }
522
GenRealPath(const string & rootPath,const string & realName)523 string UntarFile::GenRealPath(const string &rootPath, const string &realName)
524 {
525 if (rootPath.empty() || realName.empty()) {
526 return "";
527 }
528 string realPath(rootPath);
529 size_t len = realPath.length();
530 if (realPath[len - 1] == '/') {
531 realPath = realPath.substr(0, len - 1);
532 }
533 realPath.append((realName[0] == '/') ? realName : ("/" + realName));
534 if (realPath[0] == '/') {
535 realPath = realPath.substr(1, realPath.length());
536 }
537 return realPath;
538 }
539
CreateDir(string & path,mode_t mode)540 ErrFileInfo UntarFile::CreateDir(string &path, mode_t mode)
541 {
542 ErrFileInfo errFileInfo;
543 if (path.empty()) {
544 return errFileInfo;
545 }
546 size_t len = path.length();
547 if (path[len - 1] == '/') {
548 path[len - 1] = '\0';
549 }
550 if (access(path.c_str(), F_OK) != 0) {
551 HILOGE("directory does not exist, path:%{public}s, err = %{public}d", path.c_str(), errno);
552 if (!ForceCreateDirectoryWithMode(path, mode)) {
553 HILOGE("Failed to force create directory %{public}s, err = %{public}d", path.c_str(), errno);
554 errFileInfo[path].push_back(errno);
555 }
556 }
557 return errFileInfo;
558 }
559
CreateFile(string & filePath)560 FILE *UntarFile::CreateFile(string &filePath)
561 {
562 FILE *f = fopen(filePath.c_str(), "wb+");
563 if (f != nullptr) {
564 return f;
565 }
566
567 uint32_t len = filePath.length();
568 HILOGE("Failed to open file %{public}d, %{public}s, err = %{public}d", len,
569 GetAnonyPath(filePath).c_str(), errno);
570 size_t pos = filePath.rfind('/');
571 if (pos == string::npos) {
572 return nullptr;
573 }
574
575 string path = filePath.substr(0, pos);
576 if (ForceCreateDirectory(path)) {
577 f = fopen(filePath.c_str(), "wb+");
578 if (f == nullptr) {
579 HILOGE("Failed to open file %{public}s, err = %{public}d", GetAnonyPath(filePath).c_str(), errno);
580 }
581 }
582
583 return f;
584 }
585
586 } // namespace OHOS::FileManagement::Backup