diff --git a/frameworks/native/backup_ext/include/ext_extension.h b/frameworks/native/backup_ext/include/ext_extension.h index db933dad2a0667de58fc464f371a91820fa26af8..ae249cdc63a855440b0195ca12a60f7a4b64371d 100644 --- a/frameworks/native/backup_ext/include/ext_extension.h +++ b/frameworks/native/backup_ext/include/ext_extension.h @@ -336,7 +336,9 @@ private: void ClearNoPermissionFiles(TarMap &pkgInfo, vector &noPermissionFiles); std::function ReportOnProcessResultCallback(wptr obj, BackupRestoreScenario scenario); - + bool IfCloudSpecialRestore(std::string tarName); + ErrCode CloudSpecialRestore(std::string tarName, std::string untarPath, off_t tarFileSize); + void GetTarIncludes(const string &tarName, unordered_map &infos); private: std::shared_mutex lock_; std::shared_ptr extension_; diff --git a/frameworks/native/backup_ext/include/tar_file.h b/frameworks/native/backup_ext/include/tar_file.h index a728e4d4a10cad406e2c9f442e76bb801f4a646d..d183d88854d402d4e118d5118e6a6b97a7bbdcd4 100644 --- a/frameworks/native/backup_ext/include/tar_file.h +++ b/frameworks/native/backup_ext/include/tar_file.h @@ -56,6 +56,8 @@ const char AREGTYPE = '\0'; // regular file const char SYMTYPE = '2'; // reserved const char DIRTYPE = '5'; // directory const char GNUTYPE_LONGNAME = 'L'; +const char EXTENSION_HEADER = 'x'; +const int OTHER_HEADER = 78; const int ERR_NO_PERMISSION = 13; } // namespace diff --git a/frameworks/native/backup_ext/include/untar_file.h b/frameworks/native/backup_ext/include/untar_file.h index e08be8853dd047865d5dd11d28c8617e64720fff..9db404b5159b308767cc61b76a924a8f909ad0bc 100644 --- a/frameworks/native/backup_ext/include/untar_file.h +++ b/frameworks/native/backup_ext/include/untar_file.h @@ -191,6 +191,15 @@ private: bool DealFileTag(ErrFileInfo &errFileInfo, FileStatInfo &info, bool &isFilter, const std::string &tmpFullPath); + std::tuple ParsePaxBlock(); + + void CheckLongName(std::string &longName); + + std::tuple GetLongName(uint32_t recLen, uint32_t allLen); + + std::tuple CaseScene(bool isFilter, ErrFileInfo &errFileInfo, + std::string tmpFullPath, char typeFlag, FileStatInfo &info); + private: std::string rootPath_ {}; diff --git a/frameworks/native/backup_ext/src/ext_extension.cpp b/frameworks/native/backup_ext/src/ext_extension.cpp index 1119285af81d4ed82d7d34ba1f241f1681813c15..cc95f58575d3f0ef0d36b53b92a433e1caf32f6d 100644 --- a/frameworks/native/backup_ext/src/ext_extension.cpp +++ b/frameworks/native/backup_ext/src/ext_extension.cpp @@ -313,7 +313,7 @@ static tuple GetIncreFileHandleForSpecialVersion(co "GetIncreFileHandleForSpecialVersion", "CommonFile", GetAnonyPath(path)}; HiAudit::GetInstance(false).Write(auditLog); } - string reportName = path + BConstants::BLANK_REPORT_NAME; + string reportName = GetReportFileName(fileName); UniqueFd reportFd(open(reportName.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); if (reportFd < 0) { HILOGE("Failed to open report file = %{private}s, err = %{public}d", reportName.c_str(), errno); @@ -904,7 +904,7 @@ int BackupExtExtension::DoRestore(const string &fileName, const off_t fileSize) return ERR_OK; } -static void GetTarIncludes(const string &tarName, unordered_map &infos) +void BackupExtExtension::GetTarIncludes(const string &tarName, unordered_map &infos) { // 获取简报文件内容 string reportName = GetReportFileName(tarName); @@ -1117,6 +1117,10 @@ ErrCode BackupExtExtension::RestoreTarForSpecialCloneCloud(const ExtManageInfo & HILOGE("Check spec tarfile path : %{public}s err, path is forbidden", GetAnonyPath(untarPath).c_str()); return ERR_INVALID_VALUE; } + if (IfCloudSpecialRestore(tarName)) { + auto ret = CloudSpecialRestore(tarName, untarPath, item.sta.st_size); + return ret; + } auto [err, fileInfos, errInfos] = UntarFile::GetInstance().UnPacket(tarName, untarPath); if (isDebug_) { endFileInfos_.merge(fileInfos); diff --git a/frameworks/native/backup_ext/src/sub_ext_extension.cpp b/frameworks/native/backup_ext/src/sub_ext_extension.cpp index 24e2a9c110254d418bf60209a9816489a1beb764..08c511353e899727c37bdd2db1e01748b02a5546 100644 --- a/frameworks/native/backup_ext/src/sub_ext_extension.cpp +++ b/frameworks/native/backup_ext/src/sub_ext_extension.cpp @@ -1357,4 +1357,34 @@ void BackupExtExtension::CompareFiles(vector &allFiles, } } } + +bool BackupExtExtension::IfCloudSpecialRestore(string tarName) +{ + unordered_map result; + GetTarIncludes(tarName, result); + if (result.empty()) { + HILOGI("is not CloudSpecialRestore"); + return false; + } + HILOGI("is CloudSpecialRestore"); + return true; +} + +ErrCode BackupExtExtension::CloudSpecialRestore(string tarName, string untarPath, off_t tarFileSize) +{ + unordered_map result; + GetTarIncludes(tarName, result); + if (isDebug_) { + FillEndFileInfos(untarPath, result); + } + auto unPacketRes = UntarFile::GetInstance().IncrementalUnPacket(tarName, untarPath, result); + ErrCode err = ERR_OK; + err = std::get(unPacketRes); + if (int tmpErr = DealIncreUnPacketResult(tarFileSize, tarName, unPacketRes); tmpErr != ERR_OK) { + return BError(BError::Codes::EXT_FORBID_BACKUP_RESTORE).GetCode(); + } + HILOGI("Application recovered successfully, package path is %{public}s", tarName.c_str()); + DeleteBackupIncrementalTars(tarName); + return err; +} } // namespace OHOS::FileManagement::Backup diff --git a/frameworks/native/backup_ext/src/untar_file.cpp b/frameworks/native/backup_ext/src/untar_file.cpp index 76181b091429ddae80ca836b62e06ab45ac75761..3f05fd0789b8bdba11bbf578e2e208b93697db82 100644 --- a/frameworks/native/backup_ext/src/untar_file.cpp +++ b/frameworks/native/backup_ext/src/untar_file.cpp @@ -399,14 +399,9 @@ bool UntarFile::DealFileTag(ErrFileInfo &errFileInfo, return true; } - -std::tuple UntarFile::ParseIncrementalFileByTypeFlag(char typeFlag, FileStatInfo &info) +std::tuple UntarFile::CaseScene(bool isFilter, ErrFileInfo &errFileInfo, + string tmpFullPath, char typeFlag, FileStatInfo &info) { - HILOGD("untar file: %{public}s, rootPath: %{public}s", GetAnonyPath(info.fullPath).c_str(), rootPath_.c_str()); - string tmpFullPath = info.fullPath; - bool isFilter = true; - ErrFileInfo errFileInfo; - RTrimNull(tmpFullPath); switch (typeFlag) { case REGTYPE: case AREGTYPE: { @@ -435,6 +430,16 @@ std::tuple UntarFile::ParseIncrementalFileByTypeFlag(cha return {std::get(result), isFilter, std::get(result)}; break; } + case EXTENSION_HEADER: { // pax x header + auto [err, LongName] = ParsePaxBlock(); + if (err == ERR_OK) { + CheckLongName(LongName); + info.longName = LongName; + return {err, true, errFileInfo}; + } + return {err, isFilter, {{info.fullPath, {DEFAULT_ERR}}}}; + break; + } default: { if (fseeko(tarFilePtr_, tarFileBlockCnt_ * BLOCK_SIZE, SEEK_CUR) != 0) { HILOGE("Failed to fseeko of %{private}s, err = %{public}d", info.fullPath.c_str(), errno); @@ -443,10 +448,19 @@ std::tuple UntarFile::ParseIncrementalFileByTypeFlag(cha break; } } - return {0, isFilter, errFileInfo}; } +std::tuple UntarFile::ParseIncrementalFileByTypeFlag(char typeFlag, FileStatInfo &info) +{ + HILOGD("untar file: %{public}s, rootPath: %{public}s", GetAnonyPath(info.fullPath).c_str(), rootPath_.c_str()); + string tmpFullPath = info.fullPath; + bool isFilter = true; + ErrFileInfo errFileInfo; + RTrimNull(tmpFullPath); + return CaseScene(isFilter, errFileInfo, tmpFullPath, typeFlag, info); +} + ErrFileInfo UntarFile::ParseRegularFile(FileStatInfo &info) { ErrFileInfo errFileInfo; @@ -600,4 +614,103 @@ FILE *UntarFile::CreateFile(string &filePath) return f; } +std::tuple UntarFile::ParsePaxBlock() +{ + ErrCode err = DEFAULT_ERR; + char block[BLOCK_SIZE] = {0}; + auto readCnt_ = fread(block, 1, BLOCK_SIZE, tarFilePtr_); + if (readCnt_ < BLOCK_SIZE) { + HILOGE("Parsing tar file completed, read data count is less then block size."); + return {err, ""}; + } + string content(block, BLOCK_SIZE); + string longName = ""; + size_t pos = 0; + uint32_t recLen = 0; + uint32_t allLen = 0; + bool isLongName = false; + while (pos < BLOCK_SIZE) { + size_t lenEnd = content.find(' ', pos); + if (lenEnd == string::npos) { + err = ERR_OK; + break; + } + string pathLen = content.substr(pos, lenEnd - pos); + recLen = std::atoi(pathLen.c_str()); + allLen = recLen + OTHER_HEADER; + if (allLen > BLOCK_SIZE) { + isLongName = true; + break; + } + string kvPair = content.substr(lenEnd + 1, recLen - (lenEnd - pos + 1)); + size_t eqPos = kvPair.find('='); + string key = kvPair.substr(0, eqPos); + string value = kvPair.substr(eqPos + 1); + if (key == "path") { + longName = value; + err = ERR_OK; + } + pos += recLen; + } + if (isLongName) { + HILOGI("is long name"); + return GetLongName(recLen, allLen); + } + return {err, longName}; +} + +void UntarFile::CheckLongName(std::string &longName) +{ + if (!longName.empty() && longName.back() == '\n') { + longName.pop_back(); + } + HILOGI("this longName = %{public}s", longName.c_str()); +} + +std::tuple UntarFile::GetLongName(uint32_t recLen, uint32_t allLen) +{ + ErrCode err = DEFAULT_ERR; + off_t curPos = ftello(tarFilePtr_); + if (fseeko(tarFilePtr_, curPos - BLOCK_SIZE, SEEK_SET) != 0) { + HILOGE("fseeko failed"); + return {err, ""}; + } + double result = static_cast(allLen) / BLOCK_SIZE; + auto ret = static_cast(std::ceil(result)); + auto curSize = ret * BLOCK_SIZE; + char *block = new char[curSize]; + if (memset_s(block, curSize, 0, curSize) != EOK) { + delete[] block; + return {err, ""}; + } + auto readCnt_ = fread(block, 1, curSize, tarFilePtr_); + if (readCnt_ < curSize) { + HILOGE("Parsing tar file completed, read data count is less then block size."); + delete[] block; + return {err, ""}; + } + string content(block, curSize); + string longName = ""; + size_t pos = 0; + while (pos < curSize) { + size_t lenEnd = content.find(' ', pos); + if (lenEnd == string::npos) { + err = ERR_OK; + break; + } + string pathLen = content.substr(pos, lenEnd - pos); + int recLen = std::atoi(pathLen.c_str()); + string KvPair = content.substr(lenEnd + 1, recLen - (lenEnd - pos + 1)); + size_t eqPos = KvPair.find('='); + string key = KvPair.substr(0, eqPos); + string value = KvPair.substr(eqPos + 1); + if (key == "path") { + longName = value; + err = ERR_OK; + } + pos += recLen; + } + delete[] block; + return {err, longName}; +} } // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_ext/ext_extension_test.cpp b/tests/unittests/backup_ext/ext_extension_test.cpp index f4d66f998fd3f47e0d18c3527cd4eb199c60d9ba..204661ec83771f82215ab871895d752ab9aaaeda 100644 --- a/tests/unittests/backup_ext/ext_extension_test.cpp +++ b/tests/unittests/backup_ext/ext_extension_test.cpp @@ -222,29 +222,6 @@ HWTEST_F(ExtExtensionTest, Ext_Extension_Test_0302, testing::ext::TestSize.Level GTEST_LOG_(INFO) << "ExtExtensionTest-end Ext_Extension_Test_0302"; } -/** - * @tc.number: SUB_Ext_Extension_0400 - * @tc.name: Ext_Extension_Test_0400 - * @tc.desc: 测试打开失败 - * @tc.size: MEDIUM - * @tc.type: FUNC - * @tc.level Level 1 - * @tc.require: I9P3Y3 - */ -HWTEST_F(ExtExtensionTest, Ext_Extension_Test_0400, testing::ext::TestSize.Level1) -{ - GTEST_LOG_(INFO) << "ExtExtensionTest-begin Ext_Extension_Test_0400"; - try { - string tarName = " "; - unordered_map infos; - GetTarIncludes(tarName, infos); - EXPECT_EQ(infos.size(), 0); - } catch (...) { - EXPECT_TRUE(false); - GTEST_LOG_(INFO) << "ExtExtensionTest-an exception occurred by construction."; - } - GTEST_LOG_(INFO) << "ExtExtensionTest-end Ext_Extension_Test_0400"; -} /** * @tc.number: SUB_Ext_Extension_0500 diff --git a/tests/unittests/backup_ext/untar_file_sup_test.cpp b/tests/unittests/backup_ext/untar_file_sup_test.cpp index ba695a52c4ae04f24e733e5c9f8aa07afb030294..1cf75e534fd914214b6c90edf98ac1e037eb5914 100644 --- a/tests/unittests/backup_ext/untar_file_sup_test.cpp +++ b/tests/unittests/backup_ext/untar_file_sup_test.cpp @@ -945,7 +945,7 @@ HWTEST_F(UntarFileSupTest, SUB_Untar_File_ParseIncrementalTarFile_0100, testing: string sum = "01647"; TarHeader header; - header.typeFlag = 'x'; + header.typeFlag = 'y'; memcpy_s(&header.magic, sizeof(header.magic), TMAGIC.c_str(), TMAGIC.length()); memcpy_s(&header.chksum, sizeof(header.chksum), sum.c_str(), sum.length()); EXPECT_CALL(*funcMock, fseeko(_, _, _)).WillOnce(Return(0)).WillOnce(Return(0)).WillOnce(Return(EPERM)); @@ -972,6 +972,41 @@ HWTEST_F(UntarFileSupTest, SUB_Untar_File_ParseIncrementalTarFile_0100, testing: GTEST_LOG_(INFO) << "UntarFileSupTest-end SUB_Untar_File_ParseIncrementalTarFile_0100"; } +/** + * @tc.number: SUB_Untar_File_ParseIncrementalTarFile_0200 + * @tc.name: SUB_Untar_File_ParseIncrementalTarFile_0200 + * @tc.desc: 测试 ParseIncrementalTarFile 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: I6F3GV + */ +HWTEST_F(UntarFileSupTest, SUB_Untar_File_ParseIncrementalTarFile_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "UntarFileSupTest-begin SUB_Untar_File_ParseIncrementalTarFile_0200"; + try { + string rootPath; + string sum = "01647"; + TarHeader header; + header.typeFlag = 'x'; + memcpy_s(&header.magic, sizeof(header.magic), TMAGIC.c_str(), TMAGIC.length()); + memcpy_s(&header.chksum, sizeof(header.chksum), sum.c_str(), sum.length()); + EXPECT_CALL(*funcMock, fseeko(_, _, _)).WillOnce(Return(0)).WillOnce(Return(0)); + EXPECT_CALL(*funcMock, ftello(_)).WillOnce(Return(0)).WillOnce(Return(0)); + EXPECT_CALL(*funcMock, fread(_, _, _, _)).WillOnce(WithArgs<0>(Invoke([&header](void* buff) { + memcpy_s(buff, BLOCK_SIZE, &header, sizeof(header)); + return BLOCK_SIZE; + }))).WillOnce(Return(0)).WillOnce(Return(0)); + auto [ret, info, err] = UntarFile::GetInstance().ParseIncrementalTarFile(rootPath); + EXPECT_EQ(ret, 0); + + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "UntarFileSupTest-an exception occurred by ParseIncrementalTarFile."; + } + GTEST_LOG_(INFO) << "UntarFileSupTest-end SUB_Untar_File_ParseIncrementalTarFile_0200"; +} + /** * @tc.number: SUB_Untar_File_HandleTarBuffer_0100 * @tc.name: SUB_Untar_File_HandleTarBuffer_0100