• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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