1 /*
2 * Copyright (c) 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 "installd_un_tar_file.h"
17
18 #include <cstdio>
19 #include <directory_ex.h>
20 #include <string>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "securec.h"
26
27 #include <hilog/log.h>
28
29 namespace installd {
30 const uid_t OCTAL = 8;
31 const mode_t FILE_MODE = 448;
32
FixUpOwnerDirFile(const uid_t uid,const gid_t gid,const uid_t owner,gid_t & newGid)33 uid_t FixUpOwnerDirFile(const uid_t uid, const gid_t gid, const uid_t owner, gid_t& newGid)
34 {
35 uid_t newUid = owner;
36 if (0 == owner || uid < APP_ID_START) {
37 newUid = uid;
38 newGid = gid;
39
40 return newUid;
41 }
42
43 if (uid == gid) {
44 newGid = newUid;
45 } else if (0 == ((gid - uid) % UID_GID_OFFSET)) {
46 newGid = (gid - uid) + newUid;
47 } else {
48 newGid = gid;
49 }
50
51 return newUid;
52 }
53
ParseOctalStr(const char * p,size_t n)54 off_t ParseOctalStr(const char* p, size_t n)
55 {
56 off_t ret = 0;
57 std::string octalStr(p);
58 auto it = octalStr.begin();
59
60 while (it != octalStr.end() && (*it < '0' || *it > '7') && n > 0) {
61 ++it;
62 --n;
63 }
64
65 while (it != octalStr.end() && *it >= '0' && *it <= '7' && n > 0) {
66 ret *= OCTAL;
67 ret += *it - '0';
68 ++it;
69 --n;
70 }
71
72 return ret;
73 }
74
GenRealPath(const char * rootPath,const char * pathName,char * & realPath)75 static int GenRealPath(const char *rootPath, const char *pathName, char* &realPath)
76 {
77 if (rootPath == nullptr || pathName == nullptr || realPath == nullptr) {
78 return ERR_PARAM;
79 }
80 size_t allLen = strlen(rootPath);
81 if (rootPath[allLen - 1] != '/') {
82 allLen += 1;
83 }
84 allLen += strlen(pathName);
85 if (0 == allLen || allLen >= PATH_MAX_LEN) {
86 LOGE("ERR_PARAM");
87 return ERR_PARAM;
88 }
89
90 size_t curLen = strlen(rootPath);
91 if (strncpy_s(realPath, PATH_MAX_LEN, rootPath, curLen) != 0) {
92 LOGE("GenRealPath get realPath error");
93 return ERR_PARAM;
94 }
95
96 if (rootPath[curLen - 1] != '/') {
97 realPath[curLen] = '/';
98 curLen += 1;
99 }
100
101 if (strncpy_s(realPath + curLen, PATH_MAX_LEN - curLen, pathName, strlen(pathName)) != 0) {
102 LOGE("GenRealPath get realPath by curLen error");
103 return ERR_PARAM;
104 }
105 realPath[allLen] = '\0';
106 return 0;
107 }
108
CreateDir(char * path,mode_t mode)109 static int CreateDir(char *path, mode_t mode)
110 {
111 if (path == nullptr) {
112 return ERR_PARAM;
113 }
114
115 size_t len = strlen(path);
116 if (path[len - 1] == '/') {
117 path[len - 1] = '\0';
118 }
119
120 int ret = access(path, F_OK);
121 if (ret == -1) {
122 ret = mkdir(path, mode);
123 }
124 return ret;
125 }
126
CreateFile(char * path,mode_t mode,char fileType)127 static FILE *CreateFile(char* path, mode_t mode, char fileType)
128 {
129 if (path == nullptr) {
130 return nullptr;
131 }
132
133 std::string appendStr = "wb+";
134 if (fileType == SPLIT_END_TYPE || fileType == SPLIT_CONTINUE_TYPE) {
135 appendStr = "ab+";
136 }
137 FILE *f = fopen(path, appendStr.c_str());
138 if (f == nullptr) {
139 char *p = strrchr(path, '/');
140 if (p != nullptr) {
141 *p = '\0';
142 if (CreateDir(path, mode) == 0) {
143 *p = '/';
144 f = fopen(path, "wb+");
145 }
146 }
147 }
148 if (f == nullptr) {
149 return f;
150 }
151 if (fchmod(fileno(f), S_IRUSR | S_IWUSR) == -1) {
152 LOGE("fail to change file permission");
153 (void)fclose(f);
154 return nullptr;
155 }
156
157 return f;
158 }
159
CreateSoftlink(const char * oldPath,const char * newPath)160 static int CreateSoftlink(const char* oldPath, const char* newPath)
161 {
162 if (oldPath == nullptr || newPath == nullptr) {
163 return ERR_PARAM;
164 }
165
166 unlink(newPath);
167 int ret = symlink(oldPath, newPath);
168 return ret;
169 }
170
UnTarFile(const char * tarPath)171 UnTarFile::UnTarFile(const char *tarPath): FilePtr(nullptr), tarSize(0), newOwner(0)
172 {
173 file_names.clear();
174 file_sizes.clear();
175 file_data_addrs.clear();
176
177 if (tarPath != nullptr) {
178 LOGI("untarfile begin..");
179 m_srcPath = tarPath;
180 FilePtr = fopen(tarPath, "rb");
181 if (FilePtr == nullptr) {
182 LOGE("open file fail");
183 }
184 }
185 }
186
~UnTarFile(void)187 UnTarFile::~UnTarFile(void)
188 {
189 if (FilePtr != nullptr) {
190 (void)fclose(FilePtr);
191 FilePtr = nullptr;
192 }
193
194 file_names.clear();
195 file_sizes.clear();
196 file_data_addrs.clear();
197 }
198
Reset()199 void UnTarFile::Reset()
200 {
201 if (FilePtr != nullptr) {
202 (void)fclose(FilePtr);
203 FilePtr = nullptr;
204 }
205
206 isSplit = false;
207 file_names.clear();
208 file_sizes.clear();
209 file_data_addrs.clear();
210 }
211
UnSplitTar(const std::string & tarFile,const std::string & rootpath)212 int UnTarFile::UnSplitTar(const std::string &tarFile, const std::string &rootpath)
213 {
214 FilePtr = fopen(tarFile.c_str(), "rb");
215 if (FilePtr == nullptr) {
216 LOGE("UnTarFile::UnSplitPack, untar split failed!");
217 }
218 isSplit = true;
219 std::string destPath(rootpath);
220
221 CreateDirWithRecursive(destPath);
222
223 int parseRet = ParseTarFile(destPath.c_str(), eUnpack);
224 if (parseRet != 0) {
225 LOGE("UnTarFile::UnSplitPack, untar split failed!");
226 } else {
227 LOGI("UnTarFile::UnSplitPack, untar split suc!");
228 }
229 if (FilePtr != nullptr) {
230 (void)fclose(FilePtr);
231 FilePtr = nullptr;
232 }
233 return parseRet;
234 }
235
CheckIsSplitTar(const std::string & tarFile,const std::string & rootpath)236 bool UnTarFile::CheckIsSplitTar(const std::string &tarFile, const std::string &rootpath)
237 {
238 FilePtr = fopen(tarFile.c_str(), "rb");
239 if (FilePtr == nullptr) {
240 LOGE("UnTarFile::CheckIsSplitTar, open split failed!");
241 }
242 std::string destPath(rootpath);
243 int parseRet = ParseTarFile(destPath.c_str(), eCheckSplit);
244 if (parseRet != 0) {
245 LOGE("UnTarFile::CheckIsSplitTar, check is split failed!");
246 } else {
247 LOGI("UnTarFile::CheckIsSplitTar, check is split, %{public}d", isSplit);
248 }
249 if (FilePtr != nullptr) {
250 (void)fclose(FilePtr);
251 FilePtr = nullptr;
252 }
253 if (isSplit) {
254 return true;
255 }
256 return false;
257 }
258
VerifyChecksum(const TarHeader * tarHeader)259 bool UnTarFile::VerifyChecksum(const TarHeader *tarHeader)
260 {
261 if (tarHeader == nullptr) {
262 return false;
263 }
264
265 char *headerBuff = (char *)tarHeader;
266
267 int u = 0;
268 for (int n = 0; n < BLOCK_SIZE; ++n) {
269 if (n < CHKSUM_BASE || n > CHKSUM_BASE + TarUtil::CHKSUM_LEN - 1) {
270 /* Standard tar checksum adds unsigned bytes. */
271 u += (*(headerBuff + n) & 0xFF);
272 } else {
273 u += BLANK_SPACE;
274 }
275 }
276
277 return (u == static_cast<int>(ParseOctalStr(headerBuff + CHKSUM_BASE, TarUtil::CHKSUM_LEN)));
278 }
279
IsValidTarBlock(const TarHeader * tarHeader)280 bool UnTarFile::IsValidTarBlock(const TarHeader *tarHeader)
281 {
282 if (tarHeader == nullptr) {
283 return false;
284 }
285
286 // check magic && checksum
287 if (0 == strncmp(tarHeader->magic, TMAGIC, TMAGIC_LEN - 1) && VerifyChecksum(tarHeader)) {
288 return true;
289 }
290
291 LOGD("Invalid tar format.");
292 return false;
293 }
294
IsEmptyBlock(const char * p)295 bool UnTarFile::IsEmptyBlock(const char *p)
296 {
297 return ('\0' == p[0]);
298 }
299
CheckFileAndInitPath(const char * rootPath,ParseTarPath * parseTarPath)300 int UnTarFile::CheckFileAndInitPath(const char *rootPath, ParseTarPath *parseTarPath)
301 {
302 if (FilePtr == nullptr) {
303 LOGE("read tar happened error!\n");
304 return ERR_PARAM;
305 }
306
307 if (rootPath == nullptr) {
308 LOGE("rootPath is nullptr!\n");
309 return ERR_NOEXIST;
310 }
311 // tarSize
312 fseeko(FilePtr, 0L, SEEK_END);
313 tarSize = ftello(FilePtr);
314 // reback file to begin
315 fseeko(FilePtr, 0L, SEEK_SET);
316 if (tarSize % BLOCK_SIZE != 0) {
317 LOGE("tarfile size should be a multiple of 512 bytes");
318 return ERR_FORMAT;
319 }
320
321 parseTarPath->fullPath = (char *)malloc(PATH_MAX_LEN * sizeof(char));
322 if (parseTarPath->fullPath == nullptr) {
323 return ERR_MALLOC;
324 }
325 memset_s(parseTarPath->fullPath, PATH_MAX_LEN * sizeof(char), 0, PATH_MAX_LEN * sizeof(char));
326 return 0;
327 }
328
ProcessTarBlock(char * buff,EParseType type,ParseTarPath * parseTarPath,bool & isSkip,bool & isSoftLink)329 bool UnTarFile::ProcessTarBlock(char *buff, EParseType type, ParseTarPath *parseTarPath, bool &isSkip, bool &isSoftLink)
330 {
331 TarHeader *tarHeader = (TarHeader *)buff;
332 TarFileInfo tarFileInfo = {};
333 tarFileInfo.fileSize = ParseOctalStr(buff + TSIZE_BASE, TSIZE_LEN);
334 tarFileInfo.fileBlockCnt = (tarFileInfo.fileSize + BLOCK_SIZE - 1) / BLOCK_SIZE;
335 tarFileInfo.pos = ftello(FilePtr);
336 switch (tarHeader->typeflag) {
337 case SPLIT_START_TYPE:
338 case SPLIT_END_TYPE:
339 case SPLIT_CONTINUE_TYPE:
340 if (eCheckSplit == type) {
341 isSplit = true;
342 return false;
343 }
344 case REGTYPE:
345 case AREGTYPE:
346 HandleRegularFile(buff, type, parseTarPath, isSkip, tarFileInfo);
347 break;
348 case SYMTYPE:
349 CreateSoftlink(parseTarPath->realLink, parseTarPath->fullPath);
350 isSoftLink = true;
351 isSkip = false;
352 break;
353 case DIRTYPE:
354 CreateDir(parseTarPath->fullPath, FILE_MODE);
355 isSkip = false;
356 break;
357 case TarUtil::GNUTYPE_LONGNAME:
358 HandleGnuLongName(parseTarPath, isSkip, tarFileInfo);
359 return true;
360 case GNUTYPE_LONGLINK:
361 HandleGnuLongLink(parseTarPath, isSkip, tarFileInfo);
362 return true;
363 default:
364 isSkip = true;
365 fseeko(FilePtr, tarFileInfo.fileBlockCnt * BLOCK_SIZE, SEEK_CUR);
366 break;
367 }
368
369 if (!isSkip) {
370 SetFileChmodAndChown(buff, parseTarPath, isSoftLink);
371 }
372 isSkip = false;
373 FreeLongTypePointer(parseTarPath);
374 return true;
375 }
376
SetFileChmodAndChown(char * buff,ParseTarPath * parseTarPath,bool & isSoftLink)377 void UnTarFile::SetFileChmodAndChown(char *buff, ParseTarPath *parseTarPath, bool &isSoftLink)
378 {
379 // uid & gid
380 gid_t newGid = 0;
381 uid_t uid = (uid_t)ParseOctalStr(buff + TUID_BASE, TUID_LEN);
382 gid_t gid = (gid_t)ParseOctalStr(buff + TGID_BASE, TGID_LEN);
383 uid_t newUid = FixUpOwnerDirFile(uid, gid, newOwner, newGid);
384 if (!isSoftLink) {
385 chmod(parseTarPath->fullPath, FILE_MODE);
386 chown(parseTarPath->fullPath, newUid, newGid);
387 return;
388 }
389 lchown(parseTarPath->fullPath, newUid, newGid);
390 isSoftLink = false;
391 }
392
HandleGnuLongLink(ParseTarPath * parseTarPath,bool & isSkip,TarFileInfo & tarFileInfo)393 void UnTarFile::HandleGnuLongLink(ParseTarPath *parseTarPath, bool &isSkip, TarFileInfo &tarFileInfo)
394 {
395 /* long link */
396 if (parseTarPath->longLink != nullptr) {
397 free(parseTarPath->longLink);
398 parseTarPath->longLink = nullptr;
399 }
400 size_t nameLen = (size_t)tarFileInfo.fileSize;
401 if (nameLen < PATH_MAX_LEN) {
402 parseTarPath->longLink = (char *)malloc((nameLen + 1) * sizeof(char));
403 }
404 if (parseTarPath->longLink != nullptr) {
405 memset_s(parseTarPath->longLink, (nameLen + 1) * sizeof(char), 0, (nameLen + 1) * sizeof(char));
406 if (nameLen != fread(parseTarPath->longLink, sizeof(char), nameLen, FilePtr)) {
407 free(parseTarPath->longLink);
408 parseTarPath->longLink = nullptr;
409 }
410 }
411
412 // anyway, go to correct pos
413 isSkip = true;
414 fseeko(FilePtr, tarFileInfo.pos + tarFileInfo.fileBlockCnt * BLOCK_SIZE, SEEK_SET);
415 }
416
HandleGnuLongName(ParseTarPath * parseTarPath,bool & isSkip,TarFileInfo & tarFileInfo)417 void UnTarFile::HandleGnuLongName(ParseTarPath *parseTarPath, bool &isSkip, TarFileInfo &tarFileInfo)
418 {
419 if (parseTarPath->longName != nullptr) {
420 free(parseTarPath->longName);
421 parseTarPath->longName = nullptr;
422 }
423 size_t nameLen = (size_t)tarFileInfo.fileSize;
424 if (nameLen < PATH_MAX_LEN) {
425 parseTarPath->longName = (char *)malloc((nameLen + 1) * sizeof(char));
426 }
427 if (parseTarPath->longName != nullptr) {
428 memset_s(parseTarPath->longName, (nameLen + 1) * sizeof(char), 0, (nameLen + 1) * sizeof(char));
429 if (nameLen != fread(parseTarPath->longName, sizeof(char), nameLen, FilePtr)) {
430 free(parseTarPath->longName);
431 parseTarPath->longName = nullptr;
432 }
433 }
434
435 // anyway, go to correct pos
436 isSkip = true;
437 fseeko(FilePtr, tarFileInfo.pos + tarFileInfo.fileBlockCnt * BLOCK_SIZE, SEEK_SET);
438 }
439
HandleRegularFile(char * buff,EParseType type,ParseTarPath * parseTarPath,bool & isSkip,TarFileInfo & tarFileInfo)440 void UnTarFile::HandleRegularFile(char *buff, EParseType type, ParseTarPath *parseTarPath, bool &isSkip,
441 TarFileInfo &tarFileInfo)
442 {
443 if (eList == type) {
444 file_names.push_back(std::string(parseTarPath->realName));
445 file_sizes.push_back(tarFileInfo.fileSize);
446 file_data_addrs.push_back(tarFileInfo.pos);
447
448 fseeko(FilePtr, tarFileInfo.fileBlockCnt * BLOCK_SIZE, SEEK_CUR);
449 return;
450 }
451 if (eUnpack == type) {
452 HandleRegularEUnpackFile(buff, parseTarPath, isSkip, tarFileInfo);
453 }
454 }
455
FileReadAndWrite(char * destBuff,FILE * destF,size_t readBuffSize)456 bool UnTarFile::FileReadAndWrite(char *destBuff, FILE *destF, size_t readBuffSize)
457 {
458 if (readBuffSize != fread(destBuff, sizeof(char), readBuffSize, FilePtr)) {
459 LOGE("read file content shorter than expect!\n");
460 return false;
461 }
462
463 if (readBuffSize != fwrite(destBuff, sizeof(char), readBuffSize, destF)) {
464 LOGE("write file content shorter than expect!\n");
465 return false;
466 }
467 return true;
468 }
469
HandleRegularEUnpackFile(char * buff,ParseTarPath * parseTarPath,bool & isSkip,TarFileInfo & tarFileInfo)470 void UnTarFile::HandleRegularEUnpackFile(char *buff, ParseTarPath *parseTarPath, bool &isSkip, TarFileInfo &tarFileInfo)
471 {
472 TarHeader *tarHeader = (TarHeader *)buff;
473 char *destBuff = (char *)malloc(READ_BUFF_SIZE * sizeof(char));
474 if (destBuff == nullptr) {
475 LOGE("malloc memory fail!skip!");
476 isSkip = false;
477 return;
478 }
479 FILE *destF = CreateFile(parseTarPath->fullPath, FILE_MODE, tarHeader->typeflag);
480 if (destF == nullptr) {
481 LOGE("destF is null!");
482 free(destBuff);
483 fseeko(FilePtr, tarFileInfo.fileBlockCnt * BLOCK_SIZE, SEEK_CUR);
484 isSkip = false;
485 return;
486 }
487 memset_s(destBuff, READ_BUFF_SIZE * sizeof(char), 0, READ_BUFF_SIZE * sizeof(char));
488 bool isInvalid = false;
489 off_t readBuffSize = READ_BUFF_SIZE;
490 off_t restSize = tarFileInfo.fileSize;
491 while (restSize > 0) {
492 if (restSize < READ_BUFF_SIZE) {
493 readBuffSize = restSize;
494 }
495 if (!FileReadAndWrite(destBuff, destF, readBuffSize)) {
496 isInvalid = true;
497 break;
498 }
499 restSize -= readBuffSize;
500 }
501
502 if (destBuff != nullptr) {
503 free(destBuff);
504 destBuff = nullptr;
505 }
506 if (destF != nullptr) {
507 fflush(destF);
508 (void)fclose(destF);
509 destF = nullptr;
510 }
511 if (isInvalid) {
512 unlink(parseTarPath->fullPath);
513 isSkip = true;
514 } else {
515 isSkip = false;
516 }
517 // anyway, go to correct pos
518 fseeko(FilePtr, tarFileInfo.pos + tarFileInfo.fileBlockCnt * BLOCK_SIZE, SEEK_SET);
519 }
520
IsProcessTarEnd(char * buff,int & ret)521 bool UnTarFile::IsProcessTarEnd(char *buff, int &ret)
522 {
523 size_t readCnt = fread(buff, 1, BLOCK_SIZE, FilePtr);
524 if (readCnt < BLOCK_SIZE) {
525 LOGE("read short than 512 expected, got %{public}zu, tarSize", readCnt);
526
527 // when split unpack, ftell size is over than file really size [0,READ_BUFF_SIZE]
528 if (!isSplit || readCnt != 0 || ftello(FilePtr) > (tarSize + READ_BUFF_SIZE)) {
529 ret = ERR_IO;
530 }
531 return true;
532 }
533
534 // two empty continuous block indicate end of file
535 if (IsEmptyBlock(buff)) {
536 char tailBuff[BLOCK_SIZE] = {0};
537 size_t tailRead = 0;
538 tailRead = fread(tailBuff, 1, BLOCK_SIZE, FilePtr);
539 if ((tailRead == BLOCK_SIZE) && IsEmptyBlock(tailBuff)) {
540 LOGI("untarfile is end.Success!");
541 return true;
542 }
543 }
544
545 // check header
546 TarHeader *tarHeader = (TarHeader *)buff;
547 if (!IsValidTarBlock(tarHeader)) {
548 LOGE("isSplit cur size %{public}jd, tarSize %{public}jd", ftello(FilePtr), tarSize);
549
550 // when split unpack, ftell size is over than file really size [0,READ_BUFF_SIZE]
551 if (!isSplit || ftello(FilePtr) > (tarSize + READ_BUFF_SIZE) || !IsEmptyBlock(buff)) {
552 ret = ERR_FORMAT;
553 }
554 return true;
555 }
556 return false;
557 }
558
ParseTarFile(const char * rootPath,EParseType type)559 int UnTarFile::ParseTarFile(const char *rootPath, EParseType type)
560 {
561 ParseTarPath parseTarPath = {};
562 int ret = CheckFileAndInitPath(rootPath, &parseTarPath);
563 if (ret != 0) {
564 return ret;
565 }
566 LOGI("ParseTarFile");
567
568 // re-parse tar header
569 char buff[BLOCK_SIZE] = {};
570 bool isSkip = false;
571 bool isSoftLink = false;
572 const off_t blockCnt = tarSize / BLOCK_SIZE;
573 for (off_t i = 0; i < blockCnt; i++) {
574 if (IsProcessTarEnd(buff, ret)) {
575 FreePointer(&parseTarPath);
576 return ret;
577 }
578
579 TarHeader *tarHeader = (TarHeader *)buff;
580 parseTarPath.realName = tarHeader->name;
581 if (parseTarPath.longName != nullptr) {
582 parseTarPath.realName = parseTarPath.longName;
583 }
584
585 GenRealPath(rootPath, parseTarPath.realName, parseTarPath.fullPath);
586 parseTarPath.realLink = tarHeader->linkname;
587 if (parseTarPath.longLink != nullptr) {
588 parseTarPath.realLink = parseTarPath.longLink;
589 }
590
591 CreateDir(const_cast<char *>(rootPath), FILE_MODE);
592
593 if (!ProcessTarBlock(buff, type, &parseTarPath, isSkip, isSoftLink)) {
594 FreePointer(&parseTarPath);
595 return ret;
596 }
597 }
598 LOGI("blockCnt overflow");
599 FreePointer(&parseTarPath);
600 return ret;
601 }
602
FreePointer(ParseTarPath * parseTarPath)603 void UnTarFile::FreePointer(ParseTarPath *parseTarPath)
604 {
605 if (parseTarPath->fullPath != nullptr) {
606 free(parseTarPath->fullPath);
607 parseTarPath->fullPath = nullptr;
608 }
609 if (parseTarPath->longName != nullptr) {
610 free(parseTarPath->longName);
611 parseTarPath->longName = nullptr;
612 }
613 if (parseTarPath->longLink != nullptr) {
614 free(parseTarPath->longLink);
615 parseTarPath->longLink = nullptr;
616 }
617 }
618
FreeLongTypePointer(ParseTarPath * parseTarPath)619 void UnTarFile::FreeLongTypePointer(ParseTarPath *parseTarPath)
620 {
621 if (parseTarPath->longName != nullptr) {
622 free(parseTarPath->longName);
623 parseTarPath->longName = nullptr;
624 }
625 if (parseTarPath->longLink != nullptr) {
626 free(parseTarPath->longLink);
627 parseTarPath->longLink = nullptr;
628 }
629 }
630
CreateDirWithRecursive(const std::string & filePath,mode_t mode)631 bool UnTarFile::CreateDirWithRecursive(const std::string &filePath, mode_t mode)
632 {
633 if (filePath.empty()) {
634 LOGE("CreateDirWithRecursive filePath is empty");
635 return false;
636 }
637 if (access(filePath.c_str(), F_OK) == 0) {
638 return true;
639 }
640
641 LOGI("CreateDirWithRecursive filePath %{public}s is not exist, need create", filePath.c_str());
642 std::string::size_type index = 0;
643 do {
644 index = filePath.find('/', index + 1);
645 std::string subPath = (index == std::string::npos) ? filePath : filePath.substr(0, index);
646 if (access(subPath.c_str(), F_OK) != 0) {
647 if (mkdir(subPath.c_str(), mode) != 0) {
648 return false;
649 }
650 }
651 } while (index != std::string::npos);
652 return access(filePath.c_str(), F_OK) == 0;
653 }
654 } // namespace installd
655