diff --git a/frameworks/native/backup_ext/src/untar_file.cpp b/frameworks/native/backup_ext/src/untar_file.cpp index 52c9964d3fda02fcd318f710a181a43e441c1882..bf367c10be78ec8dc59171640462c40a55ec76a5 100644 --- a/frameworks/native/backup_ext/src/untar_file.cpp +++ b/frameworks/native/backup_ext/src/untar_file.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -178,8 +178,9 @@ int UntarFile::ParseTarFile(const string &rootPath) HILOGE("Parsing tar file completed, read data count is less then block size."); return 0; } + TarHeader *header = reinterpret_cast(buff); // two empty continuous block indicate end of file - if (IsEmptyBlock(buff)) { + if (IsEmptyBlock(buff) && header->typeFlag != GNUTYPE_LONGNAME) { char tailBuff[BLOCK_SIZE] = {0}; size_t tailRead = fread(tailBuff, 1, BLOCK_SIZE, tarFilePtr_); if (tailRead == BLOCK_SIZE && IsEmptyBlock(tailBuff)) { @@ -188,7 +189,6 @@ int UntarFile::ParseTarFile(const string &rootPath) } } // check header - TarHeader *header = reinterpret_cast(buff); if (!IsValidTarBlock(*header)) { // when split unpack, ftell size is over than file really size [0,READ_BUFF_SIZE] if (ftello(tarFilePtr_) > (tarFileSize_ + READ_BUFF_SIZE) || !IsEmptyBlock(buff)) { @@ -442,6 +442,9 @@ string UntarFile::GenRealPath(const string &rootPath, const string &realName) realPath = realPath.substr(0, len - 1); } realPath.append((realName[0] == '/') ? realName : ("/" + realName)); + if (realPath[0] == '/') { + realPath = realPath.substr(1, realPath.length()); + } return realPath; } diff --git a/tests/unittests/backup_ext/untar_file_test.cpp b/tests/unittests/backup_ext/untar_file_test.cpp index bc9dc946243a4e6be9060506b70af9a3e3131742..60df5d74ccdf5ef7804c6b6e231e0bf7b32fdafe 100644 --- a/tests/unittests/backup_ext/untar_file_test.cpp +++ b/tests/unittests/backup_ext/untar_file_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Copyright (c) 2022-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -220,4 +220,55 @@ HWTEST_F(UntarFileTest, SUB_Untar_File_UnPacket_0400, testing::ext::TestSize.Lev } GTEST_LOG_(INFO) << "UntarFileTest-end SUB_Untar_File_UnPacket_0400"; } + +/** + * @tc.number: SUB_Untar_File_UnPacket_0500 + * @tc.name: SUB_Untar_File_UnPacket_0500 + * @tc.desc: 测试 UnPacket 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: I6F3GV + */ +HWTEST_F(UntarFileTest, SUB_Untar_File_UnPacket_0500, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "UntarFileTest-begin SUB_Untar_File_UnPacket_0500"; + try { + // 预置文件和目录 + TestManager tm("SUB_Untar_File_UnPacket_0500"); + string root = tm.GetRootDirCurTest(); + string testDir = root + "/testdir/"; + if (mkdir(testDir.data(), S_IRWXU) && errno != EEXIST) { + GTEST_LOG_(INFO) << " invoked mkdir failure, errno :" << errno; + throw BError(errno); + } + string aFile = testDir; + string bFile = testDir; + // 循环100次,用来构造超长路径和超长文件名 + for (int i = 0; i < 100; i++) { + aFile += "test001/test002/test003/test004/test005/"; + bFile += "ab"; + } + aFile += "a.txt"; + bFile += ".txt"; + SaveStringToFile(aFile, "hello"); + SaveStringToFile(bFile, "world"); + + string tarFile = root + "/test.0.tar"; + TarMap tarMap {}; + vector smallFiles; + smallFiles.emplace_back(aFile); + smallFiles.emplace_back(bFile); + TarFile::GetInstance().Packet(smallFiles, "test", root, tarMap); + + string rootPath(root); + int ret = UntarFile::GetInstance().UnPacket(tarFile, rootPath); + EXPECT_EQ(ret, 0); + ClearCache(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "UntarFileTest-an exception occurred by UntarFile."; + } + GTEST_LOG_(INFO) << "UntarFileTest-end SUB_Untar_File_UnPacket_0500"; +} } // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_filesystem/b_dir.cpp b/utils/src/b_filesystem/b_dir.cpp index 3f02020cd43bd93a6b9bd850f3d243cc5a287fa5..618bcbb7c53f854c86a817aa18d62e51a0ff2861 100644 --- a/utils/src/b_filesystem/b_dir.cpp +++ b/utils/src/b_filesystem/b_dir.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Copyright (c) 2022-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -34,6 +34,7 @@ namespace OHOS::FileManagement::Backup { using namespace std; +const int32_t PATH_MAX_LEN = 4096; static bool IsEmptyDirectory(const string &path) { @@ -72,6 +73,17 @@ static tuple, vector> GetFile(const st return {BError(BError::Codes::OK).GetCode(), files, smallFiles}; } +static uint32_t CheckOverLongPath(const string &path) +{ + uint32_t len = path.length(); + if (len >= PATH_MAX_LEN) { + size_t found = path.find_last_of('/'); + string sub = path.substr(found + 1); + HILOGE("Path over long, length:%{public}d, fileName:%{public}s.", len, sub.c_str()); + } + return len; +} + static tuple, vector> GetDirFilesDetail(const string &path, bool recursion, off_t size = -1) @@ -114,7 +126,7 @@ static tuple, vector> GetDirFilesDetai } else { struct stat sta = {}; string fileName = IncludeTrailingPathDelimiter(path) + string(ptr->d_name); - if (stat(fileName.data(), &sta) == -1) { + if (CheckOverLongPath(fileName) >= PATH_MAX_LEN || stat(fileName.data(), &sta) == -1) { continue; } if (sta.st_size <= size) {