From 415939bd11d3eb174884edb68e1f084fbba448ad Mon Sep 17 00:00:00 2001 From: changleipeng Date: Mon, 16 Dec 2024 10:36:38 +0800 Subject: [PATCH] test Signed-off-by: changleipeng --- tools/hmfs-tools/BUILD.gn | 32 + tools/hmfs-tools/hmfs.gni | 19 + tools/hmfs-tools/test/unittest/BUILD.gn | 27 + .../test/unittest/mkfs_test/BUILD.gn | 77 + .../unittest/mkfs_test/mkfs_multi_test.cpp | 1267 +++++++++++ .../unittest/mkfs_test/mkfs_single_test.cpp | 1899 +++++++++++++++++ .../test/unittest/resize_test/BUILD.gn | 73 + .../resize_test/resize_multi_test.cpp | 575 +++++ .../resize_test/resize_single_test.cpp | 1504 +++++++++++++ tools/hmfs-tools/test/unittest/utils/BUILD.gn | 33 + .../test/unittest/utils/dump_test.cpp | 30 + .../test/unittest/utils/hmfs_check.cpp | 0 .../test/unittest/utils/hmfs_check.h | 0 .../test/unittest/utils/hmfs_test_utils.cpp | 1523 +++++++++++++ .../test/unittest/utils/hmfs_test_utils.h | 226 ++ ...346\226\260\346\226\207\344\273\266 9.txt" | 45 + tools/hmfs-tools/tools/common/BUILD.gn | 60 + .../tools/common/device_manager.cpp | 341 +++ .../hmfs-tools/tools/common/device_manager.h | 79 + .../hmfs-tools/tools/common/hmfs_command.cpp | 150 ++ tools/hmfs-tools/tools/common/hmfs_command.h | 115 + tools/hmfs-tools/tools/common/hmfs_common.cpp | 920 ++++++++ tools/hmfs-tools/tools/common/hmfs_common.h | 131 ++ tools/hmfs-tools/tools/common/hmfs_data.h | 501 +++++ tools/hmfs-tools/tools/common/hmfs_define.h | 567 +++++ .../hmfs-tools/tools/common/hmfs_encoding.cpp | 313 +++ tools/hmfs-tools/tools/common/hmfs_encoding.h | 50 + tools/hmfs-tools/tools/common/hmfs_io.cpp | 777 +++++++ tools/hmfs-tools/tools/common/hmfs_io.h | 134 ++ tools/hmfs-tools/tools/common/hmfs_quota.h | 92 + tools/hmfs-tools/tools/common/hmfs_utils.h | 92 + tools/hmfs-tools/tools/common/hmfs_zoned.cpp | 561 +++++ tools/hmfs-tools/tools/common/hmfs_zoned.h | 108 + tools/hmfs-tools/tools/mkfs/BUILD.gn | 60 + .../tools/mkfs/include/area_formater.h | 35 + .../hmfs-tools/tools/mkfs/include/cp_writer.h | 90 + .../tools/mkfs/include/main_writer.h | 67 + .../tools/mkfs/include/mkfs_command.h | 72 + .../tools/mkfs/include/mkfs_format.h | 132 ++ .../tools/mkfs/include/nat_writer.h | 52 + .../tools/mkfs/include/sit_writer.h | 45 + .../tools/mkfs/include/super_block_writer.h | 64 + tools/hmfs-tools/tools/mkfs/src/cp_writer.cpp | 501 +++++ .../hmfs-tools/tools/mkfs/src/main_writer.cpp | 524 +++++ .../tools/mkfs/src/mkfs_command.cpp | 461 ++++ .../hmfs-tools/tools/mkfs/src/mkfs_format.cpp | 481 +++++ .../hmfs-tools/tools/mkfs/src/nat_writer.cpp | 114 + .../hmfs-tools/tools/mkfs/src/sit_writer.cpp | 64 + .../tools/mkfs/src/super_block_writer.cpp | 339 +++ tools/hmfs-tools/tools/resize/BUILD.gn | 59 + tools/hmfs-tools/tools/resize/include/node.h | 320 +++ .../tools/resize/include/resize_command.h | 93 + .../tools/resize/include/resize_data.h | 518 +++++ .../tools/resize/include/resize_defrag.h | 67 + .../tools/resize/include/resize_list.h | 149 ++ .../tools/resize/include/resize_load.h | 67 + .../tools/resize/include/resize_load_cp.h | 48 + .../tools/resize/include/resize_load_nat.h | 45 + .../tools/resize/include/resize_load_sb.h | 51 + .../tools/resize/include/resize_load_sit.h | 70 + .../tools/resize/include/resize_operator.h | 91 + .../tools/resize/include/resize_utils.h | 349 +++ .../tools/resize/src/resize_command.cpp | 344 +++ .../tools/resize/src/resize_defrag.cpp | 456 ++++ .../tools/resize/src/resize_load.cpp | 679 ++++++ .../tools/resize/src/resize_load_cp.cpp | 330 +++ .../tools/resize/src/resize_load_nat.cpp | 156 ++ .../tools/resize/src/resize_load_sb.cpp | 392 ++++ .../tools/resize/src/resize_load_sit.cpp | 432 ++++ .../tools/resize/src/resize_main.cpp | 35 + .../tools/resize/src/resize_operator.cpp | 1338 ++++++++++++ 71 files changed, 21511 insertions(+) create mode 100755 tools/hmfs-tools/BUILD.gn create mode 100755 tools/hmfs-tools/hmfs.gni create mode 100755 tools/hmfs-tools/test/unittest/BUILD.gn create mode 100755 tools/hmfs-tools/test/unittest/mkfs_test/BUILD.gn create mode 100755 tools/hmfs-tools/test/unittest/mkfs_test/mkfs_multi_test.cpp create mode 100755 tools/hmfs-tools/test/unittest/mkfs_test/mkfs_single_test.cpp create mode 100755 tools/hmfs-tools/test/unittest/resize_test/BUILD.gn create mode 100755 tools/hmfs-tools/test/unittest/resize_test/resize_multi_test.cpp create mode 100755 tools/hmfs-tools/test/unittest/resize_test/resize_single_test.cpp create mode 100755 tools/hmfs-tools/test/unittest/utils/BUILD.gn create mode 100755 tools/hmfs-tools/test/unittest/utils/dump_test.cpp create mode 100755 tools/hmfs-tools/test/unittest/utils/hmfs_check.cpp create mode 100755 tools/hmfs-tools/test/unittest/utils/hmfs_check.h create mode 100755 tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.cpp create mode 100755 tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.h create mode 100755 "tools/hmfs-tools/test/unittest/utils/\346\226\260\346\226\207\344\273\266 9.txt" create mode 100755 tools/hmfs-tools/tools/common/BUILD.gn create mode 100755 tools/hmfs-tools/tools/common/device_manager.cpp create mode 100755 tools/hmfs-tools/tools/common/device_manager.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_command.cpp create mode 100755 tools/hmfs-tools/tools/common/hmfs_command.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_common.cpp create mode 100755 tools/hmfs-tools/tools/common/hmfs_common.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_data.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_define.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_encoding.cpp create mode 100755 tools/hmfs-tools/tools/common/hmfs_encoding.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_io.cpp create mode 100755 tools/hmfs-tools/tools/common/hmfs_io.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_quota.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_utils.h create mode 100755 tools/hmfs-tools/tools/common/hmfs_zoned.cpp create mode 100755 tools/hmfs-tools/tools/common/hmfs_zoned.h create mode 100755 tools/hmfs-tools/tools/mkfs/BUILD.gn create mode 100755 tools/hmfs-tools/tools/mkfs/include/area_formater.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/cp_writer.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/main_writer.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/mkfs_command.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/mkfs_format.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/nat_writer.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/sit_writer.h create mode 100755 tools/hmfs-tools/tools/mkfs/include/super_block_writer.h create mode 100755 tools/hmfs-tools/tools/mkfs/src/cp_writer.cpp create mode 100755 tools/hmfs-tools/tools/mkfs/src/main_writer.cpp create mode 100755 tools/hmfs-tools/tools/mkfs/src/mkfs_command.cpp create mode 100755 tools/hmfs-tools/tools/mkfs/src/mkfs_format.cpp create mode 100755 tools/hmfs-tools/tools/mkfs/src/nat_writer.cpp create mode 100755 tools/hmfs-tools/tools/mkfs/src/sit_writer.cpp create mode 100755 tools/hmfs-tools/tools/mkfs/src/super_block_writer.cpp create mode 100755 tools/hmfs-tools/tools/resize/BUILD.gn create mode 100755 tools/hmfs-tools/tools/resize/include/node.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_command.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_data.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_defrag.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_list.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_load.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_load_cp.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_load_nat.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_load_sb.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_load_sit.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_operator.h create mode 100755 tools/hmfs-tools/tools/resize/include/resize_utils.h create mode 100755 tools/hmfs-tools/tools/resize/src/resize_command.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_defrag.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_load.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_load_cp.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_load_nat.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_load_sb.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_load_sit.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_main.cpp create mode 100755 tools/hmfs-tools/tools/resize/src/resize_operator.cpp diff --git a/tools/hmfs-tools/BUILD.gn b/tools/hmfs-tools/BUILD.gn new file mode 100755 index 0000000..c6fde19 --- /dev/null +++ b/tools/hmfs-tools/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +group("hmfs-tools") { + deps = [ + "//third_party/hmfs-tools/tools/common:libhmfs", + "//third_party/hmfs-tools/tools/mkfs:mkfs.hmfs", + "//third_party/hmfs-tools/tools/resize:resize.hmfs", + "//third_party/hmfs-tools/tools/compare:compare", + ] +} + +group("hmfs-tools_host_toolchain") { + deps = [ + "//third_party/hmfs-tools/tools/common:libhmfs($host_toolchain)", + "//third_party/hmfs-tools/tools/mkfs:mkfs.hmfs($host_toolchain)", + "//third_party/hmfs-tools/tools/resize:resize.hmfs($host_toolchain)", + "//third_party/hmfs-tools/tools/compare:compare($host_toolchain)", + ] +} diff --git a/tools/hmfs-tools/hmfs.gni b/tools/hmfs-tools/hmfs.gni new file mode 100755 index 0000000..626134e --- /dev/null +++ b/tools/hmfs-tools/hmfs.gni @@ -0,0 +1,19 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +hmfs_path = "//third_party/hmfs-tools" +hmfs_tools_path = "//third_party/hmfs-tools/tools" +subsystem_name = "thirdparty" +part_name = "hmfs-tools" +module_output_path = "${subsystem_name}/hmfs-tools" +hmfs_unittest_coverage = false \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/BUILD.gn b/tools/hmfs-tools/test/unittest/BUILD.gn new file mode 100755 index 0000000..485a73a --- /dev/null +++ b/tools/hmfs-tools/test/unittest/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright (c) 2021-2022 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +group("unittest") { + if (!defined(ohos_lite)) { + testonly = true + deps = [ + "mkfs_test:mkfs_hmfs_single_test", + "mkfs_test:mkfs_hmfs_multi_test", + "resize_test:resize_hmfs_single_test", + "resize_test:resize_hmfs_multi_test", + ] + } +} diff --git a/tools/hmfs-tools/test/unittest/mkfs_test/BUILD.gn b/tools/hmfs-tools/test/unittest/mkfs_test/BUILD.gn new file mode 100755 index 0000000..a1710d8 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/mkfs_test/BUILD.gn @@ -0,0 +1,77 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +ohos_unittest("mkfs_hmfs_single_test") { + module_out_path = "${module_output_path}" + if (hmfs_unittest_coverage) { + cflags = [ "--coverage" ] + ldflags = [ "--coverage" ] + cflags_cc = [ "--coverage" ] + } + deps = [] + defines = [ "HMFS_UNIT_TEST" ] + + # 被测试代码 + include_dirs = [ "${hmfs_tools_path}/common" ] + sources = [] + + # 测试代码 + include_dirs += [ "${hmfs_path}/test/unittest/utils" ] + sources += [ + "${hmfs_path}/test/unittest/mkfs_test/mkfs_single_test.cpp", + "${hmfs_path}/test/unittest/utils/hmfs_test_utils.cpp", + ] + + deps = [ "${hmfs_tools_path}/common:libhmfs" ] + + external_deps = [ + "bounds_checking_function:libsec_shared", + "googletest:gmock", + "googletest:gtest", + "hilog:libhilog", + ] +} + +ohos_unittest("mkfs_hmfs_multi_test") { + module_out_path = "${module_output_path}" + if (hmfs_unittest_coverage) { + cflags = [ "--coverage" ] + ldflags = [ "--coverage" ] + cflags_cc = [ "--coverage" ] + } + deps = [] + defines = [ "HMFS_UNIT_TEST" ] + + # 被测试代码 + include_dirs = [ "${hmfs_tools_path}/common" ] + sources = [] + + # 测试代码 + include_dirs += [ "${hmfs_path}/test/unittest/utils" ] + sources += [ + "${hmfs_path}/test/unittest/mkfs_test/mkfs_multi_test.cpp", + "${hmfs_path}/test/unittest/utils/hmfs_test_utils.cpp", + ] + + deps = [ "${hmfs_tools_path}/common:libhmfs" ] + + external_deps = [ + "bounds_checking_function:libsec_shared", + "googletest:gmock", + "googletest:gtest", + "hilog:libhilog", + ] +} diff --git a/tools/hmfs-tools/test/unittest/mkfs_test/mkfs_multi_test.cpp b/tools/hmfs-tools/test/unittest/mkfs_test/mkfs_multi_test.cpp new file mode 100755 index 0000000..8257b80 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/mkfs_test/mkfs_multi_test.cpp @@ -0,0 +1,1267 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, Hardware + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "hmfs_test_utils.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Hmfs { +const std::string F2FS_BINARY_PATH = "/system/bin/mkfs.f2fs"; +//const std::string HMFS_BINARY_PATH = "/system/bin/mkfs.f2fs"; +const std::string HMFS_BINARY_PATH = "/system/bin/mkfs.hmfs"; +const std::string FSCK_BINARY_PATH = "/system/bin/fsck.f2fs"; + +const std::string STDOUT_OUTPUT_FILE_PATH = "/data/local/"; +constexpr uint32_t loopNum = 2000; + +class MkfsHmfsMultiTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + static int32_t ExecutableCmd(const char *path, char *const argv[]); + static int32_t ExecMkfsBinary(std::vector ¶ms, const std::string &binaryPath, + const std::string &outputFile); + static std::vector ConstructCombinationParameters(const std::string &optionGroup, + const bool containReadOnly = false, const bool changePath = false); + static void DataDuplicatorDevice(const std::string &devicePath); + static int32_t RemoveFile(const std::string &removeCommand); +}; + +void MkfsHmfsMultiTest::SetUpTestCase() {} +void MkfsHmfsMultiTest::TearDownTestCase() {} +void MkfsHmfsMultiTest::SetUp() +{ + for (uint8_t i = 0; i < 4; i++) { + DataDuplicatorDevice(HMFS_DEVICE_PATH_LIST[i]); + DataDuplicatorDevice(F2FS_DEVICE_PATH_LIST[i]); + } +} + +int32_t MkfsHmfsMultiTest::RemoveFile(const std::string &removeCommand) +{ + std::vector argv; + argv.emplace_back(const_cast("/bin/sh")); + argv.emplace_back(const_cast("-c")); + argv.emplace_back(const_cast(removeCommand.c_str())); + argv.emplace_back(nullptr); + int32_t res = MkfsHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); + std::cout << "MkfsHmfsMultiTest::RemoveFile removeCommand : " << removeCommand << + " res = " << res << std::endl; + return res; +} + +void MkfsHmfsMultiTest::TearDown() +{ + std::cout << "MkfsHmfsMultiTest::TearDown res = " << RemoveFile("rm -rf /data/local/hmfs* /data/local/f2fs*") + << std::endl; +} + +int32_t MkfsHmfsMultiTest::ExecutableCmd(const char *path, char *const argv[]) +{ + if (path == nullptr || argv == nullptr ) { + return -1; + } + + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + execv(path, argv); + _exit(EXIT_FAILURE); + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1 || wpid != pid) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + +int32_t MkfsHmfsMultiTest::ExecMkfsBinary(std::vector ¶ms, const std::string &binaryPath, + const std::string &outputFile) +{ + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + int fd = open(outputFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd < 0) { + _exit(EXIT_FAILURE); + } + dup2(fd, STDOUT_FILENO); + close(fd); + + std::vector argv; + argv.emplace_back(const_cast(binaryPath.c_str())); + uint16_t i = 0; + for (const auto ¶m : params) { + std::cout << " MkfsHmfsMultiTest::ExecMkfsBinary i = " << i++ << " param = " << param << std::endl; + argv.emplace_back(const_cast(param.c_str())); + } + argv.emplace_back(nullptr); + + execv(argv[0], argv.data()); + _exit(EXIT_FAILURE); + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1 || wpid != pid) { + std::cout << " MkfsHmfsMultiTest::ExecMkfsBinary failed -errno = " << -errno << std::endl; + return -errno; + } + + if (WIFEXITED(status)) { + int32_t exitStatus = WEXITSTATUS(status); + std::cout << " MkfsHmfsMultiTest::ExecMkfsBinary failed exitStatus = " << exitStatus << std::endl; + return exitStatus; + } + std::cout << " MkfsHmfsMultiTest::ExecMkfsBinary failed -ECHILD = " << -ECHILD << std::endl; + return -ECHILD; +} + +void MkfsHmfsMultiTest::DataDuplicatorDevice(const std::string &devicePath) +{ + std::vector argv; + argv.emplace_back(const_cast("/system/bin/dd")); + argv.emplace_back(const_cast("if=/dev/zero")); + + std::string outputFile = "of=" + devicePath; + argv.emplace_back(const_cast(outputFile.c_str())); + argv.emplace_back(const_cast("bs=1M")); + argv.emplace_back(const_cast("count=100")); + argv.emplace_back(nullptr); + MkfsHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); +} + +std::vector MkfsHmfsMultiTest::ConstructCombinationParameters(const std::string &optionGroup, + const bool containReadOnly, const bool changePath) +{ + std::vector params; + params.emplace_back("-a 1"); + params.emplace_back("-d 1"); + + if (optionGroup.find("-e") != std::string::npos) { + params.emplace_back("-e cool"); + } + + if (optionGroup.find("-E") != std::string::npos) { + params.emplace_back("-E hot"); + } + + params.emplace_back("-i"); + + if (optionGroup.find("-m") != std::string::npos) { + params.emplace_back("-m"); + } + + params.emplace_back("-C"); + params.emplace_back("utf8"); + params.emplace_back("-r"); + params.emplace_back("-R 1000:1000"); + params.emplace_back("-s 2"); + params.emplace_back("-t 1"); + params.emplace_back("-T 10086"); + + params.emplace_back("-z 2"); + + if (optionGroup.find("-O") != std::string::npos) { + std::string defaultList("-O inode_checksum,flexible_inline_xattr,inode_crtime,lost_found,casefold," + "verity,quota,encrypt,sb_checksum,extra_attr,project_quota,compression"); + defaultList += containReadOnly ? ",ro" : ""; + params.emplace_back(defaultList); + } + + bool contaionWantSecSize = optionGroup.find("-w") != std::string::npos; + if (contaionWantSecSize) { + params.emplace_back("-l hmfsTestLablew"); + params.emplace_back("-w 1024"); + if (optionGroup.find("-o") != std::string::npos) { + params.emplace_back("-o 50"); + } + } + + if (optionGroup.find("-c") != std::string::npos) { + params.emplace_back("-l hmfsTestLablec"); + + if (optionGroup.find("-o") != std::string::npos) { + params.emplace_back("-o 20"); + } + + if (changePath) { + params.emplace_back("-c"); + params.emplace_back(F2FS_DEVICE_PATH_LIST[1]); + params.emplace_back("-c"); + params.emplace_back(F2FS_DEVICE_PATH_LIST[2]); + params.emplace_back("-c"); + params.emplace_back(F2FS_DEVICE_PATH_LIST[3]); + } else { + params.emplace_back("-c"); + params.emplace_back(HMFS_DEVICE_PATH_LIST[1]); + params.emplace_back("-c"); + params.emplace_back(HMFS_DEVICE_PATH_LIST[2]); + params.emplace_back("-c"); + params.emplace_back(HMFS_DEVICE_PATH_LIST[3]); + } + } + + params.emplace_back(changePath ? F2FS_DEVICE_PATH_LIST[0] : HMFS_DEVICE_PATH_LIST[0]); + + if (contaionWantSecSize) { + params.emplace_back("150000"); + } + + return params; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_001 + * @tc.desc: Test the combination parameters, including the -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test001, TestSize.Level1) +{ + std::cout << "Test001 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test001.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-o-O-c", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test001.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test001.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-o-O-c", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test001.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test001 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test001 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_002 + * @tc.desc: Test the combination parameters, including the -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test002, TestSize.Level1) +{ + std::cout << "Test002 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test002.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-O-c", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test002.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test002.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-O-c", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test002.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test002 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test002 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_003 + * @tc.desc: Test the combination parameters, including the -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test003, TestSize.Level1) +{ + std::cout << "Test003 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test003.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-E-O-c", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test003.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test003.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-E-O-c", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test003.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test003 res = " << RemoveFile(rmCmd) << std::endl; + } + std::cout << "Test003 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_004 + * @tc.desc: Test the combination parameters, including the -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test004, TestSize.Level1) +{ + std::cout << "Test004 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test004.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-E-O-c", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test004.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test004.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-E-O-c", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test004.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test004 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test004 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_005 + * @tc.desc: Test the combination parameters, including the -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test005, TestSize.Level1) +{ + std::cout << "Test005 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test005.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-c", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test005.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test005.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-c", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test005.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test005 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test005 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_006 + * @tc.desc: Test the combination parameters, including the -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test006, TestSize.Level1) +{ + std::cout << "Test006 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test006.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-c", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test006.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test006.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-c", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test006.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test006 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test006 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_007 + * @tc.desc: Test the combination parameters, including the -w option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test007, TestSize.Level1) +{ + std::cout << "Test007 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test007.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-O-w", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test007.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test007.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-O-w", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test007.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test007 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test007 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_008 + * @tc.desc: Test the combination parameters, including the -w option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test008, TestSize.Level1) +{ + std::cout << "Test008 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test008.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-O-w", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test008.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test008.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-O-w", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test008.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test008 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test008 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_009 + * @tc.desc: Test the combination parameters, including the -w option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test009, TestSize.Level1) +{ + std::cout << "Test009 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test009.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-E-O-w", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test009.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test009.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-E-O-w", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test009.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test009 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test009 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_010 + * @tc.desc: Test the combination parameters, including the -w option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test010, TestSize.Level1) +{ + std::cout << "Test010 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test010.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-E-O-w", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test010.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test010.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-E-O-w", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test010.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test010 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test010 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_011 + * @tc.desc: Test the combination parameters, including the -w option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test011, TestSize.Level1) +{ + std::cout << "Test011 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test011.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-w", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test011.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test011.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-w", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test011.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test011 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test011 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_012 + * @tc.desc: Test the combination parameters, including the -w option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test012, TestSize.Level1) +{ + std::cout << "Test012 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test012.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-w", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(0, hmfsRes); + + std::vector hmfsDevice { HMFS_DEVICE_PATH_LIST[0] }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test012.txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + GetCheckPoint(hmfsDevice.at(0), hmfsCheckPoint); + GetSuperBlock(hmfsDevice.at(0), hmfsSuperBlock); + + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevice.at(0), hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test012.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-w", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(0, f2fsRes); + + std::vector f2fsDevice { F2FS_DEVICE_PATH_LIST[0] }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test012.txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + auto f2fsSuperBlock = std::make_unique(); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(f2fsDevice.at(0), f2fsCheckPoint); + GetSuperBlock(f2fsDevice.at(0), f2fsSuperBlock); + + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevice.at(0), f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(hmfsAddrIndex, f2fsAddrIndex); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, compSB); + + CheckPointCode compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(SUCCESSED_CP, compCP); + + NodeDataCode compND = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + EXPECT_EQ(SUCCESSED_ND, compND); + + if (hmfsRes == 0 && f2fsRes == 0 && compSB == SUCCESSED_SB && compCP == SUCCESSED_CP && compND == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test012 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test012 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_013 + * @tc.desc: Test the combination parameters, including the -w -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test013, TestSize.Level1) +{ + std::cout << "Test013 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test013.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-O-w-c", false, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(255, hmfsRes); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test013.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-O-w-c", false, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(1, f2fsRes); + + if ((hmfsRes == 0) == (f2fsRes == 0)) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test013 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test013 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_014 + * @tc.desc: Test the combination parameters, including the -w -c option. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test014, TestSize.Level1) +{ + std::cout << "Test014 begin" << std::endl; + + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test014.txt"; + std::vector hmfsComParameters = ConstructCombinationParameters("-e-O-w-c", true, false); + PrintParameters(hmfsComParameters); + int32_t hmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + EXPECT_EQ(255, hmfsRes); + + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test014.txt"; + std::vector f2fsComParameters = ConstructCombinationParameters("-e-O-w-c", true, true); + PrintParameters(f2fsComParameters); + int32_t f2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + EXPECT_EQ(1, f2fsRes); + + if ((hmfsRes == 0) == (f2fsRes == 0)) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test014 res = " << RemoveFile(rmCmd) << std::endl; + } + + std::cout << "Test014 end" << std::endl; +} + +/* + * @tc.name: MkfsHmfsTest_Combination_015 + * @tc.desc: The test parameter options are random and the parameter option values are also random. + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsMultiTest, Test015, TestSize.Level1) +{ + std::cout << "Test015 begin" << std::endl; + for (uint8_t i = 4; i < MAX_DEVICE_COUNTS - 1; i++) { + DataDuplicatorDevice(HMFS_DEVICE_PATH_LIST[i]); + DataDuplicatorDevice(F2FS_DEVICE_PATH_LIST[i]); + } + + std::srand(std::time(nullptr)); + std::vector f2fsComParameters; + std::vector hmfsComParameters; + for (uint32_t i = 0; i < loopNum; ++i) { + f2fsComParameters.clear(); + hmfsComParameters.clear(); + f2fsComParameters = GenerateParams(false); + hmfsComParameters = f2fsComParameters; + ReplaceDevicePaths(hmfsComParameters); + PrintParameters(f2fsComParameters); + PrintParameters(hmfsComParameters); + + std::map parameterMap{}; + bool correct = CheckParametersVaild(f2fsComParameters, parameterMap); + std::string indexNum = std::to_string(i); + std::string f2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Test015_" + indexNum + ".txt"; + std::string hmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Test015_" + indexNum + ".txt"; + + int32_t f2fsExeRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsComParameters, F2FS_BINARY_PATH, f2fsOutFileName); + int32_t hmfsExeRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsComParameters, HMFS_BINARY_PATH, hmfsOutFileName); + // EXPECT_EQ(f2fsExeRes, hmfsExeRes); + std::cout << "i : " << i << " f2fsExeRes = " << f2fsExeRes << " hmfsExeRes = " << hmfsExeRes << std::endl; + if (!correct || (f2fsExeRes != 0 && hmfsExeRes != 0)) { + //预期命令会执行失败 + EXPECT_NE(f2fsExeRes, 0); + std::string removeCmd = "rm -rf " + hmfsOutFileName + " " + f2fsOutFileName; + std::cout << "Test015_" << i << " res : " << RemoveFile(removeCmd) << std::endl; + continue; + } + + std::string f2fsDevicePath = ConfirmDevicePath(f2fsComParameters); + std::string hmfsDevicePath = ConfirmDevicePath(hmfsComParameters, false); + + std::cout << "Test015_" << i << " f2fsDevicePath : " << f2fsDevicePath << std::endl; + std::cout << "Test015_" << i << " hmfsDevicePath : " << hmfsDevicePath << std::endl; + + std::vector f2fsDevice { f2fsDevicePath }; + std::string fsckF2fsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_F2fs_Fsck_Test015_" + indexNum + ".txt"; + int32_t fsckF2fsRes = MkfsHmfsMultiTest::ExecMkfsBinary(f2fsDevice, FSCK_BINARY_PATH, fsckF2fsOutFileName); + EXPECT_EQ(0, fsckF2fsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckF2fsOutFileName, f2fsDevice.at(0))); + + std::vector hmfsDevice { hmfsDevicePath }; + std::string fsckHmfsOutFileName = STDOUT_OUTPUT_FILE_PATH + "Mkfs_Hmfs_Fsck_Test015_" + indexNum + ".txt"; + int32_t fsckHmfsRes = MkfsHmfsMultiTest::ExecMkfsBinary(hmfsDevice, FSCK_BINARY_PATH, fsckHmfsOutFileName); + EXPECT_EQ(0, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(fsckHmfsOutFileName, hmfsDevice.at(0))); + + auto f2fsCheckPoint = std::make_unique(); + auto f2fsSuperBlock = std::make_unique(); + auto f2fsNodeData = std::make_unique(); + GetSuperBlock(f2fsDevicePath, f2fsSuperBlock); + GetCheckPoint(f2fsDevicePath, f2fsCheckPoint); + int16_t f2fsAddrIndex = -1; + GetInodeInfo(f2fsDevicePath, f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + uint32_t f2fsFeatures = GetLeValue(f2fsSuperBlock->features); + PrintInodeInfo(f2fsFeatures, f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + auto hmfsCheckPoint = std::make_unique(); + auto hmfsSuperBlock = std::make_unique(); + auto hmfsNodeData = std::make_unique(); + GetSuperBlock(hmfsDevicePath, hmfsSuperBlock); + GetCheckPoint(hmfsDevicePath, hmfsCheckPoint); + int16_t hmfsAddrIndex = -1; + GetInodeInfo(hmfsDevicePath, hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + uint32_t hmfsFeatures = GetLeValue(hmfsSuperBlock->features); + PrintInodeInfo(hmfsFeatures, hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + bool mkfsF2fsRes = CheckMkfsHmfsResult(parameterMap, f2fsCheckPoint, f2fsSuperBlock, f2fsNodeData); + bool mkfsHmfsRes = CheckMkfsHmfsResult(parameterMap, hmfsCheckPoint, hmfsSuperBlock, hmfsNodeData); + if ((!mkfsF2fsRes) || (!mkfsHmfsRes)) { + EXPECT_TRUE(false); + break; + } + + // 封装对比f2fs和hmfs工具格式化之后的checkPoint和superBlck主要字段值,如果相等,用例成功 + SuperBlockCode supBlkCode = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + CheckPointCode chkPointCode = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + EXPECT_EQ(supBlkCode, SUCCESSED_SB); + EXPECT_EQ(chkPointCode, SUCCESSED_CP); + + EXPECT_EQ(f2fsAddrIndex, hmfsAddrIndex); + std::vector::const_iterator iter = std::find(f2fsComParameters.begin(), + f2fsComParameters.end(), "-T"); + NodeDataCode nodeDataCode = ERROR_NODE_UNKNOWN; + if (iter != f2fsComParameters.end()) { + nodeDataCode = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, true); + } else { + nodeDataCode = CompareNodeData(f2fsNodeData, hmfsNodeData, f2fsAddrIndex, false); + } + EXPECT_EQ(nodeDataCode, SUCCESSED_ND); + + if (f2fsExeRes == hmfsExeRes && supBlkCode == SUCCESSED_SB && + chkPointCode == SUCCESSED_CP && nodeDataCode == SUCCESSED_ND) { + std::string rmCmd = "rm -rf " + STDOUT_OUTPUT_FILE_PATH + "Mkfs_*"; + std::cout << "Test015_" << i << " res : " << RemoveFile(rmCmd) << std::endl; + } + } + + std::cout << "Test015 end" << std::endl; +} + +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/mkfs_test/mkfs_single_test.cpp b/tools/hmfs-tools/test/unittest/mkfs_test/mkfs_single_test.cpp new file mode 100755 index 0000000..5b7c29e --- /dev/null +++ b/tools/hmfs-tools/test/unittest/mkfs_test/mkfs_single_test.cpp @@ -0,0 +1,1899 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, Hardware + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include +#include + +#include "hmfs_encoding.h" +#include "hmfs_common.h" +#include "hmfs_test_utils.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Hmfs { +const std::string F2FS_BINARY_PATH = "/system/bin/mkfs.f2fs"; +const std::string HMFS_BINARY_PATH = "/system/bin/mkfs.hmfs"; + +class MkfsHmfsSingleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + static int32_t ExecutableCmd(const char *path, char *const argv[]); + static int32_t ExecMkfsBinary(const std::string &fsType, std::vector& params, + const std::string &devPath = nullptr); + static int32_t ExecDdBinary(const std::string &devPath); + static bool ExecFsckBinaryAndCkeck(const std::string &devPath); +}; + +void MkfsHmfsSingleTest::SetUpTestCase() {} +void MkfsHmfsSingleTest::TearDownTestCase() {} +void MkfsHmfsSingleTest::SetUp() +{ + std::vector f2fsArgv; + f2fsArgv.emplace_back(const_cast("/system/bin/dd")); + f2fsArgv.emplace_back(const_cast("if=/dev/zero")); + f2fsArgv.emplace_back(const_cast("of=/data/f2fsTest")); + f2fsArgv.emplace_back(const_cast("bs=1M")); + f2fsArgv.emplace_back(const_cast("count=100")); + f2fsArgv.emplace_back(nullptr); + int32_t res = MkfsHmfsSingleTest::ExecutableCmd(f2fsArgv[0], f2fsArgv.data()); + + std::cout << "MkfsHmfsSingleTest::SetUp res = " << res << std::endl; + std::vector hmfsArgv; + hmfsArgv.emplace_back(const_cast("/system/bin/dd")); + hmfsArgv.emplace_back(const_cast("if=/dev/zero")); + hmfsArgv.emplace_back(const_cast("of=/data/hmfsTest")); + hmfsArgv.emplace_back(const_cast("bs=1M")); + hmfsArgv.emplace_back(const_cast("count=100")); + hmfsArgv.emplace_back(nullptr); + MkfsHmfsSingleTest::ExecutableCmd(hmfsArgv[0], hmfsArgv.data()); + + +} + +void MkfsHmfsSingleTest::TearDown() +{ + std::vector f2fsArgv; + f2fsArgv.emplace_back(const_cast("/bin/sh")); + f2fsArgv.emplace_back(const_cast("-c")); + f2fsArgv.emplace_back(const_cast("rm -rf /data/f2fsTest*")); + f2fsArgv.emplace_back(nullptr); + MkfsHmfsSingleTest::ExecutableCmd(f2fsArgv[0], f2fsArgv.data()); + std::vector hmfsArgv; + hmfsArgv.emplace_back(const_cast("/bin/sh")); + hmfsArgv.emplace_back(const_cast("-c")); + hmfsArgv.emplace_back(const_cast("rm -rf /data/hmfsTest*")); + hmfsArgv.emplace_back(nullptr); + MkfsHmfsSingleTest::ExecutableCmd(hmfsArgv[0], hmfsArgv.data()); +} + +int32_t MkfsHmfsSingleTest::ExecutableCmd(const char *path, char *const argv[]) +{ + if (path == nullptr || argv == nullptr ) { + return -1; + } + + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + if (execv(path, argv) == -1) { + _exit(EXIT_FAILURE); + } + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + +int32_t MkfsHmfsSingleTest::ExecDdBinary(const std::string &devPath) +{ + if (devPath.empty()) { + std::cout<<"ExecDdBinary Invalid param"< argv; + argv.emplace_back(const_cast("/system/bin/dd")); + argv.emplace_back(const_cast("if=/dev/zero")); + argv.emplace_back(const_cast(str.c_str())); + argv.emplace_back(const_cast("bs=1M")); + argv.emplace_back(const_cast("count=100")); + argv.emplace_back(nullptr); + if (execv(argv[0], argv.data()) == -1) { + _exit(EXIT_FAILURE); + } + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + +int32_t MkfsHmfsSingleTest::ExecMkfsBinary(const std::string &fsType, std::vector& params, + const std::string &devPath) +{ + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + std::vector argv; + if (fsType == "f2fs") { + argv.emplace_back(const_cast(F2FS_BINARY_PATH.c_str())); + } + if (fsType == "hmfs") { + argv.emplace_back(const_cast(HMFS_BINARY_PATH.c_str())); + } + for (const auto ¶m : params) { + argv.emplace_back(const_cast(param.c_str())); + } + argv.emplace_back(const_cast(devPath.c_str())); + argv.emplace_back(nullptr); + if (execv(argv[0], argv.data()) == -1) { + _exit(EXIT_FAILURE); + } + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + +bool MkfsHmfsSingleTest::ExecFsckBinaryAndCkeck(const std::string &devPath) +{ + std::string outputFile = "/data/local/fsck.txt"; + std::vector argv; + argv.push_back("/system/bin/fsck.f2fs"); + argv.push_back(devPath); + + ExecutableCmdWithOutput(argv, outputFile); + return PrintFsckErrorMsg(outputFile,devPath); +} +/* + * @tc.name: MkfsHmfsTest_001 + * @tc.desc: test for no parameter + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_no_param_001, TestSize.Level1) +{ + std::vector params; + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + params.clear(); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + SuperBlockCode sbRet = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, sbRet); + CheckPointCode cpRet = CompareCheckPoint(f2fsCkeckPoint, hmfsCkeckPoint); + EXPECT_EQ(SUCCESSED_CP, cpRet); +} + +/* + * @tc.name: MkfsHmfsTest_a_001 + * @tc.desc: test for parameter a + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_a_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-a 1"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + EXPECT_EQ(f2fsCkeckPoint->curNodeSegNo[0], hmfsCkeckPoint->curNodeSegNo[0]); + EXPECT_EQ(f2fsCkeckPoint->curNodeSegNo[1], hmfsCkeckPoint->curNodeSegNo[1]); + EXPECT_EQ(f2fsCkeckPoint->curNodeSegNo[2], hmfsCkeckPoint->curNodeSegNo[2]); + EXPECT_EQ(f2fsCkeckPoint->curDataSegNo[0], hmfsCkeckPoint->curDataSegNo[0]); + EXPECT_EQ(f2fsCkeckPoint->curDataSegNo[1], hmfsCkeckPoint->curDataSegNo[1]); + EXPECT_EQ(f2fsCkeckPoint->curDataSegNo[2], hmfsCkeckPoint->curDataSegNo[2]); +} + +/* + * @tc.name: MkfsHmfsTest_a_002 + * @tc.desc: test for parameter a + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_a_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-a 0"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + EXPECT_EQ(f2fsCkeckPoint->curNodeSegNo[0], hmfsCkeckPoint->curNodeSegNo[0]); + EXPECT_EQ(f2fsCkeckPoint->curNodeSegNo[1], hmfsCkeckPoint->curNodeSegNo[1]); + EXPECT_EQ(f2fsCkeckPoint->curNodeSegNo[2], hmfsCkeckPoint->curNodeSegNo[2]); + EXPECT_EQ(f2fsCkeckPoint->curDataSegNo[0], hmfsCkeckPoint->curDataSegNo[0]); + EXPECT_EQ(f2fsCkeckPoint->curDataSegNo[1], hmfsCkeckPoint->curDataSegNo[1]); + EXPECT_EQ(f2fsCkeckPoint->curDataSegNo[2], hmfsCkeckPoint->curDataSegNo[2]); +} + +/* + * @tc.name: MkfsHmfsTest_c_001 + * @tc.desc: test for parameter c + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_c_001, TestSize.Level1) +{ + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest1")); + std::vector params; + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest1"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest1")); + params.clear(); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest1"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/hmfsTest", hmfsCkeckPoint); + + EXPECT_EQ(f2fsSuperBlock->blockCount, hmfsSuperBlock->blockCount); + EXPECT_EQ(f2fsSuperBlock->sectionCount, hmfsSuperBlock->sectionCount); + EXPECT_EQ(f2fsSuperBlock->segmentCount, hmfsSuperBlock->segmentCount); + EXPECT_EQ(f2fsSuperBlock->segmentCountInMain, hmfsSuperBlock->segmentCountInMain); + EXPECT_EQ(f2fsCkeckPoint->userBlockCount, hmfsCkeckPoint->userBlockCount); + EXPECT_EQ(f2fsCkeckPoint->validBlockCount, hmfsCkeckPoint->validBlockCount); + EXPECT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + EXPECT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + EXPECT_EQ(f2fsCkeckPoint->freeSegmentCount, hmfsCkeckPoint->freeSegmentCount); + + SuperBlockCode sbRet = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, sbRet); + CheckPointCode cpRet = CompareCheckPoint(f2fsCkeckPoint, hmfsCkeckPoint); + EXPECT_EQ(SUCCESSED_CP, cpRet); +} + +/* + * @tc.name: MkfsHmfsTest_c_002 + * @tc.desc: test for parameter c + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_c_002, TestSize.Level1) +{ + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest1")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest2")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest3")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest4")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest5")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest6")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest7")); + std::vector params; + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest1"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest2"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest3"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest4"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest5"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest6"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest7"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest1")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest2")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest3")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest4")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest5")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest6")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest7")); + params.clear(); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest1"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest2"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest3"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest4"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest5"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest6"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest7"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/hmfsTest", hmfsCkeckPoint); + + SuperBlockCode sbRet = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + EXPECT_EQ(SUCCESSED_SB, sbRet); + CheckPointCode cpRet = CompareCheckPoint(f2fsCkeckPoint, hmfsCkeckPoint); + EXPECT_EQ(SUCCESSED_CP, cpRet); +} + +/* + * @tc.name: MkfsHmfsTest_c_003 + * @tc.desc: test for parameter c, + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_c_003, TestSize.Level1) +{ + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest1")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest2")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest3")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest4")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest5")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest6")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest7")); + EXPECT_EQ(0, ExecDdBinary("/data/f2fsTest8")); + std::vector params; + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest1"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest2"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest3"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest4"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest5"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest6"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest7"); + params.emplace_back("-c"); + params.emplace_back("/data/f2fsTest8"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest1")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest2")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest3")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest4")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest5")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest6")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest7")); + EXPECT_EQ(0, ExecDdBinary("/data/hmfsTest8")); + params.clear(); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest1"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest2"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest3"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest4"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest5"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest6"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest7"); + params.emplace_back("-c"); + params.emplace_back("/data/hmfsTest8"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_c_004 + * @tc.desc: test for parameter c + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_c_004, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-c /data/xxxxxxxxx/xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx/hmfsTest1"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_e_001 + * @tc.desc: test for parameter e + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_e_001, TestSize.Level1) +{ + std::vector params; + std::string fileSuffix = "cold"; + params.emplace_back("-e"); + params.emplace_back(fileSuffix); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->coldExtensionCount, hmfsSuperBlock->coldExtensionCount); + bool flag = false; + + for(int32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + EXPECT_STREQ(reinterpret_cast(f2fsSuperBlock->extensionList[i]), + reinterpret_cast(hmfsSuperBlock->extensionList[i])); + if (strcmp(reinterpret_cast(hmfsSuperBlock->extensionList[i]), fileSuffix.c_str()) == 0) { + flag = true; + } + } + EXPECT_TRUE(flag); +} + +/* + * @tc.name: MkfsHmfsTest_e_002 + * @tc.desc: test for parameter e, fileSuffix length is 7 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_e_002, TestSize.Level1) +{ + std::vector params; + std::string fileSuffix = "xxxxxxx"; + params.emplace_back("-e"); + params.emplace_back(fileSuffix); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->coldExtensionCount, hmfsSuperBlock->coldExtensionCount); + bool flag = false; + + for(int32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + EXPECT_STREQ(reinterpret_cast(f2fsSuperBlock->extensionList[i]), + reinterpret_cast(hmfsSuperBlock->extensionList[i])); + if (strcmp(reinterpret_cast(hmfsSuperBlock->extensionList[i]), fileSuffix.c_str()) == 0) { + flag = true; + } + } + EXPECT_TRUE(flag); +} + +/* + * @tc.name: MkfsHmfsTest_e_003 + * @tc.desc: test for parameter e, fileSuffix length is 8 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_e_003, TestSize.Level1) +{ + std::vector params; + std::string fileSuffix = "xxxxxxxx"; + params.emplace_back("-e"); + params.emplace_back(fileSuffix); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->coldExtensionCount, hmfsSuperBlock->coldExtensionCount); + bool flag = false; + + for(int32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + EXPECT_STREQ(reinterpret_cast(f2fsSuperBlock->extensionList[i]), + reinterpret_cast(hmfsSuperBlock->extensionList[i])); + if (strcmp(reinterpret_cast(hmfsSuperBlock->extensionList[i]), fileSuffix.c_str()) == 0) { + flag = true; + } + } + EXPECT_FALSE(flag); +} + +/* + * @tc.name: MkfsHmfsTest_E_001 + * @tc.desc: test for parameter E + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_E_001, TestSize.Level1) +{ + std::vector params; + std::string fileSuffix = "hot"; + params.emplace_back("-E"); + params.emplace_back(fileSuffix); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->hotExtensionCount, hmfsSuperBlock->hotExtensionCount); + EXPECT_EQ(f2fsSuperBlock->coldExtensionCount, hmfsSuperBlock->coldExtensionCount); + bool flag = false; + + for(int32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + EXPECT_STREQ(reinterpret_cast(f2fsSuperBlock->extensionList[i]), + reinterpret_cast(hmfsSuperBlock->extensionList[i])); + if (strcmp(reinterpret_cast(hmfsSuperBlock->extensionList[i]), fileSuffix.c_str()) == 0) { + flag = true; + } + } + EXPECT_TRUE(flag); +} + +/* + * @tc.name: MkfsHmfsTest_E_002 + * @tc.desc: test for parameter E, fileSuffix length is 7 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_E_002, TestSize.Level1) +{ + std::vector params; + std::string fileSuffix = "hhhhhhh"; + params.emplace_back("-E"); + params.emplace_back(fileSuffix); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->hotExtensionCount, hmfsSuperBlock->hotExtensionCount); + EXPECT_EQ(f2fsSuperBlock->coldExtensionCount, hmfsSuperBlock->coldExtensionCount); + bool flag = false; + + for(int32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + EXPECT_STREQ(reinterpret_cast(f2fsSuperBlock->extensionList[i]), + reinterpret_cast(hmfsSuperBlock->extensionList[i])); + if (strcmp(reinterpret_cast(hmfsSuperBlock->extensionList[i]), fileSuffix.c_str()) == 0) { + flag = true; + } + } + EXPECT_TRUE(flag); +} + +/* + * @tc.name: MkfsHmfsTest_E_003 + * @tc.desc: test for parameter E, fileSuffix length is 8 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_E_003, TestSize.Level1) +{ + std::vector params; + std::string fileSuffix = "hhhhhhhh"; + params.emplace_back("-E"); + params.emplace_back(fileSuffix); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->hotExtensionCount, hmfsSuperBlock->hotExtensionCount); + EXPECT_EQ(f2fsSuperBlock->coldExtensionCount, hmfsSuperBlock->coldExtensionCount); + bool flag = false; + + for(int32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + EXPECT_STREQ(reinterpret_cast(f2fsSuperBlock->extensionList[i]), + reinterpret_cast(hmfsSuperBlock->extensionList[i])); + if (strcmp(reinterpret_cast(hmfsSuperBlock->extensionList[i]), fileSuffix.c_str()) == 0) { + flag = true; + } + } + EXPECT_FALSE(flag); +} +/* + * @tc.name: MkfsHmfsTest_f_001 + * @tc.desc: test for parameter f + * @tc.type: FUNC + */ +// HWTEST_F(MkfsHmfsSingleTest, Test_param_f_001, TestSize.Level1) +// { +// std::vector params; +// params.emplace_back("-f"); +// params.emplace_back("/data/f2fsTest"); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary(params)); + +// params.clear(); +// params.emplace_back("-f"); +// params.emplace_back("/data/hmfsTest"); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary(params)); +// } + +/* + * @tc.name: MkfsHmfsTest_g_001 + * @tc.desc: test for parameter g + * @tc.type: FUNC + */ +// HWTEST_F(MkfsHmfsSingleTest, Test_param_g_001, TestSize.Level1) +// { +// std::vector params; +// params.emplace_back("-g android"); +// params.emplace_back("/data/f2fsTest"); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary(params)); + +// params.clear(); +// params.emplace_back("-g android"); +// params.emplace_back("/data/hmfsTest"); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary(params)); + +// } + + +/* + * @tc.name: MkfsHmfsTest_i_001 + * @tc.desc: test for parameter i + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_i_001, TestSize.Level1) //设置使能,不设不使能 +{ + std::vector params; + params.emplace_back("-i"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + EXPECT_EQ(f2fsSuperBlock->cpPayload, hmfsSuperBlock->cpPayload); + EXPECT_EQ(f2fsSuperBlock->segmentCountInNAT, hmfsSuperBlock->segmentCountInNAT); + EXPECT_EQ(f2fsCkeckPoint->cpFlags, hmfsCkeckPoint->cpFlags); + EXPECT_EQ(f2fsCkeckPoint->checksumOffset, hmfsCkeckPoint->checksumOffset); +} + +/* + * @tc.name: MkfsHmfsTest_l_001 + * @tc.desc: test for parameter l + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_l_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-l MyVolume"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + char f2fsVolumeName[MAX_VOLUME_NAME]; + int ret = Utf16Toutf8(f2fsVolumeName, + f2fsSuperBlock->volumeName, MAX_VOLUME_NAME, MAX_VOLUME_NAME); + EXPECT_EQ(ret, 0); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + char hmfsVolumeName[MAX_VOLUME_NAME]; + ret = Utf16Toutf8(hmfsVolumeName, + hmfsSuperBlock->volumeName, MAX_VOLUME_NAME, MAX_VOLUME_NAME); + EXPECT_EQ(ret, 0); + EXPECT_STREQ(f2fsVolumeName, hmfsVolumeName); +} + +/* + * @tc.name: MkfsHmfsTest_m_001 + * @tc.desc: test for parameter m + * @tc.type: FUNC + */ +// HWTEST_F(MkfsHmfsSingleTest, Test_param_m_001, TestSize.Level1) +// { +// std::vector params; +// params.emplace_back("-m"); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +// } + +/* + * @tc.name: MkfsHmfsTest_o_001 + * @tc.desc: test for parameter o, the value is 10 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_o_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-o 10"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + EXPECT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + EXPECT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); +} + +/* + * @tc.name: MkfsHmfsTest_o_002 + * @tc.desc: test for parameter o, the value is 99.99 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_o_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-o 99.99"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", f2fsCkeckPoint); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + EXPECT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + EXPECT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); +} + +/* + * @tc.name: MkfsHmfsTest_o_003 + * @tc.desc: test for parameter o, the value is 100 + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_o_003, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-o 100"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_O_000 + * @tc.desc: test for parameter "-O encrypt" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_000, TestSize.Level1) +{ + std::vector params; + params.clear(); + params.emplace_back("-O encrypt"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_ENCRYPT); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_001 + * @tc.desc: test for parameter "-O extra_attr" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_001, TestSize.Level1) +{ + std::vector params; + params.clear(); + params.emplace_back("-O extra_attr"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_EXTRA_ATTR); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_002 + * @tc.desc: test for parameter "-O extra_attr,project_quota" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O project_quota"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + params.clear(); + params.emplace_back("-O extra_attr,project_quota"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_TRUE(hmfsSuperBlock->features & (HMFS_FEATURE_EXTRA_ATTR|HMFS_FEATURE_PRJQUOTA)); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + EXPECT_EQ(f2fsNodeData->i.iProjid, hmfsNodeData->i.iProjid); +} + +/* + * @tc.name: MkfsHmfsTest_O_003 + * @tc.desc: test for parameter "-O extra_attr,inode_checksum" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_003, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O inode_checksum"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + params.clear(); + params.emplace_back("-O extra_attr,inode_checksum"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_TRUE(hmfsSuperBlock->features & (HMFS_FEATURE_EXTRA_ATTR|HMFS_FEATURE_INODE_CHKSUM)); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + EXPECT_NE(0, hmfsNodeData->i.iInodeChecksum); +} + +/* + * @tc.name: MkfsHmfsTest_O_004 + * @tc.desc: test for parameter "-O extra_attr,flexible_inline_xattr" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_004, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O flexible_inline_xattr"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + params.clear(); + params.emplace_back("-O extra_attr,flexible_inline_xattr"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_TRUE(hmfsSuperBlock->features & (HMFS_FEATURE_EXTRA_ATTR|HMFS_FEATURE_FLEXIBLE_INLINE_XATTR)); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + EXPECT_EQ(f2fsNodeData->i.iInlineXattrSize, hmfsNodeData->i.iInlineXattrSize); +} + +/* + * @tc.name: MkfsHmfsTest_O_005 + * @tc.desc: test for parameter "-O quota" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_005, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O quota"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_QUOTA_INO); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_006 + * @tc.desc: test for parameter "-O extra_attr,inode_crtime" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_006, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O inode_crtime"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + params.clear(); + params.emplace_back("-O extra_attr,inode_crtime"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_TRUE(hmfsSuperBlock->features & (HMFS_FEATURE_EXTRA_ATTR|HMFS_FEATURE_INODE_CRTIME)); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + EXPECT_NE(hmfsNodeData->i.iCrtime, 0); +} + +/* + * @tc.name: MkfsHmfsTest_O_007 + * @tc.desc: test for parameter "-O lost_found" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_007, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O lost_found"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_LOST_FOUND); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_008 + * @tc.desc: test for parameter "-O verity" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_008, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O verity"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_VERITY); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_009 + * @tc.desc: test for parameter "-O sb_checksum" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_009, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O sb_checksum"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_SB_CHKSUM); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_010 + * @tc.desc: test for parameter "-O casefold" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_010, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O casefold"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); +} + +/* + * @tc.name: MkfsHmfsTest_O_011 + * @tc.desc: test for parameter "-O extra_attr,compression" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_011, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O compression"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + + params.clear(); + params.emplace_back("-O extra_attr,compression"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_TRUE(hmfsSuperBlock->features & (HMFS_FEATURE_EXTRA_ATTR|HMFS_FEATURE_COMPRESSION)); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + EXPECT_EQ(f2fsNodeData->i.iComprBlocks, hmfsNodeData->i.iComprBlocks); + EXPECT_EQ(f2fsNodeData->i.iCompressAlgrithm, hmfsNodeData->i.iCompressAlgrithm); + EXPECT_EQ(f2fsNodeData->i.iLogClusterSize, hmfsNodeData->i.iLogClusterSize); + EXPECT_EQ(f2fsNodeData->i.iPadding, hmfsNodeData->i.iPadding); +} + +/* + * @tc.name: MkfsHmfsTest_O_012 + * @tc.desc: test for parameter "-O ro" + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_O_012, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-O ro"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_RO); + EXPECT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint("/data/f2fsTest", hmfsCkeckPoint); + + EXPECT_EQ(hmfsCkeckPoint->curNodeSegNo[1], 0); + EXPECT_EQ(hmfsCkeckPoint->curNodeSegNo[2], 0); + EXPECT_EQ(hmfsCkeckPoint->curDataSegNo[0], 0); + EXPECT_EQ(hmfsCkeckPoint->curDataSegNo[1], 0); + EXPECT_EQ(hmfsCkeckPoint->curDataSegNo[2], 0); +} + +/* + * @tc.name: MkfsHmfsTest_C_001 + * @tc.desc: test for parameter C + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_C_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-C"); + params.emplace_back("utf8"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_EQ(f2fsSuperBlock->encoding, hmfsSuperBlock->encoding); + EXPECT_EQ(f2fsSuperBlock->encodingFlags, hmfsSuperBlock->encodingFlags); +} + +/* + * @tc.name: MkfsHmfsTest_C_002 + * @tc.desc: test for parameter C + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_C_002, TestSize.Level1) +{ + std::vector params; + params.clear(); + params.emplace_back("-C gbk"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_C_003 + * @tc.desc: test for parameter C + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_C_003, TestSize.Level1) +{ + char name[] = LPF_STRING; + int len = strlen(LPF_STRING); + + bool flag = IsNeedEncoding(1); + EXPECT_TRUE(flag); + auto buff = std::make_unique(HMFS_NAME_LEN); + int32_t dlen = CaseFold((const unsigned char *)name, len, buff.get(), HMFS_NAME_LEN); + EXPECT_TRUE(memcmp(buff.get(), LPF_STRING, dlen) == 0); +} +/* + * @tc.name: MkfsHmfsTest_r_001 + * @tc.desc: test for parameter r + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_r_001, TestSize.Level1) //随机值不可判断 +{ + std::vector params; + params.emplace_back("-r"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); +} + +/* + * @tc.name: MkfsHmfsTest_R_001 + * @tc.desc: test for parameter R + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_R_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-R 0:0"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_EQ(f2fsNodeData->i.iUid, hmfsNodeData->i.iUid); + EXPECT_EQ(f2fsNodeData->i.iGid, hmfsNodeData->i.iGid); + EXPECT_EQ(hmfsNodeData->i.iGid, 0); + EXPECT_EQ(hmfsNodeData->i.iGid, 0); +} + +/* + * @tc.name: MkfsHmfsTest_R_002 + * @tc.desc: test for parameter R + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_R_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-R 1000:1000"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_EQ(f2fsNodeData->i.iUid, hmfsNodeData->i.iUid); + EXPECT_EQ(f2fsNodeData->i.iGid, hmfsNodeData->i.iGid); + EXPECT_EQ(hmfsNodeData->i.iGid, 1000); + EXPECT_EQ(hmfsNodeData->i.iGid, 1000); +} +/* + * @tc.name: MkfsHmfsTest_R_003 + * @tc.desc: test for parameter R + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_R_003, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-R -1000:-1000"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_EQ(f2fsNodeData->i.iUid, hmfsNodeData->i.iUid); + EXPECT_EQ(f2fsNodeData->i.iGid, hmfsNodeData->i.iGid); + uint32_t res = -1000; + EXPECT_EQ(hmfsNodeData->i.iGid, res); + EXPECT_EQ(hmfsNodeData->i.iGid, res); +} + +/* + * @tc.name: MkfsHmfsTest_s_001 + * @tc.desc: test for parameter s + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_s_001, TestSize.Level1) +{ + std::vector params; + params.clear(); + params.emplace_back("-s 0"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_s_002 + * @tc.desc: test for parameter s + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_s_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-s 2"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + + EXPECT_EQ(f2fsSuperBlock->segsPerSection, hmfsSuperBlock->segsPerSection); + EXPECT_EQ(f2fsSuperBlock->segmentCountInMain, hmfsSuperBlock->segmentCountInMain); + EXPECT_EQ(f2fsSuperBlock->sectionCount, hmfsSuperBlock->sectionCount); + EXPECT_TRUE(hmfsSuperBlock->segsPerSection == 2); + EXPECT_TRUE(hmfsSuperBlock->sectionCount > 10); +} + +/* + * @tc.name: MkfsHmfsTest_s_003 + * @tc.desc: test for parameter s + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_s_003, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-s 3"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_s_004 + * @tc.desc: test for parameter s + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_s_004, TestSize.Level1) +{ + std::vector params; + params.clear(); + params.emplace_back("-s 1"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + EXPECT_TRUE(f2fsSuperBlock->segsPerSection == 1); + EXPECT_TRUE(f2fsSuperBlock->sectionCount > 10); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->segsPerSection == 1); + EXPECT_TRUE(hmfsSuperBlock->sectionCount > 10); + + EXPECT_EQ(f2fsSuperBlock->segsPerSection, hmfsSuperBlock->segsPerSection); + EXPECT_EQ(f2fsSuperBlock->segmentCountInMain, hmfsSuperBlock->segmentCountInMain); + EXPECT_EQ(f2fsSuperBlock->sectionCount, hmfsSuperBlock->sectionCount); +} + +/* + * @tc.name: MkfsHmfsTest_S_001 + * @tc.desc: test for parameter S + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_S_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-S"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_t_001 + * @tc.desc: test for parameter t + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-t 0"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); +} + +/* + * @tc.name: MkfsHmfsTest_t_002 + * @tc.desc: test for parameter t + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-t 1"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); +} + +/* + * @tc.name: MkfsHmfsTest_T_001 + * @tc.desc: test for parameter T + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_T_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-T -1000"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_EQ(f2fsNodeData->i.iAtime, hmfsNodeData->i.iAtime); + EXPECT_EQ(f2fsNodeData->i.iAtimeNsec, hmfsNodeData->i.iAtimeNsec); + EXPECT_EQ(f2fsNodeData->i.iCtime, hmfsNodeData->i.iCtime); + EXPECT_EQ(f2fsNodeData->i.iCtimeNsec, hmfsNodeData->i.iCtimeNsec); + EXPECT_EQ(f2fsNodeData->i.iMtime, hmfsNodeData->i.iMtime); + EXPECT_EQ(f2fsNodeData->i.iMtimeNsec, hmfsNodeData->i.iMtimeNsec); + uint32_t res = -1000; + EXPECT_EQ(hmfsNodeData->i.iAtime, res); + EXPECT_EQ(hmfsNodeData->i.iCtime, res); + EXPECT_EQ(hmfsNodeData->i.iMtime, res); +} + +/* + * @tc.name: MkfsHmfsTest_T_002 + * @tc.desc: test for parameter T + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_T_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-T 1731565670"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + auto f2fsNodeData = std::make_unique(); + int16_t f2fsAddrIndex = -1; + GetInodeInfo("/data/f2fsTest", f2fsNodeData, f2fsAddrIndex, GetLeValue(f2fsSuperBlock->rootInodeId)); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + auto hmfsNodeData = std::make_unique(); + int16_t hmfsAddrIndex = -1; + GetInodeInfo("/data/hmfsTest", hmfsNodeData, hmfsAddrIndex, GetLeValue(hmfsSuperBlock->rootInodeId)); + + EXPECT_EQ(f2fsNodeData->i.iAtime, hmfsNodeData->i.iAtime); + EXPECT_EQ(f2fsNodeData->i.iAtimeNsec, hmfsNodeData->i.iAtimeNsec); + EXPECT_EQ(f2fsNodeData->i.iCtime, hmfsNodeData->i.iCtime); + EXPECT_EQ(f2fsNodeData->i.iCtimeNsec, hmfsNodeData->i.iCtimeNsec); + EXPECT_EQ(f2fsNodeData->i.iMtime, hmfsNodeData->i.iMtime); + EXPECT_EQ(f2fsNodeData->i.iMtimeNsec, hmfsNodeData->i.iMtimeNsec); + EXPECT_EQ(hmfsNodeData->i.iAtime, 1731565670); + EXPECT_EQ(hmfsNodeData->i.iCtime, 1731565670); + EXPECT_EQ(hmfsNodeData->i.iMtime, 1731565670); +} + +/* + * @tc.name: MkfsHmfsTest_w_001 + * @tc.desc: test for parameter w + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_w_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back(const_cast("/system/bin/mkfs.f2fs")); + params.emplace_back(const_cast("-w 1024")); + params.emplace_back(const_cast("/data/f2fsTest")); + params.emplace_back(const_cast("15000000")); + params.emplace_back(nullptr); + EXPECT_EQ(0, ExecutableCmd(params[0], params.data())); + + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.hmfs")); + params.emplace_back(const_cast("-w 1024")); + params.emplace_back(const_cast("/data/hmfsTest")); + params.emplace_back(const_cast("15000000")); + params.emplace_back(nullptr); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + EXPECT_EQ(0, ExecutableCmd(params[0], params.data())); +} + + +/* + * @tc.name: MkfsHmfsTest_w_002 + * @tc.desc: test for parameter w + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_w_002, TestSize.Level1) +{ + //f2fs + std::vector params; + params.emplace_back(const_cast("/system/bin/mkfs.f2fs")); + params.emplace_back(const_cast("-w 1024")); + params.emplace_back(const_cast("/data/f2fsTest")); + params.emplace_back(const_cast("49152")); // 12 * 4096 + params.emplace_back(nullptr); + EXPECT_NE(0, ExecutableCmd(params[0], params.data())); + + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.f2fs")); + params.emplace_back(const_cast("-w 1024")); + params.emplace_back(const_cast("/data/f2fsTest")); + params.emplace_back(const_cast("53248")); // 13 * 4096 + params.emplace_back(nullptr); + EXPECT_EQ(0, ExecutableCmd(params[0], params.data())); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + EXPECT_TRUE(f2fsSuperBlock->sectionCount > 10); + + // hmfs + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.hmfs")); + params.emplace_back(const_cast("-w 1024")); + params.emplace_back(const_cast("/data/hmfsTest")); + params.emplace_back(const_cast("49152")); // 12 * 4096 + params.emplace_back(nullptr); + // Expected: (0) != (ExecutableCmd(params[0], params.data())), actual: 0 vs 0 + EXPECT_NE(0, ExecutableCmd(params[0], params.data())); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.hmfs")); + params.emplace_back(const_cast("-w 1024")); + params.emplace_back(const_cast("/data/hmfsTest")); + params.emplace_back(const_cast("53248")); // 13 * 4096 + params.emplace_back(nullptr); + EXPECT_EQ(0, ExecutableCmd(params[0], params.data())); + fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->sectionCount > 10); +} + +/* + * @tc.name: MkfsHmfsTest_w_003 + * @tc.desc: test for parameter w + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_w_003, TestSize.Level1) +{ + //f2fs + std::vector params; + params.emplace_back(const_cast("/system/bin/mkfs.f2fs")); + params.emplace_back(const_cast("-w 2048")); + params.emplace_back(const_cast("/data/f2fsTest")); + params.emplace_back(const_cast("24576")); // 6 * 4096 + params.emplace_back(nullptr); + EXPECT_NE(0, ExecutableCmd(params[0], params.data())); + + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.f2fs")); + params.emplace_back(const_cast("-w 2048")); + params.emplace_back(const_cast("/data/f2fsTest")); + params.emplace_back(const_cast("28672")); // 7 * 4096 + params.emplace_back(nullptr); + EXPECT_EQ(0, ExecutableCmd(params[0], params.data())); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + EXPECT_TRUE(f2fsSuperBlock->sectionCount > 10); + + // hmfs + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.hmfs")); + params.emplace_back(const_cast("-w 2048")); + params.emplace_back(const_cast("/data/hmfsTest")); + params.emplace_back(const_cast("24576")); // 6 * 4096 + params.emplace_back(nullptr); + // Expected: (0) != (ExecutableCmd(params[0], params.data())), actual: 0 vs 0 + EXPECT_NE(0, ExecutableCmd(params[0], params.data())); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + params.clear(); + params.emplace_back(const_cast("/system/bin/mkfs.hmfs")); + params.emplace_back(const_cast("-w 2048")); + params.emplace_back(const_cast("/data/hmfsTest")); + params.emplace_back(const_cast("28672")); // 7 * 4096 + params.emplace_back(nullptr); + EXPECT_EQ(0, ExecutableCmd(params[0], params.data())); + fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->sectionCount > 10); +} + +/* + * @tc.name: MkfsHmfsTest_z_000 + * @tc.desc: test for parameter z + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_z_000, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-z 0"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +/* + * @tc.name: MkfsHmfsTest_z_001 + * @tc.desc: test for parameter z + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_z_001, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-z 1"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + EXPECT_TRUE(f2fsSuperBlock->sectionsPerZone == 1); + EXPECT_TRUE(f2fsSuperBlock->sectionCount > 10); + + // hmfs + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->sectionsPerZone == 1); + EXPECT_TRUE(hmfsSuperBlock->sectionCount > 10); +} + +/* + * @tc.name: MkfsHmfsTest_z_002 + * @tc.desc: test for parameter z + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_z_002, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-z 2"); + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock("/data/f2fsTest", f2fsSuperBlock); + EXPECT_TRUE(f2fsSuperBlock->sectionsPerZone == 2); + EXPECT_TRUE(f2fsSuperBlock->sectionCount > 10); + + EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); + bool fsckRes = ExecFsckBinaryAndCkeck("/data/hmfsTest"); + EXPECT_TRUE(fsckRes); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock("/data/hmfsTest", hmfsSuperBlock); + EXPECT_TRUE(hmfsSuperBlock->sectionsPerZone == 2); + EXPECT_TRUE(hmfsSuperBlock->sectionCount > 10); + + EXPECT_EQ(f2fsSuperBlock->sectionsPerZone, hmfsSuperBlock->sectionsPerZone); + EXPECT_EQ(f2fsSuperBlock->sectionCount, hmfsSuperBlock->sectionCount); +} + +/* + * @tc.name: MkfsHmfsTest_z_003 + * @tc.desc: test for parameter z + * @tc.type: FUNC + */ +HWTEST_F(MkfsHmfsSingleTest, Test_param_z_003, TestSize.Level1) +{ + std::vector params; + params.emplace_back("-z 6"); + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params, "/data/f2fsTest")); + + EXPECT_NE(0, MkfsHmfsSingleTest::ExecMkfsBinary("hmfs", params, "/data/hmfsTest")); +} + +// /* +// * @tc.name: MkfsHmfsTest_t_002 +// * @tc.desc: test for parameter t +// * @tc.type: FUNC +// */ +// HWTEST_F(MkfsHmfsSingleTest, Test002, TestSize.Level1) +// { +// std::string fileName("/data/hmfs_example.txt"); +// EXPECT_EQ(WriteFile(fileName), 0); +// EXPECT_NE(ReadFile(fileName), ""); + +// EXPECT_EQ(FAllocateFile(fileName), 0); +// EXPECT_EQ(CheckDataIsZero(fileName), HmfsCode::SUCCESSED); +// EXPECT_NE(ReadFile(fileName), ""); + +// EXPECT_EQ(WriteFile(fileName), 0); +// EXPECT_NE(ReadFile(fileName), ""); + +// std::string hmfsName("/data/hmfsTest"); + +// std::vector params; +// params.emplace_back("-a 0"); +// params.emplace_back(hmfsName); +// EXPECT_EQ(0, MkfsHmfsSingleTest::ExecMkfsBinary("f2fs", params)); + +// EXPECT_EQ(CheckDataIsZero(hmfsName), HmfsCode::FAILED); + +// struct stat statBuf{}; +// EXPECT_EQ(GetFileStat(hmfsName, &statBuf), 0);; +// } + +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/resize_test/BUILD.gn b/tools/hmfs-tools/test/unittest/resize_test/BUILD.gn new file mode 100755 index 0000000..a9a0477 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/resize_test/BUILD.gn @@ -0,0 +1,73 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +ohos_unittest("resize_hmfs_single_test") { + module_out_path = "${module_output_path}" + if (hmfs_unittest_coverage) { + cflags = [ "--coverage" ] + ldflags = [ "--coverage" ] + cflags_cc = [ "--coverage" ] + } + defines = [ "HMFS_UNIT_TEST" ] + deps = [ "${hmfs_tools_path}/common:libhmfs" ] + + # 被测试代码 + include_dirs = [ "${hmfs_tools_path}/common" ] + sources = [] + + # 测试代码 + include_dirs += [ "${hmfs_path}/test/unittest/utils" ] + sources += [ + "${hmfs_path}/test/unittest/resize_test/resize_single_test.cpp", + "${hmfs_path}/test/unittest/utils/hmfs_test_utils.cpp", + ] + + external_deps = [ + "bounds_checking_function:libsec_shared", + "googletest:gmock", + "googletest:gtest", + "hilog:libhilog", + ] +} + +ohos_unittest("resize_hmfs_multi_test") { + module_out_path = "${module_output_path}" + if (hmfs_unittest_coverage) { + cflags = [ "--coverage" ] + ldflags = [ "--coverage" ] + cflags_cc = [ "--coverage" ] + } + defines = [ "HMFS_UNIT_TEST" ] + deps = [ "${hmfs_tools_path}/common:libhmfs" ] + + # 被测试代码 + include_dirs = [ "${hmfs_tools_path}/common" ] + sources = [] + + # 测试代码 + include_dirs += [ "${hmfs_path}/test/unittest/utils" ] + sources += [ + "${hmfs_path}/test/unittest/resize_test/resize_multi_test.cpp", + "${hmfs_path}/test/unittest/utils/hmfs_test_utils.cpp", + ] + + external_deps = [ + "bounds_checking_function:libsec_shared", + "googletest:gmock", + "googletest:gtest", + "hilog:libhilog", + ] +} diff --git a/tools/hmfs-tools/test/unittest/resize_test/resize_multi_test.cpp b/tools/hmfs-tools/test/unittest/resize_test/resize_multi_test.cpp new file mode 100755 index 0000000..c9c937b --- /dev/null +++ b/tools/hmfs-tools/test/unittest/resize_test/resize_multi_test.cpp @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, Hardware + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "gtest/gtest.h" +#include "hmfs_test_utils.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Hmfs { +class ResizeHmfsMultiTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + static int32_t ExecResizeBinary(std::string tool, std::vector ¶ms, std::string device); + static int32_t ExecutableCmd(const char *path, char *const argv[]); + static int32_t ExecutableDdCmd(std::string& device, const int32_t count); + static int32_t ExecutableRmCmd(std::string file); + static int32_t ExecutableMkfsCmd(std::string tool, std::string& device); + static int32_t ExecutableCmdWithOutput(std::vector& params, std::string& outputFile); + static int32_t ExecResizeBinaryWithOutput(std::string tool, std::vector& params, + std::string device, std::string& outputFile); + static int32_t ExecFsckWithOutput(std::string& device, std::string& outputFile); + void PrintResizeParameters(const std::vector ¶ms); + uint64_t GetDeviceSectorCount(const std::string& filePath); +}; + +void ResizeHmfsMultiTest::SetUpTestCase() {} + +void ResizeHmfsMultiTest::TearDownTestCase() {} + +void ResizeHmfsMultiTest::SetUp() {} + +void ResizeHmfsMultiTest::TearDown() +{ + std::vector argv; + argv.push_back(const_cast("/bin/sh")); + argv.push_back(const_cast("-c")); + argv.push_back(const_cast("rm -rf /data/Fs* /data/HM*")); + argv.push_back(nullptr); + + ResizeHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsMultiTest::ExecutableRmCmd(std::string file) +{ + std::vector argv; + argv.push_back(const_cast("/bin/sh")); + argv.push_back(const_cast("-c")); + argv.push_back(const_cast(("rm -rf " + file).c_str())); + argv.push_back(nullptr); + + return ResizeHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsMultiTest::ExecutableCmd(const char *path, char *const argv[]) +{ + if (path == nullptr || argv == nullptr ) { + return -1; + } + + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + execv(path, argv); + _exit(EXIT_FAILURE); + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1 || wpid != pid) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + +int32_t ResizeHmfsMultiTest::ExecutableCmdWithOutput(std::vector& params, std::string& outputFile) +{ + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + int fd = open(outputFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd < 0) { + _exit(EXIT_FAILURE); + } + dup2(fd, STDOUT_FILENO); + close(fd); + + std::vector argv; + for (const auto& param : params) { + argv.push_back(const_cast(param.c_str())); + } + argv.push_back(nullptr); + execv(argv[0], argv.data()); + _exit(EXIT_FAILURE); + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1 || wpid != pid) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + + +int32_t ResizeHmfsMultiTest::ExecutableMkfsCmd(std::string tool, std::string& device) +{ + std::vector argv; + argv.push_back(const_cast(("/system/bin/mkfs." + tool).c_str())); + argv.push_back(const_cast((device).c_str())); + argv.push_back(nullptr); + return ResizeHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsMultiTest::ExecutableDdCmd(std::string& device, int32_t count) +{ + std::string countStr = std::to_string(count); + std::vector argv; + argv.push_back(const_cast("/system/bin/dd")); + argv.push_back(const_cast("if=/dev/zero")); + argv.push_back(const_cast(("of=" + device).c_str())); + argv.push_back(const_cast("bs=1M")); + argv.push_back(const_cast(("count=" + countStr).c_str())); + argv.push_back(nullptr); + return ResizeHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsMultiTest::ExecResizeBinary(std::string tool, std::vector ¶ms, std::string device) +{ + std::vector argv; + argv.push_back(const_cast(("/system/bin/resize." + tool).c_str())); + for (const auto ¶m : params) { + argv.push_back(const_cast(param.c_str())); + } + argv.push_back(const_cast(device.c_str())); + argv.push_back(nullptr); + return ResizeHmfsMultiTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsMultiTest::ExecResizeBinaryWithOutput(std::string tool, std::vector& params, + std::string device, std::string& outputFile) +{ + std::vector argv; + argv.push_back("/system/bin/resize." + tool); + for (const auto& param : params) { + argv.push_back(param); + } + argv.push_back(device); + return ExecutableCmdWithOutput(argv, outputFile); +} + +int32_t ResizeHmfsMultiTest::ExecFsckWithOutput(std::string& device, std::string& outputFile) +{ + std::vector argv; + argv.push_back("/system/bin/fsck.f2fs"); + argv.push_back(device); + return ExecutableCmdWithOutput(argv, outputFile); +} + +void ResizeHmfsMultiTest::PrintResizeParameters(const std::vector ¶ms) +{ + std::cout << "+----------------------------------------------------------------+" << std::endl; + for (int32_t i = 0; i < params.size(); i++) { + std::cout << params[i] << " "; + } + std::cout << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; +} + +uint64_t ResizeHmfsMultiTest::GetDeviceSectorCount(const std::string& filePath) +{ + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(filePath, hmfsSuperBlock); + + return hmfsSuperBlock->blockCount * DEFAULT_SECTORS_PER_BLOCK; +} + +/* + * @tc.name: ResizeHmfsMultiTest_MultiParams_001 + * @tc.desc: Test resize.hmfs with multiple random parameters. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsMultiTest, ResizeHmfsMultiTest_MultiParams_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsMultiTest_MultiParams_001 BEGIN" << std::endl; + std::string device = "/data/FsMultiTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(device, 1000)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("f2fs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("1024000"); + params.push_back("-O"); + params.push_back("extra_attr,project_quota,casefold"); + params.push_back("-C"); + params.push_back("utf8"); + params.push_back("-i"); + params.push_back("-o"); + params.push_back("60"); + params.push_back("-d"); + params.push_back("1"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecResizeBinaryWithOutput("f2fs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + EXPECT_TRUE(output.find("Info: Done to update superblock") != std::string::npos); + EXPECT_TRUE(output.find("Info: Debug level = 1") != std::string::npos); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCheckPoint); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecResizeBinary("hmfs", params, hmDevice)); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCheckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCheckPoint); + ASSERT_EQ(f2fsCheckPoint->cpFlags, hmfsCheckPoint->cpFlags); + ASSERT_EQ(f2fsCheckPoint->checksumOffset, hmfsCheckPoint->checksumOffset); + ASSERT_EQ(f2fsCheckPoint->overprovSegmentCount, hmfsCheckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCheckPoint->rsvdSegmentCount, hmfsCheckPoint->rsvdSegmentCount); + ASSERT_EQ(f2fsSuperBlock->encoding, hmfsSuperBlock->encoding); + ASSERT_EQ(f2fsSuperBlock->encodingFlags, hmfsSuperBlock->encodingFlags); + ASSERT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + ASSERT_EQ(f2fsSuperBlock->blockCount, hmfsSuperBlock->blockCount); + + ASSERT_EQ(hmfsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_PRJQUOTA); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_EXTRA_ATTR); + ASSERT_TRUE(hmfsCheckPoint->cpFlags & CP_FLAG_LARGE_NAT_BITMAP); + + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_MultiParams_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_MultiParams_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsMultiTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsMultiTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + + std::cout << "-------------------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + std::cout << "-------------------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + std::cout << "ResizeHmfsMultiTest_MultiParams_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsMultiTest_MultiParams_002 + * @tc.desc: Test resize.hmfs with multiple random parameters. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsMultiTest, ResizeHmfsMultiTest_MultiParams_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsMultiTest_MultiParams_002 BEGIN" << std::endl; + std::srand(std::time(nullptr)); // 初始化随机数种子 + std::string device = "/data/FsMultiTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(device, 1000)); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(hmDevice, 1000)); + + for (int i = 0; i < 2000; ++i) { + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("f2fs", device)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("hmfs", hmDevice)); + uint64_t sectorCount = ResizeHmfsMultiTest::GetDeviceSectorCount(hmDevice); + + std::vector generateParams = GenerateParams(); + ResizeHmfsMultiTest::PrintResizeParameters(generateParams); + + std::map parameterMap{}; + int32_t verifParameters = CheckResizeParameters(hmDevice, generateParams, sectorCount, parameterMap); + + std::string hmfsOutputFile = "/data/test_output_hmfs_multi_" + std::to_string(i) + ".txt"; + std::string f2fsOutputFile = "/data/test_output_f2fs_multi_" + std::to_string(i) + ".txt"; + int32_t f2fsResult = ResizeHmfsMultiTest::ExecResizeBinaryWithOutput("f2fs", generateParams, device, f2fsOutputFile); + int32_t hmfsResult = ResizeHmfsMultiTest::ExecResizeBinaryWithOutput("hmfs", generateParams, hmDevice, hmfsOutputFile); + std::string output = ReadFile(hmfsOutputFile); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCheckPoint); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCheckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCheckPoint); + PrintSuperBlockAndCheckPointData(hmDevice); + + if (verifParameters == NEED_SAFE_RESIZE_FLAG) { + ASSERT_TRUE(output.find("Nothing to resize, now only supports resizing with safe resize flag") != std::string::npos); + ASSERT_EQ(0, ExecutableRmCmd(hmfsOutputFile)); + ASSERT_EQ(0, ExecutableRmCmd(f2fsOutputFile)); + } else if (verifParameters == OUT_OF_RANGE) { + ASSERT_TRUE(output.find("Out-of-range Target") != std::string::npos); + ASSERT_EQ(0, ExecutableRmCmd(hmfsOutputFile)); + ASSERT_EQ(0, ExecutableRmCmd(f2fsOutputFile)); + } else if (verifParameters == MORE_SEGMENT_NEEDED) { + ASSERT_TRUE(output.find("Error: Device size is not sufficient for F2FS volume, more segment needed") != std::string::npos); + ASSERT_EQ(0, ExecutableRmCmd(hmfsOutputFile)); + ASSERT_EQ(0, ExecutableRmCmd(f2fsOutputFile)); + } else if (verifParameters == VALID) { + ASSERT_EQ(f2fsResult, hmfsResult); + if (hmfsResult == 0) { + ASSERT_TRUE(!output.empty()); + // 对比hmfs和f2fs字段一致 + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + ASSERT_EQ(SUCCESSED_SB, compSB); + CheckPointCode compCP = ERROR_CP_UNKNOWN; + if (f2fsCheckPoint != nullptr && hmfsCheckPoint != nullptr) { + compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + ASSERT_EQ(SUCCESSED_CP, compCP); + } + if (output.find("Info: Done to update superblock") != std::string::npos && + output.find("Info: Done to rebuild checkpoint blocks") != std::string::npos) { + ASSERT_TRUE(CheckResizeHmfsResult(parameterMap, hmfsCheckPoint, hmfsSuperBlock, output)); + if (CheckResizeHmfsResult(parameterMap, hmfsCheckPoint, hmfsSuperBlock, output)) + { + ASSERT_EQ(0, ExecutableRmCmd(hmfsOutputFile)); + ASSERT_EQ(0, ExecutableRmCmd(f2fsOutputFile)); + } + } else { + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + ASSERT_EQ(SUCCESSED_SB, compSB); + CheckPointCode compCP = ERROR_CP_UNKNOWN; + if (f2fsCheckPoint != nullptr && hmfsCheckPoint != nullptr) { + compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + ASSERT_EQ(SUCCESSED_CP, compCP); + } + // ASSERT_EQ(0, ExecutableRmCmd(hmfsOutputFile)); + // ASSERT_EQ(0, ExecutableRmCmd(f2fsOutputFile)); + } + } + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_MultiParams_002_" + std::to_string(i) + ".txt";; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_MultiParams_002_" + std::to_string(i) + ".txt"; + int32_t fsckHmfsRes = ResizeHmfsMultiTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + int32_t fsckF2fsRes = ResizeHmfsMultiTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + } + } + std::cout << "ResizeHmfsMultiTest_MultiParams_002 END" << std::endl; +} + +#ifdef AAA +/* + * @tc.name: ResizeHmfsMultiTest_MultiParams_003 + * @tc.desc: Test resize.hmfs multiple times with randomly generated parameters. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsMultiTest, ResizeHmfsMultiTest_MultiParams_003, TestSize.Level1) +{ + std::cout << "ResizeHmfsMultiTest_MultiParams_003 BEGIN" << std::endl; + std::srand(std::time(nullptr)); + std::string device = "/data/FsMultiTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(device, 100)); + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(hmDevice, 100)); + + for (int32_t i = 0; i < 10; ++i) { + std::cout << "---- Iteration " << i + 1 << " ----" << std::endl; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("f2fs", device)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("f2fs", hmDevice)); + uint64_t sectorCount = ResizeHmfsMultiTest::GetDeviceSectorCount(hmDevice); + for (int j = 0; j < 5; ++j) { + std::cout << "Resize attempt " << j + 1 << " for iteration " << i + 1 << std::endl; + std::vector generateParams = GenerateParams(); + ResizeHmfsMultiTest::PrintResizeParameters(generateParams); + std::map parameterMap{}; + int32_t verifParameters = CheckResizeParameters(hmDevice, generateParams, sectorCount, parameterMap); + + std::string outputFile = "/data/test_output_multi_" + std::to_string(i) + "_" + std::to_string(j) + ".txt"; + int32_t f2fsResult = ResizeHmfsMultiTest::ExecResizeBinary("f2fs", generateParams, device); + int32_t hmfsResult = ResizeHmfsMultiTest::ExecResizeBinaryWithOutput("f2fs", generateParams, hmDevice, outputFile); + std::string output = ReadFile(outputFile); + + std::string HmfsFsckOutFileName = "/data/Mkfs_Hmfs_Fsck_MultiParams_002_" + std::to_string(i) + ".txt";; + std::string F2fsFsckOutFileName = "/data/Mkfs_F2fs_Fsck_MultiParams_002_" + std::to_string(i) + ".txt"; + int32_t fsckF2fsRes = ResizeHmfsMultiTest::ExecFsckWithOutput(hmfsDevice, HmfsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsMultiTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + } + } + + if (verifParameters == NEED_SAFE_RESIZE_FLAG) { + ASSERT_TRUE(output.find("Nothing to resize, now only supports resizing with safe resize flag") != std::string::npos); + ASSERT_EQ(0, ExecutableRmCmd(outputFile)); + } else if (verifParameters == OUT_OF_RANGE) { + ASSERT_TRUE(output.find("Out-of-range Target") != std::string::npos); + ASSERT_EQ(0, ExecutableRmCmd(outputFile)); + } else if (verifParameters == MORE_SEGMENT_NEEDED) { + ASSERT_TRUE(output.find("Error: Device size is not sufficient for F2FS volume, more segment needed") != std::string::npos); + ASSERT_EQ(0, ExecutableRmCmd(outputFile)); + } else if (verifParameters == VALID) { + ASSERT_EQ(f2fsResult, hmfsResult); + if (hmfsResult == 0) { + ASSERT_TRUE(!output.empty()); + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCheckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCheckPoint); + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCheckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCheckPoint); + // PrintSuperBlockAndCheckPointData(hmDevice); + + SuperBlockCode compSB = CompareSuperBlock(f2fsSuperBlock, hmfsSuperBlock); + ASSERT_EQ(SUCCESSED_SB, compSB); + CheckPointCode compCP = ERROR_CP_UNKNOWN; + if (f2fsCheckPoint != nullptr && hmfsCheckPoint != nullptr) { + compCP = CompareCheckPoint(f2fsCheckPoint, hmfsCheckPoint); + ASSERT_EQ(SUCCESSED_CP, compCP); + } + if (output.find("Info: Done to update superblock") != std::string::npos && + output.find("Info: Done to rebuild checkpoint blocks") != std::string::npos) { + ASSERT_TRUE(CheckResizeHmfsResult(parameterMap, hmfsCheckPoint, hmfsSuperBlock, output)); + if (CheckResizeHmfsResult(parameterMap, hmfsCheckPoint, hmfsSuperBlock, output)) + { + ASSERT_EQ(0, ExecutableRmCmd(outputFile)); + } + } + } + } + } + } + std::cout << "ResizeHmfsMultiTest_MultiParams_003 END" << std::endl; +} +#endif + +/* + * @tc.name: ResizeHmfsMultiTest_ExitUnexpectedly_001 + * @tc.desc: Test resize.hmfs multiple times with randomly generated parameters. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsMultiTest, ResizeHmfsMultiTest_ExitUnexpectedly_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsMultiTest_ExitUnexpectedly_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(device, 1000)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("f2fs", device)); + std::vector params; + params.clear(); + params.push_back("-O"); + params.push_back("extra_attr,project_quota"); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + std::string outputFile = "/data/test_output.txt"; + auto f2fsSuperBlock = std::make_unique(); + pid_t pid = fork(); + if (pid < 0) { + assert(pid >= 0 && "fork failed with errno = " + std::to_string(errno)); + } + if (pid == 0) { + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecResizeBinary("f2fs", params, device)); + sleep(10); + } + while (true) { + GetSuperBlock(device, f2fsSuperBlock); + uint32_t features = f2fsSuperBlock->features; + if (features & HMFS_FEATURE_EXTRA_ATTR) { + kill(pid, SIGKILL); + break; + } + } + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecResizeBinaryWithOutput("f2fs", params, device, outputFile)); + std::cout << "ResizeHmfsMultiTest_ExitUnexpectedly_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsMultiTest_ExitUnexpectedly_002 + * @tc.desc: Test resize.hmfs multiple times with randomly generated parameters. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsMultiTest, ResizeHmfsMultiTest_ExitUnexpectedly_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsMultiTest_ExitUnexpectedly_002 BEGIN" << std::endl; + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableDdCmd(hmDevice, 1000)); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecutableMkfsCmd("hmfs", hmDevice)); + std::vector params; + params.clear(); + params.push_back("-O"); + params.push_back("extra_attr,project_quota"); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + std::string outputFile = "/data/test_output.txt"; + auto hmfsSuperBlock = std::make_unique(); + pid_t pid = fork(); + if (pid < 0) { + assert(pid >= 0 && "fork failed with errno = " + std::to_string(errno)); + } + if (pid == 0) { + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecResizeBinary("hmfs", params, hmDevice)); + sleep(10); + } + while (true) { + GetSuperBlock(hmDevice, hmfsSuperBlock); + uint32_t features = hmfsSuperBlock->features; + if (features & HMFS_FEATURE_EXTRA_ATTR) { + kill(pid, SIGKILL); + break; + } + } + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + ASSERT_EQ(0, ResizeHmfsMultiTest::ExecResizeBinaryWithOutput("hmfs", params, hmDevice, outputFile)); + std::cout << "ResizeHmfsMultiTest_ExitUnexpectedly_002 END" << std::endl; +} +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/resize_test/resize_single_test.cpp b/tools/hmfs-tools/test/unittest/resize_test/resize_single_test.cpp new file mode 100755 index 0000000..4b7b800 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/resize_test/resize_single_test.cpp @@ -0,0 +1,1504 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, Hardware + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "gtest/gtest.h" +#include "hmfs_test_utils.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace Hmfs { +const std::string F2FS_RESIZE_BINARY_PATH = "/system/bin/resize.f2fs"; +const std::string HMFS_RESIZE_BINARY_PATH = "/system/bin/resize.hmfs"; +const std::string F2FS_MKFS_BINARY_PATH = "/system/bin/mkfs.f2fs"; +const std::string HMFS_MKFS_BINARY_PATH = "/system/bin/mkfs.hmfs"; +const std::string FSCK_BINARY_PATH = "/system/bin/fsck.f2fs"; + +class ResizeHmfsSingleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + static int32_t ExecResizeBinary(std::string tool, std::vector ¶ms, std::string device); + static int32_t ExecutableCmd(const char *path, char *const argv[]); + static int32_t ExecutableDdCmd(std::string& device, const int32_t count); + static int32_t ExecutableRmCmd(std::string file); + static int32_t ExecutableMkfsCmd(std::string tool, std::string& device); + static int32_t ExecutableCmdWithOutput(std::vector& params, std::string& outputFile); + static int32_t ExecResizeBinaryWithOutput(std::string tool, std::vector& params, + std::string device, std::string& outputFile); + static int32_t ExecFsckWithOutput(std::string& device, std::string& outputFile); +}; + +void ResizeHmfsSingleTest::SetUpTestCase() {} + +void ResizeHmfsSingleTest::TearDownTestCase() {} + +void ResizeHmfsSingleTest::SetUp() {} + +void ResizeHmfsSingleTest::TearDown() +{ + std::vector argv; + argv.push_back(const_cast("/bin/sh")); + argv.push_back(const_cast("-c")); + argv.push_back(const_cast("rm -rf /data/Fs* /data/HM*")); + argv.push_back(nullptr); + + ResizeHmfsSingleTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsSingleTest::ExecutableRmCmd(std::string file) +{ + std::vector argv; + argv.push_back(const_cast("/bin/sh")); + argv.push_back(const_cast("-c")); + argv.push_back(const_cast(("rm -rf " + file).c_str())); + argv.push_back(nullptr); + + return ResizeHmfsSingleTest::ExecutableCmd(argv[0], argv.data()); +} + + +int32_t ResizeHmfsSingleTest::ExecutableCmd(const char *path, char *const argv[]) +{ + if (path == nullptr || argv == nullptr ) { + return -1; + } + + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + execv(path, argv); + _exit(EXIT_FAILURE); + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1 || wpid != pid) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + +int32_t ResizeHmfsSingleTest::ExecutableCmdWithOutput(std::vector& params, std::string& outputFile) +{ + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + int fd = open(outputFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd < 0) { + _exit(EXIT_FAILURE); + } + dup2(fd, STDOUT_FILENO); + close(fd); + + std::vector argv; + for (const auto& param : params) { + argv.push_back(const_cast(param.c_str())); + } + argv.push_back(nullptr); + execv(argv[0], argv.data()); + _exit(EXIT_FAILURE); + } + + int status = -1; + pid_t wpid = waitpid(pid, &status, 0); + if (wpid == -1 || wpid != pid) { + return -errno; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -ECHILD; +} + + +int32_t ResizeHmfsSingleTest::ExecutableMkfsCmd(std::string tool, std::string& device) +{ + std::vector argv; + if (tool == "f2fs") { + argv.emplace_back(const_cast(F2FS_MKFS_BINARY_PATH.c_str())); + } + if (tool == "hmfs") { + argv.emplace_back(const_cast(HMFS_MKFS_BINARY_PATH.c_str())); + } + argv.push_back(const_cast((device).c_str())); + argv.push_back(nullptr); + return ResizeHmfsSingleTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsSingleTest::ExecutableDdCmd(std::string& device, int32_t count) +{ + std::string countStr = std::to_string(count); + std::vector argv; + argv.push_back(const_cast("/system/bin/dd")); + argv.push_back(const_cast("if=/dev/zero")); + argv.push_back(const_cast(("of=" + device).c_str())); + argv.push_back(const_cast("bs=1M")); + argv.push_back(const_cast(("count=" + countStr).c_str())); + argv.push_back(nullptr); + return ResizeHmfsSingleTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsSingleTest::ExecResizeBinary(std::string tool, std::vector ¶ms, std::string device) +{ + std::vector argv; + if (tool == "f2fs") { + argv.emplace_back(const_cast(F2FS_RESIZE_BINARY_PATH.c_str())); + } + if (tool == "hmfs") { + argv.emplace_back(const_cast(HMFS_RESIZE_BINARY_PATH.c_str())); + } + for (const auto ¶m : params) { + argv.push_back(const_cast(param.c_str())); + } + argv.push_back(const_cast(device.c_str())); + argv.push_back(nullptr); + return ResizeHmfsSingleTest::ExecutableCmd(argv[0], argv.data()); +} + +int32_t ResizeHmfsSingleTest::ExecResizeBinaryWithOutput(std::string tool, std::vector& params, + std::string device, std::string& outputFile) +{ + std::vector argv; + if (tool == "f2fs") { + argv.emplace_back(const_cast(F2FS_RESIZE_BINARY_PATH.c_str())); + } + if (tool == "hmfs") { + argv.emplace_back(const_cast(HMFS_RESIZE_BINARY_PATH.c_str())); + } + for (const auto& param : params) { + argv.push_back(param); + } + argv.push_back(device); + return ExecutableCmdWithOutput(argv, outputFile); +} + +int32_t ResizeHmfsSingleTest::ExecFsckWithOutput(std::string& device, std::string& outputFile) +{ + std::vector argv; + argv.push_back(FSCK_BINARY_PATH); + argv.push_back(device); + return ExecutableCmdWithOutput(argv, outputFile); +} + +/* + * @tc.name: ResizeHmfsSingleTest_V_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_V_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_V_001 BEGIN" << std::endl; + std::vector params; + params.push_back("/system/bin/resize.hmfs"); + params.push_back("-V"); + + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableCmdWithOutput(params, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Hmfstool version") != std::string::npos); + std::cout << "ResizeHmfsSingleTest_V_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_C_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_C_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_C_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + std::vector params; + params.clear(); + params.push_back("-C"); + params.push_back("utf8"); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + + ASSERT_EQ(f2fsSuperBlock->encoding, hmfsSuperBlock->encoding); + ASSERT_EQ(f2fsSuperBlock->encodingFlags, hmfsSuperBlock->encodingFlags); + ASSERT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + + ASSERT_EQ(f2fsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + ASSERT_EQ(hmfsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_C_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_C_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_C_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_C_002 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_C_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_C_002 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + std::vector params; + params.clear(); + params.push_back("-C"); + params.push_back("ascii"); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, device)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::cout << "ResizeHmfsSingleTest_C_002 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_O_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_O_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_O_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + std::vector params; + params.clear(); + params.push_back("-O"); + params.push_back("extra_attr,project_quota"); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsCTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + + ASSERT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_EXTRA_ATTR); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_PRJQUOTA); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_EXTRA_ATTR); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_PRJQUOTA); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_O_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_O_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_O_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_O_002 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_O_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_O_002 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + std::vector params; + params.clear(); + params.push_back("-O"); + params.push_back("casefold"); + params.push_back("-C"); + params.push_back("utf8"); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + + ASSERT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + ASSERT_EQ(f2fsSuperBlock->encoding, hmfsSuperBlock->encoding); + ASSERT_EQ(f2fsSuperBlock->encodingFlags, hmfsSuperBlock->encodingFlags); + + ASSERT_EQ(f2fsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + ASSERT_EQ(hmfsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_O_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_O_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_O_002 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_O_003 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_O_003, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_O_003 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + std::vector params; + params.clear(); + params.push_back("-O"); + params.push_back("casefold,extra_attr,project_quota"); + params.push_back("-C"); + params.push_back("utf8"); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + + ASSERT_EQ(f2fsSuperBlock->features, hmfsSuperBlock->features); + ASSERT_EQ(f2fsSuperBlock->encoding, hmfsSuperBlock->encoding); + ASSERT_EQ(f2fsSuperBlock->encodingFlags, hmfsSuperBlock->encodingFlags); + + ASSERT_EQ(f2fsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_EXTRA_ATTR); + ASSERT_TRUE(f2fsSuperBlock->features & HMFS_FEATURE_PRJQUOTA); + + ASSERT_EQ(hmfsSuperBlock->encoding, HMFS_ENC_UTF8_12_1); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_CASEFOLD); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_EXTRA_ATTR); + ASSERT_TRUE(hmfsSuperBlock->features & HMFS_FEATURE_PRJQUOTA); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_O_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_O_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_O_003 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_O_004 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_O_004, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_O_004 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + std::vector params; + params.clear(); + params.push_back("-O"); + params.push_back("abcd"); + + std::string outputFile = "/data/test_output_ResizeHmfsSingleTest_O_004.txt"; + ASSERT_EQ(1, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Error: Wrong features") != std::string::npos); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_O_004 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_s_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_s_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_s_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + std::vector params; + params.clear(); + params.push_back("-t"); + params.push_back("102400"); + + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Nothing to resize, now only supports resizing with safe resize flag") != std::string::npos); + + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_s_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_t_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_t_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_t_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + + //mkfs fsck check + std::string F2fsMkfsFsckOutFileName = "/data/Fsck_F2fs_Mkfs_SingleParams_t_001.txt"; + int32_t fsckMkfsF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsMkfsFsckOutFileName); + std::string HmfsMkfsFsckOutFileName = "/data/Fsck_Hmfs_Mkfs_SingleParams_t_001.txt"; + int32_t fsckMkfsHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsMkfsFsckOutFileName); + ASSERT_EQ(fsckMkfsF2fsRes, fsckMkfsHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsMkfsFsckOutFileName, hmDevice)); + if (fsckMkfsHmfsRes == 0) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsMkfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsMkfsFsckOutFileName)); + } + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + ASSERT_EQ(f2fsSuperBlock->blockCount, hmfsSuperBlock->blockCount); + + uint64_t targetSectors = 102400; + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back(std::to_string(targetSectors)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto resizeF2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, resizeF2fsSuperBlock); + auto resizeHmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, resizeHmfsSuperBlock); + ASSERT_EQ(resizeF2fsSuperBlock->blockCount, resizeHmfsSuperBlock->blockCount); + ASSERT_EQ(hmfsSuperBlock->blockCount, resizeHmfsSuperBlock->blockCount*2); + + //值校验 + uint64_t targetBlockCounts = targetSectors >> resizeF2fsSuperBlock->logSectorsPerBlk; + ASSERT_EQ(targetBlockCounts, resizeF2fsSuperBlock->blockCount); + + //resize fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_t_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_t_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckHmfsRes == 0) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + std::cout << "ResizeHmfsSingleTest_t_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_t_002 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_t_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_t_002 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + uint64_t targetSectors = 122880; + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back(std::to_string(targetSectors)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + + ASSERT_EQ(f2fsSuperBlock->blockCount, hmfsSuperBlock->blockCount); + //值校验 + uint64_t targetBlockCounts = targetSectors >> f2fsSuperBlock->logSectorsPerBlk; + ASSERT_EQ(targetBlockCounts, f2fsSuperBlock->blockCount); + + targetSectors = 184320; + std::vector resizeParams; + resizeParams.clear(); + resizeParams.push_back("-t"); + resizeParams.push_back(std::to_string(targetSectors)); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", resizeParams, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto resizeF2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, resizeF2fsSuperBlock); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", resizeParams, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto resizeHmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, resizeHmfsSuperBlock); + + ASSERT_EQ(resizeF2fsSuperBlock->blockCount, resizeHmfsSuperBlock->blockCount); + //值校验 + targetBlockCounts = targetSectors >> resizeF2fsSuperBlock->logSectorsPerBlk; + ASSERT_EQ(targetBlockCounts, resizeF2fsSuperBlock->blockCount); + + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_t_002.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_t_002.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_t_002 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_t_003 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_t_003, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_t_003 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsCTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + ASSERT_EQ(f2fsSuperBlock->blockCount, hmfsSuperBlock->blockCount); + + std::vector resizeParams; + resizeParams.clear(); + + EXPECT_NE(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", resizeParams, device)); + EXPECT_NE(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", resizeParams, hmDevice)); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_t_002.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_t_002.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_t_003 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_t_004 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_t_004, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_t_004 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 1000)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 1000)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + ASSERT_EQ(f2fsSuperBlock->blockCount, hmfsSuperBlock->blockCount); + uint64_t targetSectors = 1024000; + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back(std::to_string(targetSectors)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto resizeF2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, resizeF2fsSuperBlock); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto resizeHmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, resizeHmfsSuperBlock); + ASSERT_EQ(resizeF2fsSuperBlock->blockCount, resizeHmfsSuperBlock->blockCount); + ASSERT_EQ(hmfsSuperBlock->blockCount, resizeHmfsSuperBlock->blockCount*2); + //值校验 + uint64_t targetBlockCounts = targetSectors >> resizeF2fsSuperBlock->logSectorsPerBlk; + ASSERT_EQ(targetBlockCounts, resizeF2fsSuperBlock->blockCount); + + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_t_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_t_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_t_004 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_t_005 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_t_005, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_t_005 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("20"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Error: Device size is not sufficient for F2FS volume, more segment needed") != std::string::npos); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_t_005 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_t_006 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_t_006, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_t_006 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-t"); + params.push_back("409600"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Out-of-range Target") != std::string::npos); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_t_006 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + double overprovision = 60.0; + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-o"); + params.push_back(std::to_string(overprovision)); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("f2fs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Info: Overprovision ratio = 60.000%") != std::string::npos); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + std::cout << "overprovSegmentCount: " << f2fsCkeckPoint->overprovSegmentCount << std::endl; + std::cout << "rsvdSegmentCount: " << f2fsCkeckPoint->rsvdSegmentCount << std::endl; + + uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * f2fsSuperBlock->segsPerSection; + std::cout << "f2fsSuperBlock->segsPerSection: " << f2fsSuperBlock->segsPerSection << std::endl; + std::cout << "校验-o参数 reservedSegments = " << reservedSegments << std::endl; + uint32_t overprov_segment_count = (f2fsSuperBlock->segmentCountInMain - reservedSegments) * overprovision / 100; + overprov_segment_count = overprov_segment_count + reservedSegments; + std::cout << "校验-o参数 overprov_segment_count = " << overprov_segment_count << std::endl; + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, overprov_segment_count); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, reservedSegments); + + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_001.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_001.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_o_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_002 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_002 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 1000)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + double overprovision = 60.0; + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("1024000"); + params.push_back("-o"); + params.push_back(std::to_string(overprovision)); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("f2fs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Info: Overprovision ratio = 60.000%") != std::string::npos); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 1000)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + std::cout << "overprovSegmentCount: " << f2fsCkeckPoint->overprovSegmentCount << std::endl; + std::cout << "rsvdSegmentCount: " << f2fsCkeckPoint->rsvdSegmentCount << std::endl; + + uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * f2fsSuperBlock->segsPerSection; + std::cout << "f2fsSuperBlock->segsPerSection: " << f2fsSuperBlock->segsPerSection << std::endl; + std::cout << "校验-o参数 reservedSegments = " << reservedSegments << std::endl; + uint32_t overprov_segment_count = (f2fsSuperBlock->segmentCountInMain - reservedSegments) * overprovision / 100; + overprov_segment_count = overprov_segment_count + reservedSegments; + std::cout << "校验-o参数 overprov_segment_count = " << overprov_segment_count << std::endl; + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, overprov_segment_count); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, reservedSegments); + + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_002.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_002.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_o_002 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_003 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_003, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_003 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-o"); + params.push_back("1"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Error: Device size is not sufficient for F2FS volume, more segment needed") != std::string::npos); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_o_003 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_004 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_004, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_004 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-o"); + params.push_back("100"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::cout << "ResizeHmfsSingleTest_o_004 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_005 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_005, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_005 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + double overprovision = 0.0; + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-o"); + params.push_back("0"); + + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + overprovision = HmfsCommon::GetInstance().GetBestOverProvision(hmfsSuperBlock.get()); + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * f2fsSuperBlock->segsPerSection; + std::cout << "f2fsSuperBlock->segsPerSection: " << f2fsSuperBlock->segsPerSection << std::endl; + std::cout << "校验-o参数 reservedSegments = " << reservedSegments << std::endl; + uint32_t overprov_segment_count = (f2fsSuperBlock->segmentCountInMain - reservedSegments) * overprovision / 100; + overprov_segment_count = overprov_segment_count + reservedSegments; + std::cout << "校验-o参数 overprov_segment_count = " << overprov_segment_count << std::endl; + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, overprov_segment_count); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, reservedSegments); + + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_005.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_005.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_o_005 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_006 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_006, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_006 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-o"); + params.push_back("1000"); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_006.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_006.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_o_006 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_o_007 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_o_007, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_o_007 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-o"); + params.push_back("-1000"); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + + ASSERT_EQ(f2fsCkeckPoint->overprovSegmentCount, hmfsCkeckPoint->overprovSegmentCount); + ASSERT_EQ(f2fsCkeckPoint->rsvdSegmentCount, hmfsCkeckPoint->rsvdSegmentCount); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_007.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_007.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_o_007 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_i_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_i_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_i_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-i"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + + ASSERT_EQ(f2fsCkeckPoint->cpFlags, hmfsCkeckPoint->cpFlags); + ASSERT_EQ(f2fsCkeckPoint->checksumOffset, f2fsCkeckPoint->checksumOffset); + ASSERT_TRUE(hmfsCkeckPoint->cpFlags & CP_FLAG_LARGE_NAT_BITMAP); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_004.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_004.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_i_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_i_002 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_i_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_i_002 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 1000)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("f2fs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("1024000"); + params.push_back("-i"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("f2fs", params, device)); + std::cout << "----------------------------------------------------------------F2FS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + auto f2fsSuperBlock = std::make_unique(); + GetSuperBlock(device, f2fsSuperBlock); + auto f2fsCkeckPoint = std::make_unique(); + GetCheckPoint(device, f2fsCkeckPoint); + + std::string hmDevice = "/data/HMFsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(hmDevice, 1000)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", hmDevice)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, hmDevice)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(hmDevice); + + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(hmDevice, hmfsSuperBlock); + auto hmfsCkeckPoint = std::make_unique(); + GetCheckPoint(hmDevice, hmfsCkeckPoint); + + ASSERT_EQ(f2fsCkeckPoint->cpFlags, hmfsCkeckPoint->cpFlags); + ASSERT_EQ(f2fsCkeckPoint->checksumOffset, f2fsCkeckPoint->checksumOffset); + ASSERT_TRUE(hmfsCkeckPoint->cpFlags & CP_FLAG_LARGE_NAT_BITMAP); + //fsck check + std::string HmfsFsckOutFileName = "/data/Fsck_Hmfs_SingleParams_o_004.txt"; + std::string F2fsFsckOutFileName = "/data/Fsck_F2fs_SingleParams_o_004.txt"; + int32_t fsckF2fsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(device, F2fsFsckOutFileName); + int32_t fsckHmfsRes = ResizeHmfsSingleTest::ExecFsckWithOutput(hmDevice, HmfsFsckOutFileName); + ASSERT_EQ(fsckF2fsRes, fsckHmfsRes); + ASSERT_TRUE(PrintFsckErrorMsg(HmfsFsckOutFileName, hmDevice)); + if (fsckF2fsRes == fsckHmfsRes && fsckHmfsRes == 0) { + if (PrintFsckErrorMsg(F2fsFsckOutFileName, device)) { + ASSERT_EQ(0, ExecutableRmCmd(HmfsFsckOutFileName)); + ASSERT_EQ(0, ExecutableRmCmd(F2fsFsckOutFileName)); + } + } + std::cout << "ResizeHmfsSingleTest_i_002 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_d_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_d_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_d_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-d"); + params.push_back("0"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + // ASSERT_TRUE(output.find("Info: Debug level = 0") != std::string::npos); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_d_001 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_d_002 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_d_002, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_d_002 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-d"); + params.push_back("1"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + // ASSERT_TRUE(output.find("Info: Debug level = 1") != std::string::npos); + std::cout << "ResizeHmfsSingleTest_d_002 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_d_003 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_d_003, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_d_003 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-d"); + params.push_back("10"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::cout << "----------------------------------------------------------------HMFS" << std::endl; + PrintSuperBlockAndCheckPointData(device); + + std::string output = ReadFile(outputFile); + // ASSERT_TRUE(output.find("Info: Debug level = 10") != std::string::npos); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_d_003 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_d_004 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_d_004, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_d_004 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-s"); + params.push_back("-t"); + params.push_back("102400"); + params.push_back("-d"); + params.push_back("-1"); + ASSERT_EQ(1, ResizeHmfsSingleTest::ExecResizeBinary("hmfs", params, device)); + std::cout << "ResizeHmfsSingleTest_d_004 END" << std::endl; +} + +/* + * @tc.name: ResizeHmfsSingleTest_f_001 + * @tc.desc: test for resize hmfs. + * @tc.type: FUNC + */ +HWTEST_F(ResizeHmfsSingleTest, ResizeHmfsSingleTest_f_001, TestSize.Level1) +{ + std::cout << "ResizeHmfsSingleTest_f_001 BEGIN" << std::endl; + std::string device = "/data/FsTest"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableDdCmd(device, 100)); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableMkfsCmd("hmfs", device)); + + std::vector params; + params.clear(); + params.push_back("-f"); + std::string outputFile = "/data/test_output.txt"; + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecResizeBinaryWithOutput("hmfs", params, device, outputFile)); + std::string output = ReadFile(outputFile); + ASSERT_TRUE(output.find("Info: Done to rebuild checkpoint blocks") != std::string::npos); + ASSERT_EQ(0, ResizeHmfsSingleTest::ExecutableRmCmd(outputFile)); + std::cout << "ResizeHmfsSingleTest_f_001 END" << std::endl; +} +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/utils/BUILD.gn b/tools/hmfs-tools/test/unittest/utils/BUILD.gn new file mode 100755 index 0000000..4721ea1 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/utils/BUILD.gn @@ -0,0 +1,33 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +ohos_executable("hmfsDumpTest") { + include_dirs = [ + "${hmfs_path}/test/unittest/utils", + "${hmfs_tools_path}/common", + ] + sources = [ + "dump_test.cpp", + "hmfs_test_utils.cpp", + ] + + external_deps = [ "bounds_checking_function:libsec_shared" ] + deps = [ "${hmfs_tools_path}/common:libhmfs" ] + install_enable = true + install_images = [ "system" ] + subsystem_name = "thirdparty" + part_name = "hmfs-tools" +} diff --git a/tools/hmfs-tools/test/unittest/utils/dump_test.cpp b/tools/hmfs-tools/test/unittest/utils/dump_test.cpp new file mode 100755 index 0000000..bf925a1 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/utils/dump_test.cpp @@ -0,0 +1,30 @@ +#include "hmfs_test_utils.h" +#include + +using namespace OHOS::Hmfs; + +int main(int argc, const char* argv[]) + { + if (argc < 2) { + std::cout<<"argc is too few"<(); + GetSuperBlock(devPath, superBlock); + PrintRawSBInfo(superBlock); + + + auto checkPoint = std::make_unique(); + GetCheckPoint(devPath, checkPoint); + PrintCPInfo(checkPoint); + + auto nodeData = std::make_unique(); + int16_t addrIndex = -1; + GetInodeInfo(devPath, nodeData, addrIndex, GetLeValue(superBlock->rootInodeId)); + uint32_t features = GetLeValue(superBlock->features); + PrintInodeInfo(features, nodeData, addrIndex, GetLeValue(superBlock->rootInodeId)); + + return 0; +} \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/utils/hmfs_check.cpp b/tools/hmfs-tools/test/unittest/utils/hmfs_check.cpp new file mode 100755 index 0000000..e69de29 diff --git a/tools/hmfs-tools/test/unittest/utils/hmfs_check.h b/tools/hmfs-tools/test/unittest/utils/hmfs_check.h new file mode 100755 index 0000000..e69de29 diff --git a/tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.cpp b/tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.cpp new file mode 100755 index 0000000..6f4c5b7 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.cpp @@ -0,0 +1,1523 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, Hardware + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmfs_test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hmfs_encoding.h" +#include "securec.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define CRCPOLY_LE 0xedb88320 + +#define COMPARE_SB_FIELD(field) (f2SB->field == hmSB->field) +#define COMPARE_CP_FIELD(field) (f2CP->field == hmCP->field) + +namespace OHOS { +namespace Hmfs { +template +bool CompValue(const Value1 &value1, const Value2 &value2) +{ + return value1 == value2; +} + +template +bool CompValue(const Value1 first1, const Value1 last1, const Value2 first2) +{ + return std::equal(first1, last1, first2); +} + +template +bool CompValue(const Value1 first1, const Value1 last1, const Value2 first2, const Value2 last2) +{ + return std::equal(first1, last1, first2, last2); +} + +#define COMPARE_FIELD_RET_CODE(superBlockCode, ...) \ + do { \ + if (!CompValue(__VA_ARGS__)) { \ + return superBlockCode; \ + } \ + } while (0) + +HmfsCode WriteFile(const std::string& fileName) +{ + if (fileName.empty()) { + std::cout << "Failed to write file, invalid parameter" << std::endl; + return HmfsCode::FAILED; + } + + std::ofstream file(fileName.c_str(), std::ios::binary); + if (!file.is_open()) { + std::cout << "Failed to open the file, file name: " << fileName << ", error: " << strerror(errno) << std::endl; + return HmfsCode::FAILED; + } + + const std::string text = "Hello, World!"; + if (!file.write(text.c_str(), text.size())) { + std::cout << "Failed to write file, file name: " << fileName << ", error: " << strerror(errno) << std::endl; + return HmfsCode::FAILED; + } + std::cout << "Succeed in writing file, file name : " << fileName << std::endl; + return HmfsCode::SUCCESSED; +} + +HmfsCode GetFileStat(const std::string &fileName, struct stat *statBuf) +{ + if (fileName.empty() || statBuf == nullptr) { + std::cout << "Failed to get file status, invalid parameter" << std::endl; + return HmfsCode::FAILED; + } + + if (stat(fileName.c_str(), statBuf) != 0) { + std::cout << "ReadFile Error getting file status : " << strerror(errno) << std::endl; + return HmfsCode::FAILED; + } + std::cout << "Succeed in getting file status, file name : " << fileName << std::endl; + return HmfsCode::SUCCESSED; +} + +std::string ReadFile(const std::string& filePath) +{ + std::ifstream file(filePath, std::ios::binary); + if (!file.is_open()) { + std::cout << "Failed to open the file, file name: " << filePath << ", error: " << strerror(errno) << std::endl; + return ""; + } + std::stringstream buffer; + buffer << file.rdbuf(); + file.close(); + return buffer.str(); +} + +unsigned long long GetFileSize(const std::string &fileName) +{ + if (fileName.empty()) { + std::cout << "Failed to get file size, invalid parameter" << std::endl; + return (unsigned long long)-1; + } + std::ifstream file(fileName, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + std::cout << "Failed to open the file, file name: " << fileName << ", error: " << strerror(errno) << std::endl; + return (unsigned long long)-1; + } + return file.tellg(); +} + +HmfsCode FAllocateFile(const std::string &fileName) +{ + if (fileName.empty()) { + std::cout << "Failed to format file, invalid parameter" << std::endl; + return HmfsCode::FAILED; + } + + unsigned long long len = GetFileSize(fileName); + if (len <= 0) { + std::cout << "Failed to format file, file name : " << fileName << std::endl; + return HmfsCode::FAILED; + } + + int fd = open(fileName.c_str(), O_RDWR); + if (fd == -1) { + std::cerr << "Failed to open file, file name: " << fileName << ", error: " << strerror(errno) << std::endl; + return HmfsCode::FAILED; + } + + unsigned long long offset = 0; + if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, len) < 0) { + std::cerr << "Failed to allocate file space, file name: " << fileName << ", file size: " << len << + ", error: " << strerror(errno) << std::endl; + close(fd); + return HmfsCode::FAILED; + } + std::cout << "Succeed in formatting file, file name : " << fileName << std::endl; + close(fd); + return HmfsCode::SUCCESSED; +} + +HmfsCode CheckDataIsZero(const std::string &fileName) +{ + if (fileName.empty()) { + std::cout << "Failed to format file, invalid parameter" << std::endl; + return HmfsCode::ERROR_OTHER; + } + + std::ifstream file(fileName, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + std::cout << "Failed to open the file, file name : " << fileName << std::endl; + return HmfsCode::ERROR_OTHER; + } + + const size_t fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(fileSize); + if (!file.read(buffer.data(), fileSize)) { + std::cout << "Failed to read the file, file name : " << fileName << std::endl; + return HmfsCode::ERROR_OTHER; + } + + if (std::all_of(buffer.begin(), buffer.end(), [](char c) { return c == '\0'; })) { + std::cout << "The file " << fileName << " contains only '\\0'." << std::endl; + return HmfsCode::SUCCESSED; + } else { + std::cout << "The file " << fileName << " does not contain only '\\0'." << std::endl; + return HmfsCode::FAILED; + } +} + +void PrintParameters(const std::vector ¶ms) +{ + std::cout << std::accumulate(params.begin(), params.end(), std::string{}, + [](const std::string& str1, const std::string& str2) { + return str1.empty() ? str2 : str1 + " " + str2; + }) << std::endl << std::endl; +} + +// 随机生成一个扇区大小的值 +static int32_t GenerateSectorCount(int32_t min, int32_t max) +{ + return min + (std::rand() % (max - min + 1)); +} + +// 生成随机特性 +std::string GenerateFeatures(bool isResizeTool) +{ + std::string features; + features += (std::rand() % 2 == 0) ? "extra_attr," : ""; + features += (std::rand() % 2 == 0) ? "project_quota," : ""; + features += (std::rand() % 2 == 0) ? "casefold," : ""; + + if (!isResizeTool) { + features += (std::rand() % 2 == 0) ? "inode_checksum," : ""; + features += (std::rand() % 2 == 0) ? "flexible_inline_xattr," : ""; + features += (std::rand() % 2 == 0) ? "inode_crtime," : ""; + features += (std::rand() % 2 == 0) ? "lost_found," : ""; + features += (std::rand() % 2 == 0) ? "verity," : ""; + features += (std::rand() % 2 == 0) ? "quota," : ""; + features += (std::rand() % 2 == 0) ? "sb_checksum," : ""; + features += (std::rand() % 2 == 0) ? "compression," : ""; + features += (std::rand() % 2 == 0) ? "ro," : ""; + } + + return features; +} + +std::string GenerateRandomString(const size_t length) +{ + const std::string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::mt19937 generator(std::random_device{}()); + std::uniform_int_distribution<> distribution(0, characters.size() - 1); + + std::string randomStr; + randomStr.reserve(length); + for (size_t i = 0; i < length; ++i) { + randomStr += characters[distribution(generator)]; + } + + return randomStr; +} + +int32_t GenerateRandomInt32(const int32_t startNum) +{ + std::mt19937 generator(std::random_device{}()); + std::uniform_int_distribution distribution(startNum, INT32_MAX); + return distribution(generator); +} + +void GenerateMkfsParams(std::vector ¶ms) +{ + // 随机选择是否加入 -a 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-a"); + params.emplace_back(std::to_string(std::rand() % 2)); // [0, 1] + } + + // 随机选择是否加入 -e 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-e"); + params.emplace_back(GenerateRandomString(std::rand() % 21 + 1)); // [1, 20] + } + + // 随机选择是否加入 -E 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-E"); + params.emplace_back(GenerateRandomString(std::rand() % 21 + 1)); // [0, 20] + } + + // 随机选择是否加入 -m 参数,先不添加m参数,需要特殊设备,配置CONFIG_BLK_DEV_ZONED + if (std::rand() % 2 == 2) { + params.emplace_back("-m"); + } + + // 随机选择是否加入 -l 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-l"); + params.emplace_back(GenerateRandomString(std::rand() % 10 + 1)); // [1, 10] + } + + // 随机选择是否加入 -r 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-r"); + } + + // 随机选择是否加入 -R 参数 + if (std::rand() % 2 == 0) { + std::string combinedStr = "-R " + std::to_string(GenerateRandomInt32()) + ":" + + std::to_string(GenerateRandomInt32()); + params.emplace_back(combinedStr); + } + + // 随机选择是否加入 -s 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-s"); + params.emplace_back(std::to_string(GenerateRandomInt32())); + } + + // 随机选择是否加入 -t 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-t"); + params.emplace_back(std::to_string(std::rand() % 2)); // [0, 1] + } + + // 随机选择是否加入 -T 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-T"); + params.emplace_back(std::to_string(GenerateRandomInt32(0))); + } +} + +void GenerateMkfsParamsEnd(std::vector ¶ms) +{ + //std::srand(static_cast(std::time(0))); + // 随机选择是否加入 -w 参数,期望扇区的大小 + if (std::rand() % 2 == 0) { + params.emplace_back("-w"); + params.emplace_back(std::to_string(GenerateRandomInt32())); + } + + // 随机选择是否加入 -z 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-z"); + params.emplace_back(std::to_string(GenerateRandomInt32())); + } + + const uint8_t deviceCount = MAX_DEVICE_COUNTS - 1; + // 随机选择是否加入 -c 参数 + if (std::rand() % 2 == 0) { + for (uint8_t index = 0; index < deviceCount; index++) { + if (std::rand() % 2 == 0) { + params.emplace_back("-c"); + params.emplace_back(F2FS_DEVICE_PATH_LIST[std::rand() % (deviceCount)]); + } + } + } + + params.emplace_back(F2FS_DEVICE_PATH_LIST[std::rand() % (deviceCount)]); + + // 随机选择是否加入期望扇区的总个数 + if (std::rand() % 2 == 0) { + params.emplace_back(std::to_string(GenerateRandomInt32())); + } +} + +// 生成参数组合 +std::vector GenerateParams(bool isResizeTool) +{ + //std::srand(static_cast(std::time(0))); + std::vector params; + // 随机选择是否加入 -C 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-C"); + params.emplace_back("utf8"); + } + + // 随机选择是否加入 -O 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-O"); + params.emplace_back(GenerateFeatures(isResizeTool)); + } + + // 随机选择是否加入 -o 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-o"); + params.emplace_back(std::to_string(std::rand() % 101)); // [0, 100] + } + + // 随机选择是否加入 -d 调试参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-d"); + params.emplace_back(std::to_string(std::rand() % 10)); // [0, 9] + } + + // 随机选择是否加入 -i 参数 + if (std::rand() % 2 == 0) { + params.emplace_back("-i"); + } + + if (isResizeTool) { + // 随机选择是否加入 -s 参数 + if (std::rand() % 3 != 0) { + params.emplace_back("-s"); + } + // 添加 -t 扇区个数参数 + params.emplace_back("-t"); + params.emplace_back(std::to_string(GenerateSectorCount(20480, 2048000))); + } else { + GenerateMkfsParams(params); + GenerateMkfsParamsEnd(params); + } + + return params; +} + +void ReplaceDevicePaths(std::vector ¶ms) +{ + for (auto& param : params) { + for (uint8_t i = 0; i < MAX_DEVICE_COUNTS - 1; ++i) { + if (param == F2FS_DEVICE_PATH_LIST[i]) { + param = HMFS_DEVICE_PATH_LIST[i]; + } + } + } +} + +static int VerifyCheckSum(struct CheckPointData *checkPoint) +{ + if (checkPoint == nullptr) { + std::cout << "VerifyCheckSum invalid parameter" << std::endl; + return -1; + } + uint32_t checksumOffset = GetLeValue(checkPoint->checksumOffset); + uint32_t crc, calCrc; + + if (checksumOffset < CP_MIN_CHKSUM_OFFSET || checksumOffset > CP_CHKSUM_OFFSET) { + std::cout << "Invalid checkPoint crc offset" << std::endl; + return -1; + } + + crc = LE32_TO_NATIVE(*(reinterpret_cast((reinterpret_cast(checkPoint) + checksumOffset)))); + calCrc = HmfsCommon::GetInstance().HmfsCheckpointChksum(checkPoint); + if (calCrc != crc) { + std::cout<< "Invalid CP CRC: offset: "<< checksumOffset << "crc: " << crc << "calCrc: "<< calCrc < buf{}; + ssize_t readSize = pread64(fd, buf.data(), PREAD_BUFFER_SIZE, cpBlkAddr << 12); + if (readSize < 0) { + std::cout << "Failed to pread64, errno " << errno << std::endl; + close(fd); + return false; + } + + struct CheckPointData *checkPoint1 = reinterpret_cast(buf.data()); + if (VerifyCheckSum(checkPoint1)) { + std::cout << " page1 VerifyCheckSum is failed" << std::endl; + close(fd); + return false; + } + + cpBlkAddr += GetLeValue(checkPoint1->cpPackBlockCount) - 1; + + std::array buf1{}; + readSize = pread64(fd, buf1.data(), PREAD_BUFFER_SIZE, cpBlkAddr << 12); + if (readSize < 0) { + std::cout << "Failed to pread64, errno " << errno << std::endl; + close(fd); + return false; + } + close(fd); + + struct CheckPointData *checkPoint2 = reinterpret_cast(buf1.data()); + if (VerifyCheckSum(checkPoint2)) { + std::cout << " page2 VerifyCheckSum is failed" << std::endl; + return false; + } + + if (GetLeValue(checkPoint1->cpVersion) == GetLeValue(checkPoint2->cpVersion)) { + if (memcpy_s(checkPoint, PREAD_BUFFER_SIZE, checkPoint1, PREAD_BUFFER_SIZE) != 0) { + std::cout << "Failed to copy checkPoint" << std::endl; + } + return true; + } + + return false; +} + +void GetCheckPoint(const std::string &devPath, std::unique_ptr &checkPoint) +{ + if (devPath.empty() || checkPoint == nullptr) { + std::cout << "GetCheckPoint invalid parameter" << std::endl; + return; + } + + auto superBlock = std::make_unique(); + GetSuperBlock(devPath, superBlock); + uint32_t cpBlkId = GetLeValue(superBlock->cpBlkId); + uint32_t blocksize = 1 << GetLeValue(superBlock->logBlockSize); + + auto ckpt1 = std::make_unique(blocksize); + int ret1 = ValidateCheckpoint(devPath, cpBlkId, reinterpret_cast(ckpt1.get())); + uint64_t cpVersion1 = reinterpret_cast(ckpt1.get())->cpVersion; + + auto ckpt2 = std::make_unique(blocksize); + cpBlkId += 1 << GetLeValue(superBlock->logBlksPerSeg); + int ret2 = ValidateCheckpoint(devPath, cpBlkId, reinterpret_cast(ckpt2.get())); + + uint64_t cpVersion2 = reinterpret_cast(ckpt2.get())->cpVersion; + + if (ret1 && ret2) { + std::cout << "cpVersion1 " << cpVersion1 << " cpVersion2 " << cpVersion2 << std::endl; + if (cpVersion2 > cpVersion1) { + checkPoint.reset(reinterpret_cast(ckpt2.release())); + } else { + checkPoint.reset(reinterpret_cast(ckpt1.release())); + } + } else if (ret1) { + checkPoint.reset(reinterpret_cast(ckpt1.release())); + } else if (ret2) { + checkPoint.reset(reinterpret_cast(ckpt2.release())); + } else { + std::cout << "GetCheckPoint failed!" << std::endl; + } +} + +void GetSuperBlock(const std::string &devPath, std::unique_ptr &superBlock) +{ + std::cout << "GetSuperBlock begin" << std::endl; + + if (devPath.empty() || superBlock == nullptr) { + std::cout << "GetSuperBlock invalid parameter" << std::endl; + return; + } + + std::array buf {}; + int fd = open(devPath.c_str(), O_RDWR | O_BINARY); + if (fd < 0) { + std::cout << "Failed to open " << devPath << " errno " << errno << std::endl; + return; + } + + if (pread64(fd, buf.data(), buf.size(), 0) < 0) { + std::cout << "Failed to pread64, errno " << errno << std::endl; + close(fd); + return; + } + close(fd); + + if (memcpy_s(superBlock.get(), sizeof(*superBlock), buf.data() + SUPER_BLOCK_OFFSET, sizeof(*superBlock)) != 0) { + std::cout << "Failed to copy superBlockData" << std::endl; + return; + } + + std::cout << "GetSuperBlock end" << std::endl; +} + +int32_t ExecutableCmdWithOutput(std::vector ¶ms, std::string &outputFile) +{ + pid_t pid = fork(); + if (pid < 0) { + return -errno; + } + + if (pid == 0) { + int fd = open(outputFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd < 0) { + std::cout<<"open outfile failed!"< argv; + for (const auto& param : params) { + argv.push_back(const_cast(param.c_str())); + } + argv.push_back(nullptr); + std::cout<<"begin exec dump"<= ADDR_COUNT_PER_INODE) { + addrIndex = -1; + } + return addrIndex; +} + +void GetNodeDataFromMap(std::unique_ptr &nodeData, int16_t &addrIndex, + const std::unordered_map &inodeInfo) +{ + static const std::unordered_map> inodeMap = { + {"iMode", [](NodeData *nd, uint64_t v) { nd->i.iMode = static_cast(v); }}, + {"iAdvise", [](NodeData *nd, uint64_t v) { nd->i.iAdvise = static_cast(v); }}, + {"iUid", [](NodeData *nd, uint64_t v) { nd->i.iUid = static_cast(v); }}, + {"iGid", [](NodeData *nd, uint64_t v) { nd->i.iGid = static_cast(v); }}, + {"iLinks", [](NodeData *nd, uint64_t v) { nd->i.iLinks = static_cast(v); }}, + {"iSize", [](NodeData *nd, uint64_t v) { nd->i.iSize = v; }}, + {"iBlocks", [](NodeData *nd, uint64_t v) { nd->i.iBlocks = v; }}, + {"iAtime", [](NodeData *nd, uint64_t v) { nd->i.iAtime = v; }}, + {"iAtimeNsec", [](NodeData *nd, uint64_t v) { nd->i.iAtimeNsec = static_cast(v); }}, + {"iCtime", [](NodeData *nd, uint64_t v) { nd->i.iCtime = v; }}, + {"iCtimeNsec", [](NodeData *nd, uint64_t v) { nd->i.iCtimeNsec = static_cast(v); }}, + {"iMtime", [](NodeData *nd, uint64_t v) { nd->i.iMtime = v; }}, + {"iMtimeNsec", [](NodeData *nd, uint64_t v) { nd->i.iMtimeNsec = static_cast(v); }}, + {"iGeneration", [](NodeData *nd, uint64_t v) { nd->i.iGeneration = static_cast(v); }}, + {"iCurrentDepth", [](NodeData *nd, uint64_t v) { nd->i.iCurrentDepth = static_cast(v); }}, + {"iXattrNid", [](NodeData *nd, uint64_t v) { nd->i.iXattrNid = static_cast(v); }}, + {"iFlags", [](NodeData *nd, uint64_t v) { nd->i.iFlags = static_cast(v); }}, + {"iInline", [](NodeData *nd, uint64_t v) { nd->i.iInline = static_cast(v); }}, + {"iPino", [](NodeData *nd, uint64_t v) { nd->i.iPino = static_cast(v); }}, + {"iDirLevel", [](NodeData *nd, uint64_t v) { nd->i.iDirLevel = static_cast(v); }}, + {"iCrtime", [](NodeData *nd, uint64_t v) { nd->i.iCrtime = v; }}, + {"iCrtimeNsec", [](NodeData *nd, uint64_t v) { nd->i.iCrtimeNsec = static_cast(v); }}, + {"iExtraIsize", [](NodeData *nd, uint64_t v) { nd->i.iExtraIsize = static_cast(v); }}, + {"iInlineXattrSize", [](NodeData *nd, uint64_t v) { nd->i.iInlineXattrSize = static_cast(v); }}, + {"iProjid", [](NodeData *nd, uint64_t v) { nd->i.iProjid = static_cast(v); }}, + {"iComprBlocks", [](NodeData *nd, uint64_t v) { nd->i.iComprBlocks = v; }}, + {"iCompressAlgrithm", [](NodeData *nd, uint64_t v) { nd->i.iCompressAlgrithm = static_cast(v); }}, + {"iLogClusterSize", [](NodeData *nd, uint64_t v) { nd->i.iLogClusterSize = static_cast(v); }}, + {"iPadding", [](NodeData *nd, uint64_t v) { nd->i.iPadding = static_cast(v); }}, + {"i_nid[0]", [](NodeData* nd, uint64_t v) { nd->i.i_nid[0] = static_cast(v); }}, + {"i_nid[1]", [](NodeData* nd, uint64_t v) { nd->i.i_nid[1] = static_cast(v); }}, + {"i_nid[2]", [](NodeData* nd, uint64_t v) { nd->i.i_nid[2] = static_cast(v); }}, + {"i_nid[3]", [](NodeData* nd, uint64_t v) { nd->i.i_nid[3] = static_cast(v); }}, + {"i_nid[4]", [](NodeData* nd, uint64_t v) { nd->i.i_nid[4] = static_cast(v); }}, + }; + + for (const auto& element : inodeInfo) { + auto pos = element.first.find("i_addr"); + if (pos != std::string::npos) { + addrIndex = ParseInodeAddrIndex(element.first); + if (addrIndex != -1) { + nodeData->i.i_addr[addrIndex] = element.second; + std::cout << "i.i_addr[0x" << std::hex << addrIndex << "] = " << + std::dec << element.second << std::endl; + continue; + } + } + + auto it = inodeMap.find(element.first); + if (it != inodeMap.end()) { + it->second(nodeData.get(), element.second); + } else { + std::cout << "Unknown key: " << element.first << std::endl; + } + } +} + +std::unordered_map ParseInodeInfo(const std::string &outputFile) +{ + std::unordered_map inodeInfo; + std::ifstream file(outputFile); + if (!file.is_open()) { + return inodeInfo; + } + + std::string line; + while (std::getline(file, line)) { + size_t leftBracket = line.rfind("[0x"); + size_t colon = line.find(':'); + size_t rightBracket = line.rfind(']'); + + if (leftBracket != std::string::npos && colon != std::string::npos && rightBracket != std::string::npos) { + std::string key = line.substr(0, leftBracket - 1); + key.erase(key.find_last_not_of(" \t") + 1); + key.erase(0, key.find_first_not_of(" \t")); + std::string decValue = line.substr(colon + 1, rightBracket - colon - 1); + key.erase(key.find_last_not_of(" ") + 1); + key.erase(0, key.find_first_not_of(" ")); + std::cout << key << " = " << decValue < &nodeData, + int16_t &addrIndex, const uint32_t iNode) +{ + if (nodeData == nullptr || devPath.empty()) { + std::cout << "GetInodeInfo invalid parameter" << std::endl; + return; + } + + std::string outputFile = "/data/inodeInfo"; + std::vector argv; + argv.push_back("/system/bin/dump.f2fs"); + argv.push_back("-i"); + argv.push_back(std::to_string(iNode)); + argv.push_back(devPath); + + ExecutableCmdWithOutput(argv, outputFile); + + auto inodeInfo = ParseInodeInfo(outputFile); + GetNodeDataFromMap(nodeData, addrIndex, inodeInfo); +} + +// 需要确认最后指定的设备是哪个 +std::string ConfirmDevicePath(const std::vector ¶ms, const bool changePath) +{ + std::vector::const_reverse_iterator result = std::find_if( + params.rbegin(), params.rend(), [changePath](const std::string& str) { + return str.find(changePath ? F2FS_DEVICE_PATH_LIST[0] : HMFS_DEVICE_PATH_LIST[0]) != std::string::npos; + }); + + if (result != params.rend()) { + std::cout << "Confirm device path : " << *result << std::endl; + return *result; + } + return ""; +} + +std::string FindSpecifyStr(const std::vector &vecStr, const std::string &item) +{ + std::vector::const_iterator iter = std::find(vecStr.begin(), vecStr.end(), item); + if (iter != vecStr.end() && ++iter != vecStr.end()) { + std::cout << "The value after " << item << " is: " << *iter << std::endl; + return *iter; + } else { + std::cout << "item : " << item << " not found or it's the last element in the vector." << std::endl; + return ""; + } +} + +bool ContainSubStr(const std::string ¶meterValue, const std::string &subStr) +{ + size_t pos = parameterValue.find(subStr); + if (pos != std::string::npos) { + std::cout << "Found '" << subStr << "' in value at position: " << pos << std::endl; + std::string ro("ro"); + if (subStr == ro && ((pos + ro.length() >= parameterValue.length()) || + parameterValue[pos + ro.length()] != ',')) { + return false; + } + return true; + } else { + std::cout << "'" << subStr << "' not found in value." << std::endl; + return false; + } +} + +bool CheckFeatures(const uint32_t features, const std::string &featureNameList) +{ + std::unordered_map featureMap = { + { "encrypt", HMFS_FEATURE_ENCRYPT }, + { "extra_attr", HMFS_FEATURE_EXTRA_ATTR }, + { "project_quota", HMFS_FEATURE_PRJQUOTA }, + { "inode_checksum", HMFS_FEATURE_INODE_CHKSUM }, + { "flexible_inline_xattr", HMFS_FEATURE_FLEXIBLE_INLINE_XATTR }, + { "quota", HMFS_FEATURE_QUOTA_INO }, + { "inode_crtime", HMFS_FEATURE_INODE_CRTIME }, + { "lost_found", HMFS_FEATURE_LOST_FOUND }, + { "verity", HMFS_FEATURE_VERITY }, + { "sb_checksum", HMFS_FEATURE_SB_CHKSUM }, + { "casefold", HMFS_FEATURE_CASEFOLD }, + { "compression", HMFS_FEATURE_COMPRESSION }, + { "ro", HMFS_FEATURE_RO}, + }; + + for (const auto& [key, feature] : featureMap) { + if (ContainSubStr(featureNameList, key) && (!(features & feature))) { + return false; + } + } + return true; +} + +bool CheckParametersVaild(const std::vector ¶ms, std::map ¶meterMap) +{ + std::string value; + for (const std::string ¶m : HMFS_PARAMETER_LIST) { + std::cout << "Parameter: " << param << std::endl; + value = FindSpecifyStr(params, param); + if (value.empty()) { + continue; + } + if ((param == "-s" || param == "-w" || param == "-z") && (static_cast(std::stoi(value) <= 0))) { + return false; + } + if ((param == "-O") && ((ContainSubStr(value, "project_quota") || ContainSubStr(value, "inode_checksum") || + ContainSubStr(value, "flexible_inline_xattr") || ContainSubStr(value, "inode_crtime") || + ContainSubStr(value, "compression")) && (!ContainSubStr(value, "extra_attr")))) { + return false; + } + parameterMap[param] = value; + value.clear(); + } + return true; +} + +int32_t CheckResizeParameters(std::string &device, const std::vector ¶ms, + const uint32_t deviceSectorCount, std::map ¶meterMap) +{ + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(device, hmfsSuperBlock); + if (std::find(params.begin(), params.end(), "-i") != params.end()) { + parameterMap["-i"] = ""; + } + bool hasSafeResizeFlag = (std::find(params.begin(), params.end(), "-s") != params.end()); + for (const std::string& param : HMFS_RESIZE_PARAMETER_LIST) { + std::string value = FindSpecifyStr(params, param); + if (value.empty()) { + continue; + } + if (param == "-t") { + uint64_t num = std::stoull(value); + if ((num >> hmfsSuperBlock->logSectorsPerBlk) < hmfsSuperBlock->blockCount && !hasSafeResizeFlag) { + return NEED_SAFE_RESIZE_FLAG; + } + if (num > deviceSectorCount) { + return OUT_OF_RANGE; + } + } + parameterMap[param] = value; + } + if (!CheckSafeResize(parameterMap, hmfsSuperBlock)) { + std::cout << "MORE_SEGMENT_NEEDED" << std::endl; + return MORE_SEGMENT_NEEDED; + } + return VALID; +} + +bool CheckSafeResize(const std::map ¶meterMap, const std::unique_ptr &superBlock) +{ + SuperBlockData newSuperBlock = *superBlock; + uint32_t segmentSizeBytes = 1 << (newSuperBlock.logBlockSize + newSuperBlock.logBlksPerSeg); + uint32_t segsPerZone = newSuperBlock.segsPerSection * newSuperBlock.sectionsPerZone; + uint64_t targetSectors = 0; + auto it = parameterMap.find("-t"); + if (it != parameterMap.end()) { + std::string parameterValue = it->second; + if (!parameterValue.empty()) { + targetSectors = std::stoull(parameterValue); + } + } + newSuperBlock.blockCount = targetSectors >> newSuperBlock.logSectorsPerBlk; + uint32_t zoneSizeBytes = segmentSizeBytes * segsPerZone; + uint32_t startSector = 0; + uint64_t zoneAlignStartOffset = ((uint64_t) startSector * DEFAULT_SECTOR_SIZE + 2 * HMFS_BLKSIZE + zoneSizeBytes - 1) / + zoneSizeBytes * zoneSizeBytes - (uint64_t) startSector * DEFAULT_SECTOR_SIZE; + newSuperBlock.segmentCount = (targetSectors * DEFAULT_SECTOR_SIZE - zoneAlignStartOffset) / + segmentSizeBytes / newSuperBlock.segsPerSection * newSuperBlock.segsPerSection; + newSuperBlock.segmentCountInMain = newSuperBlock.segmentCount - newSuperBlock.segmentCountInCP - + newSuperBlock.segmentCountInSIT - newSuperBlock.segmentCountInNAT - newSuperBlock.segmentCountInSSA; + newSuperBlock.sectionCount = newSuperBlock.segmentCountInMain / newSuperBlock.segsPerSection; + newSuperBlock.segmentCountInMain = newSuperBlock.sectionCount * newSuperBlock.segsPerSection; + double overprovision = 0; + it = parameterMap.find("-o"); + if (it != parameterMap.end()) { + std::string parameterValue = it->second; + if (!parameterValue.empty()) { + overprovision = std::stod(parameterValue); + } + } + if (overprovision == 0) { + overprovision = HmfsCommon::GetInstance().GetBestOverProvision(&newSuperBlock); + } + uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * newSuperBlock.segsPerSection; + uint32_t blksPerSeg = 1 << newSuperBlock.logBlksPerSeg; + if ((newSuperBlock.segmentCountInMain - 2) < reservedSegments || + newSuperBlock.segmentCountInMain * blksPerSeg > newSuperBlock.blockCount) { + // std::cout << "\tError: Device size is not sufficient for F2FS volume, " + // "more segment needed" << reservedSegments - (superBlock.segmentCountInMain - 2) << std::endl; + return false; + } + return true; +} + +bool CheckResizeHmfsResult(const std::map& parameterMap, + const std::unique_ptr& checkPoint, + const std::unique_ptr& superBlock, + const std::string& output) +{ + if (checkPoint == nullptr || superBlock == nullptr) { + return false; + } + + // 校验-t参数 + auto CheckParameterT = [&](const std::string& parameterValue) -> bool { + if (parameterValue.empty()) { + return true; + } + uint64_t targetSectors = std::stoull(parameterValue); + if (superBlock->blockCount != (targetSectors >> superBlock->logSectorsPerBlk)) { + std::cout << "Failed to check the result of parameter 't'" << std::endl; + return false; + } + return true; + }; + + // 校验-o参数 + auto CheckParameterO = [&](const std::string& parameterValue) -> bool { + if (parameterValue.empty()) { + return true; + } + double overprovision = std::stod(parameterValue); + if (overprovision == 0) { + overprovision = HmfsCommon::GetInstance().GetBestOverProvision(superBlock.get()); + } + + uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * superBlock->segsPerSection; + std::cout << "test parameter o, reservedSegments = " << reservedSegments << std::endl; + + uint32_t overprov_segment_count = (superBlock->segmentCountInMain - reservedSegments) * overprovision / 100; + overprov_segment_count += reservedSegments; + std::cout << "test parameter o, overprov_segment_count = " << overprov_segment_count << std::endl; + + if (checkPoint->overprovSegmentCount != overprov_segment_count || + checkPoint->rsvdSegmentCount != reservedSegments) { + std::cout << "Failed to check the result of parameter 'o'" << std::endl; + return false; + } + return true; + }; + + // 校验-i参数 + auto CheckParameterI = [&](const std::string& parameterValue) -> bool { + if (!parameterValue.empty() && !(checkPoint->cpFlags & CP_FLAG_LARGE_NAT_BITMAP)) { + std::cout << "Failed to check the result of parameter 'i'" << std::endl; + return false; + } + return true; + }; + + // 校验-C参数 + auto CheckParameterC = [&](const std::string& parameterValue) -> bool { + if (!parameterValue.empty() && + (!(superBlock->encoding == HMFS_ENC_UTF8_12_1)) && + (!(superBlock->features & HMFS_FEATURE_CASEFOLD))) { + std::cout << "Failed to check the result of parameter 'C'" << std::endl; + return false; + } + return true; + }; + + // 校验-O参数 + auto CheckParameterOFeatures = [&](const std::string& parameterValue) -> bool { + if (parameterValue.empty()) { + return true; + } + + std::unordered_map featureMap = { + { "extra_attr", HMFS_FEATURE_EXTRA_ATTR }, + { "project_quota", HMFS_FEATURE_PRJQUOTA }, + { "casefold", HMFS_FEATURE_CASEFOLD }, + }; + + for (const auto& [key, feature] : featureMap) { + if (ContainSubStr(parameterValue, key) && !(superBlock->features & feature)) { + std::cout << "Failed to check the result of parameter 'O'" << std::endl; + return false; + } + } + return true; + }; + + // 参数检查逻辑 + const std::vector>> parameterCheckers = { + { "-t", CheckParameterT }, + { "-o", CheckParameterO }, + { "-i", CheckParameterI }, + { "-C", CheckParameterC }, + { "-O", CheckParameterOFeatures }, + }; + + for (const auto& [param, checker] : parameterCheckers) { + auto it = parameterMap.find(param); + if (it != parameterMap.end() && !checker(it->second)) { + return false; + } + } + + return true; +} + +bool PrintFsckErrorMsg(const std::string &outputFile, const std::string &devicePath) +{ + std::ifstream file(outputFile); + if (!file.is_open()) { + std::cout << "Failed to open file : " << outputFile << std::endl; + return false; + } + + std::string line; + bool checkRes = true; + while (std::getline(file, line)) { + if (line.find("Fail") != std::string::npos) { + std::cout << "fsck error : " << line << std::endl; + checkRes = false; + } + } + + file.close(); + + if (checkRes) { + std::cout << "The fsck tool reported a successful check, file path : " << devicePath << std::endl; + } else { + std::cout << "The fsck tool reports that the check failed, file path : " << devicePath << std::endl; + } + return checkRes; +} + +// -a 、-m 、-O "ro" 3个互斥 +// 先不校验 -m 参数,需要特殊设备,配置CONFIG_BLK_DEV_ZONED +bool CheckMkfsHmfsResult(const std::map ¶meterMap, + const std::unique_ptr &checkPoint, const std::unique_ptr &superBlock, + const std::unique_ptr &nodeData) +{ + if (checkPoint == nullptr || superBlock == nullptr) { + return false; + } + std::map::const_iterator aIter = parameterMap.find("-a"); + std::map::const_iterator mIter = parameterMap.find("-m"); + if (superBlock->features & HMFS_FEATURE_RO) { + if (checkPoint->curNodeSegNo[0] == 0 || checkPoint->curNodeSegNo[1] != 0 || checkPoint->curNodeSegNo[2] != 0 || + checkPoint->curDataSegNo[0] != 0 || checkPoint->curDataSegNo[1] != 0 || checkPoint->curDataSegNo[2] != 0) { + std::cout << "Failed to check ro feature" << std::endl; + return false; + } + } else if ((aIter != parameterMap.end()) && ((static_cast(std::stoi(aIter->second) != 0)))) { + if (checkPoint->curNodeSegNo[0] == 0 || checkPoint->curNodeSegNo[1] == 0 || checkPoint->curNodeSegNo[2] == 0 || + checkPoint->curDataSegNo[0] == 0 || checkPoint->curDataSegNo[1] == 0 || checkPoint->curDataSegNo[2] != 0) { + std::cout << "Failed to check the result of parameter 'a'" << std::endl; + return false; + } + } else if ((mIter != parameterMap.end()) && ((static_cast(std::stoi(mIter->second) != 0)))) { + if (checkPoint->curNodeSegNo[0] != 0 || checkPoint->curNodeSegNo[1] == 0 || checkPoint->curNodeSegNo[2] == 0 || + checkPoint->curDataSegNo[0] == 0 || checkPoint->curDataSegNo[1] == 0 || checkPoint->curDataSegNo[2] == 0) { + std::cout << "Failed to check the result of parameter 'm'" << std::endl; + return false; + } + } else { + if (checkPoint->curNodeSegNo[0] != 0 || checkPoint->curNodeSegNo[1] == 0 || checkPoint->curNodeSegNo[2] == 0 || + checkPoint->curDataSegNo[0] == 0 || checkPoint->curDataSegNo[1] == 0 || checkPoint->curDataSegNo[2] == 0) { + std::cout << "Failed to check the current node and data segments" << std::endl; + return false; + } + } + + // -c -i 对比f2fs、hmfs执行成功后字段是否一致 + + std::map::const_iterator iter = parameterMap.find("-e"); + std::vector extensionList; + for (int32_t i = 0; i < EXTENSION_COUNT_MAX; ++i) { + std::string extension(const_cast(superBlock->extensionList[i])); + extensionList.push_back(extension); + } + + if (iter != parameterMap.end() && (iter->second.size() < EXTENSION_LEN_MAX) && + std::find(extensionList.begin(), extensionList.end(), iter->second) == extensionList.end()) { + std::cout << "Failed to check the result of parameter 'e',iter->second : " << iter->second << std::endl; + return false; + } + + iter = parameterMap.find("-E"); + if (iter != parameterMap.end() && (iter->second.size() < EXTENSION_LEN_MAX) && + std::find(extensionList.begin(), extensionList.end(), iter->second) == extensionList.end()) { + std::cout << "Failed to check the result of parameter 'E',iter->second : " << iter->second << std::endl; + return false; + } + + iter = parameterMap.find("-l"); + if (iter != parameterMap.end()) { + char buffer[MAX_VOLUME_NAME]; + int res = Utf16Toutf8(buffer, superBlock->volumeName, + MAX_VOLUME_NAME, MAX_VOLUME_NAME); + std::string volumeName(buffer); + if (volumeName != iter->second) { + std::cout << "Failed to check the result of parameter 'l',res " << res << " volumeName : " << volumeName << + " iter->second : " << iter->second << std::endl; + return false; + } + } + + // 检查参数-O + iter = parameterMap.find("-O"); + if ((iter != parameterMap.end()) && (!CheckFeatures(superBlock->features, iter->second))) { + std::cout << "Failed to check the result of parameter 'O'" << std::endl; + return false; + } + + // 检查参数-C + iter = parameterMap.find("-C"); + if ((iter != parameterMap.end()) && (iter->second == "utf8") && (!(superBlock->encoding == 1)) && + (!(superBlock->features & HMFS_FEATURE_CASEFOLD))) { + std::cout << "Failed to check the result of parameter 'C'" << std::endl; + return false; + } + + // 检查参数-R,inode根节点中的i_uid、i_gid与设置的是否一致 + iter = parameterMap.find("-R"); + if (iter != parameterMap.end()) { + size_t colonPos = iter->second.find(':'); + if (colonPos == std::string::npos) { + std::cout << "Failed to find colon" << std::endl; + return false; + } + + std::string userIdStr = iter->second.substr(0, colonPos); + std::string groupIdStr = iter->second.substr(colonPos + 1); + int32_t userId = static_cast(std::stoi(userIdStr)); + int32_t groupId = static_cast(std::stoi(groupIdStr)); + + // 获取inode根节点中的i_uid、iGid + if ((userId != nodeData->i.iUid) || (groupId != nodeData->i.iGid)) { + std::cout << "Failed to verify the userId or the groupId" << std::endl; + return false; + } + } + + // 检查参数-T,inode根节点中i.iAtime、i.iCtime、i.iMtime + iter = parameterMap.find("-T"); + if ((iter != parameterMap.end()) && (iter->second != "-1")) { + uint64_t timeStamp = NATIVE_TO_LE32(strtoul(iter->second.c_str(), nullptr, 0)); + // 获取inode根节点中的i_atime、i.iCtime、i.iMtime + uint64_t accessTime = nodeData->i.iAtime; + uint64_t changeTime = nodeData->i.iCtime; + uint64_t modificationTime = nodeData->i.iMtime; + if ((accessTime != timeStamp) || (changeTime != timeStamp) || (modificationTime != timeStamp)) { + std::cout << "Failed to check the timestamp,timeStamp : " << timeStamp << " accessTime : " << accessTime << + " changeTime : " << changeTime << " modificationTime : " << modificationTime << + " nodeData.i.iAtime = " << nodeData->i.iAtime << " nodeData.i.iCtime = " << nodeData->i.iCtime << + " nodeData.i.iMtime = " << nodeData->i.iMtime << std::endl; + return false; + } + } + + return true; +} + +SuperBlockCode CompareSuperBlock(const std::unique_ptr &f2SB, const std::unique_ptr &hmSB) +{ + // if (f2SB == nullptr || hmSB == nullptr) { + // return ERROR_SB_UNKNOWN; + // } + // 待确认字段 + // uint32_t magicNo; --一致,要比较 + // uint16_t majorVersion; --由宏F2FS_MAJOR_VERSION定义,不比较 + // uint16_t minorVersion; --由宏F2FS_MINOR_VERSION定义,不比较 + // uint8_t uuid[16]; --代码中没用到,不比较 + // uint8_t version[VERSION_TOTAL_LEN]; --目前hmfs为空,不比较 + // uint8_t initVersion[VERSION_TOTAL_LEN]; --同version + // uint8_t encryptPwSalt[16]; --代码中没用到,不比较 + // struct hmfs_device devices[MAX_DEVICE_COUNT]; --设备名称不比较 + // uint32_t qfInodeId[HMFS_MAX_QUOTAS]; --fsck未检查,不比较 + // uint8_t stopReason[CP_STOP_REASON_MAX]; --代码中没用到,不比较 + // uint8_t errors[HMFS_MAX_ERRORS]; --代码中没用到,不比较 + // uint8_t reserved[258]; --不比较 + // uint32_t checksum; --不比较 +/* + bool isEuqal = f2SB->logSectorSize == hmSB->logSectorSize && f2SB->logSectorsPerBlk == hmSB->logSectorsPerBlk && + f2SB->logBlockSize == hmSB->logBlockSize && f2SB->logBlksPerSeg == hmSB->logBlksPerSeg && + f2SB->segsPerSection == hmSB->segsPerSection && f2SB->sectionsPerZone == hmSB->sectionsPerZone && + f2SB->checksumOffset == hmSB->checksumOffset && f2SB->blockCount == hmSB->blockCount && + f2SB->sectionCount == hmSB->sectionCount && f2SB->segmentCount == hmSB->segmentCount && + f2SB->segmentCountInCP == hmSB->segmentCountInCP && f2SB->segmentCountInSIT == hmSB->segmentCountInSIT && + f2SB->segmentCountInNAT == hmSB->segmentCountInNAT && f2SB->segmentCountInSSA == hmSB->segmentCountInSSA && + f2SB->segmentCountInMain == hmSB->segmentCountInMain && f2SB->segmentCountInSSA == hmSB->segmentCountInSSA && + f2SB->segment0BlkId == hmSB->segment0BlkId && f2SB->cpBlkId == hmSB->cpBlkId && f2SB->sitBlkId == hmSB->sitBlkId && + f2SB->natBlkId == hmSB->natBlkId && f2SB->ssaBlkId == hmSB->ssaBlkId && f2SB->mainBlkId == hmSB->mainBlkId && + f2SB->rootInodeId == hmSB->rootInodeId && f2SB->nodeInodeId == hmSB->nodeInodeId && + f2SB->metaInodeId == hmSB->metaInodeId && + std::equal(f2SB->volumeName, f2SB->volumeName + VOLUME_NAME_MAX_LEN, hmSB->volumeName) && + f2SB->extensionCount == hmSB->extensionCount; +*/ + COMPARE_FIELD_RET_CODE(ERROR_LOG_SECTOR_SIZE, f2SB->logSectorSize, hmSB->logSectorSize); + COMPARE_FIELD_RET_CODE(ERROR_LOG_SECTORS_PER_BLK, f2SB->logSectorsPerBlk, hmSB->logSectorsPerBlk); + COMPARE_FIELD_RET_CODE(ERROR_LOG_BLOCK_SIZE, f2SB->logBlockSize, hmSB->logBlockSize); + COMPARE_FIELD_RET_CODE(ERROR_LOG_BLKS_PER_SEG, f2SB->logBlksPerSeg, hmSB->logBlksPerSeg); + COMPARE_FIELD_RET_CODE(ERROR_SEGS_PER_SECTION, f2SB->segsPerSection, hmSB->segsPerSection); + + COMPARE_FIELD_RET_CODE(ERROR_SECTIONS_PER_ZONE, f2SB->sectionsPerZone, hmSB->sectionsPerZone); + COMPARE_FIELD_RET_CODE(ERROR_SB_CHECKSUM_OFFSET, f2SB->checksumOffset, hmSB->checksumOffset); + COMPARE_FIELD_RET_CODE(ERROR_BLOCK_COUNT, f2SB->blockCount, hmSB->blockCount); + COMPARE_FIELD_RET_CODE(ERROR_SECTION_COUNT, f2SB->sectionCount, hmSB->sectionCount); + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT, f2SB->segmentCount, hmSB->segmentCount); + + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_CP, f2SB->segmentCountInCP, hmSB->segmentCountInCP); + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_SIT, f2SB->segmentCountInSIT, hmSB->segmentCountInSIT); + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_NAT, f2SB->segmentCountInNAT, hmSB->segmentCountInNAT); + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_SSA, f2SB->segmentCountInSSA, hmSB->segmentCountInSSA); + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_MAIN, f2SB->segmentCountInMain, hmSB->segmentCountInMain); + + COMPARE_FIELD_RET_CODE(ERROR_SEGMENT0_BLKID, f2SB->segment0BlkId, hmSB->segment0BlkId); + COMPARE_FIELD_RET_CODE(ERROR_CP_BLKID, f2SB->cpBlkId, hmSB->cpBlkId); + COMPARE_FIELD_RET_CODE(ERROR_SIT_BLKID, f2SB->sitBlkId, hmSB->sitBlkId); + COMPARE_FIELD_RET_CODE(ERROR_NAT_BLKID, f2SB->natBlkId, hmSB->natBlkId); + COMPARE_FIELD_RET_CODE(ERROR_SSA_BLKID, f2SB->ssaBlkId, hmSB->ssaBlkId); + + COMPARE_FIELD_RET_CODE(ERROR_MAIN_BLKID, f2SB->mainBlkId, hmSB->mainBlkId); + COMPARE_FIELD_RET_CODE(ERROR_ROOT_INODE_ID, f2SB->rootInodeId, hmSB->rootInodeId); + COMPARE_FIELD_RET_CODE(ERROR_NODE_INODE_ID, f2SB->nodeInodeId, hmSB->nodeInodeId); + COMPARE_FIELD_RET_CODE(ERROR_META_INODE_ID, f2SB->metaInodeId, hmSB->metaInodeId); + COMPARE_FIELD_RET_CODE(ERROR_EXTENSION_COUNT, f2SB->coldExtensionCount, hmSB->coldExtensionCount); + + COMPARE_FIELD_RET_CODE(ERROR_VOLUME_NAME, f2SB->volumeName, f2SB->volumeName + VOLUME_NAME_MAX_LEN, hmSB->volumeName); + + std::vector f2fsExtList; + std::vector hmfsExtList; + for (int32_t i = 0; i < EXTENSION_COUNT_MAX; ++i) { + std::string extension(const_cast(f2SB->extensionList[i])); + f2fsExtList.push_back(extension); + } + for (int32_t i = 0; i < EXTENSION_COUNT_MAX; ++i) { + std::string extension(const_cast(hmSB->extensionList[i])); + hmfsExtList.push_back(extension); + } + + // return std::equal(f2fsExtList.begin(), f2fsExtList.end(), hmfsExtList.begin(), hmfsExtList.end()) && + // f2SB.cpPayload == hmSB.cpPayload && f2SB.features == hmSB.features && + // f2SB.encryptionLevel == hmSB.encryptionLevel && f2SB.hotExtensionCount == hmSB.hotExtensionCount && + // f2SB.encoding == hmSB.encoding && f2SB.encodingFlags == hmSB.encodingFlags; + + COMPARE_FIELD_RET_CODE(ERROR_EXTENSION_LIST, f2fsExtList.begin(), f2fsExtList.end(), hmfsExtList.begin(), hmfsExtList.end()); + COMPARE_FIELD_RET_CODE(ERROR_CP_PAY_LOAD, f2SB->cpPayload, hmSB->cpPayload); + COMPARE_FIELD_RET_CODE(ERROR_FEATURES, f2SB->features, hmSB->features); + COMPARE_FIELD_RET_CODE(ERROR_ENCRYPTION_LEVEL, f2SB->encryptionLevel, hmSB->encryptionLevel); + + COMPARE_FIELD_RET_CODE(ERROR_HOT_EXTENSION_COUNT, f2SB->hotExtensionCount, hmSB->hotExtensionCount); + COMPARE_FIELD_RET_CODE(ERROR_S_ENCODING, f2SB->encoding, hmSB->encoding); + COMPARE_FIELD_RET_CODE(ERROR_S_ENCODING_FLAGS, f2SB->encodingFlags, hmSB->encodingFlags); + return SUCCESSED_SB; +} + +CheckPointCode CompareCheckPoint(const std::unique_ptr &f2CP, const std::unique_ptr &hmCP) +{ + COMPARE_FIELD_RET_CODE(ERROR_USER_BLOCK_COUNT, f2CP->userBlockCount, hmCP->userBlockCount); + COMPARE_FIELD_RET_CODE(ERROR_VALID_BLOCK_COUNT, f2CP->validBlockCount, hmCP->validBlockCount); + COMPARE_FIELD_RET_CODE(ERROR_RSVD_SEGMENT_COUNT, f2CP->rsvdSegmentCount, hmCP->rsvdSegmentCount); + COMPARE_FIELD_RET_CODE(ERROR_OVERPROV_SEGMENT_COUNT, f2CP->overprovSegmentCount, hmCP->overprovSegmentCount); + COMPARE_FIELD_RET_CODE(ERROR_FREE_SEGMENT_COUNT, f2CP->freeSegmentCount, hmCP->freeSegmentCount); + + // uint64_t cpVersion; --随机值不需要比较 + // uint8_t sitNatVersionBitmap[]; --随机值不需要比较 +/* + return std::equal(f2CP->curNodeSegNo, f2CP->curNodeSegNo + CURSEG_NODE_TYPE_COUNT, hmCP->curNodeSegNo) && + std::equal(f2CP->curNodeBlkOffset, f2CP->curNodeBlkOffset + CURSEG_NODE_TYPE_COUNT, hmCP->curNodeBlkOffset) && + std::equal(f2CP->curDataSegNo, f2CP->curDataSegNo + CURSEG_DATA_TYPE_COUNT, hmCP->curDataSegNo) && + std::equal(f2CP->curDataBlkOffset, f2CP->curDataBlkOffset + CURSEG_DATA_TYPE_COUNT, hmCP->curDataBlkOffset) && + f2CP->cpFlags == hmCP->cpFlags && f2CP->cpPackBlockCount == hmCP->cpPackBlockCount && + f2CP->cpPackStartSum == hmCP->cpPackStartSum && f2CP->validNodeCount == hmCP->validNodeCount && + f2CP->validInodeCount == hmCP->validInodeCount && f2CP->nextFreeNodeId == hmCP->nextFreeNodeId && + f2CP->sitVersionBitmapSize == hmCP->sitVersionBitmapSize && + f2CP->natVersionBitmapSize == hmCP->natVersionBitmapSize && + f2CP->checksumOffset == hmCP->checksumOffset && + std::equal(f2CP->allocType, f2CP->allocType + CURSEG_NODE_COLD, hmCP->allocType); +*/ + + COMPARE_FIELD_RET_CODE(ERROR_CUR_NODE_SEG_NO, f2CP->curNodeSegNo, f2CP->curNodeSegNo + CURSEG_NODE_TYPE_COUNT, + hmCP->curNodeSegNo); + COMPARE_FIELD_RET_CODE(ERROR_CUR_NODE_BLK_OFFSET, f2CP->curNodeBlkOffset, + f2CP->curNodeBlkOffset + CURSEG_NODE_TYPE_COUNT, hmCP->curNodeBlkOffset); + COMPARE_FIELD_RET_CODE(ERROR_CUR_DATA_SEG_NO, f2CP->curDataSegNo, f2CP->curDataSegNo + CURSEG_DATA_TYPE_COUNT, + hmCP->curDataSegNo); + COMPARE_FIELD_RET_CODE(ERROR_CUR_DATA_BLK_OFFSET, f2CP->curDataBlkOffset, + f2CP->curDataBlkOffset + CURSEG_DATA_TYPE_COUNT, hmCP->curDataBlkOffset); + COMPARE_FIELD_RET_CODE(ERROR_ALLOC_TYPE, f2CP->allocType, f2CP->allocType + CURSEG_NODE_COLD, hmCP->allocType); + + COMPARE_FIELD_RET_CODE(ERROR_CP_FLAGS, f2CP->cpFlags, hmCP->cpFlags); + COMPARE_FIELD_RET_CODE(ERROR_CP_PACK_BLOCK_COUNT, f2CP->cpPackBlockCount, hmCP->cpPackBlockCount); + COMPARE_FIELD_RET_CODE(ERROR_CP_PACK_START_SUM, f2CP->cpPackBlockCount, hmCP->cpPackBlockCount); + COMPARE_FIELD_RET_CODE(ERROR_VALID_NODE_COUNT, f2CP->validNodeCount, hmCP->validNodeCount); + COMPARE_FIELD_RET_CODE(ERROR_VALID_INODE_COUNT, f2CP->validInodeCount, hmCP->validInodeCount); + + COMPARE_FIELD_RET_CODE(ERROR_NEXT_FREE_NODE_ID, f2CP->nextFreeNodeId, hmCP->nextFreeNodeId); + COMPARE_FIELD_RET_CODE(ERROR_SIT_VERSION_BITMAP_SIZE, f2CP->sitVersionBitmapSize, hmCP->sitVersionBitmapSize); + COMPARE_FIELD_RET_CODE(ERROR_NAT_VERSION_BITMAP_SIZE, f2CP->natVersionBitmapSize, hmCP->natVersionBitmapSize); + COMPARE_FIELD_RET_CODE(ERROR_CP_CHECKSUM_OFFSET, f2CP->checksumOffset, hmCP->checksumOffset); + + return SUCCESSED_CP; +} + +NodeDataCode CompareNodeData(const std::unique_ptr &f2CP, const std::unique_ptr &hmCP, + const int16_t addrIndex, const bool compTime) +{ + COMPARE_FIELD_RET_CODE(ERROR_NODE_MODE, f2CP->i.iMode, hmCP->i.iMode); + COMPARE_FIELD_RET_CODE(ERROR_NODE_ADVISE, f2CP->i.iAdvise, hmCP->i.iAdvise); + COMPARE_FIELD_RET_CODE(ERROR_NODE_UID, f2CP->i.iUid, hmCP->i.iUid); + COMPARE_FIELD_RET_CODE(ERROR_NODE_GID, f2CP->i.iGid, hmCP->i.iGid); + COMPARE_FIELD_RET_CODE(ERROR_NODE_LINKS, f2CP->i.iLinks, hmCP->i.iLinks); + + COMPARE_FIELD_RET_CODE(ERROR_NODE_SIZE, f2CP->i.iSize, hmCP->i.iSize); + COMPARE_FIELD_RET_CODE(ERROR_NODE_BLOCKS, f2CP->i.iBlocks, hmCP->i.iBlocks); + + if (compTime) { + COMPARE_FIELD_RET_CODE(ERROR_NODE_ATIME, f2CP->i.iAtime, hmCP->i.iAtime); + COMPARE_FIELD_RET_CODE(ERROR_NODE_ATIME_NSEC, f2CP->i.iAtimeNsec, hmCP->i.iAtimeNsec); + COMPARE_FIELD_RET_CODE(ERROR_NODE_CTIME, f2CP->i.iCtime, hmCP->i.iCtime); + COMPARE_FIELD_RET_CODE(ERROR_NODE_CTIME_NSEC, f2CP->i.iCtimeNsec, hmCP->i.iCtimeNsec); + COMPARE_FIELD_RET_CODE(ERROR_NODE_MTIME, f2CP->i.iMtime, hmCP->i.iMtime); + COMPARE_FIELD_RET_CODE(ERROR_NODE_MTIME_NSEC, f2CP->i.iMtimeNsec, hmCP->i.iMtimeNsec); + } + + COMPARE_FIELD_RET_CODE(ERROR_NODE_GENRATION, f2CP->i.iGeneration, hmCP->i.iGeneration); + COMPARE_FIELD_RET_CODE(ERROR_NODE_CURRENT_DEPTH, f2CP->i.iCurrentDepth, hmCP->i.iCurrentDepth); + COMPARE_FIELD_RET_CODE(ERROR_NODE_XATTR_NID, f2CP->i.iXattrNid, hmCP->i.iXattrNid); + COMPARE_FIELD_RET_CODE(ERROR_NODE_FLAGS, f2CP->i.iFlags, hmCP->i.iFlags); + COMPARE_FIELD_RET_CODE(ERROR_NODE_INLINE, f2CP->i.iInline, hmCP->i.iInline); + + COMPARE_FIELD_RET_CODE(ERROR_NODE_PINO, f2CP->i.iPino, hmCP->i.iPino); + COMPARE_FIELD_RET_CODE(ERROR_NODE_DIR_LEVEL, f2CP->i.iDirLevel, hmCP->i.iDirLevel); + + // COMPARE_FIELD_RET_CODE(ERROR_NODE_EXT, f2CP->i.iExt.fofs, hmCP->i.iExt.fofs); + // COMPARE_FIELD_RET_CODE(ERROR_NODE_EXT, f2CP->i.iExt.blkAddr, hmCP->i.iExt.blkAddr); + // COMPARE_FIELD_RET_CODE(ERROR_NODE_EXT, f2CP->i.iExt.len, hmCP->i.iExt.len); + + COMPARE_FIELD_RET_CODE(ERROR_NODE_ADDR, f2CP->i.i_addr[addrIndex], hmCP->i.i_addr[addrIndex]); + + // COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->i.i_nid[0], hmCP->i.i_nid[0]); + // COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->i.i_nid[1], hmCP->i.i_nid[1]); + // COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->i.i_nid[2], hmCP->i.i_nid[2]); + // COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->i.i_nid[3], hmCP->i.i_nid[3]); + // COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->i.i_nid[4], hmCP->i.i_nid[4]); + + COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->i.i_nid, f2CP->i.i_nid + 4, + hmCP->i.i_nid, hmCP->i.i_nid + 4); + + return SUCCESSED_ND; +} + +void PrintRawSBInfo(const std::unique_ptr &sb) +{ + std::cout << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| hmfs Super block |" << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + + PRINT_TO_COLSOLE(sb, magicNo); + PRINT_TO_COLSOLE(sb, majorVersion); + + PRINT_TO_COLSOLE(sb, minorVersion); + PRINT_TO_COLSOLE(sb, logSectorSize); + PRINT_TO_COLSOLE(sb, logSectorsPerBlk); + + PRINT_TO_COLSOLE(sb, logBlockSize); + PRINT_TO_COLSOLE(sb, logBlksPerSeg); + PRINT_TO_COLSOLE(sb, segsPerSection); + PRINT_TO_COLSOLE(sb, sectionsPerZone); + PRINT_TO_COLSOLE(sb, checksumOffset); + PRINT_TO_COLSOLE(sb, blockCount); + + PRINT_TO_COLSOLE(sb, sectionCount); + PRINT_TO_COLSOLE(sb, segmentCount); + PRINT_TO_COLSOLE(sb, segmentCountInCP); + PRINT_TO_COLSOLE(sb, segmentCountInSIT); + PRINT_TO_COLSOLE(sb, segmentCountInNAT); + + PRINT_TO_COLSOLE(sb, segmentCountInSSA); + PRINT_TO_COLSOLE(sb, segmentCountInMain); + PRINT_TO_COLSOLE(sb, segment0BlkId); + + PRINT_TO_COLSOLE(sb, cpBlkId); + PRINT_TO_COLSOLE(sb, sitBlkId); + PRINT_TO_COLSOLE(sb, natBlkId); + PRINT_TO_COLSOLE(sb, ssaBlkId); + PRINT_TO_COLSOLE(sb, mainBlkId); + + PRINT_TO_COLSOLE(sb, rootInodeId); + PRINT_TO_COLSOLE(sb, nodeInodeId); + PRINT_TO_COLSOLE(sb, metaInodeId); + PRINT_TO_COLSOLE(sb, cpPayload); + PRINT_TO_COLSOLE(sb, checksum); + printf("%-25s%-.255s", "version", sb->version); + std::cout << std::endl; +} + +void PrintCPInfo(const std::unique_ptr &cp) +{ + std::cout << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| hmfs Checkpoint |" << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + + PRINT_TO_COLSOLE(cp, cpVersion); + PRINT_TO_COLSOLE(cp, userBlockCount); + PRINT_TO_COLSOLE(cp, validBlockCount); + PRINT_TO_COLSOLE(cp, rsvdSegmentCount); + PRINT_TO_COLSOLE(cp, overprovSegmentCount); + PRINT_TO_COLSOLE(cp, freeSegmentCount); + + PRINT_TO_COLSOLE(cp, allocType[3]); + PRINT_TO_COLSOLE(cp, allocType[4]); + PRINT_TO_COLSOLE(cp, allocType[5]); + PRINT_TO_COLSOLE(cp, curNodeSegNo[0]); + PRINT_TO_COLSOLE(cp, curNodeSegNo[1]); + PRINT_TO_COLSOLE(cp, curNodeSegNo[2]); + + PRINT_TO_COLSOLE(cp, curNodeBlkOffset[0]); + PRINT_TO_COLSOLE(cp, curNodeBlkOffset[1]); + PRINT_TO_COLSOLE(cp, curNodeBlkOffset[2]); + + + PRINT_TO_COLSOLE(cp, allocType[0]); + PRINT_TO_COLSOLE(cp, allocType[1]); + PRINT_TO_COLSOLE(cp, allocType[2]); + PRINT_TO_COLSOLE(cp, curDataSegNo[0]); + PRINT_TO_COLSOLE(cp, curDataSegNo[1]); + PRINT_TO_COLSOLE(cp, curDataSegNo[2]); + + PRINT_TO_COLSOLE(cp, curDataBlkOffset[0]); + PRINT_TO_COLSOLE(cp, curDataBlkOffset[1]); + PRINT_TO_COLSOLE(cp, curDataBlkOffset[2]); + + PRINT_TO_COLSOLE(cp, cpFlags); + PRINT_TO_COLSOLE(cp, cpPackBlockCount); + PRINT_TO_COLSOLE(cp, cpPackStartSum); + PRINT_TO_COLSOLE(cp, validNodeCount); + PRINT_TO_COLSOLE(cp, validInodeCount); + PRINT_TO_COLSOLE(cp, nextFreeNodeId); + PRINT_TO_COLSOLE(cp, sitVersionBitmapSize); + PRINT_TO_COLSOLE(cp, natVersionBitmapSize); + PRINT_TO_COLSOLE(cp, checksumOffset); + PRINT_TO_COLSOLE(cp, elapsedTime); + + PRINT_TO_COLSOLE(cp, sitNatVersionBitmap[0]); + std::cout << std::endl; +} + +void PrintInodeInfo(uint32_t features, const std::unique_ptr &node, + const int16_t addrIndex, const uint32_t iNodeNum) +{ + std::cout << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + std::cout << "| hmfs IndeInfo iNodeNum : " << iNodeNum << " |" << std::endl; + std::cout << "+--------------------------------------------------------+" << std::endl; + + auto inode = &node->i; + PRINT_TO_COLSOLE(inode, iMode); + PRINT_TO_COLSOLE(inode, iAdvise); + PRINT_TO_COLSOLE(inode, iUid); + PRINT_TO_COLSOLE(inode, iGid); + PRINT_TO_COLSOLE(inode, iLinks); + PRINT_TO_COLSOLE(inode, iSize); + PRINT_TO_COLSOLE(inode, iBlocks); + + PRINT_TO_COLSOLE(inode, iAtime); + PRINT_TO_COLSOLE(inode, iAtimeNsec); + PRINT_TO_COLSOLE(inode, iCtime); + PRINT_TO_COLSOLE(inode, iCtimeNsec); + PRINT_TO_COLSOLE(inode, iMtime); + PRINT_TO_COLSOLE(inode, iMtimeNsec); + + PRINT_TO_COLSOLE(inode, iGeneration); + PRINT_TO_COLSOLE(inode, iCurrentDepth); + PRINT_TO_COLSOLE(inode, iXattrNid); + PRINT_TO_COLSOLE(inode, iFlags); + PRINT_TO_COLSOLE(inode, iInline); + PRINT_TO_COLSOLE(inode, iPino); + PRINT_TO_COLSOLE(inode, iDirLevel); + + if (features & HMFS_FEATURE_EXTRA_ATTR) { + PRINT_TO_COLSOLE(inode, iExtraIsize); + if (features & HMFS_FEATURE_FLEXIBLE_INLINE_XATTR) + PRINT_TO_COLSOLE(inode, iInlineXattrSize); + if (features & HMFS_FEATURE_PRJQUOTA) + PRINT_TO_COLSOLE(inode, iProjid); + // if (features & HMFS_FEATURE_INODE_CHKSUM) + // PRINT_TO_COLSOLE(inode, iInodeChecksum); + if (features & HMFS_FEATURE_INODE_CRTIME) { + PRINT_TO_COLSOLE(inode, iCrtime); + PRINT_TO_COLSOLE(inode, iCrtimeNsec); + } + if (features & HMFS_FEATURE_COMPRESSION) { + PRINT_TO_COLSOLE(inode, iComprBlocks); + PRINT_TO_COLSOLE(inode, iCompressAlgrithm); + PRINT_TO_COLSOLE(inode, iLogClusterSize); + PRINT_TO_COLSOLE(inode, iPadding); + } + } + + std::cout << "i.i_addr[0x" << std::hex << addrIndex << "] = " << + std::dec << node->i.i_addr[addrIndex] << std::endl; + + PRINT_TO_COLSOLE(inode, i_nid[0]); /* direct */ + PRINT_TO_COLSOLE(inode, i_nid[1]); /* direct */ + PRINT_TO_COLSOLE(inode, i_nid[2]); /* indirect */ + PRINT_TO_COLSOLE(inode, i_nid[3]); /* indirect */ + PRINT_TO_COLSOLE(inode, i_nid[4]); /* double indirect */ + + std::cout << std::endl; +} + +void PrintSuperBlockAndCheckPointData(const std::string& device) +{ + auto hmfsSuperBlock = std::make_unique(); + GetSuperBlock(device, hmfsSuperBlock); + PrintRawSBInfo(hmfsSuperBlock); + + auto checkPoint = std::make_unique(); + GetCheckPoint(device, checkPoint); + PrintCPInfo(checkPoint); +} +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.h b/tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.h new file mode 100755 index 0000000..f4fb1a4 --- /dev/null +++ b/tools/hmfs-tools/test/unittest/utils/hmfs_test_utils.h @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, Hardware + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_TEST_UTILS_H +#define HMFS_TEST_UTILS_H + +#include +#include +#include +#include +#include +#include + +#include "hmfs_common.h" +#include "hmfs_define.h" +#include "hmfs_data.h" + +namespace OHOS { +namespace Hmfs { +constexpr int32_t NEED_SAFE_RESIZE_FLAG = 1; +constexpr int32_t OUT_OF_RANGE = 2; +constexpr int32_t VALID = 0; +constexpr int32_t MORE_SEGMENT_NEEDED = 3; + +constexpr int32_t PREAD_BUFFER_SIZE = 4096; +constexpr int32_t SUPER_BLOCK_OFFSET = 1024; +constexpr uint8_t MAX_DEVICE_COUNTS = 8; +const std::string HMFS_DEVICE_PATH_LIST[MAX_DEVICE_COUNTS - 1] = { + "/data/local/hmfsTest", + "/data/local/hmfsTest1", + "/data/local/hmfsTest2", + "/data/local/hmfsTest3", + "/data/local/hmfsTest4", + "/data/local/hmfsTest5", + "/data/local/hmfsTest6" +}; + +const std::string F2FS_DEVICE_PATH_LIST[MAX_DEVICE_COUNTS - 1] = { + "/data/local/f2fsTest", + "/data/local/f2fsTest1", + "/data/local/f2fsTest2", + "/data/local/f2fsTest3", + "/data/local/f2fsTest4", + "/data/local/f2fsTest5", + "/data/local/f2fsTest6" +}; + +const std::string HMFS_PARAMETER_LIST[] = { + "-a", "-d", "-e", "-E", "-l", "-o", "-O", "-C", "-R", "-s", "-t", "-T", "-w", "-z" +}; + +const std::string HMFS_RESIZE_PARAMETER_LIST[] = { + "-d", "-C", "-O", "-o", "-t", +}; + +enum HmfsCode { + SUCCESSED = 0, + FAILED = 1, + // other reasons, such as empty file name, failed to open the file, failed to format the file + ERROR_OTHER = 2 +}; + +enum SuperBlockCode { + SUCCESSED_SB = 0, + ERROR_SB_UNKNOWN, + ERROR_LOG_SECTOR_SIZE, + ERROR_LOG_SECTORS_PER_BLK, + ERROR_LOG_BLOCK_SIZE, + ERROR_LOG_BLKS_PER_SEG, + ERROR_SEGS_PER_SECTION, + ERROR_SECTIONS_PER_ZONE, + ERROR_SB_CHECKSUM_OFFSET, + ERROR_BLOCK_COUNT, + ERROR_SECTION_COUNT, + ERROR_SEGMENT_COUNT, + ERROR_SEGMENT_COUNT_IN_CP, + ERROR_SEGMENT_COUNT_IN_SIT, + ERROR_SEGMENT_COUNT_IN_NAT, + ERROR_SEGMENT_COUNT_IN_SSA, + ERROR_SEGMENT_COUNT_IN_MAIN, + ERROR_SEGMENT0_BLKID, + ERROR_CP_BLKID, + ERROR_SIT_BLKID, + ERROR_NAT_BLKID, + ERROR_SSA_BLKID, + ERROR_MAIN_BLKID, + ERROR_ROOT_INODE_ID, + ERROR_NODE_INODE_ID, + ERROR_META_INODE_ID, + ERROR_EXTENSION_COUNT, + ERROR_VOLUME_NAME, + ERROR_EXTENSION_LIST, + ERROR_CP_PAY_LOAD, + ERROR_FEATURES, + ERROR_ENCRYPTION_LEVEL, + ERROR_HOT_EXTENSION_COUNT, + ERROR_S_ENCODING, + ERROR_S_ENCODING_FLAGS +}; + +enum CheckPointCode { + SUCCESSED_CP = 0, + ERROR_CP_UNKNOWN, + ERROR_USER_BLOCK_COUNT, + ERROR_VALID_BLOCK_COUNT, + ERROR_RSVD_SEGMENT_COUNT, + ERROR_OVERPROV_SEGMENT_COUNT, + ERROR_FREE_SEGMENT_COUNT, + ERROR_CUR_NODE_SEG_NO, + ERROR_CUR_NODE_BLK_OFFSET, + ERROR_CUR_DATA_SEG_NO, + ERROR_CUR_DATA_BLK_OFFSET, + ERROR_ALLOC_TYPE, + ERROR_CP_FLAGS, + ERROR_CP_PACK_BLOCK_COUNT, + ERROR_CP_PACK_START_SUM, + ERROR_VALID_NODE_COUNT, + ERROR_VALID_INODE_COUNT, + ERROR_NEXT_FREE_NODE_ID, + ERROR_SIT_VERSION_BITMAP_SIZE, + ERROR_NAT_VERSION_BITMAP_SIZE, + ERROR_CP_CHECKSUM_OFFSET +}; + +enum NodeDataCode { + SUCCESSED_ND = 0, + ERROR_NODE_UNKNOWN, + ERROR_NODE_MODE, + ERROR_NODE_ADVISE, + ERROR_NODE_UID, + ERROR_NODE_GID, + ERROR_NODE_LINKS, + ERROR_NODE_SIZE, + ERROR_NODE_BLOCKS, + ERROR_NODE_ATIME, + ERROR_NODE_ATIME_NSEC, + ERROR_NODE_CTIME, + ERROR_NODE_CTIME_NSEC, + ERROR_NODE_MTIME, + ERROR_NODE_MTIME_NSEC, + ERROR_NODE_GENRATION, + ERROR_NODE_CURRENT_DEPTH, + ERROR_NODE_XATTR_NID, + ERROR_NODE_FLAGS, + ERROR_NODE_INLINE, + ERROR_NODE_PINO, + ERROR_NODE_DIR_LEVEL, + ERROR_NODE_EXT, + ERROR_NODE_ADDR, + ERROR_NODE_NID, + ERROR_NODE_EXTRA_ISIZE, + ERROR_NODE_INLINE_XATTR_SIZE, + ERROR_NODE_PROJID, + ERROR_NODE_COMPRESSION +}; + +HmfsCode WriteFile(const std::string &fileName); +std::string ReadFile(const std::string &fileName); +HmfsCode GetFileStat(const std::string &fileName, struct stat *statBuf); +HmfsCode CheckDataIsZero(const std::string &fileName); +HmfsCode FAllocateFile(const std::string &fileName); +unsigned long long GetFileSize(const std::string &fileName); +void PrintParameters(const std::vector ¶ms); + +int16_t ParseInodeAddrIndex(const std::string &addr); +int32_t ExecutableCmdWithOutput(std::vector ¶ms, std::string &outputFile); +std::unordered_map ParseInodeInfo(const std::string &outputFile); +void GetNodeDataFromMap(std::unique_ptr &nodeData, int16_t &addrIndex, + const std::unordered_map &inodeInfo); +// Dump data +void GetSuperBlock(const std::string &devPath, std::unique_ptr &superBlock); +void GetCheckPoint(const std::string &devPath, std::unique_ptr &checkPoint); +void GetInodeInfo(const std::string &devPath, std::unique_ptr &nodeData, + int16_t &addrIndex, const uint32_t iNode); +void PrintRawSBInfo(const std::unique_ptr &sb); +void PrintCPInfo(const std::unique_ptr &cp); +void PrintInodeInfo(uint32_t features, const std::unique_ptr &node, + const int16_t addrIndex, const uint32_t iNodeNum); +void PrintSuperBlockAndCheckPointData(const std::string& device); + +std::string ConfirmDevicePath(const std::vector ¶ms, const bool changePath = true); +std::string FindSpecifyStr(const std::vector &vecStr, const std::string& item); +bool ContainSubStr(const std::string ¶meterValue, const std::string &subStr); + +bool CheckFeatures(const uint32_t features, const std::string &featureNameList); +bool CheckParametersVaild(const std::vector ¶ms, std::map ¶meterMap); +int32_t CheckResizeParameters(std::string &device, const std::vector ¶ms, + const uint32_t deviceSectorCount, std::map ¶meterMap); +bool CheckMkfsHmfsResult(const std::map ¶meterMap, + const std::unique_ptr &checkPoint, const std::unique_ptr &superBlock, + const std::unique_ptr &nodeData); +bool CheckResizeHmfsResult(const std::map ¶meterMap, + const std::unique_ptr &checkPoint, const std::unique_ptr &superBlock, + const std::string &output); +bool PrintFsckErrorMsg(const std::string &outputFile, const std::string &devicePath); +bool CheckSafeResize(const std::map ¶meterMap, const std::unique_ptr &superBlock); +SuperBlockCode CompareSuperBlock(const std::unique_ptr &f2SB, const std::unique_ptr &hmSB); +CheckPointCode CompareCheckPoint(const std::unique_ptr &f2CP, const std::unique_ptr &hmCP); +NodeDataCode CompareNodeData(const std::unique_ptr &f2CP, const std::unique_ptr &hmCP, + const int16_t addrIndex, const bool compTime = false); + +// Generate random +std::vector GenerateParams(bool isResizeTool = true); +void GenerateMkfsParams(std::vector ¶ms); +void GenerateMkfsParamsEnd(std::vector ¶ms); + +void ReplaceDevicePaths(std::vector ¶ms); + +std::string GenerateFeatures(bool isResizeTool = true); +std::string GenerateRandomString(const size_t length); +int32_t GenerateRandomInt32(const int32_t startNum = -10); +} // namespace Hmfs +} // namespace OHOS +#endif // HMFS_TEST_UTILS_H \ No newline at end of file diff --git "a/tools/hmfs-tools/test/unittest/utils/\346\226\260\346\226\207\344\273\266 9.txt" "b/tools/hmfs-tools/test/unittest/utils/\346\226\260\346\226\207\344\273\266 9.txt" new file mode 100755 index 0000000..41adb0d --- /dev/null +++ "b/tools/hmfs-tools/test/unittest/utils/\346\226\260\346\226\207\344\273\266 9.txt" @@ -0,0 +1,45 @@ +void GetInodeInfo(const std::string &devPath, std::unique_ptr &nodeData, uint32_t iNode) +{ + if (nodeData == nullptr || devPath.empty()) { + std::cout << "GetInodeInfo invalid parameter" << std::endl; + return; + } + auto superBlock = std::make_unique(); + GetSuperBlock(devPath, superBlock); + + uint32_t natBlockAddr = GetLeValue(superBlock->natBlkId); // NAT start address + int fd = open(devPath.c_str(), O_RDWR | O_BINARY); + if (fd < 0) { + std::cout << "Failed to open " << devPath << " errno " << errno << std::endl; + return; + } + + std::array buf {}; + if (pread64(fd, buf.data(), buf.size(), natBlockAddr<<12) < 0) { + std::cout << "Failed to pread64, errno " << errno << std::endl; + close(fd); + return; + } + + struct natBlockData natBlock {}; + if (memcpy_s(&natBlock, sizeof(natBlock), buf.data(), sizeof(natBlock)) != 0) { + std::cout << "Failed to memcpy natBlock" << std::endl; + return; + } + + std::array buf1 {}; + for (int32_t i = 0; i <= NAT_ENTRIES_PER_BLOCK; i++) { + if (natBlock.entries[i].inodeNo == iNode) { + if (pread64(fd, buf1.data(), buf1.size(), natBlock.entries[i].blockId<< 12) < 0) { + std::cout << "Failed to pread64, errno " << errno << std::endl; + close(fd); + return; + } + + if (memcpy_s(nodeData.get(), sizeof(*nodeData), buf1.data(), PREAD_BUFFER_SIZE) != 0) { + std::cout << "Failed to memcpy nodeData" << std::endl; + return; + } + } + } +} \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/BUILD.gn b/tools/hmfs-tools/tools/common/BUILD.gn new file mode 100755 index 0000000..625111d --- /dev/null +++ b/tools/hmfs-tools/tools/common/BUILD.gn @@ -0,0 +1,60 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +config("hmfs-defaults") { + cflags = [ + #"-Wall", + #"-Werror", + "-Wno-incompatible-pointer-types", + "-Wno-unused-function", + "-Wno-unused-parameter", + "-Wno-format", + ] +} + +# ohos_shared_library("libhmfs") { +ohos_static_library("libhmfs") { + # TODO + # sources = [ "${hmfs_tools_path}/common/hmfs_mount.cpp" ] + sources = [ + "hmfs_common.cpp", + "hmfs_io.cpp", + "hmfs_encoding.cpp", + "hmfs_zoned.cpp", + "hmfs_command.cpp", + "device_manager.cpp", + ] + + include_dirs = [ + ".", + "${hmfs_tools_path}/common/", + ] + + configs = [ + ":hmfs-defaults", + ] + + external_deps = [ + "hilog:libhilog", + "bounds_checking_function:libsec_shared", + "icu:shared_icui18n", + "icu:shared_icuuc", + ] + + defines = [ "HAVE_CONFIG_H" ] + subsystem_name = "thirdparty" + part_name = "hmfs-tools" +} diff --git a/tools/hmfs-tools/tools/common/device_manager.cpp b/tools/hmfs-tools/tools/common/device_manager.cpp new file mode 100755 index 0000000..6fd2860 --- /dev/null +++ b/tools/hmfs-tools/tools/common/device_manager.cpp @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "device_manager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBBLKID +#include +#endif + +#ifdef HAVE_SCSI_SG_H +#include +#endif + +#ifndef _WIN32 +#define O_BINARY 0 +#endif + +#include "hmfs_utils.h" +#include "hmfs_zoned.h" +#include "hmfs_common.h" +#include "hmfs_io.h" + + +namespace OHOS { +namespace Hmfs { + +std::unique_ptr DeviceManager::instance_ = nullptr; +void DeviceManager::CreateInstance(CmdConfig &cfgPara) +{ + if (instance_ == nullptr) { + instance_ = std::make_unique(cfgPara); + } +} + +DeviceManager& DeviceManager::GetInstance() +{ + return *instance_.get(); +} + +int32_t DeviceManager::CreateDeviceInfo(std::string& path, bool isMetaDevice) +{ + HMFS_INFO("DeviceManager::CreateDeviceInfo, path = %s", path.c_str()); + auto device = std::make_unique(); + device->path = path; + device->isMetaDevice = isMetaDevice; + + struct stat statInfo; + if (stat(path.c_str(), &statInfo) < 0 ) { + HMFS_ERROR("Failed to get the device stat for %s. errno: %d", path.c_str(), errno); + return -1; + } + + if (S_ISBLK(statInfo.st_mode)) { + if (HmfsZoned::GetInstance().HmfsGetZonedModel(device.get()) < 0) { + return -1; + } + } + + if (cmdPara_.sparseMode) { + device->fd = open(path.c_str(), O_RDWR | O_CREAT | O_BINARY, 0644); + if (device->fd < 0) { + HMFS_ERROR("Failed to open a sparse file. errno: %d", errno); + return -1; + } + } else { + int32_t flags = O_RDWR; + if (S_ISBLK(statInfo.st_mode)) { + flags |= O_EXCL; + } + device->fd = open(path.c_str(), flags); + if (device->fd < 0) { + HMFS_ERROR("Failed to open the device. errno: %d", errno); + return -1; + } + } + + if (cmdPara_.sparseMode) { + if (HmfsIo::GetInstance().HmfsInitSparseFile()) { + return -1; + } + device->sectorCount = cmdPara_.deviceSize / device->sectorSize; + } else if (S_ISREG(statInfo.st_mode)) { + device->sectorCount = statInfo.st_size / device->sectorSize; + } else if (S_ISBLK(statInfo.st_mode)) { + #ifdef BLKSSZGET + uint32_t sectorSize; + if (ioctl(device->fd, BLKSSZGET, §orSize) < 0) { + HMFS_ERROR("Using the default sector size. errno: %d", errno); + } else if (device->sectorSize < sectorSize) { + device->sectorSize = sectorSize; + } + #endif + + #ifdef BLKGETSIZE64 + if (ioctl(device->fd, BLKGETSIZE64, &device->sectorCount) < 0) { + HMFS_ERROR("Cannot get the device size. errno: %d", errno); + return -1; + } + #else + if (ioctl(device->fd, BLKGETSIZE, &device->sectorCount) < 0) { + HMFS_ERROR("Cannot get the device size. errno: %d", errno); + return -1; + } + #endif + device->sectorCount /= device->sectorSize; + + // if (isMetaDevice) { + // #ifdef HDIO_GETGIO + // if (ioctl(device->fd, HDIO_GETGEO, &geom) < 0) + // c.startSector = 0; + // else + // c.startSector = geom.start; + // #else + // c.startSector = 0; + // #endif + // } + + #if !defined(WITH_OHOS) && defined(__linux__) + /* Send INQUIRY command */ + /* SCSI command for standard inquiry*/ + #define MODELINQUIRY 0x12,0x00,0x00,0x00,0x4A,0x00 + sg_io_hdr_t io_hdr; + unsigned char reply_buffer[96] = {0}; + unsigned char model_inq[6] = {MODELINQUIRY}; + memset_s(&io_hdr, sizeof(sg_io_hdr_t), 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = sizeof(reply_buffer); + io_hdr.dxferp = reply_buffer; + io_hdr.cmd_len = sizeof(model_inq); + io_hdr.cmdp = model_inq; + io_hdr.timeout = 1000; + + if (!ioctl(device->fd, SG_IO, &io_hdr)) { + HMFS_INFO("[%s] Disk Model: %.16s", path.c_str(), reply_buffer+16); + } + #endif + } else { + HMFS_ERROR("Volume type is not supported"); + return -1; + } + + if ((!isMetaDevice) && (device->sectorSize != devices_[0]->sectorSize)) { + HMFS_ERROR("Different sector sizes"); + return -1; + } + + if (device->zonedModel != HMFS_ZONED_NONE) { + /* Get the number of blocks per zones */ + if (HmfsZoned::GetInstance().HmfsGetZoneBlocks(device.get())) { + HMFS_ERROR("Failed to get number of blocks per zone"); + return -1; + } + + if (!HmfsCommon::GetInstance().IsPowerOf2(device->zoneSize)) { + HMFS_INFO("zoned: zone size %" PRIu64 " (not a power of 2)", device->zoneSize); + } + + /* + * Check zone configuration: for the first disk of a + * multi-device volume, conventional zones are needed. + */ + if (HmfsZoned::GetInstance().HmfsCheckZones(device.get())) { + HMFS_ERROR("Failed to check zone configuration"); + return -1; + } + HMFS_INFO("Host-%s zoned block device:", (device->zonedModel == HMFS_ZONED_HA) ? "aware" : "managed"); + HMFS_INFO(" %u zones, %" PRIu64 " zone size(bytes), %u randomly writeable zones", + device->nrZones, device->zoneSize, device->nrRndZones); + HMFS_INFO(" %zu blocks per zone", device->zoneBlocks); + } + + /* adjust wantedSectorCount */ + if (cmdPara_.wantedSectorCount != std::numeric_limits::max()) { + HMFS_INFO("wanted sector count = %" PRIu64 ", wanted sector size = %" PRIu64 ".", + cmdPara_.wantedSectorCount, cmdPara_.wantedSectorSize); + if (cmdPara_.wantedSectorSize == std::numeric_limits::max()) { + cmdPara_.wantedSectorSize = device->sectorSize; + } else if (device->sectorSize != cmdPara_.wantedSectorSize) { + cmdPara_.wantedSectorCount *= cmdPara_.wantedSectorSize; + cmdPara_.wantedSectorCount /= device->sectorSize; + } + } + + totalSectors_ += device->sectorCount; + devices_.emplace_back(std::move(device)); + return 0; +} + +uint32_t DeviceManager::GetDeviceCount() +{ + return devices_.size(); +} + +DeviceInfo* DeviceManager::GetDeviceInfo(uint32_t deviceId) +{ + if (deviceId >= devices_.size()) { + return nullptr; + } + return devices_[deviceId].get(); +} + +uint64_t DeviceManager::GetTotalSectors() +{ + return totalSectors_; +} + +bool DeviceManager::CheckDeviceFormated() +{ +#ifdef HAVE_LIBBLKID + for (auto& device : devices_) { + if (IsFileSystemExist(device.get())) { + return true; + } + } +#endif + return false; +} + +#ifdef HAVE_LIBBLKID +bool DeviceManager::IsFileSystemExist(DeviceInfo* deviceInfo) +{ + blkid_probe probe = blkid_new_probe_from_filename(deviceInfo->path.c_str()); + if (probe == nullptr) { + HMFS_INFO("failed to probe device %s, cannot detect existing filesystem.", deviceInfo->path.c_str()); + return true; + } + + int32_t ret = blkid_probe_enable_partitions(probe, 1); + if (ret < 0) { + blkid_free_probe(probe); + HMFS_INFO("failed to probe device %s, cannot detect existing filesystem.", deviceInfo->path.c_str()); + return true; + } + + ret = blkid_do_fullprobe(probe); + if (ret < 0) { + blkid_free_probe(probe); + HMFS_INFO("failed to probe device %s, cannot detect existing filesystem.", deviceInfo->path.c_str()); + return true; + } else if (ret > 0) { + blkid_free_probe(probe); + return false; + } + + const char* type; + if (!blkid_probe_lookup_value(probe, "TYPE", &type, NULL)) { + HMFS_INFO("%s appears to contain an existing filesystem (%s).", deviceInfo->path.c_str(), type); + } else if (!blkid_probe_lookup_value(probe, "PTTYPE", &type, NULL)) { + HMFS_INFO("%s appears to contain an partition table (%s).", deviceInfo->path.c_str(), type); + } else { + HMFS_INFO("%s appears to contain something weird according to blkid.", deviceInfo->path.c_str()); + } + + blkid_free_probe(probe); + return true; +} +#endif + +int32_t DeviceManager::TrimDevices() +{ + for (auto &device : devices_) { + if (TrimDevice(device.get())) { + HMFS_ERROR("Failed to trim whole device."); + return -1; + } + } + + return 0; +} + +int32_t DeviceManager::TrimDevice(DeviceInfo *deviceInfo) +{ + int32_t fd = deviceInfo->fd; + struct stat statInfo; + if (fstat(fd, &statInfo) < 0 ) { + HMFS_ERROR("Failed to get the device stat."); + return -1; + } + + uint64_t range[2] = {0, deviceInfo->sectorCount * deviceInfo->sectorSize}; + + #if defined(WITH_BLKDISCARD) && defined(BLKDISCARD) + HMFS_INFO("[%s] Discarding device", deviceInfo->path.c_str()); + if (S_ISREG(statInfo.st_mode)) { + #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) + HMFS_INFO("range[1] = %d", range[1]); + if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, range[0], range[1]) < 0) { + HMFS_INFO("fallocate(PUNCH_HOLE|KEEP_SIZE) is failed"); + } + #endif + return 0; + } else if (S_ISBLK(statInfo.st_mode)) { + if (deviceInfo->zonedModel != HMFS_ZONED_NONE) { + return HmfsZoned::GetInstance().HmfsResetZones(deviceInfo); + } + #ifdef BLKSECDISCARD + if (ioctl(fd, BLKSECDISCARD, &range) < 0) { + HMFS_INFO("This device doesn't support BLKSECDISCARD"); + } else { + HMFS_INFO("Secure Discarded %lu MB", (unsigned long)statInfo.st_size >> 20); + return 0; + } + #endif + if (ioctl(fd, BLKDISCARD, &range) < 0) { + HMFS_INFO("This device doesn't support BLKDISCARD"); + } else { + HMFS_INFO("Discarded %" PRIu64 " MB", range[1] >> 20); + } + } else { + return -1; + } + #endif + return 0; +} + + + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/common/device_manager.h b/tools/hmfs-tools/tools/common/device_manager.h new file mode 100755 index 0000000..49d747a --- /dev/null +++ b/tools/hmfs-tools/tools/common/device_manager.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEVICE_MANAGER_H +#define DEVICE_MANAGER_H + +#include +#include +#include + +#include "hmfs_data.h" +#include "hmfs_command.h" +#include "config.h" + +namespace OHOS { +namespace Hmfs { + +struct DeviceInfo { + std::string path; + int32_t fd = -1; + uint32_t sectorSize = DEFAULT_SECTOR_SIZE; + uint64_t sectorCount; + uint64_t startBlkId; + uint64_t endBlkId; + uint32_t segmentCount; + bool isMetaDevice = false; + + /* to handle zone block devices */ + int32_t zonedModel; + uint32_t nrZones; + uint32_t nrRndZones; + size_t zoneBlocks; + uint64_t zoneSize; + std::unique_ptr zoneCapBlocks = nullptr; +}; + +class DeviceManager{ +public: + ~DeviceManager() = default; + DeviceManager(CmdConfig& cmdPara) : cmdPara_(cmdPara) {}; + + static void CreateInstance(CmdConfig& cmdPara); + static DeviceManager& GetInstance(); + int32_t CreateDeviceInfo(std::string& path, bool isMetaDevice); + DeviceInfo* GetDeviceInfo(uint32_t deviceId); + uint32_t GetDeviceCount(); + bool CheckDeviceFormated(); + int32_t TrimDevices(); + uint64_t GetTotalSectors(); + +private: +#ifdef HAVE_LIBBLKID + bool IsFileSystemExist(DeviceInfo* deviceInfo); +#endif + int32_t TrimDevice(DeviceInfo *deviceInfo); + + static std::unique_ptr instance_; + std::vector> devices_; + uint64_t totalSectors_ = 0; + CmdConfig& cmdPara_; +}; + + + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/common/hmfs_command.cpp b/tools/hmfs-tools/tools/common/hmfs_command.cpp new file mode 100755 index 0000000..43aac46 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_command.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "hmfs_command.h" + +#include +#include +#include +#include +#include + +#include "hmfs_utils.h" +#include "hmfs_data.h" +#include "hmfs_common.h" +#include "hmfs_encoding.h" + +namespace OHOS { +namespace Hmfs { + +CmdParser* CmdParser::instance_ = nullptr; +void CmdParser::RegCmdOption(char option, bool hasPara, HandleArgValue handle) +{ + optionString_ += option; + if (hasPara) { + optionString_ += ':'; + } + handles_.emplace(option, handle); +} + +int32_t CmdParser::ParseOption(int32_t argc, char *argv[]) +{ + const struct option longOptions[] = { + {"help", no_argument, nullptr, 'h'}, + {nullptr, 0, nullptr, 0} + }; + + int32_t ret; + while ((ret = getopt_long(argc, argv, optionString_.c_str(), longOptions, nullptr)) != EOF) { + char option = static_cast(ret); + std::string argValue = (optarg != nullptr) ? optarg : ""; + ArgParseResult result = ProcessOption(option, argValue); + if (result != ArgParseResult::OK) { + if (result != ArgParseResult::FINISH) { + ShowCmdUsage(); + } + return -1; + } + } + + return 0; +} + +ArgParseResult CmdParser::ProcessOption(char option, const std::string &argValue) +{ + auto handler = handles_.find(option); + if (handler == handles_.end()) { + HMFS_ERROR("Unknown option '%c'", option); + return ArgParseResult::ERROR; + } + return handler->second(argValue); +} + +ArgParseResult CmdParser::ProcessCasefolding(const std::string& argValue) +{ + std::stringstream input(argValue); + std::string encodingStr; + std::getline(input, encodingStr, ':'); + if (EncodingStrToValue(encodingStr, cfgPara_.sEncoding)) { + HMFS_ERROR("Unknown encoding : %s", encodingStr.c_str()); + return ArgParseResult::ERROR; + } + + std::string flagStr; + if (std::getline(input, flagStr, ':')) { + if (EncodingFlagStrToValue(flagStr, cfgPara_.sEncodingFlags)) { + HMFS_ERROR("Unknown flag : %s", flagStr.c_str()); + return ArgParseResult::ERROR; + } + } else { + cfgPara_.sEncodingFlags = GetDefaultEncodingFlag(cfgPara_.sEncoding); + } + + cfgPara_.features |= HMFS_FEATURE_CASEFOLD; + return ArgParseResult::OK; +} + +ArgParseResult CmdParser::ProcessDebugLevel(const std::string& argValue) +{ + cfgPara_.debugLevel = atoi(argValue.c_str()); + return ArgParseResult::OK; +} + +ArgParseResult CmdParser::ProcessFeatures(const std::string& argValue) +{ + std::unordered_map featureTable = { + {"encrypt", HMFS_FEATURE_ENCRYPT}, + {"extra_attr", HMFS_FEATURE_EXTRA_ATTR}, + {"project_quota", HMFS_FEATURE_PRJQUOTA}, + {"inode_checksum", HMFS_FEATURE_INODE_CHKSUM}, + {"flexible_inline_xattr", HMFS_FEATURE_FLEXIBLE_INLINE_XATTR}, + {"quota", HMFS_FEATURE_QUOTA_INO}, + {"inode_crtime", HMFS_FEATURE_INODE_CRTIME}, + {"lost_found", HMFS_FEATURE_LOST_FOUND}, + {"verity", HMFS_FEATURE_VERITY}, + {"sb_checksum", HMFS_FEATURE_SB_CHKSUM}, + {"casefold", HMFS_FEATURE_CASEFOLD}, + {"compression", HMFS_FEATURE_COMPRESSION}, + {"ro", HMFS_FEATURE_RO}, + }; + + std::vector featureList = HmfsCommon::GetInstance().SplitStringList(argValue, ','); + for (auto& feature : featureList) { + HMFS_DEBUG("-O featureTrim: %s", feature.c_str()); + auto it = featureTable.find(feature); + if (it == featureTable.end()) { + HMFS_ERROR("Wrong features: %s", feature.c_str()); + return ArgParseResult::ERROR; + } + cfgPara_.features |= it->second; + } + return ArgParseResult::OK; +} + +ArgParseResult CmdParser::ProcessOverProvision(const std::string& argValue) +{ + cfgPara_.overProvision = atof(argValue.c_str()); + return ArgParseResult::OK; +} + +ArgParseResult CmdParser::ProcessLargeNatBitmap(const std::string& argValue) +{ + (void)argValue; + cfgPara_.largeNatBitmap = 1; + return ArgParseResult::OK; +} + + +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_command.h b/tools/hmfs-tools/tools/common/hmfs_command.h new file mode 100755 index 0000000..8899215 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_command.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_COMMAND_H +#define HMFS_COMMAND_H + +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace Hmfs { + +// enum class CmdFunc { +// MKFS, +// RESIZE, +// }; + +typedef struct CmdConfig { + int func; + bool heapBasedAllocation = false; + bool forceOverwrite = false; + bool zonedMode = false; + std::vector deviceList; + int32_t debugLevel = 0; + uint64_t wantedSectorSize = std::numeric_limits::max(); + uint64_t wantedSectorCount = std::numeric_limits::max(); + uint32_t features = 0; + uint32_t segsPerSection = 1; + uint32_t sectionsPerZone = 1; + double overProvision = 0.0; + std::vector coldExtList; + std::vector hotExtList; + std::string volume; + int32_t force = 0; + int32_t safeResize = 0; + int32_t largeNatBitmap = 0; + uint16_t sEncoding = 0; + uint16_t sEncodingFlags = 0; + double newOverprovision; + uint32_t rootUid = getuid(); + uint32_t rootGid = getgid(); + bool sparseMode = false; + uint64_t deviceSize = 0; + uint64_t targetSectors = 0; + uint32_t quotaBits; + bool trim = true; + uint32_t defaultOptionSet = 0; + bool fakeSeed = false; + uint32_t timeStamp = std::numeric_limits::max(); + std::string uuid; + +} CmdConfig; + +enum class ArgParseResult { + OK = 0, + FINISH, + ERROR, +}; + +class CmdParser { +public: + CmdParser(CmdConfig& cmdPara) : cfgPara_(cmdPara) {} + ~CmdParser() = default; + int32_t ParseOption(int32_t argc, char *argv[]); + virtual void ShowCmdUsage() = 0; + using HandleArgValue = std::function; + void RegCmdOption(char option, bool hasPara, HandleArgValue handle); + ArgParseResult ProcessOption(char option, const std::string &argValue); + ArgParseResult ProcessCasefolding(const std::string& argValue); + ArgParseResult ProcessDebugLevel(const std::string& argValue); + ArgParseResult ProcessFeatures(const std::string& argValue); + ArgParseResult ProcessOverProvision(const std::string& argValue); + ArgParseResult ProcessLargeNatBitmap(const std::string& argValue); + + CmdConfig& GetCmdConfig() + { + return cfgPara_; + } + static CmdParser* GetSingleton() + { + return instance_; + } + +protected: + CmdConfig& cfgPara_; + static void RegisterSingleton(CmdParser* instance) + { + instance_ = instance; + } + +private: + std::map handles_; + std::string optionString_; + static CmdParser* instance_; +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/common/hmfs_common.cpp b/tools/hmfs-tools/tools/common/hmfs_common.cpp new file mode 100755 index 0000000..31c894e --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_common.cpp @@ -0,0 +1,920 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmfs_common.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#if defined(__APPLE__) +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif +#ifdef HAVE_SCSI_SG_H +#include +#endif +#ifdef HAVE_LINUX_HDREG_H +#include +#endif +#ifdef HAVE_LINUX_LIMITS_H +#include +#endif +#include +#include + +#ifdef _WIN32 +#include "windows.h" +#include "winioctl.h" +#endif + +#include "securec.h" +#include "hmfs_data.h" +#include "hmfs_io.h" +#include "hmfs_encoding.h" +#include "hmfs_zoned.h" +#include "hmfs_utils.h" + +namespace OHOS::Hmfs { +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#if defined(__APPLE__) +#define BLKGETSIZE DKIOCGETBLOCKCOUNT +#define BLKSSZGET DKIOCGETBLOCKCOUNT +#endif /* APPLE_DARWIN */ + + +#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) +#define BLKGETSIZE _IO(0x12,96) +#endif + +#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) +#define BLKGETSIZE64 _IOR(0x12,114, size_t) +#endif + +#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET) +#define BLKSSZGET _IO(0x12,104) +#endif + +/* SCSI command for standard inquiry*/ +#define MODELINQUIRY 0x12,0x00,0x00,0x00,0x4A,0x00 + +#ifndef _WIN32 /* O_BINARY is windows-specific flag */ +#define O_BINARY 0 +#else +/* On Windows, wchar_t is 8 bit sized and it causes compilation errors. */ +#define wchar_t int +#endif + +#ifdef _WIN32 +#if (_WIN32_WINNT >= 0x0500) +#define HAVE_GET_FILE_SIZE_EX 1 +#endif +#endif + +extern hmfs_configuration g_hmfsConfig; +#define _FILE_OFFSET_BITS 64 + +/* Copied from linux/lib/find_bit.c */ +#define BITMAP_FIRST_BYTE_MASK(start) (0xff << ((start) & (BITS_PER_BYTE - 1))) + +/* + * CRC32 + */ +#define CRCPOLY_LE 0xedb88320 +/* + * f2fs bit operations + */ +static const int bitsInByte[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +std::unique_ptr HmfsCommon::instance_ = nullptr; +void HmfsCommon::CreateInstance(CmdConfig &cfgPara) +{ + if (instance_ == nullptr) { + instance_ = std::make_unique(cfgPara); + } +} + +HmfsCommon& HmfsCommon::GetInstance() +{ + return *instance_.get(); +} + +int HmfsCommon::LogBase2(uint32_t num) +{ + int ret = 0; + if (num <= 0 || (num & (num - 1)) != 0) { + return -1; + } + + while (num >>= 1) { + ret++; + } + return ret; +} + +int HmfsCommon::GetBitsInByte(unsigned char n) +{ + return bitsInByte[n]; +} + +int HmfsCommon::TestAndSetBitLe(uint32_t nr, uint8_t *addr) +{ + addr += nr >> 3; + int mask = 1 << ((nr & 0x07)); + int retval = mask & *addr; + *addr |= mask; + return retval; +} + +int HmfsCommon::TestAndClearBitLe(uint32_t nr, uint8_t *addr) +{ + addr += nr >> 3; + int mask = 1 << ((nr & 0x07)); + int retval = mask & *addr; + *addr &= ~mask; + return retval; +} + +int HmfsCommon::TestBitLe(uint32_t nr, const uint8_t *addr) +{ + return ((1 << (nr & 7)) & (addr[nr >> 3])); +} + +int HmfsCommon::HmfsTestBit(unsigned int nr, const char *p) +{ + char *addr = (char *)p; + addr += (nr >> 3); + int mask = 1 << (7 - (nr & 0x07)); + return (mask & *addr) != 0; +} + +int HmfsCommon::HmfsSetBit(unsigned int nr, char *addr) +{ + addr += (nr >> 3); + int mask = 1 << (7 - (nr & 0x07)); + int ret = mask & *addr; + *addr |= mask; + return ret; +} + +int HmfsCommon::HmfsClearBit(unsigned int nr, char *addr) +{ + addr += (nr >> 3); + int mask = 1 << (7 - (nr & 0x07)); + int ret = mask & *addr; + *addr &= ~mask; + return ret; +} + +uint64_t HmfsCommon::Ffs(uint8_t word) +{ + int num = 0; + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) { + num += 1; + } + return num; +} + +uint64_t HmfsCommon::FindNextBitLeFunc(const uint8_t *addr, uint64_t nbits, uint64_t start, char invert) +{ + if (nbits == 0 || start >= nbits) { + return nbits; + } + + uint8_t tmp = addr[start / BITS_PER_BYTE] ^ invert; + + /* Handle 1st word. */ + tmp &= BITMAP_FIRST_BYTE_MASK(start); + start = round_down(start, BITS_PER_BYTE); + + while (tmp == 0) { + start += BITS_PER_BYTE; + if (start >= nbits) { + return nbits; + } + + tmp = addr[start / BITS_PER_BYTE] ^ invert; + } + + return std::min(start + Ffs(tmp), nbits); +} + +uint64_t HmfsCommon::FindNextBitLe(const uint8_t *addr, uint64_t size, uint64_t offset) +{ + return FindNextBitLeFunc(addr, size, offset, 0); +} + +uint64_t HmfsCommon::FindNextZeroBitL(const uint8_t *addr, uint64_t size, uint64_t offset) +{ + return FindNextBitLeFunc(addr, size, offset, 0xff); +} + +bool HmfsCommon::HmfsHasExtraIsize(HmfsInode *inode) +{ + return (inode->iInline & HMFS_EXTRA_ATTR); +} + +int HmfsCommon::GetExtraIsize(HmfsInode *inode) +{ + if (HmfsHasExtraIsize(inode)) { + return LE16_TO_NATIVE(inode->iExtraIsize) / sizeof(uint32_t); + } + return 0; +} + +int HmfsCommon::GetInlineXattrAddrs(HmfsInode *inode) +{ + if (cfgPara_.features & HMFS_FEATURE_FLEXIBLE_INLINE_XATTR) { + return LE16_TO_NATIVE(inode->iInlineXattrSize); + } else if (inode->iInline & HMFS_INLINE_XATTR || inode->iInline & HMFS_INLINE_DENTRY) { + return DEFAULT_INLINE_XATTR_ADDRS; + } else { + return 0; + } +} + +unsigned int HmfsCommon::AddrsPerInode(HmfsInode *i) +{ + unsigned int addrs = CUR_ADDRS_PER_INODE(i) - GetInlineXattrAddrs(i); + + if (!LINUX_S_ISREG(LE16_TO_NATIVE(i->iMode)) || + !(LE32_TO_NATIVE(i->iFlags) & HMFS_COMPR_FL)) { + return addrs; + } + return ALIGN_DOWN(addrs, 1 << i->iLogClusterSize); +} + +unsigned int HmfsCommon::AddrsPerBlock(HmfsInode *i) +{ + if (!LINUX_S_ISREG(LE16_TO_NATIVE(i->iMode)) || + !(LE32_TO_NATIVE(i->iFlags) & HMFS_COMPR_FL)) { + return DEF_ADDRS_PER_BLOCK; + } + return ALIGN_DOWN(DEF_ADDRS_PER_BLOCK, 1 << i->iLogClusterSize); +} + +unsigned int HmfsCommon::HmfsMaxFileOffset(HmfsInode *i) +{ + if (!LINUX_S_ISREG(LE16_TO_NATIVE(i->iMode)) || + !(LE32_TO_NATIVE(i->iFlags) & HMFS_COMPR_FL)) { + return LE64_TO_NATIVE(i->iSize); + } + return ALIGN_UP(LE64_TO_NATIVE(i->iSize), 1 << i->iLogClusterSize); +} + +uint32_t HmfsCommon::HmfsCalCrc32(uint32_t crc, void *buf, int len) +{ + unsigned char *p = (unsigned char *)buf; + while (len--) { + crc ^= *p++; + for (int i = 0; i < 8; i++) { + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); + } + } + return crc; +} + +int HmfsCommon::HmfsCrcValid(uint32_t blkCrc, void *buf, int len) +{ + uint32_t calCrc = HmfsCalCrc32(HMFS_SUPER_MAGIC, buf, len); + if (calCrc != blkCrc) { + DBG(0,"CRC validation failed: calCrc = %u, blkCrc = %u buff_size = 0x%x\n", + calCrc, blkCrc, len); + return -1; + } + return 0; +} + +uint32_t HmfsCommon::HmfsInodeChksum(NodeData *node, uint32_t crcSeed) +{ + HmfsInode *ri = &node->i; + uint32_t ino = node->footer.ino; + uint32_t gen = ri->iGeneration; + uint32_t dummyCs = 0; + unsigned int offset = offsetof(HmfsInode, iInodeChecksum); + unsigned int csSize = sizeof(dummyCs); + + uint32_t chksum = HmfsCalCrc32(crcSeed, (uint8_t *)&ino, sizeof(ino)); + uint32_t chksumSeed = HmfsCalCrc32(chksum, (uint8_t *)&gen, sizeof(gen)); + + chksum = HmfsCalCrc32(chksumSeed, (uint8_t *)ri, offset); + chksum = HmfsCalCrc32(chksum, (uint8_t *)&dummyCs, csSize); + offset += csSize; + chksum = HmfsCalCrc32(chksum, (uint8_t *)ri + offset, HMFS_BLKSIZE - offset); + return chksum; +} + +uint32_t HmfsCommon::HmfsCheckpointChksum(CheckPointData *cp) +{ + unsigned int chksumOffset = LE32_TO_NATIVE(cp->checksumOffset); + + uint32_t chksum = HmfsCalCrc32(HMFS_SUPER_MAGIC, cp, chksumOffset); + if (chksumOffset < CP_CHKSUM_OFFSET) { + chksumOffset += sizeof(chksum); + chksum = HmfsCalCrc32(chksum, (uint8_t *)cp + chksumOffset, HMFS_BLKSIZE - chksumOffset); + } + return chksum; +} + +unsigned int HmfsCommon::CalcExtraIsize(void) +{ + unsigned int size = offsetof(HmfsInode, iProjid); + if (cfgPara_.features & HMFS_FEATURE_FLEXIBLE_INLINE_XATTR) { + size = offsetof(HmfsInode, iProjid); + } + if (cfgPara_.features & HMFS_FEATURE_PRJQUOTA) { + size = offsetof(HmfsInode, iInodeChecksum); + } + if (cfgPara_.features & HMFS_FEATURE_INODE_CHKSUM) { + size = offsetof(HmfsInode, iCrtime); + } + if (cfgPara_.features & HMFS_FEATURE_INODE_CRTIME) { + size = offsetof(HmfsInode, iComprBlocks); + } + if (cfgPara_.features & HMFS_FEATURE_COMPRESSION) { + size = offsetof(HmfsInode, iExtraEnd); + } + return size - F2FS_EXTRA_ISIZE_OFFSET; +} + +void HmfsCommon::InitQfInode(NodeData *rawNode, uint32_t inodeId, time_t mtime) +{ + SetLeValue(rawNode->footer.nid, inodeId); + rawNode->footer.ino = rawNode->footer.nid; + rawNode->footer.cpVer = NATIVE_TO_LE64(1); + rawNode->i.iMode = NATIVE_TO_LE16(0x8180); + rawNode->i.iLinks = NATIVE_TO_LE32(1); + rawNode->i.iUid = NATIVE_TO_LE32(cfgPara_.rootUid); + rawNode->i.iGid = NATIVE_TO_LE32(cfgPara_.rootGid); + + rawNode->i.iSize = NATIVE_TO_LE64(1024 * 6); + rawNode->i.iBlocks = NATIVE_TO_LE64(1); + + rawNode->i.iAtime = NATIVE_TO_LE32(mtime); + rawNode->i.iAtimeNsec = 0; + rawNode->i.iCtime = NATIVE_TO_LE32(mtime); + rawNode->i.iCtimeNsec = 0; + rawNode->i.iMtime = NATIVE_TO_LE32(mtime); + rawNode->i.iMtimeNsec = 0; + rawNode->i.iGeneration = 0; + rawNode->i.iXattrNid = 0; + rawNode->i.iFlags = FS_IMMUTABLE_FL; + rawNode->i.iCurrentDepth = NATIVE_TO_LE32(0); + rawNode->i.iDirLevel = 0; + + if (cfgPara_.features & HMFS_FEATURE_EXTRA_ATTR) { + rawNode->i.iInline = HMFS_EXTRA_ATTR; + rawNode->i.iExtraIsize = NATIVE_TO_LE16(CalcExtraIsize()); + } + + if (cfgPara_.features & HMFS_FEATURE_PRJQUOTA) { + rawNode->i.iProjid = NATIVE_TO_LE32(DEFAULT_PROJECT_ID); + } + + rawNode->i.iExt.fofs = 0; + rawNode->i.iExt.blkAddr = 0; + rawNode->i.iExt.len = 0; +} + +int HmfsCommon::WriteInode(NodeData *inode, uint64_t blkaddr, uint32_t crcSeed) +{ + if (cfgPara_.features & HMFS_FEATURE_INODE_CHKSUM) { + inode->i.iInodeChecksum = NATIVE_TO_LE32(HmfsInodeChksum(inode, crcSeed)); + } + return HmfsIo::GetInstance().DevWriteBlock(inode, blkaddr); +} + +/* + * try to identify the root device + */ +std::unique_ptr HmfsCommon::GetRootdev() +{ +#if defined(_WIN32) || defined(WITH_ANDROID) + return nullptr; +#else + struct stat sb; + char buf[PATH_MAX + 1]; + + if (stat("/", &sb) == -1) { + return nullptr; + } + + snprintf(buf, PATH_MAX, "/sys/dev/block/%u:%u/uevent", major(sb.st_dev), minor(sb.st_dev)); + + int fd = open(buf, O_RDONLY); + if (fd < 0) { + return nullptr; + } + + int ret = lseek(fd, (off_t)0, SEEK_END); + (void)lseek(fd, (off_t)0, SEEK_SET); + + if (ret == -1) { + close(fd); + return nullptr; + } + auto ueventPtr = std::make_unique(ret + 1); + char *uevent = ueventPtr.get(); + if (uevent == nullptr) { + close(fd); + return nullptr; + } + + uevent[ret] = '\0'; + + ret = read(fd, uevent, ret); + close(fd); + + char *ptr = strstr(uevent, "DEVNAME"); + if (ptr == nullptr) { + return nullptr; + } + + ret = sscanf(ptr, "DEVNAME=%s\n", buf); + if (strlen(buf) == 0) { + return nullptr; + } + + ret = strlen(buf) + 5; + auto rootdevPtr = std::make_unique(ret + 1); + char *rootdev = rootdevPtr.get(); + if (!rootdevPtr) { + return nullptr; + } + rootdev[ret] = '\0'; + + snprintf(rootdev, ret + 1, "/dev/%s", buf); + return rootdevPtr; +#endif +} + +/* + * device information + */ +void HmfsCommon::HmfsInitConfiguration(void) +{ + memset(&g_hmfsConfig, 0, sizeof(hmfs_configuration)); + g_hmfsConfig.ndevs = 1; + g_hmfsConfig.sectorsPerBlk = DEFAULT_SECTORS_PER_BLK; + g_hmfsConfig.blksPerSeg = DEFAULT_BLOCKS_PER_SEGMENT; + g_hmfsConfig.wantedTotalSectors = -1; + g_hmfsConfig.wantedSectorSize = -1; +#ifndef WITH_ANDROID + g_hmfsConfig.preserveLimits = 1; + g_hmfsConfig.noKernelCheck = 1; +#else + g_hmfsConfig.noKernelCheck = 0; +#endif + + for (int i = 0; i < MAX_DEVICE_COUNT; i++) { + g_hmfsConfig.devices[i].fd = -1; + g_hmfsConfig.devices[i].sectorSize = DEFAULT_SECTOR_SIZE; + g_hmfsConfig.devices[i].endBlkaddr = -1; + g_hmfsConfig.devices[i].zonedModel = HMFS_ZONED_NONE; + } + + /* calculated by overprovision ratio */ + g_hmfsConfig.segsPerSec = 1; + g_hmfsConfig.secsPerZone = 1; + g_hmfsConfig.segsPerZone = 1; + g_hmfsConfig.volLabel = nullptr; + g_hmfsConfig.trim = 1; + g_hmfsConfig.kd = -1; + g_hmfsConfig.fixedTime = -1; + g_hmfsConfig.encoding = 0; + g_hmfsConfig.encodingFlags = 0; + + /* default root owner */ + g_hmfsConfig.rootUid = getuid(); + g_hmfsConfig.rootGid = getgid(); +} + +int HmfsCommon::HmfsDevIsWritable(void) +{ + return (g_hmfsConfig.ro == 0) || (g_hmfsConfig.force > 0); +} + +#ifdef HAVE_SETMNTENT +int HmfsCommon::IsMounted(const char *mpt, const char *device) +{ + FILE *file = nullptr; + struct mntent *mnt = nullptr; + + file = setmntent(mpt, "r"); + if (file == nullptr) { + return 0; + } + + while ((mnt = getmntent(file)) != nullptr) { + if (strcmp(device, mnt->mnt_fsname) == 0) { +#ifdef MNTOPT_RO + if (hasmntopt(mnt, MNTOPT_RO)) { + g_hmfsConfig.ro = 1; + } +#endif + break; + } + } + endmntent(file); + return mnt ? 1 : 0; +} +#endif + +int HmfsCommon::HmfsDevIsUmounted(char *path) +{ +#ifdef _WIN32 + return 0; +#else + int isRootdev = 0; + int ret = 0; + auto rootDevName = GetRootdev(); + if (rootDevName) { + if (strcmp(path, rootDevName.get()) == 0) { + isRootdev = 1; + } + } + + /* + * try with /proc/mounts fist to detect RDONLY. + * f2fs_stop_checkpoint makes RO in /proc/mounts while RW in /etc/mtab. + */ +#ifdef __linux__ + ret = IsMounted("/proc/mounts", path); + if (ret) { + HMFS_ERROR("Info: Mounted device!\n"); + return -1; + } +#endif +#if defined(MOUNTED) || defined(_PATH_MOUNTED) +#ifndef MOUNTED +#define MOUNTED _PATH_MOUNTED +#endif + ret = IsMounted(MOUNTED, path); + if (ret) { + HMFS_INFO("Info: Mounted device!\n"); + return -1; + } +#endif + /* + * If we are supposed to operate on the root device, then + * also check the mounts for '/dev/root', which sometimes + * functions as an alias for the root device. + */ + if (isRootdev) { +#ifdef __linux__ + ret = IsMounted("/proc/mounts", "/dev/root"); + if (ret) { + HMFS_INFO("Info: Mounted device!\n"); + return -1; + } +#endif + } + /* + * If f2fs is umounted with -l, the process can still use + * the file system. In this case, we should not format. + */ + auto statBuffPtr = std::unique_ptr(); + struct stat *statBuff = statBuffPtr.get(); + if (!statBuffPtr) { + return -1; + } + + if (stat(path, statBuff) == 0 && S_ISBLK(statBuff->st_mode)) { + int fd = open(path, O_RDONLY | O_EXCL); + if (fd >= 0) { + close(fd); + } else if (errno == EBUSY) { + HMFS_ERROR("\tError: In use by the system!\n"); + return -1; + } + } + return ret; +#endif +} + +int HmfsCommon::HmfsDevsAreUmounted(void) +{ + for (int i = 0; i < g_hmfsConfig.ndevs; i++) { + if (HmfsDevIsUmounted((char *)g_hmfsConfig.devices[i].path)) { + return -1; + } + } + return 0; +} + +int32_t HmfsCommon::ReadKernelVersion(const std::string& path, char* buf, size_t len) +{ + if (cfgPara_.sparseMode) { + return 0; + } + + std::ifstream file(path, std::ifstream::in); + if (!file) { + HMFS_INFO("%s not exist.", path.c_str()); + return -1; + } + + file.read(buf, len); + for (size_t i = 0; i < len; i++) { + if (buf[i] == '\n') { + buf[i] = 0; + break; + } + } + + return 0; +} + +int32_t HmfsCommon::GetKernelVersion(char *version, size_t len) +{ + if (len <= VERSION_TIMESTAMP_LEN) { + return -1; + } + size_t copyLen = len - VERSION_TIMESTAMP_LEN; + + if (ReadKernelVersion("/proc/version", version, len) == 0) { + return 0; + } + +#ifdef HAVE_SYS_UTSNAME_H + struct utsname buf; + if (uname(&buf)) { + HMFS_ERROR("Failed to get uname."); + return -1; + } +#if defined(WITH_KERNEL_VERSION) + snprintf_s(version, len, copyLen, "%s %s", buf.release, buf.version); +#else + snprintf_s(version, len, copyLen, "%s", buf.release); +#endif +#endif + return 0; +} + +void HmfsCommon::GetKernelVersion(uint8_t *version) +{ + int i; + for (i = 0; i < VERSION_STRING_LEN; i++) { + if (version[i] == '\n') { + break; + } + } + memset(version + i, 0, VERSION_LEN + 1 - i); +} + +void HmfsCommon::GetKernelUnameVersion(uint8_t *version) +{ +#ifdef HAVE_SYS_UTSNAME_H + struct utsname buf; + memset(version, 0, VERSION_LEN); + if (uname(&buf)) { + return; + } +#if defined(WITH_KERNEL_VERSION) + snprintf((char *)version, VERSION_STRING_LEN, "%s %s", buf.release, buf.version); +#else + snprintf((char *)version, VERSION_STRING_LEN, "%s", buf.release); +#endif +#else + memset(version, 0, VERSION_LEN); +#endif +} + +bool HmfsCommon::KernelVersionOver(uint32_t minMajor, uint32_t minMinor) +{ +#ifdef HAVE_SYS_UTSNAME_H + uint32_t major, minor; + struct utsname uts; + + if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) { + return false; + } + + if (major > minMajor) { + return true; + } + + if (major == minMajor && minor >= minMinor) { + return true; + } +#endif + return false; +} + + +#ifdef __linux__ +int HmfsCommon::IsPowerOf2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} +#endif + + +std::vector HmfsCommon::SplitStringList(const std::string& srcString, char delimiter) +{ + std::vector list; + std::stringstream strStream(srcString); + std::string subString; + while (std::getline(strStream, subString, delimiter)) { + size_t start = subString.find_first_not_of(" "); + if (start == std::string::npos) { + continue; + } + size_t end = subString.find_last_not_of(" "); + list.emplace_back(subString.substr(start, end - start + 1)); + } + return list; +} + +double HmfsCommon::GetBestOverProvision(SuperBlockData* superBlock) +{ + double reserved, ovp, candidate, end, diff, space; + double maxOvp = 0, maxSpace = 0; + uint32_t usableSegs = HmfsZoned::GetInstance().HmfsGetUsableSegments(superBlock); + + if (GetLeValue(superBlock->segmentCountInMain) < 256) { + candidate = 10; + end = 95; + diff = 5; + } else { + candidate = 0.01; + end = 10; + diff = 0.01; + } + + for (; candidate <= end; candidate += diff) { + reserved = (2 * (100 / candidate + 1) + 6) * + round_up(usableSegs, GetLeValue(superBlock->sectionCount)); + ovp = (usableSegs - reserved) * candidate / 100; + space = usableSegs - reserved - ovp; + if (maxSpace < space) { + maxSpace = space; + maxOvp = candidate; + } + } + return maxOvp; +} + + +#define DELTA 0x9E3779B9 +static void TeaTransform(unsigned int buf[4], unsigned int const in[]) +{ + uint32_t sum = 0; + uint32_t b0 = buf[0], b1 = buf[1]; + uint32_t a = in[0], b = in[1], c = in[2], d = in[3]; + int n = 16; + + do { + sum += DELTA; + b0 += ((b1 << 4) + a) ^ (b1 + sum) ^ ((b1 >> 5) + b); + b1 += ((b0 << 4) + c) ^ (b0 + sum) ^ ((b0 >> 5) + d); + } while (--n); + + buf[0] += b0; + buf[1] += b1; +} + +static void Str2Hashbuf(const unsigned char *msg, int len, unsigned int *buf, int num) +{ + unsigned pad = (uint32_t)len | ((uint32_t)len << 8); + pad |= pad << 16; + + unsigned val = pad; + if (len > num * 4) { + len = num * 4; + } + + for (int i = 0; i < len; i++) { + if ((i % 4) == 0) { + val = pad; + } + val = msg[i] + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; + num--; + } + } + if (--num >= 0) { + *buf++ = val; + } + while (--num >= 0) { + *buf++ = pad; + } +} + +static uint32_t HmfsDentryHash(const unsigned char *name, int len) +{ + uint32_t hash; + uint32_t hmfsHash; + const unsigned char *p; + uint32_t in[8]; + uint32_t buf[4]; + + /* special hash codes for special dentries */ + if ((len <= 2) && (name[0] == '.') && + (name[1] == '.' || name[1] == '\0')) { + return 0; + } + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + p = name; + while (1) { + Str2Hashbuf(p, len, in, 4); + TeaTransform(buf, in); + p += 16; + if (len <= 16) { + break; + } + len -= 16; + } + hash = buf[0]; + + hmfsHash = NATIVE_TO_LE32(hash & ~HMFS_HASH_COL_BIT); + return hmfsHash; +} + +uint32_t HmfsCommon::DentryHash(int encoding, int casefolded, const unsigned char *name, int len) +{ + bool isNeedEncoding = IsNeedEncoding(encoding); + if (!isNeedEncoding) { + return HmfsDentryHash(name, len); + } + + if (len != 0 && casefolded != 0) { + auto buff = std::make_unique(HMFS_NAME_LEN); + if (!buff) { + return -ENOMEM; + } + int dlen = CaseFold(name, len, buff.get(), HMFS_NAME_LEN); + if (dlen <= 0) { + return HmfsDentryHash(name, len); + } + return HmfsDentryHash(buff.get(), dlen); + } + return HmfsDentryHash(name, len); +} + +} \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_common.h b/tools/hmfs-tools/tools/common/hmfs_common.h new file mode 100755 index 0000000..95bb9d2 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_common.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HMFS_COMMON_H__ +#define __HMFS_COMMON_H__ + +#include +#include +#include +#include "hmfs_data.h" +#include "hmfs_define.h" +#include "hmfs_command.h" + +namespace OHOS::Hmfs { + +/* + * For directory operations + */ + +#define LINUX_S_IFMT 00170000 +#define LINUX_S_IFREG 0100000 +#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG) + +#define DEF_DIR_LEVEL 0 + +#define HMFS_COMPR_FL 0x00000004 /* Compress file */ + +/* 200 bytes for inline xattrs by default */ +#define DEFAULT_INLINE_XATTR_ADDRS 50 +#define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ +#define CUR_ADDRS_PER_INODE(inode) (DEF_ADDRS_PER_INODE - GetExtraIsize(inode)) + +#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ + +#define ALIGN_DOWN(addrs, size) (((addrs) / (size)) * (size)) +#define ALIGN_UP(addrs, size) ALIGN_DOWN(((addrs) + (size) - 1), (size)) + +/* + * Copied from include/linux/kernel.h + */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_down(x, y) ((x) & ~__round_mask(x, y)) +#define round_up(x, y) (((x) + (y) - 1) / (y)) + +class HmfsCommon { +public: + HmfsCommon(CmdConfig &cfgPara) : cfgPara_(cfgPara) {}; + + static HmfsCommon& GetInstance(); + static void CreateInstance(CmdConfig &cfgPara); + + int LogBase2(uint32_t num); + int GetBitsInByte(unsigned char n); + int TestAndSetBitLe(uint32_t nr, uint8_t *addr); + int TestAndClearBitLe(uint32_t nr, uint8_t *addr); + int TestBitLe(uint32_t nr, const uint8_t *addr); + + int HmfsTestBit(unsigned int nr, const char *p); + int HmfsSetBit(unsigned int nr, char *addr); + int HmfsClearBit(unsigned int nr, char *addr); + + uint64_t FindNextBitLe(const uint8_t *addr, uint64_t size, uint64_t offset); + uint64_t FindNextZeroBitL(const uint8_t *addr, uint64_t size, uint64_t offset); + + uint32_t DentryHash(int encoding, int casefolded, const unsigned char *name, int len); + + unsigned int AddrsPerInode(HmfsInode *i); + unsigned int AddrsPerBlock(HmfsInode *i); + unsigned int HmfsMaxFileOffset(HmfsInode *i); + + uint32_t HmfsCalCrc32(uint32_t crc, void *buf, int len); + int HmfsCrcValid(uint32_t blk_crc, void *buf, int len); + uint32_t HmfsInodeChksum(NodeData *node, uint32_t crcSeed); + uint32_t HmfsCheckpointChksum(CheckPointData *cp); + int WriteInode(NodeData *inode, uint64_t blkaddr, uint32_t crcSeed); + + void HmfsInitConfiguration(void); + int HmfsDevIsWritable(void); + int HmfsDevIsUmounted(char *path); + int HmfsDevsAreUmounted(void); + void GetKernelVersion(uint8_t *version); + void GetKernelUnameVersion(uint8_t *version); + int32_t GetKernelVersion(char *buf, size_t len); // 替换掉上面两个函数以及HmfsIo::DevReadVersion + bool KernelVersionOver(uint32_t minMajor, uint32_t minMinor); + bool HmfsHasExtraIsize(struct HmfsInode *inode); + int GetInlineXattrAddrs(struct HmfsInode *inode); + + unsigned int CalcExtraIsize(void); + void InitQfInode(NodeData *rawNode, uint32_t inodeId, time_t mtime); + inline uint64_t GetCpCrc(struct CheckPointData *cp) + { + uint64_t cpVersion = GetLeValue(cp->cpVersion); + size_t crcOffset = GetLeValue(cp->checksumOffset); + uint32_t crc = LE32_TO_NATIVE(*(uint32_t *)((unsigned char *)cp + crcOffset)); + cpVersion |= ((uint64_t)crc << 32); + return NATIVE_TO_LE64(cpVersion); + } + int GetExtraIsize(HmfsInode* inode); + int IsPowerOf2(unsigned long n); + double GetBestOverProvision(SuperBlockData* superBlock); + std::vector SplitStringList(const std::string& srcString, char delimiter); + +private: + static std::unique_ptr instance_; + CmdConfig& cfgPara_; + + static uint64_t Ffs(uint8_t word); + static uint64_t FindNextBitLeFunc(const uint8_t *addr, uint64_t nbits, uint64_t start, char invert); + + std::unique_ptr GetRootdev(); +#ifdef HAVE_SETMNTENT + static int IsMounted(const char *mpt, const char *device); +#endif + + int32_t ReadKernelVersion(const std::string& path, char* buf, size_t len); + +}; +} // namespace OHOS::Hmfs +#endif \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_data.h b/tools/hmfs-tools/tools/common/hmfs_data.h new file mode 100755 index 0000000..0aeb634 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_data.h @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_DATA_H +#define HMFS_DATA_H +#include +#include +#include "hmfs_quota.h" + +namespace OHOS { +namespace Hmfs { + +namespace { +template +inline T AlignUpCount(T value, S alignSize) { + return (value + alignSize - 1) / alignSize; +} + +constexpr uint32_t HMFS_FEATURE_ENCRYPT = 0x0001; +constexpr uint32_t HMFS_FEATURE_BLKZONED = 0x0002; +constexpr uint32_t HMFS_FEATURE_ATOMIC_WRITE = 0x0004; +constexpr uint32_t HMFS_FEATURE_EXTRA_ATTR = 0x0008; +constexpr uint32_t HMFS_FEATURE_PRJQUOTA = 0x0010; +constexpr uint32_t HMFS_FEATURE_INODE_CHKSUM = 0x0020; +constexpr uint32_t HMFS_FEATURE_FLEXIBLE_INLINE_XATTR = 0x0040; +constexpr uint32_t HMFS_FEATURE_QUOTA_INO = 0x0080; +constexpr uint32_t HMFS_FEATURE_INODE_CRTIME = 0x0100; +constexpr uint32_t HMFS_FEATURE_LOST_FOUND = 0x0200; +constexpr uint32_t HMFS_FEATURE_VERITY = 0x0400; +constexpr uint32_t HMFS_FEATURE_SB_CHKSUM = 0x0800; +constexpr uint32_t HMFS_FEATURE_CASEFOLD = 0x1000; +constexpr uint32_t HMFS_FEATURE_COMPRESSION = 0x2000; +constexpr uint32_t HMFS_FEATURE_RO = 0x4000; + +constexpr uint32_t MAX_DEVICE_PATH_LEN = 64; +constexpr uint32_t MAX_DEVICE_COUNT = 8; + +constexpr uint64_t HMFS_MAX_DISK_SIZE = 16ULL * 1024 * 1024 * 1024 * 1024; +} + +#define BITS_PER_BYTE 8 +#define EXTENSION_LEN_MAX 8 +#define EXTENSION_COUNT_MAX 64 + +#define HMFS_BLOCK_SIZE 4096 +#define BLOCKS_PER_SEGMENT 512 +#define HMFS_MAX_SEGMENT (HMFS_MAX_DISK_SIZE / (HMFS_BLOCK_SIZE * BLOCKS_PER_SEGMENT)) +#define HMFS_MIN_SEGMENT_COUNT 9 /* SuerBlock + (CP + SIT + NAT) * 2 + SSA + MAIN */ + +#define VERSION_TOTAL_LEN 256 +#define VERSION_TIMESTAMP_LEN 4 +#define VERSION_STRING_LEN (VERSION_TOTAL_LEN - VERSION_TIMESTAMP_LEN) + +#define VOLUME_NAME_MAX_LEN 512 +#define CP_STOP_REASON_MAX 32 +#define HMFS_MAX_ERRORS 16 +#define DEVICE_PATH_MAX_LEN 64 +#define MAX_DEVICE_COUNT 8 + +#define HMFS_MAX_ACTIVE_LOGS 16 +#define HMFS_MAX_ACTIVE_NODE_LOGS 8 +#define HMFS_MAX_ACTIVE_DATA_LOGS 8 + + +// enum class CurSegType { +// DATA_HOT = 0, /* directory entry blocks */ +// DATA_WARM, /* data blocks */ +// DATA_COLD, /* multimedia or GCed data blocks */ +// NODE_HOT, /* direct node blocks of directory files */ +// NODE_WARM, /* direct node blocks of normal files */ +// NODE_COLD, /* indirect node blocks */ +// MAX +// }; + +enum { + CURSEG_DATA_HOT = 0, /* directory entry blocks */ + CURSEG_DATA_WARM, /* data blocks */ + CURSEG_DATA_COLD, /* multimedia or GCed data blocks */ + CURSEG_NODE_HOT, /* direct node blocks of directory files */ + CURSEG_NODE_WARM, /* direct node blocks of normal files */ + CURSEG_NODE_COLD, /* indirect node blocks */ + CURSEG_TYPE_MAX +}; + +#define CURSEG_DATA_TYPE_COUNT (3) +#define CURSEG_NODE_TYPE_COUNT (3) + + +/* + * super block area, data is writed in little-ending + */ +struct hmfs_device { + char path[DEVICE_PATH_MAX_LEN]; + uint32_t segmentCount; +}; +struct SuperBlockData { + uint32_t magicNo; /* Magic Number */ + uint16_t majorVersion; /* Major Version */ + uint16_t minorVersion; /* Minor Version */ + uint32_t logSectorSize; /* log2 sector size in bytes */ + uint32_t logSectorsPerBlk; /* log2 # of sectors per block */ + uint32_t logBlockSize; /* log2 block size in bytes */ + uint32_t logBlksPerSeg; /* log2 # of blocks per segment */ + uint32_t segsPerSection; /* # of segments per section */ + uint32_t sectionsPerZone; /* # of sections per zone */ + uint32_t checksumOffset; /* checksum offset inside super block */ + uint64_t blockCount; /* total # of user blocks */ + uint32_t sectionCount; /* total # of sections */ + uint32_t segmentCount; /* total # of segments */ + uint32_t segmentCountInCP; /* # of segments for checkpoint */ + uint32_t segmentCountInSIT; /* # of segments for SIT */ + uint32_t segmentCountInNAT; /* # of segments for NAT */ + uint32_t segmentCountInSSA; /* # of segments for SSA */ + uint32_t segmentCountInMain; /* # of segments for main area */ + uint32_t segment0BlkId; /* start block address of segment 0 */ + uint32_t cpBlkId; /* start block address of checkpoint */ + uint32_t sitBlkId; /* start block address of SIT */ + uint32_t natBlkId; /* start block address of NAT */ + uint32_t ssaBlkId; /* start block address of SSA */ + uint32_t mainBlkId; /* start block address of main area */ + uint32_t rootInodeId; /* root inode number */ + uint32_t nodeInodeId; /* node inode number */ + uint32_t metaInodeId; /* meta inode number */ + uint8_t uuid[16]; /* 128-bit uuid for volume */ + uint16_t volumeName[VOLUME_NAME_MAX_LEN]; /* volume name */ + uint32_t coldExtensionCount; /* # of cold extensions */ + char extensionList[EXTENSION_COUNT_MAX][EXTENSION_LEN_MAX]; /* extension array */ + uint32_t cpPayload; + uint8_t version[VERSION_TOTAL_LEN]; /* the kernel version */ + uint8_t initVersion[VERSION_TOTAL_LEN]; /* the initial kernel version */ + uint32_t features; /* defined features */ + uint8_t encryptionLevel; /* versioning level for encryption */ + uint8_t encryptPwSalt[16]; /* Salt used for string2key algorithm */ + struct hmfs_device devices[MAX_DEVICE_COUNT]; /* device list */ + uint32_t qfInodeId[MAXQUOTAS]; /* quota inode numbers */ + uint8_t hotExtensionCount; /* # of hot file extension */ + uint16_t encoding; /* Filename charset encoding */ + uint16_t encodingFlags; /* Filename charset encoding flags */ + uint8_t stopReason[CP_STOP_REASON_MAX]; /* stop checkpoint reason */ + uint8_t errors[HMFS_MAX_ERRORS]; /* reason of image corrupts */ + uint8_t reserved[258]; /* valid reserved region */ + uint32_t checksum; /* checksum of superblock */ +}__attribute__((packed)); + +#define HMFS_SUPER_BLOCK_COUNT 2 +#define HMFS_MAGIC_NUMBER 0xF2F52010 +#define HMFS_SUPER_BLOCK_OFFSET 1024 + + +/* + * SIT + */ +#define SIT_BITMAP_SIZE (BLOCKS_PER_SEGMENT / BITS_PER_BYTE) +struct sitEntry { + uint16_t usedBlockCount; /* reference above */ + uint8_t blockBitmap[SIT_BITMAP_SIZE]; /* bitmap for valid blocks */ + uint64_t modTime; /* segment age for cleaning */ +} __attribute__((packed)); + +#define SIT_ENTRIES_PER_BLOCK (HMFS_BLOCK_SIZE / sizeof(struct sitEntry)) +struct sitBlockData { + struct sitEntry entries[SIT_ENTRIES_PER_BLOCK]; +}; + +#define HMFS_SIT_COUNT 2 +#define SIT_MAX_BITMAP_SIZE (AlignUpCount(AlignUpCount(HMFS_MAX_SEGMENT, SIT_ENTRIES_PER_BLOCK), HMFS_BLOCK_SIZE) \ + * HMFS_BLOCK_SIZE / 8) + + + +/* + * NAT + */ +struct natEntry { + uint8_t version; /* latest version of cached nat entry */ + uint32_t inodeNo; /* inode number */ + uint32_t blockId; /* block id */ +} __attribute__((packed)); + +#define NAT_ENTRIES_PER_BLOCK (HMFS_BLOCK_SIZE / sizeof(struct natEntry)) +struct natBlockData { + struct natEntry entries[NAT_ENTRIES_PER_BLOCK]; +}; + +#define HMFS_NAT_COUNT 2 +#define NAT_ENTRY_PER_BLOCK (HMFS_BLKSIZE / sizeof(struct natEntry)) +#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) +#define DEFAULT_NAT_ENTRY_RATIO 20 + +// #define NAT_BLOCK_OFFSET(startNodeId) ((startNodeId) / NAT_ENTRIES_PER_BLOCK) + + +/* + * CP + */ +struct CheckPointData { + uint64_t cpVersion; /* checkpoint block version number */ + uint64_t userBlockCount; /* # of user blocks */ + uint64_t validBlockCount; /* # of valid blocks in main area */ + uint32_t rsvdSegmentCount; /* # of reserved segments for gc */ + uint32_t overprovSegmentCount; /* # of overprovision segments */ + uint32_t freeSegmentCount; /* # of free segments in main area */ + + /* information of current node segments */ + uint32_t curNodeSegNo[HMFS_MAX_ACTIVE_NODE_LOGS]; + uint16_t curNodeBlkOffset[HMFS_MAX_ACTIVE_NODE_LOGS]; + /* information of current data segments */ + uint32_t curDataSegNo[HMFS_MAX_ACTIVE_DATA_LOGS]; + uint16_t curDataBlkOffset[HMFS_MAX_ACTIVE_DATA_LOGS]; + uint32_t cpFlags; /* Flags : umount and journal_present */ + uint32_t cpPackBlockCount; /* total # of one cp pack */ + uint32_t cpPackStartSum; /* start block number of data summary */ + uint32_t validNodeCount; /* Total number of valid nodes */ + uint32_t validInodeCount; /* Total number of valid inodes */ + uint32_t nextFreeNodeId; /* Next free node number */ + uint32_t sitVersionBitmapSize; /* Default value 64 */ + uint32_t natVersionBitmapSize; /* Default value 256 */ + uint32_t checksumOffset; /* checksum offset inside cp block */ + uint64_t elapsedTime; /* mounted time */ + /* allocation type of current segment */ + uint8_t allocType[HMFS_MAX_ACTIVE_LOGS]; + + /* SIT and NAT version bitmap */ + uint8_t sitNatVersionBitmap[]; +}; + +#define HMFS_CP_COUNT 2 +#define CP_CHECKSUM_OFFSET (HMFS_BLOCK_SIZE - sizeof(uint32_t)) +#define CP_BITMAP_OFFSET (offsetof(struct CheckPointData, sitNatVersionBitmap)) +#define CP_MIN_CHECKSUM_OFFSET CP_BITMAP_OFFSET + +#define NAT_MIN_BITMAP_SIZE 64 +#define CP_MAX_BITMAP_SIZE (CP_CHECKSUM_OFFSET - CP_BITMAP_OFFSET) +#define CP_MAX_SIT_BITMAP_SIZE (CP_MAX_BITMAP_SIZE - NAT_MIN_BITMAP_SIZE) + +#define CP_FLAG_RESIZEFS 0x00004000 +#define CP_FLAG_DISABLED 0x00001000 +#define CP_FLAG_QUOTA_NEED_FSCK 0x00000800 +#define CP_FLAG_LARGE_NAT_BITMAP 0x00000400 +#define CP_FLAG_NOCRC_RECOVERY 0x00000200 +#define CP_FLAG_TRIMMED 0x00000100 +#define CP_FLAG_NAT_BITS 0x00000080 +#define CP_FLAG_CRC_RECOVERY 0x00000040 +#define CP_FLAG_FASTBOOT 0x00000020 +#define CP_FLAG_FSCK 0x00000010 +#define CP_FLAG_ERROR 0x00000008 +#define CP_FLAG_COMPACT_SUM 0x00000004 +#define CP_FLAG_ORPHAN_PRESENT 0x00000002 +#define CP_FLAG_UMOUNT 0x00000001 + + +/* a summary entry for a 4KB-sized block in a segment */ +struct SummaryEntry { + uint32_t nid; /* parent node id */ + struct { + uint8_t version; /* node version number */ + uint16_t ofsInNode; /* block index in parent node */ + } __attribute__((packed)); +} __attribute__((packed)); + +struct NatJournalEntry { + uint32_t nid; + struct natEntry ne; +} __attribute__((packed)); + +struct SummaryFooter { + uint8_t entryType; /* SUM_TYPE_XXX */ + uint32_t checkSum; /* summary checksum */ +} __attribute__((packed)); + + +#define ENTRY_COUNT_IN_SUM 512 +#define SUMMARY_JOURNAL_SIZE (HMFS_BLOCK_SIZE - sizeof(SummaryFooter) - (sizeof(SummaryEntry) * ENTRY_COUNT_IN_SUM)) + +#define NAT_JOURNAL_ENTRY_COUNT ((SUMMARY_JOURNAL_SIZE - 2) / sizeof(struct NatJournalEntry)) +#define NAT_JOURNAL_RESERVED_COUNT ((SUMMARY_JOURNAL_SIZE - 2) % sizeof(struct NatJournalEntry)) +#define SIT_JOURNAL_ENTRY_COUNT ((SUMMARY_JOURNAL_SIZE - 2) / sizeof(struct SitJournalEntry)) +#define SIT_JOURNAL_RESERVED_COUNT ((SUMMARY_JOURNAL_SIZE - 2) % sizeof(struct SitJournalEntry)) + +struct NatJournal { + struct NatJournalEntry entries[NAT_JOURNAL_ENTRY_COUNT]; + uint8_t reserved[NAT_JOURNAL_RESERVED_COUNT]; +}; + +struct SitJournalEntry { + uint32_t segno; + struct sitEntry se; +} __attribute__((packed)); + +struct SatJournal { + struct SitJournalEntry entries[SIT_JOURNAL_ENTRY_COUNT]; + uint8_t reserved[SIT_JOURNAL_RESERVED_COUNT]; +}; + +#define EXTRA_INFO_RESERVED_SIZE (SUMMARY_JOURNAL_SIZE - 2 - 8) + +struct ExtraInfo { + uint64_t kBytesWritten; + uint8_t reserved[EXTRA_INFO_RESERVED_SIZE]; +} __attribute__((packed)); + +struct JournalEntry { + union { + uint16_t nNats; + uint16_t nSits; + }; + /* spare area is used by NAT or SIT journals or extra info */ + union { + struct NatJournal natJ; + struct SatJournal sitJ; + struct ExtraInfo info; + }; +} __attribute__((packed)); + +struct SummaryBlockData { + struct SummaryEntry entries[ENTRY_COUNT_IN_SUM]; + struct JournalEntry journal; + struct SummaryFooter footer; +}; + +#define SUMMARY_TYPE_DATA (0) +#define SUMMARY_TYPE_NODE (1) + + +struct HmfsExtent { + uint32_t fofs; /* start file offset of the extent */ + uint32_t blkAddr; /* start block address of the extent */ + uint32_t len; /* lengh of the extent */ +} __attribute__((packed)); + +#define HMFS_NAME_LEN 255 +#define ADDR_COUNT_PER_INODE 923 /* Address Pointers in an Inode */ +struct HmfsInode { + uint16_t iMode; /* file mode */ + uint8_t iAdvise; /* file hints */ + uint8_t iInline; /* file inline flags */ + uint32_t iUid; /* user ID */ + uint32_t iGid; /* group ID */ + uint32_t iLinks; /* links count */ + uint64_t iSize; /* file size in bytes */ + uint64_t iBlocks; /* file size in blocks */ + uint64_t iAtime; /* access time */ + uint64_t iCtime; /* change time */ + uint64_t iMtime; /* modification time */ + uint32_t iAtimeNsec; /* access time in nano scale */ + uint32_t iCtimeNsec; /* change time in nano scale */ + uint32_t iMtimeNsec; /* modification time in nano scale */ + uint32_t iGeneration; /* file version (for NFS) */ + union { + uint32_t iCurrentDepth; /* only for directory depth */ + uint16_t iGcFailures; /* + * # of gc failures on pinned file. + * only for regular files. + */ + }; + uint32_t iXattrNid; /* nid to save xattr */ + uint32_t iFlags; /* file attributes */ + uint32_t iPino; /* parent inode number */ + uint32_t iNamelen; /* file name length */ + uint8_t iName[HMFS_NAME_LEN]; /* file name for SPOR */ + uint8_t iDirLevel; /* dentry_level for large dir */ + + struct HmfsExtent iExt; /* caching a largest extent */ + + union { + struct { + uint16_t iExtraIsize; /* extra inode attribute size */ + uint16_t iInlineXattrSize; /* inline xattr size, unit: 4 bytes */ + uint32_t iProjid; /* project id */ + uint32_t iInodeChecksum;/* inode meta checksum */ + uint64_t iCrtime; /* creation time */ + uint32_t iCrtimeNsec; /* creation time in nano scale */ + uint64_t iComprBlocks; /* # of compressed blocks */ + uint8_t iCompressAlgrithm; /* compress algrithm */ + uint8_t iLogClusterSize; /* log of cluster size */ + uint16_t iPadding; /* padding */ + uint32_t iExtraEnd[0]; /* for attribute size calculation */ + } __attribute__((packed)); + uint32_t i_addr[ADDR_COUNT_PER_INODE]; /* Pointers to data blocks */ + }; + uint32_t i_nid[5]; /* direct(2), indirect(2), + double_indirect(1) node id */ +} __attribute__((packed)); + +#define F2FS_EXTRA_ISIZE_OFFSET offsetof(struct HmfsInode, iExtraIsize) +#define F2FS_TOTAL_EXTRA_ATTR_SIZE (offsetof(struct HmfsInode, iExtraEnd) - F2FS_EXTRA_ISIZE_OFFSET) + +#define DEF_ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ +struct DirectNode { + uint32_t addr[DEF_ADDRS_PER_BLOCK]; /* array of data block address */ +}; + +#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ +struct IndirectNode { + uint32_t nid[NIDS_PER_BLOCK]; /* array of data block address */ +}; + +struct NodeFooter { + uint32_t nid; /* node id */ + uint32_t ino; /* inode nunmber */ + uint32_t flag; /* include cold/fsync/dentry marks and offset */ + uint64_t cpVer; /* checkpoint version */ + uint32_t nextBlkaddr; /* next node page block address */ +} __attribute__((packed)); + +struct NodeData { + /* can be one of three types: inode, direct, and indirect types */ + union { + struct HmfsInode i; + struct DirectNode dn; + struct IndirectNode in; + }; + struct NodeFooter footer; +}; + +struct DirEntry { + uint32_t hash_code; /* hash code of file name */ + uint32_t ino; /* inode number */ + uint16_t nameLen; /* lengh of file name */ + uint8_t fileType; /* file type */ +} __attribute__((packed)); + +/* the number of dentry in a block */ +#define DENTRY_COUNT_IN_BLOCK 214 + +/* One directory entry slot covers 8bytes-long file name */ +#define HMFS_SLOT_LEN 8 + +#define DENTRY_BITMAP_SIZE ((DENTRY_COUNT_IN_BLOCK + BITS_PER_BYTE - 1) / BITS_PER_BYTE) +#define RESERVED_SIZE (HMFS_BLOCK_SIZE - ((sizeof(struct DirEntry) + HMFS_SLOT_LEN) * DENTRY_COUNT_IN_BLOCK + DENTRY_BITMAP_SIZE)) + +struct DentryBlock { + /* validity bitmap for directory entries in each block */ + uint8_t dentryBitmap[DENTRY_BITMAP_SIZE]; + uint8_t reserved[RESERVED_SIZE]; + struct DirEntry dentry[DENTRY_COUNT_IN_BLOCK]; + uint8_t filename[DENTRY_COUNT_IN_BLOCK][HMFS_SLOT_LEN]; +}; + +/* file types used in inode_info->flags */ +enum HMFS_FILE_TYPE { + HMFS_FT_UNKNOWN, + HMFS_FT_REG_FILE, + HMFS_FT_DIR, + HMFS_FT_CHRDEV, + HMFS_FT_BLKDEV, + HMFS_FT_FIFO, + HMFS_FT_SOCK, + HMFS_FT_SYMLINK, + HMFS_FT_MAX, + /* added for fsck */ + HMFS_FT_ORPHAN, + HMFS_FT_XATTR, + HMFS_FT_LAST_FILE_TYPE = HMFS_FT_XATTR, +}; + +#define LPF_STRING "lost+found" + + +//------------------------- +#define DEFAULT_SECTOR_SIZE 512 +#define DEFAULT_SECTORS_PER_BLK 8 +#define DEFAULT_DIR_LEVEL 0 + + +//------------------------- + +#define NULL_SEGNO ((unsigned int)~0) + +#ifndef SECTOR_SHIFT +#define SECTOR_SHIFT 9 +#endif + +/* + * Note that f2fs_sit_entry->vblocks has the following bit-field information. + * [15:10] : allocation type such as CURSEG_XXXX_TYPE + * [9:0] : valid block count + */ +#define SIT_VBLOCKS_SHIFT 10 +#define SIT_VBLOCKS_MASK ((1 << SIT_VBLOCKS_SHIFT) - 1) +#define GET_SIT_VBLOCKS(raw_sit) \ + (LE16_TO_NATIVE((raw_sit)->usedBlockCount) & SIT_VBLOCKS_MASK) +#define GET_SIT_TYPE(raw_sit) \ + ((LE16_TO_NATIVE((raw_sit)->usedBlockCount) & ~SIT_VBLOCKS_MASK) \ + >> SIT_VBLOCKS_SHIFT) + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/common/hmfs_define.h b/tools/hmfs-tools/tools/common/hmfs_define.h new file mode 100755 index 0000000..aed39a6 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_define.h @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HMFS_DEFINE_H +#define HMFS_DEFINE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#if defined(HAVE_LINUX_BLKZONED_H) +#include +#elif defined(HAVE_KERNEL_UAPI_LINUX_BLKZONED_H) +#include +#endif + +namespace OHOS { +namespace Hmfs { +/* + * Swap bits + */ +template +constexpr T SwapBits(T value, T mask, uint32_t offset) +{ + return ((value >> offset) & mask) | ((value & mask) << offset); +} + +inline uint16_t ReverseBytes(uint16_t value) +{ + constexpr uint32_t OFFSET_0 = 8; + return static_cast(value << OFFSET_0) | static_cast(value >> OFFSET_0); +} + +inline uint32_t ReverseBytes(uint32_t value) +{ + constexpr uint32_t BYTES_MASK = 0xff00ffU; + constexpr uint32_t OFFSET_0 = 8; + constexpr uint32_t OFFSET_1 = 16; + value = SwapBits(value, BYTES_MASK, OFFSET_0); + return (value >> OFFSET_1) | (value << OFFSET_1); +} + +inline uint64_t ReverseBytes(uint64_t value) +{ + constexpr uint64_t BYTES_MASK = 0xff00ff00ff00ffLU; + constexpr uint64_t WORDS_MASK = 0xffff0000ffffLU; + constexpr uint32_t OFFSET_0 = 8; + constexpr uint32_t OFFSET_1 = 16; + constexpr uint32_t OFFSET_2 = 32; + value = SwapBits(value, BYTES_MASK, OFFSET_0); + value = SwapBits(value, WORDS_MASK, OFFSET_1); + return (value >> OFFSET_2) | (value << OFFSET_2); +} + +template +constexpr T BSWAP(T x) +{ + if (sizeof(T) == sizeof(uint16_t)) { + return ReverseBytes(static_cast(x)); + } + if (sizeof(T) == sizeof(uint32_t)) { + return ReverseBytes(static_cast(x)); + } + return ReverseBytes(static_cast(x)); +} + +#if __BYTE_ORDER == __BIG_ENDIAN +#define NATIVE_TO_LE16(x) BSWAP(uint16_t(x)) +#define NATIVE_TO_LE32(x) BSWAP(uint32_t(x)) +#define NATIVE_TO_LE64(x) BSWAP(uint64_t(x)) +#define LE16_TO_NATIVE(x) BSWAP(uint16_t(x)) +#define LE32_TO_NATIVE(x) BSWAP(uint32_t(x)) +#define LE64_TO_NATIVE(x) BSWAP(uint64_t(x)) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define NATIVE_TO_LE16(x) (static_cast(x)) +#define NATIVE_TO_LE32(x) (static_cast(x)) +#define NATIVE_TO_LE64(x) (static_cast(x)) +#define LE16_TO_NATIVE(x) (static_cast(x)) +#define LE32_TO_NATIVE(x) (static_cast(x)) +#define LE64_TO_NATIVE(x) (static_cast(x)) +#endif + +template +inline void SetLeValue(T& member, V val) +{ + if constexpr (sizeof(T) == sizeof(uint16_t)) { + member = NATIVE_TO_LE16(val); + } else if constexpr (sizeof(T) == sizeof(uint32_t)) { + member = NATIVE_TO_LE32(val); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + member = NATIVE_TO_LE64(val); + } else { + member = val; + } +} + +template +inline T GetLeValue(T value) +{ + if constexpr (sizeof(T) == sizeof(uint16_t)) { + return LE16_TO_NATIVE(value); + } else if constexpr (sizeof(T) == sizeof(uint32_t)) { + return LE32_TO_NATIVE(value); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + return LE64_TO_NATIVE(value); + } else { + return value; + } +} + +/* + * Print to console + */ +template +void PrintToConsole(const char* memberName, const T& member, bool layout) +{ + static_assert(std::is_integral::value, "Type must be integral"); + T value = layout ? GetLeValue(member) : member; + printf("%-35s ", memberName); + if (layout) { + if constexpr (sizeof(T) == sizeof(uint64_t)) { + printf("%" PRIu64 "\n", value); + } else if constexpr (sizeof(T) == sizeof(uint32_t) || sizeof(T) == sizeof(uint8_t)) { + printf("%u\n", value); + } else { + printf("%u\n", value); + } + } else { + if constexpr (sizeof(T) == sizeof(uint64_t)) { + printf("\t[0x%16" PRIx64 " : %" PRIu64 "]\n", value, value); + } else if constexpr (sizeof(T) == sizeof(uint32_t) || sizeof(T) == sizeof(uint8_t)) { + printf("\t[0x%16x : %u]\n", value, value); + } else { + printf("\t[0x%16x : %u]\n", value, value); + } + } +} + +#define PRINT_TO_COLSOLE(ptr, member) PrintToConsole(#member, (ptr)->member, g_hmfsConfig.layout) + + +/* + * Debugging interfaces + */ +#define ASSERT(exp) \ + do { \ + if (!(exp)) { \ + printf("[ASSERT] (%s:%4d) %s\n", __func__, __LINE__, #exp); \ + exit(-1); \ + } \ + } while (0) + +#define MSG(n, fmt, ...) \ + do { \ + if (g_hmfsConfig.dbgLv >= n && !g_hmfsConfig.layout && !g_hmfsConfig.showFileMap) { \ + printf(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define DBG(n, fmt, ...) \ + do { \ + if (g_hmfsConfig.dbgLv >= n && !g_hmfsConfig.layout && !g_hmfsConfig.showFileMap) { \ + printf("[%s:%4d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \ + } \ + } while (0) + +#define HMFS_ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) + +#define HMFS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */ +#define CP_CHKSUM_OFFSET 4092 +#define SB_CHKSUM_OFFSET 3068 +#define MAX_PATH_LEN 64 +#define MAX_DEVICES 8 + +#define HMFS_BYTES_TO_BLK(bytes) ((bytes) >> HMFS_BLKSIZE_BITS) +#define HMFS_BLKSIZE_BITS 12 + +/* for mkfs */ +#define DEFAULT_SECTORS_PER_BLOCK 8 +#define DEFAULT_BLOCKS_PER_SEGMENT 512 + +#define VERSION_LEN 256 +#define VERSION_TIMESTAMP_LEN 4 +#define VERSION_NAME_LEN (VERSION_LEN - VERSION_TIMESTAMP_LEN) + +enum HmfsConfigFunc { + MKFS, + FSCK, + DUMP, + DEFRAG, + RESIZE, + SLOAD, + LABEL, +}; + +/* + * code borrowed from kernel f2fs dirver: f2fs.h, GPL-2.0 + * : definitions of COMPRESS_DATA_RESERVED_SIZE, + * struct CompressData, COMPRESS_HEADER_SIZE, + * and struct CompressCtx + */ +#define COMPRESS_DATA_RESERVED_SIZE 4 +struct CompressData { + uint32_t clen; /* compressed data size */ + uint32_t chksum; /* checksum of compressed data */ + uint32_t reserved[COMPRESS_DATA_RESERVED_SIZE]; /* reserved */ + uint8_t cdata[]; /* compressed data */ +}; + +/* compress context */ +struct CompressCtx { + unsigned int clusterSize; /* page count in cluster */ + unsigned int logClusterSize; /* log of cluster size */ + void *rbuf; /* compression input buffer */ + CompressData *cbuf; /* comprsssion output header + data */ + size_t rlen; /* valid data length in rbuf */ + size_t clen; /* valid data length in cbuf */ + void *privateBuf; /* work buf for compress algorithm */ +}; + +struct StructDeviceInfo { + char *path; + int32_t fd; + uint32_t sectorSize; + uint64_t totalSectors; /* got by get_device_info */ + uint64_t startBlkaddr; + uint64_t endBlkaddr; + uint32_t totalSegments; + + /* to handle zone block devices */ + int zonedModel; + uint32_t nrZones; + uint32_t nrRndZones; + size_t zoneBlocks; + uint64_t zoneSize; + size_t *zoneCapBlocks; +}; + +struct DevCacheConfig { + /* Value 0 means no cache, minimum 1024 */ + long numCacheEntry; + + /* Value 0 means always overwrite (no collision allowed). maximum 16 */ + unsigned maxHashCollision; + + bool dbgEn; +}; + +/* f2fs_configration for compression used for sload.f2fs */ +struct compressOps { + void (*init)(struct CompressCtx *cc); + int (*compress)(struct CompressCtx *cc); + void (*reset)(struct CompressCtx *cc); +}; + +/* Should be aligned to supported_comp_names and support_comp_ops */ +enum CompressAlgorithms { + COMPR_LZO, + COMPR_LZ4, + MAX_COMPRESS_ALGS, +}; + +enum FilterPolicy { + COMPR_FILTER_UNASSIGNED = 0, + COMPR_FILTER_ALLOW, + COMPR_FILTER_DENY, +}; + +struct FilterOps { + void (*add)(const char *); + void (*destroy)(void); + bool (*filter)(const char *); +}; + +struct CompressConfig { + bool enabled; /* disabled by default */ + bool required; /* require to enable */ + bool readonly; /* readonly to release blocks */ + CompressCtx cc; /* work context */ + enum CompressAlgorithms alg; /* algorithm to compress */ + compressOps *ops; /* ops per algorithm */ + unsigned int minBlocks; /* save more blocks than this */ + enum FilterPolicy filter; /* filter to try compression */ + FilterOps *FilterOps; /* filter ops */ +}; + +struct hmfs_configuration { + uint32_t reservedSegments; + uint32_t newReservedSegments; + int sparseMode; + int zonedMode; + int zonedModel; + size_t zoneBlocks; + double overprovision; + double newOverprovision; + uint32_t curSeg[6]; + uint32_t segsPerSec; + uint32_t secsPerZone; + uint32_t segsPerZone; + uint32_t startSector; + uint32_t totalSegments; + uint32_t sectorSize; + uint64_t deviceSize; + uint64_t totalSectors; + uint64_t wantedTotalSectors; + uint64_t wantedSectorSize; + uint64_t targetSectors; + uint32_t sectorsPerBlk; + uint32_t blksPerSeg; + uint8_t initVersion[VERSION_LEN + 1]; + uint8_t sbVersion[VERSION_LEN + 1]; + uint8_t version[VERSION_LEN + 1]; + char *volLabel; + char *volUuid; + uint16_t encoding; + uint16_t encodingFlags; + int heap; + int32_t kd; + int32_t dumpFd; + StructDeviceInfo devices[MAX_DEVICES]; + int ndevs; + char *extensionList[2]; + const char *rootdevName; + int dbgLv; + int showDentry; + int trim; + int trimmed; + int func; + void *privateBuf; + int dryRun; + int noKernelCheck; + int fixOn; + int force; + int defset; + int bugOn; + int forceStop; + int abnormalStop; + int fsErrors; + int bugNatBits; + bool quotaFixed; + int allocFailed; + int autoFix; + int layout; + int showFileMap; + uint64_t showFileMapMaxOffset; + int quotaFix; + int preenMode; + int ro; + int preserveLimits; /* preserve quota limits */ + int largeNatBitmap; + int fixChksum; /* fix old cp.chksum position */ + uint32_t feature; /* defined features */ + unsigned int quotaBits; /* quota bits */ + time_t fixedTime; + + /* mkfs parameters */ + int fakeSeed; + uint32_t nextFreeNid; + uint32_t quotaInum; + uint32_t quotaDnum; + uint32_t lpfInum; + uint32_t lpfDnum; + uint32_t lpfIno; + uint32_t rootUid; + uint32_t rootGid; + + /* defragmentation parameters */ + int defragShrink; + uint64_t defragStart; + uint64_t defragLen; + uint64_t defragTarget; + + /* sload parameters */ + char *fromDir; + char *mountPoint; + char *targetOutDir; + char *fsConfigFile; + int preservePerms; + + /* resize parameters */ + int safeResize; + + /* precomputed fs UUID checksum for seeding other checksums */ + uint32_t chksumSeed; + + /* cache parameters */ + DevCacheConfig cacheConfig; + + /* compression support for sload.f2fs */ + CompressConfig compress; +}; + +extern hmfs_configuration g_hmfsConfig; + +/* + * Copied from fs/f2fs/f2fs.h + */ +#define NR_CURSEG_DATA_TYPE (3) +#define NR_CURSEG_NODE_TYPE (3) +#define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) + +enum { + CURSEG_HOT_DATA = 0, /* directory entry blocks */ + CURSEG_WARM_DATA, /* data blocks */ + CURSEG_COLD_DATA, /* multimedia or GCed data blocks */ + CURSEG_HOT_NODE, /* direct node blocks of directory files */ + CURSEG_WARM_NODE, /* direct node blocks of normal files */ + CURSEG_COLD_NODE, /* indirect node blocks */ + NO_CHECK_TYPE +}; + +#define HMFS_MIN_SEGMENTS 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */ + +/* + * Copied from fs/f2fs/segment.h + */ +#define GET_SUM_TYPE(footer) ((footer)->entryType) +#define SET_SUM_TYPE(footer, type) ((footer)->entryType = type) + +/* + * Copied from include/linux/f2fs_sb.h + */ +#define HMFS_SUPER_OFFSET 1024 /* byte-size offset */ +#define HMFS_MIN_LOG_SECTOR_SIZE 9 /* 9 bits for 512 bytes */ +#define HMFS_MAX_LOG_SECTOR_SIZE 12 /* 12 bits for 4096 bytes */ +#define HMFS_BLKSIZE 4096 /* support only 4KB block */ +#define HMFS_MAX_EXTENSION 64 /* # of extension entries */ +#define HMFS_EXTENSION_LEN 8 /* max size of extension */ +#define HMFS_BLK_ALIGN(x) (((x) + HMFS_BLKSIZE - 1) / HMFS_BLKSIZE) + +#define NULL_ADDR 0x0U +#define NEW_ADDR -1U +#define COMPRESS_ADDR -2U + +#define HMFS_MAX_QUOTAS 3 + +#define HMFS_ENC_UTF8_12_1 1 + +#define MAX_VOLUME_NAME 512 + +/* reason of stop_checkpoint */ +enum StopCpReason { + STOP_CP_REASON_SHUTDOWN, + STOP_CP_REASON_FAULT_INJECT, + STOP_CP_REASON_META_PAGE, + STOP_CP_REASON_WRITE_FAIL, + STOP_CP_REASON_CORRUPTED_SUMMARY, + STOP_CP_REASON_UPDATE_INODE, + STOP_CP_REASON_FLUSH_FAIL, + STOP_CP_REASON_MAX, +}; + +#define MAX_HMFS_ERRORS 16 + +/* + * For checkpoint + */ +#define CP_RESIZEFS_FLAG 0x00004000 +#define CP_DISABLED_FLAG 0x00001000 +#define CP_QUOTA_NEED_FSCK_FLAG 0x00000800 +#define CP_LARGE_NAT_BITMAP_FLAG 0x00000400 +#define CP_NOCRC_RECOVERY_FLAG 0x00000200 +#define CP_TRIMMED_FLAG 0x00000100 +#define CP_NAT_BITS_FLAG 0x00000080 +#define CP_CRC_RECOVERY_FLAG 0x00000040 +#define CP_FASTBOOT_FLAG 0x00000020 +#define CP_FSCK_FLAG 0x00000010 +#define CP_ERROR_FLAG 0x00000008 +#define CP_COMPACT_SUM_FLAG 0x00000004 +#define CP_ORPHAN_PRESENT_FLAG 0x00000002 +#define CP_UMOUNT_FLAG 0x00000001 + +#define HMFS_CP_PACKS 2 /* # of checkpoint packs */ + +#define CP_MIN_CHKSUM_OFFSET CP_BITMAP_OFFSET + +#define MIN_NAT_BITMAP_SIZE 64 +#define MAX_SIT_BITMAP_SIZE_IN_CKPT \ + (CP_CHKSUM_OFFSET - CP_BITMAP_OFFSET - MIN_NAT_BITMAP_SIZE) +#define MAX_BITMAP_SIZE_IN_CKPT \ + (CP_CHKSUM_OFFSET - CP_BITMAP_OFFSET) + + +#define HMFS_INLINE_XATTR 0x01 /* file inline xattr flag */ +#define HMFS_INLINE_DATA 0x02 /* file inline data flag */ +#define HMFS_INLINE_DENTRY 0x04 /* file inline dentry flag */ +#define HMFS_DATA_EXIST 0x08 /* file inline data exist flag */ +#define HMFS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ +#define HMFS_EXTRA_ATTR 0x20 /* file having extra attribute */ +#define HMFS_PIN_FILE 0x40 /* file should not be gced */ +#define HMFS_COMPRESS_RELEASED 0x80 /* file released compressed blocks */ + +/* + * For SIT entries + * + * Each segment is 2MB in size by default so that a bitmap for validity of + * there-in blocks should occupy 64 bytes, 512 bits. + * Not allow to change this. + */ +#define SIT_VBLOCK_MAP_SIZE 64 +#define SIT_ENTRY_PER_BLOCK (HMFS_BLKSIZE / sizeof(struct sitEntry)) + +/* + * F2FS uses 4 bytes to represent block address. As a result, supported size of + * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments. + */ +#define SIZE_ALIGN(val, size) (((val) + (size) - 1) / (size)) +#define SEG_ALIGN(blks) SIZE_ALIGN(blks, g_hmfsConfig.blksPerSeg) +#define ZONE_ALIGN(blks) SIZE_ALIGN(blks, g_hmfsConfig.blksPerSeg * \ + g_hmfsConfig.segsPerZone) + +#define HMFS_MIN_SEGMENT 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */ +#define HMFS_MAX_SEGMENT_SIZE ((16 * 1024 * 1024) / 2) +#define MAX_SIT_BITMAP_SIZE (SEG_ALIGN(SIZE_ALIGN(HMFS_MAX_SEGMENT_SIZE, \ + SIT_ENTRY_PER_BLOCK)) * \ + g_hmfsConfig.blksPerSeg / 8) +#define MAX_CP_PAYLOAD (SEG_ALIGN(SIZE_ALIGN(UINT32_MAX, NAT_ENTRY_PER_BLOCK)) * \ + DEFAULT_NAT_ENTRY_RATIO / 100 * \ + g_hmfsConfig.blksPerSeg / 8 + \ + MAX_SIT_BITMAP_SIZE - MAX_BITMAP_SIZE_IN_CKPT) + +/* + * For segment summary + * + * One summary block contains exactly 512 summary entries, which represents + * exactly 2MB segment by default. Not allow to change the basic units. + * + * NOTE: For initializing fields, you must use set_summary + * + * - If data page, nid represents dnode's nid + * - If node page, nid represents the node page's nid. + * + * The ofsInNode is used by only data page. It represents offset + * from node's page's beginning to get a data block address. + * ex) data_blkaddr = (uint32_t)(nodepage_start_address + ofsInNode) + */ +#define ENTRIES_IN_SUM 512 +#define SUMMARY_SIZE (7) /* sizeof(struct summary) */ +#define SUM_FOOTER_SIZE (5) /* sizeof(struct SummaryFooter) */ +#define SUM_ENTRIES_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) + + +#define SUM_JOURNAL_SIZE (HMFS_BLKSIZE - SUM_FOOTER_SIZE - SUM_ENTRIES_SIZE) +#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) / sizeof(NatJournalEntry)) +#define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) / sizeof(SitJournalEntry)) + +} // namespace Hmfs +} // namespace OHOS + +#endif // HMFS_DEFINE_H \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_encoding.cpp b/tools/hmfs-tools/tools/common/hmfs_encoding.cpp new file mode 100755 index 0000000..6ef2ea5 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_encoding.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmfs_encoding.h" + +#include +#include +#include +#include +#include +#include +#include +#include "hmfs_data.h" + +namespace OHOS { +namespace Hmfs { +static const EncodingInfo g_hmfsEncodingMap[] = { + {"utf8", HMFS_ENC_UTF8_12_1, 0} +}; + +static const std::unordered_map g_encodingFlagsMap = { + {"strict", 1} +}; + +const char *Utf8ToWchar(const char *input, wchar_t *wc, size_t insize) +{ + if ((input[0] & 0x80) == 0 && insize >= 1) { + *wc = (wchar_t) input[0]; + return input + 1; + } + if ((input[0] & 0xe0) == 0xc0 && insize >= 2) { + *wc = (((wchar_t) input[0] & 0x1f) << 6) | ((wchar_t) input[1] & 0x3f); + return input + 2; + } + if ((input[0] & 0xf0) == 0xe0 && insize >= 3) { + *wc = (((wchar_t) input[0] & 0x0f) << 12) | + (((wchar_t) input[1] & 0x3f) << 6) | + ((wchar_t) input[2] & 0x3f); + return input + 3; + } + if ((input[0] & 0xf8) == 0xf0 && insize >= 4) { + *wc = (((wchar_t) input[0] & 0x07) << 18) | + (((wchar_t) input[1] & 0x3f) << 12) | + (((wchar_t) input[2] & 0x3f) << 6) | + ((wchar_t) input[3] & 0x3f); + return input + 4; + } + if ((input[0] & 0xfc) == 0xf8 && insize >= 5) { + *wc = (((wchar_t) input[0] & 0x03) << 24) | + (((wchar_t) input[1] & 0x3f) << 18) | + (((wchar_t) input[2] & 0x3f) << 12) | + (((wchar_t) input[3] & 0x3f) << 6) | + ((wchar_t) input[4] & 0x3f); + return input + 5; + } + if ((input[0] & 0xfe) == 0xfc && insize >= 6) { + *wc = (((wchar_t) input[0] & 0x01) << 30) | + (((wchar_t) input[1] & 0x3f) << 24) | + (((wchar_t) input[2] & 0x3f) << 18) | + (((wchar_t) input[3] & 0x3f) << 12) | + (((wchar_t) input[4] & 0x3f) << 6) | + ((wchar_t) input[5] & 0x3f); + return input + 6; + } + return nullptr; +} + +const uint16_t *Utf16ToWchar(const uint16_t *input, wchar_t *wc, size_t insize) +{ + if ((LE16_TO_NATIVE(input[0]) & 0xfc00) == 0xd800) { + if (insize < 2 || (LE16_TO_NATIVE(input[1]) & 0xfc00) != 0xdc00) { + return nullptr; + } + *wc = ((wchar_t) (LE16_TO_NATIVE(input[0]) & 0x3ff) << 10); + *wc |= (LE16_TO_NATIVE(input[1]) & 0x3ff); + *wc += 0x10000; + return input + 2; + } else { + *wc = LE16_TO_NATIVE(*input); + return input + 1; + } +} + +uint16_t *WcharToUtf16(uint16_t *output, wchar_t wc, size_t outsize) +{ + if (wc <= 0xffff) { + if (outsize == 0) { + return nullptr; + } + output[0] = NATIVE_TO_LE16(wc); + return output + 1; + } + if (outsize < 2) { + return nullptr; + } + wc -= 0x10000; + output[0] = NATIVE_TO_LE16(0xd800 | ((wc >> 10) & 0x3ff)); + output[1] = NATIVE_TO_LE16(0xdc00 | (wc & 0x3ff)); + return output + 2; +} + +int Utf8ToUtf16(uint16_t *output, const char *input, size_t outsize, size_t insize) +{ + const char *inp = input; + uint16_t *outp = output; + wchar_t wc; + + while ((size_t)(inp - input) < insize && *inp) { + inp = Utf8ToWchar(inp, &wc, insize - (inp - input)); + if (inp == nullptr) { + HMFS_DEBUG("illegal UTF-8 sequence\n"); + return -EILSEQ; + } + outp = WcharToUtf16(outp, wc, outsize - (outp - output)); + if (outp == nullptr) { + HMFS_DEBUG("name is too long\n"); + return -ENAMETOOLONG; + } + } + *outp = NATIVE_TO_LE16(0); + return 0; +} + +char *WcharToUtf8(char *output, wchar_t wc, size_t outsize) +{ + if (wc <= 0x7f) { + if (outsize < 1) { + return nullptr; + } + *output++ = (char) wc; + } else if (wc <= 0x7ff) { + if (outsize < 2) { + return nullptr; + } + *output++ = 0xc0 | (wc >> 6); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0xffff) { + if (outsize < 3) { + return nullptr; + } + *output++ = 0xe0 | (wc >> 12); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0x1fffff) { + if (outsize < 4) { + return nullptr; + } + *output++ = 0xf0 | (wc >> 18); + *output++ = 0x80 | ((wc >> 12) & 0x3f); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0x3ffffff) { + if (outsize < 5) { + return nullptr; + } + *output++ = 0xf8 | (wc >> 24); + *output++ = 0x80 | ((wc >> 18) & 0x3f); + *output++ = 0x80 | ((wc >> 12) & 0x3f); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0x7fffffff) { + if (outsize < 6) { + return nullptr; + } + *output++ = 0xfc | (wc >> 30); + *output++ = 0x80 | ((wc >> 24) & 0x3f); + *output++ = 0x80 | ((wc >> 18) & 0x3f); + *output++ = 0x80 | ((wc >> 12) & 0x3f); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else { + return nullptr; + } + + return output; +} + +int Utf16Toutf8(char *output, const uint16_t *input, size_t outsize, size_t insize) +{ + const uint16_t *inp = input; + char *outp = output; + wchar_t wc; + + while ((size_t)(inp - input) < insize && LE16_TO_NATIVE(*inp)) { + inp = Utf16ToWchar(inp, &wc, insize - (inp - input)); + if (inp == nullptr) { + HMFS_DEBUG("illegal UTF-16 sequence\n"); + return -EILSEQ; + } + outp = WcharToUtf8(outp, wc, outsize - (outp - output)); + if (outp == nullptr) { + HMFS_DEBUG("name is too long\n"); + return -ENAMETOOLONG; + } + } + *outp = '\0'; + return 0; +} + +int32_t EncodingStrToValue(std::string& encodingString, uint16_t& value) +{ + for (uint32_t i = 0 ; i < HMFS_ARRAY_SIZE(g_hmfsEncodingMap); i++) { + if (encodingString == g_hmfsEncodingMap[i].encodingName) { + value = g_hmfsEncodingMap[i].encodingKey; + return 0; + } + } + return -1; +} + +int32_t EncodingValueToStr(const uint16_t encodingVal, std::string& str) +{ + for (uint32_t i = 0 ; i < HMFS_ARRAY_SIZE(g_hmfsEncodingMap); i++) { + if (g_hmfsEncodingMap[i].encodingKey == encodingVal) { + str = g_hmfsEncodingMap[i].encodingName; + return 0; + } + } + return -1; +} + +uint16_t GetDefaultEncodingFlag(uint16_t encoding) +{ + for (uint32_t i = 0 ; i < HMFS_ARRAY_SIZE(g_hmfsEncodingMap); i++) { + if (g_hmfsEncodingMap[i].encodingKey == encoding) { + return g_hmfsEncodingMap[i].initialFlags; + } + } + return 0; +} + +int32_t EncodingFlagStrToValue(std::string& flagsStr, uint16_t& flags) +{ + std::stringstream flagList(flagsStr); + std::string flagStr; + while (std::getline(flagList, flagStr, ',')) { + bool negFlag = false; + if (flagStr.find("no") == 0) { + negFlag = true; + flagStr.erase(0, strlen("no")); + } + + auto it = g_encodingFlagsMap.find(flagStr); + if (it == g_encodingFlagsMap.end()) { + return -1; + } + + if (negFlag) { + HMFS_INFO("Sub %s", flagStr.c_str()); + flags &= ~it->second; + } else { + HMFS_INFO("Add %s", flagStr.c_str()); + flags |= it->second; + } + } + return 0; +} + +bool IsNeedEncoding(int32_t encoding) +{ + if (encoding == HMFS_ENC_UTF8_12_1) { + return true; + } + return false; +} + +int32_t CaseFold(const unsigned char *str, size_t len, unsigned char *dest, size_t dlen) +{ + if (str == nullptr || dest == nullptr || len == 0 || dlen == 0) { + HMFS_ERROR("Invalid input parameters"); + return -EINVAL; + } + + // Allocate a buffer for the case-folded result + UErrorCode errorCode = U_ZERO_ERROR; + icu::UnicodeString input(reinterpret_cast(str), len, "UTF-8"); + std::vector buffer(input.length()); + int32_t resultLength = icu::CaseMap::fold(U_FOLD_CASE_DEFAULT, input.getBuffer(), input.length(), + buffer.data(), buffer.size(), nullptr, errorCode); + if (U_FAILURE(errorCode)) { + HMFS_ERROR("Error case folding string: %s", u_errorName(errorCode)); + return -EINVAL; + } + + // Convert the result to UTF-8 + icu::UnicodeString caseFolded; + caseFolded.setTo(false, buffer.data(), resultLength); + std::string utf8Result; + caseFolded.toUTF8String(utf8Result); + if (utf8Result.size() > dlen) { + HMFS_ERROR("Result exceeds destination buffer size"); + return -ENAMETOOLONG; + } + + std::copy(utf8Result.begin(), utf8Result.end(), dest); + return utf8Result.size(); +} + + +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_encoding.h b/tools/hmfs-tools/tools/common/hmfs_encoding.h new file mode 100755 index 0000000..df5b8a5 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_encoding.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_ENCODING_H +#define HMFS_ENCODING_H + +#include +#include +#include +#include "hmfs_define.h" +#include "hmfs_utils.h" + +namespace OHOS { +namespace Hmfs { +#define HMFS_HASH_COL_BIT ((0x1ULL) << 63) +struct EncodingInfo { + std::string encodingName; + uint16_t encodingKey; + uint16_t initialFlags; +}; + +bool IsNeedEncoding(int32_t encoding); +int32_t CaseFold(const unsigned char *str, size_t len, unsigned char *dest, size_t dlen); + +const char *Utf8ToWchar(const char *input, wchar_t *wc, size_t insize); +const uint16_t *Utf16ToWchar(const uint16_t *input, wchar_t *wc, size_t insize); +uint16_t *WcharToUtf16(uint16_t *output, wchar_t wc, size_t outsize); +int Utf8ToUtf16(uint16_t *output, const char *input, size_t outsize, size_t insize); +char *WcharToUtf8(char *output, wchar_t wc, size_t outsize); +int Utf16Toutf8(char *output, const uint16_t *input, size_t outsize, size_t insize); +int32_t EncodingStrToValue(std::string& encodingString, uint16_t& value); +int32_t EncodingValueToStr(const uint16_t encodingVal, std::string& str); +uint16_t GetDefaultEncodingFlag(uint16_t encoding); +int32_t EncodingFlagStrToValue(std::string& flagsStr, uint16_t& flags); + +} // namespace Hmfs +} // namespace OHOS +#endif // HMFS_ENCODING_H \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_io.cpp b/tools/hmfs-tools/tools/common/hmfs_io.cpp new file mode 100755 index 0000000..bfa6abd --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_io.cpp @@ -0,0 +1,777 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "hmfs_io.h" + +#include +#include +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_HDREG_H +#include +#endif +#ifdef HAVE_SPARSE_SPARSE_H +#include +#endif +#include + +#include "hmfs_utils.h" +#include "device_manager.h" + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +namespace OHOS::Hmfs { +#define MIN_NUM_CACHE_ENTRY 1024L +#define MAX_MAX_HASH_COLLISION 16 + +#define MAX_CHUNK_SIZE (1 * 1024 * 1024 * 1024ULL) +#define MAX_CHUNK_COUNT (MAX_CHUNK_SIZE / HMFS_BLKSIZE) + +hmfs_configuration g_hmfsConfig; + +#ifndef HAVE_LSEEK64 +static inline off64_t lseek64(int fd, uint64_t offset, int set) +{ + return lseek(fd, offset, set); +} +#endif + +static int GetDeviceFd(uint64_t *offset) +{ + uint64_t blkAddr = *offset >> HMFS_BLKSIZE_BITS; + for (uint32_t i = 0; i < DeviceManager::GetInstance().GetDeviceCount(); i++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(i); + if (deviceInfo == nullptr) { + HMFS_DEBUG("failed to get device info by id %zu", i); + continue; + } + + if ((deviceInfo->startBlkId <= blkAddr) && (deviceInfo->endBlkId >= blkAddr)) { + *offset -= deviceInfo->startBlkId << HMFS_BLKSIZE_BITS; + return deviceInfo->fd; + } + } + + return -1; +} + +Dcache& Dcache::GetInstance() +{ + static Dcache instance; + return instance; +} + +void Dcache::DcachePrintStatistics(void) +{ + /* Number of used cache entries */ + long useCnt = 0; + for (long i = 0; i < dcacheConfig.numCacheEntry; i++) { + if (dcacheValid[i]) { + ++useCnt; + } + } + + /* + * c: number of cache entries + * u: used entries + * RA: number of read access blocks + * CH: cache hit + * CM: cache miss + * Repl: read cache replaced + */ + HMFS_INFO("\nc, u, RA, CH, CM, Repl=\n"); + HMFS_INFO("%ld %ld %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + dcacheConfig.numCacheEntry, + useCnt, + dcacheRaccess, + dcacheRhit, + dcacheRmiss, + dcacheRreplace); +} + +void Dcache::DcacheRelease() +{ + if (!dcacheInitialized) { + return; + } + + dcacheInitialized = false; + if (g_hmfsConfig.cacheConfig.dbgEn) { + DcachePrintStatistics(); + } + if (dcacheBlk != nullptr) { + delete(dcacheBlk); + } + if (dcacheLastused != nullptr) { + delete(dcacheLastused); + } + if (dcacheBuf != nullptr) { + delete(dcacheBuf); + } + if (dcacheValid != nullptr) { + delete(dcacheValid); + } + + dcacheConfig.numCacheEntry = 0; + dcacheBlk = nullptr; + dcacheLastused = nullptr; + dcacheBuf = nullptr; + dcacheValid = nullptr; +} + +// return 0 for success, error code for failure. +int Dcache::DcacheAllocAll(long n) +{ + if (n <= 0) { + return -1; + } + if ((dcacheBlk = new off64_t[n]) == nullptr || + (dcacheLastused = new uint64_t[n]) == nullptr || + (dcacheBuf = new char[HMFS_BLKSIZE * n]) == nullptr || + (dcacheValid = new bool[n]) == nullptr) { + DcacheRelease(); + return -1; + } + dcacheConfig.numCacheEntry = n; + return 0; +} + +void Dcache::DcacheRelocateInit(void) +{ + uint32_t n0 = (sizeof(dcacheRelocateOffset0) / sizeof(dcacheRelocateOffset0[0])); + uint32_t n = (sizeof(dcacheRelocateOffset) / sizeof(dcacheRelocateOffset[0])); + if (n0 != n) { + HMFS_INFO("dcacheRelocateOffset0 and dcacheRelocateOffset size mismatch\n"); + } + + for (uint32_t i = 0; i < n && i < dcacheConfig.maxHashCollision; i++) { + if (labs(dcacheRelocateOffset0[i]) > dcacheConfig.numCacheEntry / 2) { + dcacheConfig.maxHashCollision = i; + break; + } + dcacheRelocateOffset[i] = dcacheConfig.numCacheEntry + dcacheRelocateOffset0[i]; + } +} + +void Dcache::DcacheInit(void) +{ + if (g_hmfsConfig.cacheConfig.numCacheEntry <= 0) { + return; + } + /* release previous cache init, if any */ + DcacheRelease(); + + dcacheBlk = nullptr; + dcacheLastused = nullptr; + dcacheBuf = nullptr; + dcacheValid = nullptr; + + dcacheConfig = g_hmfsConfig.cacheConfig; + + long n = std::max(MIN_NUM_CACHE_ENTRY, dcacheConfig.numCacheEntry); + Dcache& ins = Dcache::GetInstance(); + /* halve alloc size until alloc succeed, or min cache reached */ + while (ins.DcacheAllocAll(n) != 0 && n != MIN_NUM_CACHE_ENTRY) { + n = std::max(MIN_NUM_CACHE_ENTRY, n/2); + } + + /* must be the last: data dependent on numCacheEntry */ + ins.DcacheRelocateInit(); + dcacheInitialized = true; + + if (!dcacheExitRegistered) { + dcacheExitRegistered = true; + std::atexit(Dcache::DcacheRelease); /* auto release */ + } + + dcacheRaccess = 0; + dcacheRhit = 0; + dcacheRmiss = 0; + dcacheRreplace = 0; +} + +inline char *Dcache::DcacheAddr(long entry) +{ + return dcacheBuf + HMFS_BLKSIZE * entry; +} + +/* relocate on (n+1)-th collision */ +inline long Dcache::DcacheRelocate(long entry, int n) +{ + return (entry + dcacheRelocateOffset[n]) % dcacheConfig.numCacheEntry; +} + +long Dcache::DcacheFind(off64_t blk) +{ + long n = dcacheConfig.numCacheEntry; + unsigned m = dcacheConfig.maxHashCollision; + long entry, leastUsed, target; + unsigned index; + + if (n <= 0) { + return 0; + } + target = leastUsed = entry = blk % n; /* simple modulo hash */ + + for (index = 0; index < m; index++) { + if (!dcacheValid[target] || dcacheBlk[target] == blk) { + return target; /* found target or empty cache slot */ + } + if (dcacheLastused[target] < dcacheLastused[leastUsed]) { + leastUsed = target; + } + target = DcacheRelocate(entry, index); /* next target */ + } + return leastUsed; /* max search reached, return least used slot */ +} + +/* Physical read into cache */ +int Dcache::DcacheIoRead(int fd, long entry, off64_t offset, off64_t blk) +{ + if (pread64(fd, dcacheBuf + entry * HMFS_BLKSIZE, HMFS_BLKSIZE, offset) < 0) { + HMFS_ERROR("\n read() fail.\n"); + return -1; + } + dcacheLastused[entry] = ++dcacheUsetick; + dcacheValid[entry] = true; + dcacheBlk[entry] = blk; + return 0; +} + +/* + * - Note: Read/Write are not symmetric: + * For read, we need to do it block by block, due to the cache nature: + * some blocks may be cached, and others don't. + * For write, since we always do a write-thru, we can join all writes into one, + * and write it once at the caller. This function updates the cache for write, but + * not the do a physical write. The caller is responsible for the physical write. + * - Note: We concentrate read/write together, due to the fact of similar structure to find + * the relavant cache entries + * - Return values: + * 0: success + * 1: cache not available (uninitialized) + * -1: error + */ +int Dcache::DcacheUpdateRw(int fd, void *buf, off64_t offset, size_t byteCount, bool isWrite) +{ + if (!dcacheInitialized) { + DcacheInit(); /* auto initialize */ + } + if (!dcacheInitialized) { + return 1; /* not available */ + } + off64_t blk = offset / HMFS_BLKSIZE; + int addrInBlk = offset % HMFS_BLKSIZE; + off64_t start = blk * HMFS_BLKSIZE; + + while (byteCount != 0) { + size_t curSize = std::min(byteCount, (size_t)(HMFS_BLKSIZE - addrInBlk)); + long entry = DcacheFind(blk); + if (!isWrite) { + ++dcacheRaccess; + } + + if (dcacheValid[entry] && dcacheBlk[entry] == blk) { + /* cache hit */ + if (isWrite) { /* write: update cache */ + memcpy_s(DcacheAddr(entry) + addrInBlk, curSize, buf, curSize); + } else { + ++dcacheRhit; + } + } else { + /* cache miss */ + if (!isWrite) { + ++dcacheRmiss; + if (dcacheValid[entry]) { + ++dcacheRreplace; + } + /* read: physical I/O read into cache */ + int err = DcacheIoRead(fd, entry, start, blk); + if (err) { + return err; + } + } + } + + /* read: copy data from cache */ + /* write: nothing to do, since we don't do physical write. */ + if (!isWrite) { + memcpy_s(buf, curSize, DcacheAddr(entry) + addrInBlk, curSize); + } + + /* next block */ + ++blk; + buf = (uint8_t *)buf + curSize; + start += HMFS_BLKSIZE; + byteCount -= curSize; + addrInBlk = 0; + } + return 0; +} + +/* + * DcacheUpdateCache() just update cache, won't do physical I/O. + * Thus even no error, we need normal non-cache I/O for actual write + * + * return value: 1: cache not available + * 0: success, -1: I/O error + */ +int Dcache::DcacheUpdateCache(int fd, void *buf, off64_t offset, size_t count) +{ + return DcacheUpdateRw(fd, buf, offset, count, true); +} + +/* handles read into cache + read into buffer */ +int Dcache::DcacheRead(int fd, void *buf, off64_t offset, size_t count) +{ + return DcacheUpdateRw(fd, buf, offset, count, false); +} + +std::unique_ptr HmfsIo::instance_ = nullptr; +void HmfsIo::CreateInstance(CmdConfig &cfgPara) +{ + if (instance_ == nullptr) { + instance_ = std::make_unique(cfgPara); + } +} + +HmfsIo& HmfsIo::GetInstance() +{ + return *instance_.get(); +} + +int HmfsIo::DevRead(void *buf, uint64_t offset, size_t len) +{ + if (cmdPara_.sparseMode) { + return SparseReadBlk(offset / HMFS_BLKSIZE, len / HMFS_BLKSIZE, buf); + } + + int fd = GetDeviceFd(&offset); + if (fd < 0) { + return fd; + } + + /* err = 1: cache not available, fall back to non-cache R/W */ + /* err = 0: success, err=-1: I/O error */ + int err = Dcache::GetInstance().DcacheRead(fd, buf, (off64_t)offset, len); + if (err <= 0) { + return err; + } + if (pread64(fd, buf, len, offset) < 0) { + return -1; + } + return 0; +} + +int HmfsIo::DevReadAhead(uint64_t offset) +{ + int fd = GetDeviceFd(&offset); + if (fd < 0) + return fd; + + return 0; +} + +int HmfsIo::DevWrite(void *buf, uint64_t offset, size_t len) +{ + // if (g_hmfsConfig.dryRun) { + // return 0; + // } + + if (cmdPara_.sparseMode) { + return SparseWriteBlk(offset / HMFS_BLKSIZE, len / HMFS_BLKSIZE, buf); + } + + int fd = GetDeviceFd(&offset); + if (fd < 0) { + HMFS_DEBUG("failed to GetDeviceFd offset = %" PRIu64 "", offset); + return fd; + } + + /* + * DcacheUpdateCache() just update cache, won't do I/O. + * Thus even no error, we need normal non-cache I/O for actual write + */ + if (Dcache::GetInstance().DcacheUpdateCache(fd, buf, (off64_t)offset, len) < 0) { + HMFS_DEBUG("failed to DcacheUpdateCache"); + return -1; + } + + if (pwrite64(fd, buf, len, offset) < 0) { + HMFS_DEBUG("failed to pwrite64 offset = %" PRIu64 ", len = %zu, buf = %p, error = %s", + offset, len, buf, strerror(errno)); + return -1; + } + return 0; +} + +int HmfsIo::DevWriteBlock(void *buf, uint64_t blkAddr) +{ + return DevWrite(buf, blkAddr << HMFS_BLKSIZE_BITS, HMFS_BLKSIZE); +} + +int HmfsIo::DevWriteDump(void *buf, uint64_t offset, size_t len) +{ + if (pwrite64(g_hmfsConfig.dumpFd, buf, len, offset) < 0) { + return -1; + } + return 0; +} + +int HmfsIo::DevFill(void *buf, uint64_t offset, size_t len) +{ + if (cmdPara_.sparseMode) { + return SparseWriteZeroedBlk(offset / HMFS_BLKSIZE, len / HMFS_BLKSIZE); + } + + int fd = GetDeviceFd(&offset); + if (fd < 0) { + return fd; + } + + /* Only allow fill to zero */ + if (*((uint8_t*)buf)) { + return -1; + } + + if (pwrite64(fd, buf, len, offset) < 0) { + return -1; + } + return 0; +} + +int HmfsIo::DevFillBlock(void *buf, uint64_t blkAddr) +{ + return DevFill(buf, blkAddr << HMFS_BLKSIZE_BITS, HMFS_BLKSIZE); +} + +int HmfsIo::DevReadBlock(void *buf, uint64_t blkAddr) +{ + return DevRead(buf, blkAddr << HMFS_BLKSIZE_BITS, HMFS_BLKSIZE); +} + +int HmfsIo::DevReadaBlock(uint64_t blkAddr) +{ + return DevReadAhead(blkAddr << HMFS_BLKSIZE_BITS); +} + +int HmfsIo::DevReadVersion(void *buf, uint64_t offset, size_t len) +{ + if (cmdPara_.sparseMode) { + return 0; + } + + if (pread64(g_hmfsConfig.kd, buf, len, offset) < 0) { + return -1; + } + return 0; +} + + +#ifdef HAVE_SPARSE_SPARSE_H +int HmfsIo::SparseReadBlk(uint64_t block, int count, void *buf) +{ + char *out = buf; + uint64_t curBlock; + + for (int i = 0; i < count; ++i) { + curBlock = block + i; + if (blocks_[curBlock]) { + memcpy_s(out + (i * HMFS_BLKSIZE), HMFS_BLKSIZE, blocks_[curBlock], HMFS_BLKSIZE); + } else if (blocks_) { + memset(out + (i * HMFS_BLKSIZE), 0, HMFS_BLKSIZE); + } + } + return 0; +} + +int HmfsIo::SparseWriteBlk(uint64_t block, int count, const void *buf) +{ + uint64_t curBlock; + const char *in = buf; + + for (int i = 0; i < count; ++i) { + curBlock = block + i; + if (blocks_[curBlock] == zeroedBlock) { + blocks_[curBlock] = nullptr; + } + if (blocks_[curBlock] == nullptr) { + blocks_[curBlock] = calloc(1, HMFS_BLKSIZE); + if (blocks_[curBlock] == nullptr) { + return -ENOMEM; + } + } + memcpy_s(blocks_[curBlock], HMFS_BLKSIZE, in + (i * HMFS_BLKSIZE), HMFS_BLKSIZE); + } + return 0; +} + +int HmfsIo::SparseWriteZeroedBlk(uint64_t block, int count) +{ + uint64_t curBlock; + for (int i = 0; i < count; ++i) { + curBlock = block + i; + if (blocks_[curBlock]) { + continue; + } + blocks_[curBlock] = zeroedBlock; + } + return 0; +} + + +int SparseImportSegment(const void *data, int len, unsigned int block, unsigned int nrBlock) +{ + /* Ignore chunk headers, only write the data */ + if (nrBlock == 0 || len % HMFS_BLKSIZE) { + return 0; + } + + return HmfsIo::GetInstance().SparseWriteBlk(block, nrBlock, data); +} + +int HmfsIo::SparseMergeBlocks(uint64_t start, uint64_t num, int zero) +{ + if (zero) { + blocks_[start] = nullptr; + return sparse_file_add_fill(sparseFile_, 0x0, HMFS_BLKSIZE * num, start); + } + + char *buf = calloc(num, HMFS_BLKSIZE); + if (buf == nullptr) { + fprintf(stderr, "failed to alloc %llu\n", (unsigned long long)num * HMFS_BLKSIZE); + return -ENOMEM; + } + + for (uint64_t i = 0; i < num; i++) { + memcpy_s(buf + i * HMFS_BLKSIZE, HMFS_BLKSIZE, blocks_[start + i], HMFS_BLKSIZE); + free(blocks_[start + i]); + blocks_[start + i] = nullptr; + } + + /* free_sparse_blocks will release this buf. */ + blocks_[start] = buf; + + return sparse_file_add_data(sparseFile_, blocks_[start], HMFS_BLKSIZE * num, start); +} +#else +int HmfsIo::SparseReadBlk(uint64_t block, int count, void *buf) +{ + return 0; +} + +int HmfsIo::SparseWriteBlk(uint64_t block, int count, const void *buf) +{ + return 0; +} + +int HmfsIo::SparseWriteZeroedBlk(uint64_t block, int count) +{ + return 0; +} +#endif + +int HmfsIo::HmfsFsyncDevice() +{ +#ifdef HAVE_FSYNC + for (uint32_t id = 0; id < DeviceManager::GetInstance().GetDeviceCount(); id++) { + DeviceInfo* deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(id); + if (deviceInfo != nullptr) { + if (fsync(deviceInfo->fd) < 0) { + HMFS_ERROR("failed to do fsync for %s.", deviceInfo->path.c_str()); + return -1; + } + } + } +#endif + return 0; +} + +int HmfsIo::HmfsInitSparseFile() +{ +#ifdef HAVE_SPARSE_SPARSE_H + if (cmdPara_.func == MKFS) { + sparseFile_ = sparse_file_new(HMFS_BLOCK_SIZE, cmdPara_.deviceSize); + if (sparseFile_ == nullptr) { + return -1; + } + } else { + sparseFile_ = sparse_file_import(cmdPara_.devices[0].fd, true, false); + if (sparseFile_ == nullptr) { + return -1; + } + cmdPara_.deviceSize = sparse_file_len(sparseFile_, 0, 0); + cmdPara_.deviceSize &= (~((uint64_t)(HMFS_BLOCK_SIZE - 1))); + } + + if (sparse_file_block_size(sparseFile_) != HMFS_BLOCK_SIZE) { + HMFS_ERROR("Corrupted sparse file\n"); + return -1; + } + blocksCount_ = cmdPara_.deviceSize / HMFS_BLOCK_SIZE; + blocks_ = calloc(blocksCount_, sizeof(char *)); + if (blocks_ == nullptr) { + HMFS_ERROR("Calloc Failed for blocks!!!\n"); + return -1; + } + + zeroedBlock = calloc(1, HMFS_BLOCK_SIZE); + if (zeroedBlock == nullptr) { + HMFS_ERROR("Calloc Failed for zeroed block!!!\n"); + return -1; + } + + return sparse_file_foreach_chunk(sparseFile_, true, false, SparseImportSegment, nullptr); +#else + HMFS_ERROR("Sparse mode is not supported."); + return -1; +#endif +} + +void HmfsIo::HmfsReleaseSparseResource() +{ +#ifdef HAVE_SPARSE_SPARSE_H + if (cmdPara_.sparseMode) { + if (sparseFile_ != nullptr) { + sparse_file_destroy(sparseFile_); + sparseFile_ = nullptr; + } + for (int j = 0; j < blocksCount_; j++) { + free(blocks_[j]); + } + free(blocks_); + blocks_ = nullptr; + free(zeroedBlock); + zeroedBlock = nullptr; + } +#endif +} + +void HmfsIo::HmfsFinalizeDeviceSparse(int &ret) +{ +#ifdef HAVE_SPARSE_SPARSE_H + if (!cmdPara_.sparseMode) { + return; + } + + int64_t chunkStart = (blocks_[0] == nullptr) ? -1 : 0; + DeviceInfo* device = DeviceManager::GetInstance().GetDeviceInfo(0); + ASSERT(device != nullptr); + + if (cmdPara_.func != MKFS) { + sparse_file_destroy(sparseFile_); + ret = ftruncate(device->fd, 0); + ASSERT(!ret); + lseek(device->fd, 0, SEEK_SET); + sparseFile_ = sparse_file_new(HMFS_BLKSIZE, cmdPara_.deviceSize); + } + + for (uint64_t j = 0; j < blocksCount_; ++j) { + if (chunkStart != -1) { + if (j - chunkStart >= MAX_CHUNK_COUNT) { + ret = SparseMergeBlocks(chunkStart, j - chunkStart, 0); + ASSERT(!ret); + chunkStart = -1; + } + } + + if (chunkStart == -1) { + if (blocks_[j] == nullptr) { + continue; + } + + if (blocks_[j] == zeroedBlock) { + ret = SparseMergeBlocks(j, 1, 1); + ASSERT(!ret); + } else { + chunkStart = j; + } + } else { + if (blocks_[j] && blocks_[j] != zeroedBlock) { + continue; + } + + ret = SparseMergeBlocks(chunkStart, j - chunkStart, 0); + ASSERT(!ret); + + if (blocks_[j] == zeroedBlock) { + ret = SparseMergeBlocks(j, 1, 1); + ASSERT(!ret); + } + chunkStart = -1; + } + } + if (chunkStart != -1) { + ret = SparseMergeBlocks(chunkStart, blocksCount_ - chunkStart, 0); + ASSERT(!ret); + } + + sparse_file_write(sparseFile_, device->fd, /*gzip*/0, /*sparse*/1, /*crc*/0); + + HmfsReleaseSparseResource(); +#endif +} + +int HmfsIo::HmfsFinalizeDevice() +{ + int ret = 0; + HmfsFinalizeDeviceSparse(ret); + /* + * We should call fsync() to flush out all the dirty pages + * in the block device page cache. + */ + for (uint32_t id = 0; id < DeviceManager::GetInstance().GetDeviceCount(); id++) { + DeviceInfo* device = DeviceManager::GetInstance().GetDeviceInfo(id); + if (device == nullptr) { + continue; + } + +#ifdef HAVE_FSYNC + ret = fsync(device->fd); + if (ret < 0) { + HMFS_ERROR("Could not conduct fsync."); + break; + } +#endif + ret = close(device->fd); + if (ret < 0) { + HMFS_ERROR("Failed to close device file."); + break; + } + } + + return ret; +} +} // namespace HMFS \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_io.h b/tools/hmfs-tools/tools/common/hmfs_io.h new file mode 100755 index 0000000..194ea0f --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_io.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HMFS_IO_H__ +#define __HMFS_IO_H__ + +#include +#include "hmfs_command.h" +#include "hmfs_define.h" + +#ifndef HAVE_LSEEK64 +typedef off_t off64_t; +#endif + +namespace OHOS::Hmfs { +/* ---------- dev_cache, Least Used First (LUF) policy ------------------- */ +/* + * Least used block will be the first victim to be replaced when max hash + * collision exceeds + */ +class Dcache { +public: + static Dcache& GetInstance(); + static void DcacheInit(); + static void DcacheRelease(); + + int DcacheUpdateCache(int fd, void *buf, off64_t offset, size_t count); + int DcacheRead(int fd, void *buf, off64_t offset, size_t count); + +private: + Dcache() = default; + + static void DcachePrintStatistics(); + inline char *DcacheAddr(long entry); + inline long DcacheRelocate(long entry, int n); + long DcacheFind(off64_t blk); + int DcacheIoRead(int fd, long entry, off64_t offset, off64_t blk); + int DcacheUpdateRw(int fd, void *buf, off64_t offset, size_t byteCount, bool isWrite); + int DcacheAllocAll(long n); + void DcacheRelocateInit(); + + static inline bool *dcacheValid; /* is the cached block valid? */ + static inline off64_t *dcacheBlk; /* which block it cached */ + static inline uint64_t *dcacheLastused; /* last used ticks for cache entries */ + static inline char *dcacheBuf; /* cached block data */ + static inline uint64_t dcacheUsetick; /* current use tick */ + static inline uint64_t dcacheRaccess; + static inline uint64_t dcacheRhit; + static inline uint64_t dcacheRmiss; + static inline uint64_t dcacheRreplace; + static inline bool dcacheExitRegistered = false; + static inline bool dcacheInitialized = false; + + /* + * Shadow config: + * + * Active set of the configurations. + * Global configuration 'dcacheConfig' will be transferred here when + * when DcacheInit() is called + */ + static inline DevCacheConfig dcacheConfig = {0, 16, 1}; + + static inline long dcacheRelocateOffset0[] = { + 20, -20, 40, -40, 80, -80, 160, -160, + 320, -320, 640, -640, 1280, -1280, 2560, -2560, + }; + static inline int dcacheRelocateOffset[16]; +}; + +#ifdef HAVE_SPARSE_SPARSE_H + int SparseImportSegment(const void *data, int len, unsigned int block, unsigned int nrBlock); +#endif + +class HmfsIo { +public: + int DevRead(void *buf, uint64_t offset, size_t len); + int DevReadAhead(uint64_t offset); + int DevWrite(void *buf, uint64_t offset, size_t len); + int DevWriteBlock(void *buf, uint64_t blkAddr); + int DevWriteDump(void *buf, uint64_t offset, size_t len); + + /* All bytes in the buffer must be 0 use DevFill(). */ + int DevFill(void *buf, uint64_t offset, size_t len); + int DevFillBlock(void *buf, uint64_t blkAddr); + int DevReadBlock(void *buf, uint64_t blkAddr); + int DevReadaBlock(uint64_t blkAddr); + int DevReadVersion(void *buf, uint64_t offset, size_t len); + +#ifdef HAVE_SPARSE_SPARSE_H + int SparseReadBlk(uint64_t block, int count, void *buf); + int SparseWriteBlk(uint64_t block, int count, const void *buf); + int SparseWriteZeroedBlk(uint64_t block, int count); + int SparseMergeBlocks(uint64_t start, uint64_t num, int zero); + +#else + int SparseReadBlk(uint64_t block, int count, void *buf); + int SparseWriteBlk(uint64_t block, int count, const void *buf); + int SparseWriteZeroedBlk(uint64_t block, int count); +#endif + int HmfsFsyncDevice(); + int HmfsInitSparseFile(); + void HmfsReleaseSparseResource(); + int HmfsFinalizeDevice(); + + static void CreateInstance(CmdConfig &cfgPara); + static HmfsIo& GetInstance(); + HmfsIo(CmdConfig& cmdPara) : cmdPara_(cmdPara) {} + +private: + static std::unique_ptr instance_; + CmdConfig& cmdPara_; + void HmfsFinalizeDeviceSparse(int &ret); +#ifdef HAVE_SPARSE_SPARSE_H + char **blocks_ = nullptr; + char *zeroedBlock = nullptr; + struct sparse_file *sparseFile_ = nullptr; + uint64_t blocksCount_; +#endif +}; +} + +#endif \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_quota.h b/tools/hmfs-tools/tools/common/hmfs_quota.h new file mode 100755 index 0000000..ff051e3 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_quota.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HMFS_QUOTA_H__ +#define __HMFS_QUOTA_H__ + +#include +// #include "hmfs_define.h" + +namespace OHOS::Hmfs { + +namespace { +/* + * Definitions of magics and versions of current quota files + */ +constexpr std::array INIT_QUOTA_MAGICS = { + 0xd9c01f11, /* USRQUOTA */ + 0xd9c01927, /* GRPQUOTA */ + 0xd9c03f14 /* PRJQUOTA */ +}; + + + +} + + +enum quota_type { + USRQUOTA = 0, + GRPQUOTA = 1, + PRJQUOTA = 2, + MAXQUOTAS = 3, +}; + +#define QUOTA_USR_BIT (1 << USRQUOTA) +#define QUOTA_GRP_BIT (1 << GRPQUOTA) +#define QUOTA_PRJ_BIT (1 << PRJQUOTA) +#define QUOTA_ALL_BIT (QUOTA_USR_BIT | QUOTA_GRP_BIT | QUOTA_PRJ_BIT) + +#define QUOTA_DATA_BLOCK_COUNT 2 + +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ +#define DEFAULT_PROJECT_ID 0 /* default project ID */ + + +struct DiskQuotaHeader { + uint32_t dqhMagic; /* Magic number identifying file */ + uint32_t dqhVersion; /* File version */ +}; + +/* Header with type and version specific information */ +struct DiskQuotaInfo { + uint32_t dqiBgrace; /* Time before block soft limit becomes hard limit */ + uint32_t dqiIgrace; /* Time before inode soft limit becomes hard limit */ + uint32_t dqiFlags; /* Flags for quotafile (DQF_*) */ + uint32_t dqiBlocks; /* Number of blocks in file */ + uint32_t dqiFreeBlk; /* Number of first free block in the list */ + uint32_t dqiFreeEntry; /* Number of block with at least one free entry */ +}; + +struct DiskQuotaBlock { + uint32_t dqbId; /* id this quota applies to */ + uint32_t dqbPad; + uint64_t dqbIhardlimit; /* absolute limit on allocated inodes */ + uint64_t dqbIsoftlimit; /* preferred inode limit */ + uint64_t dqbCurinodes; /* current # allocated inodes */ + uint64_t dqbBhardlimit; /* absolute limit on disk space + * (in QUOTABLOCK_SIZE) */ + uint64_t dqbBsoftlimit; /* preferred limit on disk space + * (in QUOTABLOCK_SIZE) */ + uint64_t dqbCurspace; /* current space occupied (in bytes) */ + uint64_t dqbBtime; /* time limit for excessive disk use */ + uint64_t dqbItime; /* time limit for excessive inode use */ +}; + + +} // namespace OHOS::Hmfs +#endif \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_utils.h b/tools/hmfs-tools/tools/common/hmfs_utils.h new file mode 100755 index 0000000..b2fed66 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_utils.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_UTILS_H +#define HMFS_UTILS_H + +// #include "hilog/log.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifndef HMFS_FILE_NAME +#define HMFS_FILE_NAME (strrchr((__FILE__), '/') ? strrchr((__FILE__), '/') + 1 : (__FILE__)) +#endif + +#define HMFS_DOMAIN (0xD002C00 + 0x12) +#ifndef HMFS_LABEL +#define HMFS_LABEL "HMFS_TOOLS" +#endif + +#undef LOG_TAG +#define LOG_TAG HMFS_LABEL +#undef LOG_DOMAIN +#define LOG_DOMAIN HMFS_DOMAIN + +// #define HMFS_LOGI(fmt, ...) \ +// HILOG_INFO(LOG_CORE, "[%{public}s:%{public}d]" fmt, (HMFS_FILE_NAME), (__LINE__), ##__VA_ARGS__) +// #define HMFS_LOGE(fmt, ...) \ +// HILOG_ERROR(LOG_CORE, "[%{public}s:%{public}d]" fmt, (HMFS_FILE_NAME), (__LINE__), ##__VA_ARGS__) +// #define HMFS_LOGD(fmt, ...) \ +// HILOG_DEBUG(LOG_CORE, "[%{public}s:%{public}d]" fmt, (HMFS_FILE_NAME), (__LINE__), ##__VA_ARGS__) +// #define HMFS_LOGW(fmt, ...) \ +// HILOG_WARN(LOG_CORE, "[%{public}s:%{public}d]" fmt, (HMFS_FILE_NAME), (__LINE__), ##__VA_ARGS__) +// #define HMFS_LOGF(fmt, ...) \ +// HILOG_FATAL(LOG_CORE, "[%{public}s:%{public}d]" fmt, (HMFS_FILE_NAME), (__LINE__), ##__VA_ARGS__) + +#define HMFS_PRINT(fmt, ...) \ + printf(fmt "\n", ##__VA_ARGS__) + +#define HMFS_OUTPUT(level, fmt, ...) \ + printf(fmt, ##__VA_ARGS__) + +#define HMFS_INFO(fmt, ...) \ + printf("[%s:%d]Info: " fmt "\n", (__FILE__), (__LINE__), ##__VA_ARGS__) + +#define HMFS_ERROR(fmt, ...) \ + printf("[%s:%d]Error: " fmt "\n", (__FILE__), (__LINE__), ##__VA_ARGS__) + +#define HMFS_DEBUG(fmt, ...) \ + printf("[%s:%d]Debug: " fmt "\n", (__FILE__), (__LINE__), ##__VA_ARGS__) + +#define HMFS_MINOR_DEBUG(fmt, ...) \ + printf("[%s:%d]Debug: " fmt "\n", (__FILE__), (__LINE__), ##__VA_ARGS__) + +#define HMFS_TRIVIAL_DEBUG(fmt, ...) \ + printf("[%s:%d]Debug: " fmt "\n", (__FILE__), (__LINE__), ##__VA_ARGS__) + +#define HMFS_CHECK(retCode, exper, fmt, ...) \ + if (!(retCode)) { \ + HMFS_LOGE(fmt, ##__VA_ARGS__); \ + exper; \ + } + +#define HMFS_CHECK_ONLY_EXPER(retCode, exper) \ + if (!(retCode)) { \ + exper; \ + } \ + +#define HMFS_CHECK_ONLY_LOG(retCode, fmt, ...) \ + if (!(retCode)) { \ + HMFS_LOGE(fmt, ##__VA_ARGS__); \ + } + +#ifdef __cplusplus +} +#endif // __cplusplus + + +#endif // HMFS_UTILS_H \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_zoned.cpp b/tools/hmfs-tools/tools/common/hmfs_zoned.cpp new file mode 100755 index 0000000..241c4d4 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_zoned.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmfs_zoned.h" + +#include +#include +#include +#ifdef HAVE_LINUX_LIMITS_H +#include +#endif +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif +#include +#include +#include +#include + +#include "securec.h" +#include "config.h" +#include "hmfs_utils.h" + + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + + +namespace OHOS::Hmfs { + +extern hmfs_configuration g_hmfsConfig; + +HmfsZoned& HmfsZoned::GetInstance() +{ + static HmfsZoned instance; + return instance; +} + +#ifdef HAVE_LINUX_BLKZONED_H + +int HmfsZoned::GetSysFsPath(std::string& devPath, const std::string& attr, std::string& filePath) +{ + struct stat statbuf; + if (stat(devPath.c_str(), &statbuf) < 0) { + return -1; + } + + int32_t majorNum = major(statbuf.st_rdev); + int32_t minorNum = minor(statbuf.st_rdev); + std::string sysBlockPath = "/sys/dev/block/" + std::to_string(majorNum) + ":" + std::to_string(minorNum); + + char linkBuf[PATH_MAX]; + ssize_t len = readlink(sysBlockPath.c_str(), linkBuf, sizeof(linkBuf) - 1); + if (len < 0) { + return -1; + } + linkBuf[len] = '\0'; + std::string resolvedPath(linkBuf); + + std::string sysfsPath = "/sys/dev/block/" + resolvedPath; + std::string partitionPath = sysfsPath + "/partition"; + if (std::filesystem::exists(partitionPath)) { + auto lastSlash = sysfsPath.find_last_of('/'); + if (lastSlash == std::string::npos) { + return -1; + } + sysfsPath = sysfsPath.substr(0, lastSlash); + } + + filePath = sysfsPath + "/" + attr; + return 0; +} + +int HmfsZoned::HmfsGetZonedModel(DeviceInfo *dev) +{ + /* Check that this is a zoned block device */ + std::string filePath; + int res = GetSysFsPath(dev->path, "queue/zoned", filePath); + if (res != 0) { + HMFS_INFO("can't find /sys, assuming normal block device."); + dev->zonedModel = HMFS_ZONED_NONE; + return 0; + } + + std::ifstream file(filePath, std::ifstream::in); + if (!file) { + dev->zonedModel = HMFS_ZONED_NONE; + return 0; + } + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + content.erase(std::remove(content.begin(), content.end(), '\n'), content.end()); + if (content == "none") { + /* Regular block device */ + dev->zonedModel = HMFS_ZONED_NONE; + } else if (content == "host-aware") { + /* Host-aware zoned block device: can be randomly written */ + dev->zonedModel = HMFS_ZONED_HA; + } else if (content == "host-managed") { + /* Host-managed zoned block device: sequential writes needed */ + dev->zonedModel = HMFS_ZONED_HM; + } else { + HMFS_ERROR("Unsupported device zoned model"); + return -1; + } + + return 0; +} + +uint32_t HmfsZoned::HmfsGetZoneChunkSectors(DeviceInfo *dev) +{ + std::string filePath; + int res = GetSysFsPath(dev->path, "queue/chunk_sectors", filePath); + if (res != 0) { + HMFS_ERROR("\tError: Failed to get device sysfs attribute path\n"); + return 0; + } + + std::ifstream file(filePath, std::ifstream::in); + if (!file) { + return 0; + } + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + content.erase(std::remove(content.begin(), content.end(), '\n'), content.end()); + uint32_t sectors = atoi(content.c_str()); + return sectors; +} + +int HmfsZoned::HmfsGetZoneBlocks(DeviceInfo *dev) +{ + /* Get zone size */ + dev->zoneBlocks = 0; + + uint64_t sectors = HmfsGetZoneChunkSectors(dev); + if (sectors == 0) { + return -1; + } + + dev->zoneSize = sectors << SECTOR_SHIFT; + dev->zoneBlocks = sectors >> (HMFS_BLKSIZE_BITS - SECTOR_SHIFT); + sectors = dev->zoneSize / dev->sectorSize; + + /* + * Total number of zones: there may + * be a last smaller runt zone. + */ + dev->nrZones = dev->sectorCount / sectors; + if (dev->sectorCount % sectors) { + dev->nrZones++; + } + + return 0; +} + +int HmfsZoned::HmfsReportZone(int i, uint64_t sector, BlockZone *blkzone) +{ + int ret = -1; + auto report = std::make_unique(); + OneZoneReport *rep = report.get(); + if (!report) { + HMFS_ERROR("No memory for report zones\n"); + return -ENOMEM; + } + memset_s(rep, sizeof(OneZoneReport), 0, sizeof(OneZoneReport)); + rep->rep.sector = sector; + rep->rep.nrZones = 1; + + ret = ioctl(g_hmfsConfig.devices[i].fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + HMFS_ERROR("ioctl BLKREPORTZONE failed: errno=%d\n", errno); + return ret; + } + + *blkzone = rep->zone; + return ret; +} + +int HmfsZoned::HmfsReportZones(int j, ReportZonesCb *reportZonesCb, void *opaque) +{ + StructDeviceInfo *dev = g_hmfsConfig.devices + j; + BlockZone *blkz = nullptr; + unsigned int n = 0; + uint64_t totalSectors = (dev->totalSectors * g_hmfsConfig.sectorSize) >> SECTOR_SHIFT; + uint64_t sector = 0; + int ret = -1; + + auto report = std::make_unique(HMFS_REPORT_ZONES_BUFSZ); + BlockZoneReport *rep = reinterpret_cast(report.get()); + if (rep == nullptr) { + HMFS_ERROR("No memory for report zones\n"); + return -ENOMEM; + } + + while (sector < totalSectors) { + /* Get zone info */ + rep->sector = sector; + rep->nrZones = (HMFS_REPORT_ZONES_BUFSZ - sizeof(BlockZoneReport)) / sizeof(BlockZone); + + ret = ioctl(dev->fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + HMFS_ERROR("ioctl BLKREPORTZONE failed: errno=%d\n", errno); + return ret; + } + + if (rep->nrZones == 0) { + ret = -EIO; + HMFS_ERROR("Unexpected ioctl BLKREPORTZONE result\n"); + return ret; + } + + blkz = reinterpret_cast(rep + 1); + for (unsigned int i = 0; i < rep->nrZones; i++) { + ret = reportZonesCb(n, blkz, opaque); + if (ret != 0) { + return ret; + } + sector = BLK_ZONE_SECTOR(blkz) + BLK_ZONE_LENGTH(blkz); + n++; + blkz++; + } + } + return ret; +} + +int HmfsZoned::HmfsCheckZonesPart(DeviceInfo *dev, BlockZoneReport *rep, + uint64_t §or, uint64_t &totalSectors, unsigned int &n) +{ + int lastIsConv = 1; + BlockZone *blkz = nullptr; + while (sector < totalSectors) { + /* Get zone info */ + memset_s(rep, HMFS_REPORT_ZONES_BUFSZ, 0, HMFS_REPORT_ZONES_BUFSZ); + rep->sector = sector; + rep->nrZones = (HMFS_REPORT_ZONES_BUFSZ - sizeof(BlockZoneReport)) / sizeof(BlockZone); + + int ret = ioctl(dev->fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + return ret; + } + + if (rep->nrZones == 0) { + break; + } + + blkz = reinterpret_cast(rep + 1); + for (unsigned int i = 0; i < rep->nrZones && sector < totalSectors; i++) { + if (BLK_ZONE_COND(blkz) == BLK_ZONE_COND_READONLY || BLK_ZONE_COND(blkz) == BLK_ZONE_COND_OFFLINE) { + lastIsConv = 0; + } + + if (BLK_ZONE_CONV(blkz) || BLK_ZONE_SEQ_PREF(blkz)) { + if (lastIsConv) { + dev->nrRndZones++; + } + } else { + lastIsConv = 0; + } + + if (BLK_ZONE_CONV(blkz)) { + HMFS_MINOR_DEBUG("Zone %05u: Conventional, cond 0x%x (%s), sector %llu, %llu sectors\n", + n, BLK_ZONE_COND(blkz), BlkZoneCondStr(blkz), BLK_ZONE_SECTOR(blkz), BLK_ZONE_LENGTH(blkz)); + dev->zoneCapBlocks[n] = BLK_ZONE_LENGTH(blkz) >> (HMFS_BLKSIZE_BITS - SECTOR_SHIFT); + } else { + HMFS_MINOR_DEBUG("Zone %05u: type 0x%x (%s), cond 0x%x (%s), need_reset %d, nonSeq %d, sector %llu," + " %llu sectors, capacity %llu, wp sector %llu\n", + n, BLK_ZONE_TYPE(blkz), BlkZoneTypeStr(blkz), BLK_ZONE_COND(blkz), + BlkZoneCondStr(blkz), BLK_ZONE_NEED_RESET(blkz), BLK_ZONE_NON_SEQ(blkz), + BLK_ZONE_SECTOR(blkz), BLK_ZONE_LENGTH(blkz), BLK_ZONE_CAPACITY(blkz, rep->flags), + BLK_ZONE_WP_SECTOR(blkz)); + dev->zoneCapBlocks[n] = BLK_ZONE_CAPACITY(blkz, rep->flags) >> (HMFS_BLKSIZE_BITS - SECTOR_SHIFT); + } + + sector = BLK_ZONE_SECTOR(blkz) + BLK_ZONE_LENGTH(blkz); + n++; + blkz++; + } + } + return 0; +} + +int HmfsZoned::HmfsCheckZones(DeviceInfo *dev) +{ + uint64_t sector = 0; + unsigned int n = 0; + int ret = -1; + + auto report = std::make_unique(HMFS_REPORT_ZONES_BUFSZ); + BlockZoneReport *rep = reinterpret_cast(report.get()); + if (rep == nullptr) { + HMFS_ERROR("No memory for report zones\n"); + return -ENOMEM; + } + + dev->zoneCapBlocks = std::make_unique(dev->nrZones); + if (!dev->zoneCapBlocks) { + HMFS_ERROR("No memory for zone capacity list.\n"); + return -ENOMEM; + } + memset_s(dev->zoneCapBlocks.get(), (dev->nrZones * sizeof(size_t)), 0, (dev->nrZones * sizeof(size_t))); + + dev->nrRndZones = 0; + + uint64_t totalSectors = (dev->sectorCount * g_hmfsConfig.sectorSize) >> 9; + ret = HmfsCheckZonesPart(dev, rep, sector, totalSectors, n); + if (ret < 0) { + HMFS_ERROR("ioctl BLKREPORTZONE failed\n"); + return ret; + } + + if (sector != totalSectors) { + HMFS_ERROR("Invalid zones: last sector reported is %llu, expected %llu\n", + (unsigned long long)(sector << 9) / g_hmfsConfig.sectorSize, + (unsigned long long)dev->sectorCount); + ret = -1; + return ret; + } + + if (n != dev->nrZones) { + HMFS_ERROR("Inconsistent number of zones: expected %u zones, got %u\n", dev->nrZones, n); + ret = -1; + return ret; + } + + /* + * For a multi-device volume, fixed position metadata blocks are + * stored * only on the first device of the volume. Checking for the + * presence of * conventional zones (randomly writeabl zones) for + * storing these blocks * on a host-managed device is thus needed only + * for the device index 0. + */ + if (dev->isMetaDevice && dev->zonedModel == HMFS_ZONED_HM && dev->nrRndZones == 0) { + HMFS_ERROR("No conventional zone for super block\n"); + ret = -1; + } + return ret; +} + +int HmfsZoned::HmfsResetZone(int i, void *blkzone) +{ + BlockZone *blkz = static_cast(blkzone); + StructDeviceInfo *dev = g_hmfsConfig.devices + i; + blk_zone_range range; + int ret; + + if (!BLK_ZONE_SEQ(blkz) || BLK_ZONE_EMPTY(blkz)) { + return 0; + } + + /* Non empty sequential zone: reset */ + range.sector = BLK_ZONE_SECTOR(blkz); + range.nr_sectors = BLK_ZONE_LENGTH(blkz); + ret = ioctl(dev->fd, BLKRESETZONE, &range); + if (ret != 0) { + ret = -errno; + HMFS_ERROR("ioctl BLKRESETZONE failed: errno=%d\n", errno); + } + + return ret; +} + +int HmfsZoned::HmfsResetZones(DeviceInfo *deviceInfo) +{ + auto buf = std::make_unique(HMFS_REPORT_ZONES_BUFSZ); + if (buf == nullptr) { + HMFS_ERROR("Not enough memory for reset zones."); + return -1; + } + + BlockZoneReport* report = reinterpret_cast(buf.get()); + uint64_t sector = 0; + uint64_t sectorCount = (deviceInfo->sectorCount * deviceInfo->sectorSize) / DEFAULT_SECTOR_SIZE; + while (sector < sectorCount) { + /* Get zone info */ + memset_s(report, HMFS_REPORT_ZONES_BUFSZ, 0, HMFS_REPORT_ZONES_BUFSZ); + report->sector = sector; + report->nrZones = (HMFS_REPORT_ZONES_BUFSZ - sizeof(BlockZoneReport)) / sizeof(BlockZone); + int32_t ret = ioctl(deviceInfo->fd, BLKREPORTZONE, report); + if (ret != 0) { + HMFS_ERROR("ioctl BLKREPORTZONES failed"); + return -1; + } + + if (report->nrZones == 0) { + break; + } + + BlockZone* blockZone = reinterpret_cast(report + 1); + for (uint32_t i = 0; i < report->nrZones && sector < sectorCount; i++) { + if (BLK_ZONE_SEQ(blockZone) && !BLK_ZONE_EMPTY(blockZone)) { + /* Non empty sequential zone: reset */ + struct blk_zone_range range; + range.sector = BLK_ZONE_SECTOR(blockZone); + range.nr_sectors = BLK_ZONE_LENGTH(blockZone); + ret = ioctl(deviceInfo->fd, BLKRESETZONE, &range); + if (ret != 0) { + HMFS_ERROR("Failed to perform ioctl BLKREPORTZONES"); + return -1; + } + } + sector = BLK_ZONE_SECTOR(blockZone) + BLK_ZONE_LENGTH(blockZone); + blockZone++; + } + } + + HMFS_INFO("Discarded %" PRIu64 " MB", (sector * DEFAULT_SECTOR_SIZE) / (1024 * 1024)); + return 0; +} + +uint32_t HmfsZoned::HmfsGetUsableSegments(SuperBlockData *superBlock) +{ +#ifdef HAVE_BLK_ZONE_REP_V2 + CmdConfig& cfgPara = CmdParser::GetSingleton()->GetCmdConfig(); + if (cfgPara.func == RESIZE) { + return GetLeValue(superBlock->segmentCountInMain); + } + + uint32_t usableSegs = 0; + for (uint32_t i = 0; i < DeviceManager::GetInstance().GetDeviceCount(); i++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(i); + ASSERT(deviceInfo != nullptr); + + if (deviceInfo->zonedModel <= HMFS_ZONED_HM) { + usableSegs += deviceInfo->segmentCount; + continue; + } + for (uint32_t j = 0; j < deviceInfo->nrZones; j++) { + usableSegs += AlignUpCount(deviceInfo->zoneCapBlocks[j], BLOCKS_PER_SEGMENT); + } + } + usableSegs -= (GetLeValue(superBlock->mainBlkId) - GetLeValue(superBlock->segment0BlkId)) >> + GetLeValue(superBlock->logBlksPerSeg); + return usableSegs; +#else + return GetLeValue(superBlock->segmentCountInMain); +#endif +} + + +const char *HmfsZoned::BlkZoneTypeStr(BlockZone *blkz) +{ + switch (BLK_ZONE_TYPE(blkz)) { + case BLK_ZONE_TYPE_CONVENTIONAL: + return "Conventional"; + case BLK_ZONE_TYPE_SEQWRITE_REQ: + return "Sequential-write-required"; + case BLK_ZONE_TYPE_SEQWRITE_PREF: + return "Sequential-write-preferred"; + default: + return "Unknown-type"; + } +} + +const char *HmfsZoned::BlkZoneCondStr(BlockZone *blkz) +{ + switch (BLK_ZONE_COND(blkz)) { + case BLK_ZONE_COND_NOT_WP: + return "Not-write-pointer"; + case BLK_ZONE_COND_EMPTY: + return "Empty"; + case BLK_ZONE_COND_IMP_OPEN: + return "Implicit-open"; + case BLK_ZONE_COND_EXP_OPEN: + return "Explicit-open"; + case BLK_ZONE_COND_CLOSED: + return "Closed"; + case BLK_ZONE_COND_READONLY: + return "Read-only"; + case BLK_ZONE_COND_FULL: + return "Full"; + case BLK_ZONE_COND_OFFLINE: + return "Offline"; + default: + return "Unknown-cond"; + } +} + +#else + +int HmfsZoned::HmfsReportZone(int i, uint64_t sector, BlockZone *blkzone) +{ + HMFS_ERROR("%d: Unsupported zoned block device\n", i); + return -1; +} + +int HmfsZoned::HmfsReportZones(int i, ReportZonesCb *reportZonesCb, void *opaque) +{ + HMFS_ERROR("%d: Unsupported zoned block device\n", i); + return -1; +} + +int HmfsZoned::HmfsGetZonedModel(DeviceInfo* dev) +{ + // StructDeviceInfo *dev = g_hmfsConfig.devices + i; + + g_hmfsConfig.zonedMode = 0; + dev->zonedModel = HMFS_ZONED_NONE; + return 0; +} + +int HmfsZoned::HmfsGetZoneBlocks(DeviceInfo* dev) +{ + // StructDeviceInfo *dev = g_hmfsConfig.devices + i; + + g_hmfsConfig.zonedMode = 0; + dev->nrZones = 0; + dev->zoneBlocks = 0; + dev->zonedModel = HMFS_ZONED_NONE; + + return 0; +} + +int HmfsZoned::HmfsCheckZones(DeviceInfo* dev) +{ + HMFS_ERROR("Unsupported zoned block device\n"); + return -1; +} + +int HmfsZoned::HmfsResetZone(int i, void *blkzone) +{ + HMFS_ERROR("%d: Unsupported zoned block device\n", i); + return -1; +} + +int HmfsZoned::HmfsResetZones(DeviceInfo *deviceInfo) +{ + HMFS_ERROR("%d: Unsupported zoned block device\n", i); + return -1; +} + +uint32_t HmfsZoned::HmfsGetUsableSegments(SuperBlockData *sb) +{ + return GetLeValue(sb->segmentCountInMain); +} +#endif +} \ No newline at end of file diff --git a/tools/hmfs-tools/tools/common/hmfs_zoned.h b/tools/hmfs-tools/tools/common/hmfs_zoned.h new file mode 100755 index 0000000..fb506e9 --- /dev/null +++ b/tools/hmfs-tools/tools/common/hmfs_zoned.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HMFS_ZONED_H__ +#define __HMFS_ZONED_H__ + +#include +#include "hmfs_define.h" +#include "device_manager.h" + + +namespace OHOS::Hmfs { +#define HMFS_ZONED_NONE 0 +#define HMFS_ZONED_HA 1 +#define HMFS_ZONED_HM 2 + +typedef int (ReportZonesCb)(int i, void *, void *); + +#ifdef HAVE_LINUX_BLKZONED_H + +#define HMFS_REPORT_ZONES_BUFSZ 524288 +/* Let's just use v2, since v1 should be compatible with v2 */ +#define BLK_ZONE_REP_CAPACITY (1 << 0) + +struct BlockZone { + uint64_t start; /* Zone start sector */ + uint64_t len; /* Zone length in number of sectors */ + uint64_t wp; /* Zone write pointer position */ + uint8_t type; /* Zone type */ + uint8_t cond; /* Zone condition */ + uint8_t nonSeq; /* Non-sequential write resources active */ + uint8_t reset; /* Reset write pointer recommended */ + uint8_t resv[4]; + uint64_t capacity; /* Zone capacity in number of sectors */ + uint8_t reserved[24]; +}; + +struct BlockZoneReport { + uint64_t sector; + uint32_t nrZones; + uint32_t flags; + struct BlockZone zones[0]; +}; + +#define BLK_ZONE_TYPE(z) (z)->type +#define BLK_ZONE_CONV(z) ((z)->type == BLK_ZONE_TYPE_CONVENTIONAL) +#define BLK_ZONE_SEQ_REQ(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_REQ) +#define BLK_ZONE_SEQ_PREF(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_PREF) +#define BLK_ZONE_SEQ(z) (BLK_ZONE_SEQ_REQ(z) || BLK_ZONE_SEQ_PREF(z)) +#define BLK_ZONE_COND(z) (z)->cond + +/* + * Handle kernel zone capacity support + */ +#define BLK_ZONE_EMPTY(z) (BLK_ZONE_COND(z) == BLK_ZONE_COND_EMPTY) +#define BLK_ZONE_SECTOR(z) (z)->start +#define BLK_ZONE_LENGTH(z) (z)->len +#define BLK_ZONE_WP_SECTOR(z) (z)->wp +#define BLK_ZONE_NEED_RESET(z) (int)(z)->reset +#define BLK_ZONE_NON_SEQ(z) (int)(z)->nonSeq +#define BLK_ZONE_CAPACITY(z, f) ((f & BLK_ZONE_REP_CAPACITY) ? (z)->capacity : (z)->len) + +struct OneZoneReport { + BlockZoneReport rep; + BlockZone zone; +}; +#endif +struct BlockZone; + +class HmfsZoned { +public: + static HmfsZoned& GetInstance(); +#ifdef HAVE_LINUX_BLKZONED_H + int GetSysFsPath(std::string& devPath, const std::string& attr, std::string& filePath); + uint32_t HmfsGetZoneChunkSectors(DeviceInfo *dev); +#endif + int HmfsResetZones(DeviceInfo *deviceInfo); + int HmfsGetZonedModel(DeviceInfo *dev); + int HmfsGetZoneBlocks(DeviceInfo *dev); + int HmfsCheckZones(DeviceInfo *dev); + int HmfsResetZone(int i, void *blkzone); + uint32_t HmfsGetUsableSegments(SuperBlockData *sb); + int HmfsReportZone(int i, uint64_t sector, BlockZone *blkzone); + int HmfsReportZones(int j, ReportZonesCb *reportZonesCb, void *opaque); + +private: + HmfsZoned() = default; +#ifdef HAVE_LINUX_BLKZONED_H + int HmfsCheckZonesPart(DeviceInfo *dev, BlockZoneReport *rep, + uint64_t §or, uint64_t &totalSectors, unsigned int &n); + const char *BlkZoneTypeStr(BlockZone *blkz); + const char *BlkZoneCondStr(BlockZone *blkz); +#endif +}; +} // namespace OHOS::Hmfs +#endif \ No newline at end of file diff --git a/tools/hmfs-tools/tools/mkfs/BUILD.gn b/tools/hmfs-tools/tools/mkfs/BUILD.gn new file mode 100755 index 0000000..647a36e --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/BUILD.gn @@ -0,0 +1,60 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +ohos_executable("mkfs.hmfs") { + cflags = [ + "-Wno-incompatible-pointer-types", + "-Wno-unused-function", + "-Wno-unused-parameter", + "-Wno-format", + ] + + sources = [ + "src/cp_writer.cpp", + "src/main_writer.cpp", + "src/mkfs_command.cpp", + "src/mkfs_format.cpp", + "src/nat_writer.cpp", + "src/sit_writer.cpp", + "src/super_block_writer.cpp", + ] + + include_dirs = [ + "include/", + "${hmfs_tools_path}/common", + ] + + deps = [ + "${hmfs_tools_path}/common:libhmfs", + ] + + external_deps = [ + "bounds_checking_function:libsec_shared", + ] + public_external_deps = [ + "e2fsprogs:libext2_uuid", + ] + + defines = [ "HAVE_CONFIG_H" ] + + install_enable = true + install_images = [ + "system", + "updater", + ] + subsystem_name = "thirdparty" + part_name = "hmfs-tools" +} diff --git a/tools/hmfs-tools/tools/mkfs/include/area_formater.h b/tools/hmfs-tools/tools/mkfs/include/area_formater.h new file mode 100755 index 0000000..510685e --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/area_formater.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_AREA_FORMATER_H +#define HMFS_AREA_FORMATER_H + +#include +#include + +namespace OHOS { +namespace Hmfs { + +class HmfsDataAreaFormater { +public: + virtual ~HmfsDataAreaFormater() = default; + + virtual int32_t Prepare() = 0; + virtual int32_t Write() = 0; +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/cp_writer.h b/tools/hmfs-tools/tools/mkfs/include/cp_writer.h new file mode 100755 index 0000000..636a917 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/cp_writer.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_CP_WRITER_H +#define HMFS_CP_WRITER_H + +#include +#include +#include + +#include "area_formater.h" +#include "hmfs_data.h" +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +// union CpActiveSegments { +// struct { +// JournalEntry natJournal; +// JournalEntry sitJournal; +// SummaryEntry sum_entry; +// }; + +// uint8_t size[HMFS_BLOCK_SIZE]; +// }; + +union CpOnDisk { + struct CheckPointData cp; + uint8_t size[HMFS_BLOCK_SIZE]; +}; + + + + + + +class HmfsMkfs; +class CpWriter : public HmfsDataAreaFormater { +public: + CpWriter(HmfsMkfs* mkfs); + ~CpWriter() = default; + + int32_t Prepare(); + int32_t Write(); + +private: + HmfsMkfs* mkfs_; + std::unique_ptr cp_; + std::unique_ptr activeSegments_; + std::unique_ptr hotNodeSumary_; + std::unique_ptr warmColdNodeSumary_; + std::unique_ptr natBits_; + std::unique_ptr emptyBlock_; + uint64_t writeBlockId_ = 0; + uint32_t natBitmapSize_; + uint32_t natBitsAreablocks_; + + + int32_t InitBasicInfo(); + int32_t ClacCheckSum(); + int32_t PrepareCheckPointData(); + void MakeCheckPointCrc(); + int32_t PrepareActiveSegments(); + int32_t PrepareNodeSummary(); + int32_t PrepareNatBit(); + int32_t PrepareEmptyBlock(); + int32_t WriteCpStruct(); + int32_t WriteCpPayload(); + int32_t WriteActiveSegments(); + int32_t WriteNatBit(); + + +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/main_writer.h b/tools/hmfs-tools/tools/mkfs/include/main_writer.h new file mode 100755 index 0000000..844643e --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/main_writer.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_MAIN_WRITER_H +#define HMFS_MAIN_WRITER_H + +#include +#include +#include + +#include "area_formater.h" +#include "hmfs_data.h" +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +union NodeOnDisk { + struct NodeData node; + uint8_t size[HMFS_BLOCK_SIZE]; +}; + + +class HmfsMkfs; +class MainAreaWriter : public HmfsDataAreaFormater { +public: + MainAreaWriter(HmfsMkfs* mkfs); + ~MainAreaWriter() = default; + + int32_t Prepare(); + int32_t Write(); + +private: + HmfsMkfs* mkfs_; + std::unique_ptr rootInode_; + std::unique_ptr dentryBlk_; + + int32_t PrepareRootInode(); + int32_t WriteRootInode(); + int32_t WriteLpfInode(); + uint32_t WriteDefaultLpfDentry(); + + int32_t DiscardObsoleteDnode(); + int32_t PrepareDefaultDentryRoot(); + int32_t WriteDentryBlock(); + uint64_t GetTimeStamp(); + int32_t WriteQfInodes(); + int32_t WriteQfInode(int32_t qtype, uint32_t offset); + int32_t WriteDefaultQuotaData(int32_t qtype, uint64_t dataBlkId, uint32_t id); + +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/mkfs_command.h b/tools/hmfs-tools/tools/mkfs/include/mkfs_command.h new file mode 100755 index 0000000..ea6c1b8 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/mkfs_command.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_MKFS_COMMAND_H +#define HMFS_MKFS_COMMAND_H + +#include +#include +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +class MkfsCmdParser : public CmdParser { +public: + ~MkfsCmdParser() = default; + + static MkfsCmdParser& GetInstance() + { + static MkfsCmdParser instance; + return instance; + } + int32_t Parse(int32_t argc, char *argv[]); + +private: + MkfsCmdParser(); + MkfsCmdParser(const MkfsCmdParser&) = delete; + MkfsCmdParser& operator=(const MkfsCmdParser&) = delete; + void ConfigOptionPacket(void); + void ConfigDefaultOption(void); + bool CheckOptions(void); + void ShowCmdInfo(void); + void ShowCmdUsage(void); + ArgParseResult ProcessHeapBasedAlloc(const std::string& argValue); + ArgParseResult ShowVersion(const std::string& argValue); + ArgParseResult ProcessDeviceList(const std::string& argValue); + ArgParseResult ProcessColdFileExt(const std::string& argValue); + ArgParseResult ProcessHotFileExt(const std::string& argValue); + ArgParseResult ProcessForceOverwrite(const std::string& argValue); + ArgParseResult ProcessDefaultOptionSet(const std::string& argValue); + ArgParseResult ProcessHelp(const std::string& argValue); + ArgParseResult ProcessVolumeLabel(const std::string& argValue); + ArgParseResult ProcessZonedMode(const std::string& argValue); + ArgParseResult ProcessQuietMode(const std::string& argValue); + ArgParseResult ProcessSrandSeed(const std::string& argValue); + ArgParseResult ProcessRootOwner(const std::string& argValue); + ArgParseResult ProcessSegsPerSection(const std::string& argValue); + ArgParseResult ProcessSparseMode(const std::string& argValue); + ArgParseResult ProcessDiscardPolicy(const std::string& argValue); + ArgParseResult ProcessTimestamp(const std::string& argValue); + ArgParseResult ProcessUuid(const std::string& argValue); + ArgParseResult ProcessWantedSectorSize(const std::string& argValue); + ArgParseResult ProcessSectionsPerZone(const std::string& argValue); + + CmdConfig cmdPara_; +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/mkfs_format.h b/tools/hmfs-tools/tools/mkfs/include/mkfs_format.h new file mode 100755 index 0000000..2ab0ffb --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/mkfs_format.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_MKFS_FORMAT_H +#define HMFS_MKFS_FORMAT_H + +#include +#include +#include + +#include "hmfs_data.h" +#include "hmfs_command.h" +#include "area_formater.h" +#include "super_block_writer.h" + +namespace OHOS { +namespace Hmfs { + +struct HmfsData { + // std::vector deviceList; + + uint32_t sectorSize; + uint32_t sectorsPerBlk = DEFAULT_SECTORS_PER_BLK; + uint32_t segsPerZone = 1; + uint64_t sectorCount = 0; + uint32_t startSector = 0; + size_t blocksPerZone; + + uint64_t zoneAlignStartOffset; + uint32_t segment0BlkId; + + uint32_t segmentCount = 0; + uint32_t zoneAlignedSegCount; + uint32_t segmentCountInCP = HMFS_CP_COUNT; + + uint32_t sitStartBlkId; + uint32_t segmentCountInSIT; + + uint32_t natStartBlkId; + uint32_t segmentCountInNAT; + + uint32_t cpPayload; + + uint32_t segmentCountInSSA; + + uint32_t mainStartBlkId; + uint32_t sectionCount; + uint32_t segmentCountInMain; + + uint32_t reservedSegments; + uint32_t nodeInode = 1; + uint32_t metaInode = 2; + uint32_t rootInode = 3; + uint32_t nextFreeInodeId = 4; + uint32_t qf_ino[MAXQUOTAS]; + uint32_t quotaInodeCount = 0; + uint32_t quotaDataBlks = 0; + uint32_t lpfIno = 0; + uint32_t lpfInum = 0; + uint32_t lpfDnum = 0; + uint32_t chksumSeed = 0; + int32_t zonedModel; + + char version[VERSION_TOTAL_LEN + 1]; + uint32_t curSeg[CURSEG_TYPE_MAX]; +}; + +class HmfsMkfs { +public: + HmfsMkfs(CmdConfig &cfgPara); + ~HmfsMkfs() = default; + int32_t Process(); + +private: + friend class CpWriter; + friend class MainAreaWriter; + friend class NatWriter; + friend class SitWriter; + friend class SuperBlockWriter; + + CmdConfig &cfgPara_; + HmfsData hmfsData_; + // SuperBlockWriter superBlockWriter; + std::vector> areaFormaters_; + + inline uint32_t PreviousZone(uint32_t curSegType) + { + return hmfsData_.curSeg[curSegType] - hmfsData_.segsPerZone; + } + + inline uint32_t NextZone(uint32_t curSegType) + { + return hmfsData_.curSeg[curSegType] + hmfsData_.segsPerZone; + } + + inline uint32_t LastZone(uint32_t zoneCount) + { + return (zoneCount - 1) * hmfsData_.segsPerZone; + } + + inline uint32_t LastSection(uint32_t zoneId) + { + return zoneId + (cfgPara_.sectionsPerZone - 1) * cfgPara_.segsPerSection; + } + + int32_t Format(); + int32_t ClacHmfsData(); + void VerifyCurSegData(void); + int32_t CreateDeviceInfo(); + void CreateFormaters(); + int32_t GetDeviceSectorInfo(); + SuperBlockData* GetSuperBlockData(); + int32_t OverwriteDevices(); + int32_t GetZoneInfo(); + +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/nat_writer.h b/tools/hmfs-tools/tools/mkfs/include/nat_writer.h new file mode 100755 index 0000000..11b5b66 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/nat_writer.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_NAT_WRITER_H +#define HMFS_NAT_WRITER_H + +#include +#include +#include + +#include "area_formater.h" +#include "hmfs_data.h" +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +union NatBlockOnDisk { + struct natBlockData natBlock; + uint8_t size[HMFS_BLOCK_SIZE]; +}; + + +class HmfsMkfs; +class NatWriter : public HmfsDataAreaFormater { +public: + NatWriter(HmfsMkfs* mkfs); + ~NatWriter() = default; + + int32_t Prepare(); + int32_t Write(); + +private: + HmfsMkfs* mkfs_; + std::unique_ptr natBlock_; +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/sit_writer.h b/tools/hmfs-tools/tools/mkfs/include/sit_writer.h new file mode 100755 index 0000000..7ca2c17 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/sit_writer.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_SIT_WRITER_H +#define HMFS_SIT_WRITER_H + +#include +#include +#include + +#include "area_formater.h" +#include "hmfs_data.h" +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +class HmfsMkfs; +class SitWriter : public HmfsDataAreaFormater { +public: + SitWriter(HmfsMkfs* mkfs); + ~SitWriter() = default; + + int32_t Prepare(); + int32_t Write(); + +private: + HmfsMkfs* mkfs_; +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/include/super_block_writer.h b/tools/hmfs-tools/tools/mkfs/include/super_block_writer.h new file mode 100755 index 0000000..e32cba7 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/include/super_block_writer.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_SUPER_BLOCK_WRITER_H +#define HMFS_SUPER_BLOCK_WRITER_H + +#include +#include +#include + +#include "config.h" +#include "area_formater.h" +#include "hmfs_data.h" +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +union SuperBlockOnDisk { + struct { + uint8_t empty[HMFS_SUPER_BLOCK_OFFSET]; + struct SuperBlockData superBlock; + }; + uint8_t size[HMFS_BLOCK_SIZE]; +}; + +class HmfsMkfs; +class SuperBlockWriter : public HmfsDataAreaFormater { +public: + SuperBlockWriter(HmfsMkfs* mkfs); + ~SuperBlockWriter() = default; + + int32_t Prepare(); + int32_t Write(); + +private: + friend class HmfsMkfs; + + int32_t InitBasicInfo(); + int32_t ClacCheckSum(); + int32_t FillSuperBlockData(); + void FillExtList(); + bool IsExtensionDuplicate(std::string& ext); + int32_t UpdateHmfsData(); + + HmfsMkfs* mkfs_; + std::unique_ptr superBlock_; +}; + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/mkfs/src/cp_writer.cpp b/tools/hmfs-tools/tools/mkfs/src/cp_writer.cpp new file mode 100755 index 0000000..78173b0 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/cp_writer.cpp @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "cp_writer.h" + +#include +#include +#include + +#include "hmfs_utils.h" +#include "mkfs_format.h" +#include "securec.h" +#include "device_manager.h" +#include "hmfs_define.h" +#include "hmfs_io.h" +#include "hmfs_common.h" +#include "hmfs_quota.h" +#include "hmfs_zoned.h" + + +namespace OHOS { +namespace Hmfs { + +CpWriter::CpWriter(HmfsMkfs *mkfs) : mkfs_(mkfs) +{ + +} + +int32_t CpWriter::Prepare() +{ + if (PrepareCheckPointData()) { + return -1; + } + + if (PrepareActiveSegments()) { + return -1; + } + + if (PrepareNodeSummary()) { + return -1; + } + + if (PrepareNatBit()) { + return -1; + } + + if (PrepareEmptyBlock()) { + return -1; + } + + return 0; +} + +int32_t CpWriter::PrepareCheckPointData() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + HmfsData& hmfsData = mkfs_->hmfsData_; + + cp_ = std::make_unique(); + if (cp_ == nullptr) { + return -1; + } + memset_s(cp_.get(), sizeof(CpOnDisk), 0, sizeof(CpOnDisk)); + struct CheckPointData* checkPoint = &cp_->cp; + + uint32_t segNo = 0; + SetLeValue(checkPoint->curNodeSegNo[segNo], hmfsData.curSeg[CURSEG_NODE_HOT]); + SetLeValue(checkPoint->curDataSegNo[segNo++], hmfsData.curSeg[CURSEG_DATA_HOT]); + SetLeValue(checkPoint->curNodeSegNo[segNo], hmfsData.curSeg[CURSEG_NODE_WARM]); + SetLeValue(checkPoint->curDataSegNo[segNo++], hmfsData.curSeg[CURSEG_DATA_WARM]); + SetLeValue(checkPoint->curNodeSegNo[segNo], hmfsData.curSeg[CURSEG_NODE_COLD]); + SetLeValue(checkPoint->curDataSegNo[segNo++], hmfsData.curSeg[CURSEG_DATA_COLD]); + for (; segNo < HMFS_MAX_ACTIVE_NODE_LOGS; segNo++) { + SetLeValue(checkPoint->curNodeSegNo[segNo], 0xffffffff); + SetLeValue(checkPoint->curDataSegNo[segNo], 0xffffffff); + } + + SetLeValue(checkPoint->curNodeBlkOffset[0], 1 + hmfsData.quotaInodeCount + hmfsData.lpfInum); + SetLeValue(checkPoint->curDataBlkOffset[0], 1 + hmfsData.quotaDataBlks + hmfsData.lpfDnum); + SetLeValue(checkPoint->validBlockCount, 2 + hmfsData.quotaInodeCount + hmfsData.quotaDataBlks + hmfsData.lpfInum + hmfsData.lpfDnum); + SetLeValue(checkPoint->rsvdSegmentCount, hmfsData.reservedSegments); + + struct SuperBlockData* superBlock = mkfs_->GetSuperBlockData(); + ASSERT(superBlock != nullptr); + uint32_t usableSegments = HmfsZoned::GetInstance().HmfsGetUsableSegments(superBlock); + uint32_t overprovSegmentCount = (usableSegments - hmfsData.reservedSegments) * + cfgPara.overProvision / 100 + hmfsData.reservedSegments; + SetLeValue(checkPoint->overprovSegmentCount, overprovSegmentCount); + + if (usableSegments <= overprovSegmentCount) { + HMFS_ERROR("Not enough segments to create HMFS Volume\n"); + return -1; + } + HMFS_INFO("Overprovision ratio = %.3lf%%\n", cfgPara.overProvision); + HMFS_INFO("Overprovision segments = %u (GC reserved = %u)\n", overprovSegmentCount, hmfsData.reservedSegments); + + uint32_t freeSegmentCount = usableSegments - ((cfgPara.features & HMFS_FEATURE_RO) ? 2 : 6); + SetLeValue(checkPoint->freeSegmentCount, freeSegmentCount); + SetLeValue(checkPoint->userBlockCount, (usableSegments - overprovSegmentCount) * BLOCKS_PER_SEGMENT); + + /* cp page (2), data summaries (1), node summaries (3) */ + SetLeValue(checkPoint->cpPackBlockCount, 6 + hmfsData.cpPayload); + + natBitmapSize_ = hmfsData.segmentCountInNAT / 2 * 512 / 8; + natBitsAreablocks_ = AlignUpCount(sizeof(uint64_t) + natBitmapSize_ + natBitmapSize_, HMFS_BLOCK_SIZE); + + uint32_t flags = CP_FLAG_UMOUNT | CP_FLAG_COMPACT_SUM; + if (GetLeValue(checkPoint->cpPackBlockCount) <= BLOCKS_PER_SEGMENT - natBitsAreablocks_) { + flags |= CP_FLAG_NAT_BITS; + } + + if (cfgPara.trim) { + flags |= CP_TRIMMED_FLAG; + } + + if (cfgPara.largeNatBitmap) { + flags |= CP_LARGE_NAT_BITMAP_FLAG; + } + + SetLeValue(checkPoint->cpFlags, flags); + SetLeValue(checkPoint->cpPackStartSum, 1 + hmfsData.cpPayload); + SetLeValue(checkPoint->validNodeCount, 1 + hmfsData.quotaInodeCount + hmfsData.lpfInum); + SetLeValue(checkPoint->validInodeCount, 1 + hmfsData.quotaInodeCount + hmfsData.lpfInum); + SetLeValue(checkPoint->nextFreeNodeId, hmfsData.nextFreeInodeId); + SetLeValue(checkPoint->sitVersionBitmapSize, + (hmfsData.segmentCountInSIT / HMFS_SIT_COUNT) * BLOCKS_PER_SEGMENT / BITS_PER_BYTE); + SetLeValue(checkPoint->natVersionBitmapSize, + (hmfsData.segmentCountInNAT / HMFS_NAT_COUNT) * BLOCKS_PER_SEGMENT / BITS_PER_BYTE); + + srand(cfgPara.fakeSeed ? 0 : time(NULL)); + SetLeValue(checkPoint->cpVersion, rand() | 0x1); + HMFS_DEBUG("checkPoint->cpVersion = %" PRIx64 "", checkPoint->cpVersion); + + return 0; +} + +void CpWriter::MakeCheckPointCrc() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + struct CheckPointData* checkPoint = &cp_->cp; + uint32_t checksumOffset = cfgPara.largeNatBitmap ? CP_MIN_CHKSUM_OFFSET : CP_CHECKSUM_OFFSET; + SetLeValue(checkPoint->checksumOffset, checksumOffset); + + uint32_t crc = HmfsCommon::GetInstance().HmfsCheckpointChksum(checkPoint); + HMFS_DEBUG("CP crc = 0x%x", crc); + SetLeValue(*((uint32_t *)((uint8_t *)checkPoint + checksumOffset)), crc); +} + +int32_t CpWriter::PrepareActiveSegments() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + CmdConfig& cfgPara = mkfs_->cfgPara_; + struct CheckPointData* checkPoint = &cp_->cp; + + activeSegments_ = std::make_unique(HMFS_BLOCK_SIZE); + if (activeSegments_ == nullptr) { + return -1; + } + memset_s(activeSegments_.get(), HMFS_BLOCK_SIZE, 0, HMFS_BLOCK_SIZE); + + JournalEntry* natJournal = reinterpret_cast(activeSegments_.get()); + uint32_t entryIndex = 0; + SetLeValue(natJournal->nNats, 1 + hmfsData.quotaInodeCount + hmfsData.lpfInum); + SetLeValue(natJournal->natJ.entries[entryIndex].nid, hmfsData.rootInode); + natJournal->natJ.entries[entryIndex].ne.version = 0; + natJournal->natJ.entries[entryIndex].ne.inodeNo = natJournal->natJ.entries[entryIndex].nid; + SetLeValue(natJournal->natJ.entries[entryIndex].ne.blockId, + hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT); + entryIndex++; + + struct SuperBlockData* superBlock = mkfs_->GetSuperBlockData(); + if (superBlock == nullptr) { + return -1; + } + + for (int32_t qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (!((1 << qtype) & cfgPara.quotaBits)) { + continue; + } + + natJournal->natJ.entries[entryIndex].nid = superBlock->qfInodeId[qtype]; + natJournal->natJ.entries[entryIndex].ne.version = 0; + natJournal->natJ.entries[entryIndex].ne.inodeNo = superBlock->qfInodeId[qtype]; + SetLeValue(natJournal->natJ.entries[entryIndex].ne.blockId, + hmfsData.mainStartBlkId + checkPoint->curNodeSegNo[0] * BLOCKS_PER_SEGMENT + entryIndex); + entryIndex++; + } + + if (hmfsData.lpfInum) { + natJournal->natJ.entries[entryIndex].nid = NATIVE_TO_LE32(hmfsData.lpfIno); + natJournal->natJ.entries[entryIndex].ne.version = 0; + natJournal->natJ.entries[entryIndex].ne.inodeNo = NATIVE_TO_LE32(hmfsData.lpfIno); + SetLeValue(natJournal->natJ.entries[entryIndex].ne.blockId, + hmfsData.mainStartBlkId + checkPoint->curNodeSegNo[0] * BLOCKS_PER_SEGMENT + entryIndex); + } + + JournalEntry* sitJournal = natJournal + 1; + SetLeValue(sitJournal->nSits, (cfgPara.features & HMFS_FEATURE_RO) ? 2 : 6); + sitJournal->sitJ.entries[0].segno = checkPoint->curNodeSegNo[0]; + SetLeValue(sitJournal->sitJ.entries[0].se.usedBlockCount, + (CURSEG_NODE_HOT << 10) + 1 + hmfsData.quotaInodeCount + hmfsData.lpfInum); + + uint32_t bitId = 0; + HmfsCommon::GetInstance().HmfsSetBit(bitId++, (char *)sitJournal->sitJ.entries[0].se.blockBitmap); + for (uint32_t i = 0; i < hmfsData.quotaInodeCount; i++) { + HmfsCommon::GetInstance().HmfsSetBit(bitId++, (char *)sitJournal->sitJ.entries[0].se.blockBitmap); + } + if (hmfsData.lpfInum) { + HmfsCommon::GetInstance().HmfsSetBit(bitId, (char *)sitJournal->sitJ.entries[0].se.blockBitmap); + } + + if (cfgPara.features & HMFS_FEATURE_RO) { + /* data sit for root */ + sitJournal->sitJ.entries[1].segno = checkPoint->curDataSegNo[0]; + SetLeValue(sitJournal->sitJ.entries[1].se.usedBlockCount, + (CURSEG_DATA_HOT << 10) | (1 + hmfsData.quotaDataBlks + hmfsData.lpfDnum)); + bitId = 0; + HmfsCommon::GetInstance().HmfsSetBit(bitId++, (char *)sitJournal->sitJ.entries[1].se.blockBitmap); + for (uint32_t i = 0; i < hmfsData.quotaDataBlks; i++) { + HmfsCommon::GetInstance().HmfsSetBit(bitId++, (char *)sitJournal->sitJ.entries[1].se.blockBitmap); + } + if (hmfsData.lpfDnum) { + HmfsCommon::GetInstance().HmfsSetBit(bitId, (char *)sitJournal->sitJ.entries[1].se.blockBitmap); + } + } else { + sitJournal->sitJ.entries[1].segno = checkPoint->curNodeSegNo[1]; + SetLeValue(sitJournal->sitJ.entries[1].se.usedBlockCount, CURSEG_NODE_WARM << 10); + sitJournal->sitJ.entries[2].segno = checkPoint->curNodeSegNo[2]; + SetLeValue(sitJournal->sitJ.entries[2].se.usedBlockCount, CURSEG_NODE_COLD << 10); + + /* data sit for root */ + sitJournal->sitJ.entries[3].segno = checkPoint->curDataSegNo[0]; + SetLeValue(sitJournal->sitJ.entries[3].se.usedBlockCount, + (CURSEG_DATA_HOT << 10) | (1 + hmfsData.quotaDataBlks + hmfsData.lpfDnum)); + + bitId = 0; + HmfsCommon::GetInstance().HmfsSetBit(bitId++, (char *)sitJournal->sitJ.entries[3].se.blockBitmap); + for (uint32_t i = 0; i < hmfsData.quotaDataBlks; i++) { + HmfsCommon::GetInstance().HmfsSetBit(bitId++, (char *)sitJournal->sitJ.entries[3].se.blockBitmap); + } + if (hmfsData.lpfDnum) { + HmfsCommon::GetInstance().HmfsSetBit(bitId, (char *)sitJournal->sitJ.entries[3].se.blockBitmap); + } + + sitJournal->sitJ.entries[4].segno = checkPoint->curDataSegNo[1]; + sitJournal->sitJ.entries[4].se.usedBlockCount = NATIVE_TO_LE32((CURSEG_DATA_WARM << 10)); + sitJournal->sitJ.entries[5].segno = checkPoint->curDataSegNo[2]; + sitJournal->sitJ.entries[5].se.usedBlockCount = NATIVE_TO_LE16((CURSEG_DATA_COLD << 10)); + } + + SummaryEntry* sum_entry = reinterpret_cast(sitJournal + 1); + SetLeValue(sum_entry->nid, hmfsData.rootInode); + sum_entry->ofsInNode = 0; + + uint32_t offset = 1; + for (int32_t qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (!((1 << qtype) & cfgPara.quotaBits)) { + continue; + } + + for (int32_t i = 0; i < QUOTA_DATA_BLOCK_COUNT; i++) { + (sum_entry + offset + i)->nid = superBlock->qfInodeId[qtype];; + (sum_entry + offset + i)->ofsInNode = NATIVE_TO_LE16(i); + } + offset += QUOTA_DATA_BLOCK_COUNT; + } + + if (hmfsData.lpfDnum) { + (sum_entry + offset)->nid = NATIVE_TO_LE32(hmfsData.lpfIno); + (sum_entry + offset)->ofsInNode = 0; + } + + return 0; +} + + +int32_t CpWriter::PrepareNodeSummary() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + HmfsData& hmfsData = mkfs_->hmfsData_; + struct SuperBlockData* superBlock = mkfs_->GetSuperBlockData(); + if (superBlock == nullptr) { + return -1; + } + + hotNodeSumary_ = std::make_unique(); + if (hotNodeSumary_ == nullptr) { + return -1; + } + memset_s(hotNodeSumary_.get(), sizeof(SummaryBlockData), 0, sizeof(SummaryBlockData)); + + hotNodeSumary_->footer.entryType = SUMMARY_TYPE_NODE; + + uint32_t id = 0; + SetLeValue(hotNodeSumary_->entries[id].nid, hmfsData.rootInode); + hotNodeSumary_->entries[id++].ofsInNode = 0; + for (int32_t qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (!((1 << qtype) & cfgPara.quotaBits)) { + continue; + } + + hotNodeSumary_->entries[id].nid = superBlock->qfInodeId[qtype]; + hotNodeSumary_->entries[id++].ofsInNode = 0; + } + if (hmfsData.lpfInum) { + hotNodeSumary_->entries[id].nid = NATIVE_TO_LE32(hmfsData.lpfIno); + hotNodeSumary_->entries[id].ofsInNode = 0; + } + + warmColdNodeSumary_ = std::make_unique(); + if (warmColdNodeSumary_ == nullptr) { + return -1; + } + memset_s(warmColdNodeSumary_.get(), sizeof(SummaryBlockData), 0, sizeof(SummaryBlockData)); + + warmColdNodeSumary_->footer.entryType = SUMMARY_TYPE_NODE; + + return 0; +} + +int32_t CpWriter::PrepareNatBit() +{ + struct CheckPointData* checkPoint = &cp_->cp; + + if (!(GetLeValue(checkPoint->cpFlags) & CP_FLAG_NAT_BITS)) { + return 0; + } + + /* +---------+------------------+-------------------+ + * | version | full nat bit map | empty nat bit map | + * +---------+------------------+-------------------+ + * uint64_t natBitmapSize_ natBitmapSize_ + * all zero + */ + uint32_t natBitAreaSize = HMFS_BLOCK_SIZE * natBitsAreablocks_; + natBits_ = std::make_unique(natBitAreaSize); + if (natBits_ == nullptr) { + return -1; + } + memset_s(natBits_.get(), natBitAreaSize, 0, natBitAreaSize); + + uint64_t* version = reinterpret_cast(natBits_.get()); + *version = HmfsCommon::GetInstance().GetCpCrc(checkPoint); + + uint8_t* emptyNatBitmap = natBits_.get() + sizeof(uint64_t) + natBitmapSize_; + memset_s(emptyNatBitmap, natBitmapSize_, 0xff, natBitmapSize_); + HmfsCommon::GetInstance().TestAndClearBitLe(0, emptyNatBitmap); + + return 0; +} + +int32_t CpWriter::PrepareEmptyBlock() +{ + emptyBlock_ = std::make_unique(HMFS_BLOCK_SIZE); + if (emptyBlock_ == nullptr) { + return -1; + } + memset_s(emptyBlock_.get(), HMFS_BLOCK_SIZE, 0, HMFS_BLOCK_SIZE); + return 0; +} + + +int32_t CpWriter::Write() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + + writeBlockId_ = hmfsData.segment0BlkId; + + MakeCheckPointCrc(); + if (WriteCpStruct()) { + return -1; + } + + if (WriteCpPayload()) { + return -1; + } + + if (WriteActiveSegments()) { + return -1; + } + + if (WriteCpStruct()) { + return -1; + } + + if (WriteNatBit()) { + return -1; + } + + // second segment + struct CheckPointData* checkPoint = &cp_->cp; + checkPoint->cpVersion = 0; + MakeCheckPointCrc(); + writeBlockId_ = hmfsData.segment0BlkId + BLOCKS_PER_SEGMENT; + if (WriteCpStruct()) { + return -1; + } + + if (WriteCpPayload()) { + return -1; + } + + writeBlockId_ += GetLeValue(checkPoint->cpPackBlockCount) - hmfsData.cpPayload - 2; + if (WriteCpStruct()) { + return -1; + } + + return 0; +} + +int32_t CpWriter::WriteCpStruct() +{ + if (HmfsIo::GetInstance().DevWriteBlock(cp_.get(), writeBlockId_)) { + HMFS_ERROR("failed to write the cp to disk"); + return -1; + } + writeBlockId_++; + + return 0; +} + +int32_t CpWriter::WriteCpPayload() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + + for (uint32_t i = 0; i < hmfsData.cpPayload; i++) { + if (HmfsIo::GetInstance().DevFillBlock(emptyBlock_.get(), writeBlockId_)) { + HMFS_ERROR("failed to write the sit bitmap area to disk"); + return -1; + } + writeBlockId_++; + } + + return 0; +} + +int32_t CpWriter::WriteActiveSegments() +{ + + if (HmfsIo::GetInstance().DevWriteBlock(activeSegments_.get(), writeBlockId_)) { + HMFS_ERROR("failed to write the activeSegments to disk, blockid = %" PRIu64 "", writeBlockId_); + return -1; + } + writeBlockId_++; + + // hot node summary + if (HmfsIo::GetInstance().DevWriteBlock(hotNodeSumary_.get(), writeBlockId_)) { + HMFS_ERROR("failed to write the hot Node Sumary to disk, blockid = %" PRIu64 "", writeBlockId_); + return -1; + } + writeBlockId_++; + + // warm node summary + if (HmfsIo::GetInstance().DevWriteBlock(warmColdNodeSumary_.get(), writeBlockId_)) { + HMFS_ERROR("failed to write the warm node summary to disk, blockid = %" PRIu64 "", writeBlockId_); + return -1; + } + writeBlockId_++; + + // cold node summary + if (HmfsIo::GetInstance().DevWriteBlock(warmColdNodeSumary_.get(), writeBlockId_)) { + HMFS_ERROR("failed to write the cold node summary to disk, blockid = %" PRIu64 "", writeBlockId_); + return -1; + } + writeBlockId_++; + + return 0; +} + +int32_t CpWriter::WriteNatBit() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + + writeBlockId_ = hmfsData.segment0BlkId + BLOCKS_PER_SEGMENT - natBitsAreablocks_; + + for (uint32_t i = 0; i < natBitsAreablocks_; i++) { + if (HmfsIo::GetInstance().DevWriteBlock(natBits_.get() + i * HMFS_BLOCK_SIZE, writeBlockId_)) { + HMFS_ERROR("failed to write NAT bits!\n"); + return -1; + } + writeBlockId_++; + } + return 0; +} + + + + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/mkfs/src/main_writer.cpp b/tools/hmfs-tools/tools/mkfs/src/main_writer.cpp new file mode 100755 index 0000000..43aceee --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/main_writer.cpp @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "main_writer.h" + +#include +#include +#include +#include + +#include "hmfs_utils.h" +#include "mkfs_format.h" +#include "securec.h" +#include "device_manager.h" +#include "hmfs_define.h" +#include "hmfs_encoding.h" +#include "hmfs_io.h" +#include "hmfs_common.h" +#include "hmfs_quota.h" + +namespace OHOS { +namespace Hmfs { + +MainAreaWriter::MainAreaWriter(HmfsMkfs *mkfs) : mkfs_(mkfs) +{ +} + +int32_t MainAreaWriter::Prepare() +{ + if (PrepareRootInode()) { + return -1; + } + + if (PrepareDefaultDentryRoot()) { + return -1; + } + + if (WriteRootInode()) { + return -1; + + } + if (WriteQfInodes()) { + return -1; + } + + if (WriteLpfInode()) { + return -1; + } + + if (DiscardObsoleteDnode()) { + return -1; + } + + if (WriteDentryBlock()) { + return -1; + } + + return 0; +} + +int32_t MainAreaWriter::PrepareRootInode() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + HmfsData& hmfsData = mkfs_->hmfsData_; + + rootInode_ = std::make_unique(); + if (rootInode_ == nullptr) { + return -1; + } + struct NodeData* rootInode = &rootInode_->node; + memset_s(rootInode, sizeof(NodeOnDisk), 0, sizeof(NodeOnDisk)); + + + SetLeValue(rootInode->footer.nid, hmfsData.rootInode); + rootInode->footer.ino = rootInode->footer.nid; + SetLeValue(rootInode->footer.cpVer, 1); + SetLeValue(rootInode->footer.nextBlkaddr, hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT + 1); + + SetLeValue(rootInode->i.iMode, 0x41ed); + SetLeValue(rootInode->i.iLinks, (hmfsData.lpfIno) ? 3 : 2); + SetLeValue(rootInode->i.iUid, cfgPara.rootUid); + SetLeValue(rootInode->i.iGid, cfgPara.rootGid); + SetLeValue(rootInode->i.iSize, HMFS_BLOCK_SIZE); /* dentry */ + SetLeValue(rootInode->i.iBlocks, 2); + SetLeValue(rootInode->i.iAtime, GetTimeStamp()); + rootInode->i.iAtimeNsec = 0; + SetLeValue(rootInode->i.iCtime, GetTimeStamp()); + rootInode->i.iCtimeNsec = 0; + SetLeValue(rootInode->i.iMtime, GetTimeStamp()); + rootInode->i.iMtimeNsec = 0; + rootInode->i.iGeneration = 0; + rootInode->i.iXattrNid = 0; + rootInode->i.iFlags = 0; + SetLeValue(rootInode->i.iCurrentDepth, 1); + SetLeValue(rootInode->i.iDirLevel, DEFAULT_DIR_LEVEL); + + if (cfgPara.features & HMFS_FEATURE_EXTRA_ATTR) { + rootInode->i.iInline = HMFS_EXTRA_ATTR; + SetLeValue(rootInode->i.iExtraIsize, HmfsCommon::GetInstance().CalcExtraIsize()); + } + + if (cfgPara.features & HMFS_FEATURE_PRJQUOTA) { + SetLeValue(rootInode->i.iProjid, DEFAULT_PROJECT_ID); + } + + if (cfgPara.features & HMFS_FEATURE_INODE_CRTIME) { + SetLeValue(rootInode->i.iCrtime, GetTimeStamp()); + rootInode->i.iCrtimeNsec = 0; + } + + if (cfgPara.features & HMFS_FEATURE_COMPRESSION) { + rootInode->i.iCompressAlgrithm = 0; + rootInode->i.iLogClusterSize = 0; + rootInode->i.iPadding = 0; + } + + uint32_t dataBlockCount = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_DATA_HOT] * BLOCKS_PER_SEGMENT; + SetLeValue(rootInode->i.i_addr[HmfsCommon::GetInstance().GetExtraIsize(&rootInode->i)], dataBlockCount); + + rootInode->i.iExt.fofs = 0; + rootInode->i.iExt.blkAddr = 0; + rootInode->i.iExt.len = 0; + + return 0; +} + +uint64_t MainAreaWriter::GetTimeStamp() +{ + if (mkfs_->cfgPara_.timeStamp == std::numeric_limits::max()) { + return time(NULL); + } else { + return mkfs_->cfgPara_.timeStamp; + } +} + +int32_t MainAreaWriter::Write() +{ + return 0; +} + +int32_t MainAreaWriter::WriteRootInode() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + + uint64_t blockId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT; + + HMFS_DEBUG("Writing root inode (hot node), 0x%x 0x%x at blockId 0x%" PRIx64 "", + hmfsData.mainStartBlkId, hmfsData.curSeg[CURSEG_NODE_HOT], blockId); + + if (HmfsCommon::GetInstance().WriteInode(&rootInode_->node, blockId, hmfsData.chksumSeed) < 0) { + HMFS_ERROR("failed to write the root inode to disk."); + return -1; + } + return 0; +} + +int32_t MainAreaWriter::WriteQfInodes() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + + uint32_t i = 0; + for (int32_t qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (!((1 << qtype) & cfgPara.quotaBits)) { + continue; + } + + if (WriteQfInode(qtype, i++)) { + HMFS_ERROR("Failed to write quota inode"); + } + } + + return 0; +} + +int32_t MainAreaWriter::WriteQfInode(int32_t qtype, uint32_t offset) +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + struct SuperBlockData* superBlock = mkfs_->GetSuperBlockData(); + if (superBlock == nullptr) { + return -1; + } + + auto nodeBuf = std::make_unique(); + if (nodeBuf == nullptr) { + HMFS_ERROR("not enough memory for quota inode"); + return -1; + } + struct NodeData* qfInode = &nodeBuf->node; + memset_s(qfInode, sizeof(NodeOnDisk), 0, sizeof(NodeOnDisk)); + + HmfsCommon::GetInstance().InitQfInode(qfInode, GetLeValue(superBlock->qfInodeId[qtype]), GetTimeStamp()); + + SetLeValue(qfInode->footer.nextBlkaddr, + hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT + 1 + qtype + 1); + SetLeValue(qfInode->i.iBlocks, 1 + QUOTA_DATA_BLOCK_COUNT); + + uint64_t dataBlkId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_DATA_HOT] * BLOCKS_PER_SEGMENT + 1 + + offset * QUOTA_DATA_BLOCK_COUNT; + uint32_t id = qfInode->i.iUid; + if (qtype == GRPQUOTA) { + id = qfInode->i.iGid; + } else if (qtype == PRJQUOTA) { + id = qfInode->i.iProjid; + } + + if (WriteDefaultQuotaData(qtype, dataBlkId, id)) { + return -1; + } + + for (uint32_t i = 0; i < QUOTA_DATA_BLOCK_COUNT; i++) { + SetLeValue(qfInode->i.i_addr[HmfsCommon::GetInstance().GetExtraIsize(&qfInode->i) + i], dataBlkId + i); + } + + uint64_t blockId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT + offset + 1; + + HMFS_DEBUG("Writing quota inode (hot node), 0x%x 0x%x 0x%x at blockId 0x%" PRIx64 ".", + hmfsData.mainStartBlkId, hmfsData.curSeg[CURSEG_HOT_NODE], BLOCKS_PER_SEGMENT, blockId); + + if (HmfsCommon::GetInstance().WriteInode(qfInode, blockId, hmfsData.chksumSeed) < 0) { + HMFS_ERROR("Failed to write the qfInode to disk."); + return -1; + } + + hmfsData.quotaInodeCount++; + + return 0; +} + +int32_t MainAreaWriter::WriteDefaultQuotaData(int32_t qtype, uint64_t dataBlkId, uint32_t id) +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + uint32_t bufLen = HMFS_BLOCK_SIZE * QUOTA_DATA_BLOCK_COUNT; + auto buf = std::make_unique(bufLen); + if (buf == nullptr) { + HMFS_ERROR("not enough memory for quota data"); + return -1; + } + memset_s(buf.get(), bufLen, 0, bufLen); + + /* basic quota header */ + DiskQuotaHeader* dqHeader = reinterpret_cast(buf.get()); + SetLeValue(dqHeader->dqhMagic, INIT_QUOTA_MAGICS[qtype]); + SetLeValue(dqHeader->dqhVersion, 1); /* only support QF_VFSV1 */ + + /* Initial quota file content */ + DiskQuotaInfo* dqInfo = reinterpret_cast(dqHeader + 1); + SetLeValue(dqInfo->dqiBgrace, MAX_DQ_TIME); + SetLeValue(dqInfo->dqiIgrace, MAX_IQ_TIME); + dqInfo->dqiFlags = 0; + SetLeValue(dqInfo->dqiBlocks, QT_TREEOFF + 5); + dqInfo->dqiFreeBlk = 0; + SetLeValue(dqInfo->dqiFreeEntry, 5); + + buf[1024] = 2; + buf[2048] = 3; + buf[3072] = 4; + buf[4096] = 5; + buf[5120 + 8] = 1; + + DiskQuotaBlock* dqBlock = reinterpret_cast(buf.get() + 5136); + dqBlock->dqbId = id; + dqBlock->dqbPad = 0; + dqBlock->dqbIhardlimit = 0; + dqBlock->dqbIsoftlimit = 0; + SetLeValue(dqBlock->dqbCurinodes, (hmfsData.lpfIno) ? 2 : 1); + dqBlock->dqbBhardlimit = 0; + dqBlock->dqbBsoftlimit = 0; + SetLeValue(dqBlock->dqbCurspace, (hmfsData.lpfIno) ? 8192 : 4096); + dqBlock->dqbBtime = 0; + dqBlock->dqbItime = 0; + + if (HmfsIo::GetInstance().DevWriteBlock(buf.get(), dataBlkId) || + HmfsIo::GetInstance().DevWriteBlock(buf.get() + HMFS_BLOCK_SIZE, dataBlkId + 1)) { + HMFS_ERROR("failed to write quota data block to disk."); + return -1; + } + HMFS_DEBUG("Writing quota data, at block 0x%" PRIx64 ", 0x%" PRIx64 ".", dataBlkId, dataBlkId + 1); + + hmfsData.quotaDataBlks += QUOTA_DATA_BLOCK_COUNT; + + return 0; +} + +int32_t MainAreaWriter::WriteLpfInode() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + CmdConfig& cfgPara = mkfs_->cfgPara_; + + if (!(cfgPara.features & HMFS_FEATURE_LOST_FOUND)) { + return 0; + } + + struct SuperBlockData* superBlock = mkfs_->GetSuperBlockData(); + if (superBlock == nullptr) { + return -1; + } + + auto nodeBuf = std::make_unique(); + if (nodeBuf == nullptr) { + HMFS_ERROR("not enough memory for lpf inode"); + return -1; + } + struct NodeData* lpfInode = &nodeBuf->node; + memset_s(lpfInode, sizeof(NodeOnDisk), 0, sizeof(NodeOnDisk)); + + lpfInode->footer.nid = NATIVE_TO_LE32(hmfsData.lpfIno); + lpfInode->footer.ino = lpfInode->footer.nid; + lpfInode->footer.cpVer = NATIVE_TO_LE64(1); + lpfInode->footer.nextBlkaddr = NATIVE_TO_LE32(hmfsData.mainStartBlkId + + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT + 1 + hmfsData.quotaInodeCount + 1); + + lpfInode->i.iMode = NATIVE_TO_LE16(0x41c0); /* 0700 */ + lpfInode->i.iLinks = NATIVE_TO_LE32(2); + lpfInode->i.iUid = NATIVE_TO_LE32(cfgPara.rootUid); + lpfInode->i.iGid = NATIVE_TO_LE32(cfgPara.rootGid); + + lpfInode->i.iSize = NATIVE_TO_LE64(HMFS_BLOCK_SIZE); + lpfInode->i.iBlocks = NATIVE_TO_LE64(2); + + lpfInode->i.iAtime = NATIVE_TO_LE32(GetTimeStamp()); + lpfInode->i.iAtimeNsec = 0; + lpfInode->i.iCtime = NATIVE_TO_LE32(GetTimeStamp()); + lpfInode->i.iCtimeNsec = 0; + lpfInode->i.iMtime = NATIVE_TO_LE32(GetTimeStamp()); + lpfInode->i.iMtimeNsec = 0; + lpfInode->i.iGeneration = 0; + lpfInode->i.iXattrNid = 0; + lpfInode->i.iFlags = 0; + lpfInode->i.iPino = NATIVE_TO_LE32(hmfsData.rootInode); + lpfInode->i.iNamelen = NATIVE_TO_LE32(strlen(LPF_STRING)); + memcpy_s(lpfInode->i.iName, HMFS_NAME_LEN, LPF_STRING, strlen(LPF_STRING)); + lpfInode->i.iCurrentDepth = NATIVE_TO_LE32(1); + lpfInode->i.iDirLevel = DEFAULT_DIR_LEVEL; + + if (cfgPara.features & HMFS_FEATURE_EXTRA_ATTR) { + lpfInode->i.iInline = HMFS_EXTRA_ATTR; + lpfInode->i.iExtraIsize = NATIVE_TO_LE16(HmfsCommon::GetInstance().CalcExtraIsize()); + } + + if (cfgPara.features & HMFS_FEATURE_PRJQUOTA) { + SetLeValue(lpfInode->i.iProjid, DEFAULT_PROJECT_ID); + } + + if (cfgPara.features & HMFS_FEATURE_INODE_CRTIME) { + SetLeValue(lpfInode->i.iCrtime, GetTimeStamp()); + lpfInode->i.iCrtimeNsec = 0; + } + + if (cfgPara.features & HMFS_FEATURE_COMPRESSION) { + lpfInode->i.iCompressAlgrithm = 0; + lpfInode->i.iLogClusterSize = 0; + lpfInode->i.iPadding = 0; + } + + uint32_t dataBlockId = WriteDefaultLpfDentry(); + if (dataBlockId == 0) { + HMFS_ERROR("Failed to add default dentries for lost+found"); + return -1; + } + lpfInode->i.i_addr[HmfsCommon::GetInstance().GetExtraIsize(&lpfInode->i)] = NATIVE_TO_LE32(dataBlockId); + + uint64_t blockId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT + + hmfsData.quotaInodeCount + 1; + + HMFS_DEBUG("Writing lost+found inode (hot node), 0x%x 0x%x 0x%x at offset 0x%" PRIx64 ".", + hmfsData.mainStartBlkId, hmfsData.curSeg[CURSEG_NODE_HOT], BLOCKS_PER_SEGMENT, blockId); + if (HmfsCommon::GetInstance().WriteInode(lpfInode, blockId, hmfsData.chksumSeed) < 0) { + HMFS_ERROR("Failed to write the lost+found inode to disk."); + return -1; + } + + hmfsData.lpfInum++; + return 0; +} + +uint32_t MainAreaWriter::WriteDefaultLpfDentry(void) +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + auto buf = std::make_unique(); + if (buf == nullptr) { + HMFS_ERROR("Not enough memory for lpf dentry block."); + return -1; + } + struct DentryBlock* dentryBlock = buf.get(); + memset_s(dentryBlock, sizeof(DentryBlock), 0, sizeof(DentryBlock)); + + std::vector defaultDirList = {".", ".."}; + for (size_t i = 0; i < defaultDirList.size(); i++) { + dentryBlock->dentry[i].hash_code = 0; + SetLeValue(dentryBlock->dentry[i].ino, (i == 0) ? hmfsData.lpfIno : hmfsData.rootInode); + SetLeValue(dentryBlock->dentry[i].nameLen, strlen(defaultDirList[i])); + dentryBlock->dentry[i].fileType = HMFS_FT_DIR; + memcpy_s(dentryBlock->filename[i], HMFS_SLOT_LEN, defaultDirList[i], strlen(defaultDirList[i])); + + HmfsCommon::GetInstance().TestAndSetBitLe(i, dentryBlock->dentryBitmap); + } + + uint64_t blockId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_DATA_HOT] * BLOCKS_PER_SEGMENT + 1 + + hmfsData.quotaDataBlks; + HMFS_DEBUG("Writing default dentry lost+found, at offset 0x%" PRIx64 ".", blockId); + if (HmfsIo::GetInstance().DevWriteBlock(dentryBlock, blockId)) { + HMFS_ERROR("Failed to write lost+found dentry block to disk."); + return 0; + } + + hmfsData.lpfDnum++; + return blockId; +} + +int32_t MainAreaWriter::DiscardObsoleteDnode() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + CmdConfig& cfgPara = mkfs_->cfgPara_; + + if (cfgPara.zonedMode || (cfgPara.features & HMFS_FEATURE_RO)) { + return 0; + } + + auto node = std::make_unique(); + if (node == nullptr) { + return -1; + } + + uint64_t start_inode_pos = hmfsData.mainStartBlkId; + uint64_t last_inode_pos = start_inode_pos + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT + + hmfsData.quotaInodeCount + hmfsData.lpfInum; + uint64_t endBlockId = hmfsData.mainStartBlkId + hmfsData.segmentCountInMain * BLOCKS_PER_SEGMENT; + uint64_t blockId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_WARM] * BLOCKS_PER_SEGMENT; + while ((blockId >= hmfsData.mainStartBlkId) && (blockId < endBlockId)) { + if (HmfsIo::GetInstance().DevReadBlock(node.get(), blockId)) { + HMFS_ERROR("failed to read block 0x%" PRIx64 " in traversing direct node", blockId); + return -1; + } + uint64_t nextBlockId = GetLeValue(node->footer.nextBlkaddr); + + HMFS_DEBUG("erasing direct node 0x%" PRIx64 "", blockId); + memset_s(node.get(), sizeof(NodeData), 0, sizeof(NodeData)); + if (HmfsIo::GetInstance().DevWriteBlock(node.get(), blockId)) { + HMFS_ERROR("failed to erase block 0x%" PRIx64 "", blockId); + return -1; + } + + if ((nextBlockId >= start_inode_pos) || (nextBlockId <= last_inode_pos)) { + break; + } + blockId = nextBlockId; + } + + return 0; +} + +int32_t MainAreaWriter::PrepareDefaultDentryRoot() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + + dentryBlk_ = std::make_unique(); + if (dentryBlk_ == nullptr) { + return -1; + } + struct DentryBlock* dentryBlk = dentryBlk_.get(); + memset_s(dentryBlk, sizeof(DentryBlock), 0, sizeof(DentryBlock)); + + std::vector defaultDirList = {".", ".."}; + uint32_t index = 0; + for (size_t i = 0; i < defaultDirList.size(); i++) { + dentryBlk->dentry[index].hash_code = 0; + SetLeValue(dentryBlk->dentry[index].ino, hmfsData.rootInode); + SetLeValue(dentryBlk->dentry[index].nameLen, strlen(defaultDirList[i])); + dentryBlk->dentry[index].fileType = HMFS_FT_DIR; + memcpy_s(dentryBlk->filename[index], HMFS_SLOT_LEN, defaultDirList[i], strlen(defaultDirList[i])); + + HmfsCommon::GetInstance().TestAndSetBitLe(index, dentryBlk->dentryBitmap); + index++; + } + + if (hmfsData.lpfIno) { + int len = strlen(LPF_STRING); + uint32_t hash = HmfsCommon::GetInstance().DentryHash(0, 0, (unsigned char *)LPF_STRING, len); + + dentryBlk->dentry[index].hash_code = NATIVE_TO_LE32(hash); + dentryBlk->dentry[index].ino = NATIVE_TO_LE32(hmfsData.lpfIno); + dentryBlk->dentry[index].nameLen = NATIVE_TO_LE16(len); + dentryBlk->dentry[index].fileType = HMFS_FT_DIR; + memcpy(dentryBlk->filename[index], LPF_STRING, HMFS_SLOT_LEN); + HmfsCommon::GetInstance().TestAndSetBitLe(index, dentryBlk->dentryBitmap); + index++; + + memcpy(dentryBlk->filename[index], &LPF_STRING[HMFS_SLOT_LEN], len - HMFS_SLOT_LEN); + HmfsCommon::GetInstance().TestAndSetBitLe(index, dentryBlk->dentryBitmap); + } + + return 0; +} + +int32_t MainAreaWriter::WriteDentryBlock() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + + uint64_t blockId = hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_DATA_HOT] * BLOCKS_PER_SEGMENT; + + HMFS_DEBUG("Writing default dentry root, at offset 0x%" PRIx64 "", blockId); + if (HmfsIo::GetInstance().DevWriteBlock(dentryBlk_.get(), blockId) < 0) { + HMFS_ERROR("failed to write the dentry block to disk."); + return -1; + } + + return 0; +} + + + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/mkfs/src/mkfs_command.cpp b/tools/hmfs-tools/tools/mkfs/src/mkfs_command.cpp new file mode 100755 index 0000000..3230577 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/mkfs_command.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mkfs_command.h" + +#include +#include +#include +#include +#include + +#include "config.h" +#include "hmfs_utils.h" +#include "hmfs_data.h" +#include "hmfs_quota.h" +#include "hmfs_common.h" +#include "hmfs_encoding.h" + +namespace OHOS { +namespace Hmfs { + +constexpr uint32_t DEFAULT_OPTION_SET_HARMONY = 1; + +MkfsCmdParser::MkfsCmdParser() : CmdParser(cmdPara_) +{ + cmdPara_.deviceList.resize(1); + + using namespace std::placeholders; + RegCmdOption('a', true, std::bind(&MkfsCmdParser::ProcessHeapBasedAlloc, this, _1)); + RegCmdOption('c', true, std::bind(&MkfsCmdParser::ProcessDeviceList, this, _1)); + RegCmdOption('C', true, std::bind(&MkfsCmdParser::ProcessCasefolding, this, _1)); + RegCmdOption('d', true, std::bind(&MkfsCmdParser::ProcessDebugLevel, this, _1)); + RegCmdOption('e', true, std::bind(&MkfsCmdParser::ProcessColdFileExt, this, _1)); + RegCmdOption('E', true, std::bind(&MkfsCmdParser::ProcessHotFileExt, this, _1)); + RegCmdOption('f', false, std::bind(&MkfsCmdParser::ProcessForceOverwrite, this, _1)); + RegCmdOption('g', true, std::bind(&MkfsCmdParser::ProcessDefaultOptionSet, this, _1)); + RegCmdOption('h', false, std::bind(&MkfsCmdParser::ProcessHelp, this, _1)); + RegCmdOption('i', false, std::bind(&MkfsCmdParser::ProcessLargeNatBitmap, this, _1)); + RegCmdOption('l', true, std::bind(&MkfsCmdParser::ProcessVolumeLabel, this, _1)); + RegCmdOption('m', false, std::bind(&MkfsCmdParser::ProcessZonedMode, this, _1)); + RegCmdOption('o', true, std::bind(&MkfsCmdParser::ProcessOverProvision, this, _1)); + RegCmdOption('O', true, std::bind(&MkfsCmdParser::ProcessFeatures, this, _1)); + RegCmdOption('q', false, std::bind(&MkfsCmdParser::ProcessQuietMode, this, _1)); + RegCmdOption('r', false, std::bind(&MkfsCmdParser::ProcessSrandSeed, this, _1)); + RegCmdOption('R', true, std::bind(&MkfsCmdParser::ProcessRootOwner, this, _1)); + RegCmdOption('s', true, std::bind(&MkfsCmdParser::ProcessSegsPerSection, this, _1)); + RegCmdOption('S', true, std::bind(&MkfsCmdParser::ProcessSparseMode, this, _1)); + RegCmdOption('t', true, std::bind(&MkfsCmdParser::ProcessDiscardPolicy, this, _1)); + RegCmdOption('T', true, std::bind(&MkfsCmdParser::ProcessTimestamp, this, _1)); + RegCmdOption('U', true, std::bind(&MkfsCmdParser::ProcessUuid, this, _1)); + RegCmdOption('V', false, std::bind(&MkfsCmdParser::ShowVersion, this, _1)); + RegCmdOption('w', true, std::bind(&MkfsCmdParser::ProcessWantedSectorSize, this, _1)); + RegCmdOption('z', true, std::bind(&MkfsCmdParser::ProcessSectionsPerZone, this, _1)); + + RegisterSingleton(this); +} + +ArgParseResult MkfsCmdParser::ProcessHeapBasedAlloc(const std::string& argValue) +{ + auto value = atoi(argValue.c_str()); + cmdPara_.heapBasedAllocation = (value != 0); + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ShowVersion(const std::string& argValue) +{ + (void)argValue; + HMFS_PRINT("mkfs.hmfs %s (%s)", HMFS_TOOLS_VERSION, HMFS_TOOLS_DATE); + return ArgParseResult::FINISH; +} + +ArgParseResult MkfsCmdParser::ProcessDeviceList(const std::string& argValue) +{ + if (cmdPara_.deviceList.size() >= MAX_DEVICE_COUNT) { + HMFS_ERROR("Too many devices"); + return ArgParseResult::ERROR; + } + + if (argValue.length() > MAX_DEVICE_PATH_LEN) { + HMFS_ERROR("device path should be less than %u characters", MAX_DEVICE_PATH_LEN); + return ArgParseResult::ERROR; + } + + cmdPara_.deviceList.emplace_back(argValue); + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessColdFileExt(const std::string& argValue) +{ + std::vector extList = HmfsCommon::GetInstance().SplitStringList(argValue, ','); + for (auto& ext : extList) { + if (ext.length() >= EXTENSION_LEN_MAX) { + HMFS_INFO("Extension name (%s) is too long", ext.c_str()); + continue; + } + cmdPara_.coldExtList.emplace_back(ext); + } + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessHotFileExt(const std::string& argValue) +{ + std::vector extList = HmfsCommon::GetInstance().SplitStringList(argValue, ','); + for (auto& ext : extList) { + if (ext.length() >= EXTENSION_LEN_MAX) { + HMFS_INFO("Extension name (%s) is too long", ext.c_str()); + continue; + } + cmdPara_.hotExtList.emplace_back(ext); + } + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessForceOverwrite(const std::string& argValue) +{ + (void)argValue; + cmdPara_.forceOverwrite = true; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessDefaultOptionSet(const std::string& argValue) +{ + std::unordered_map optionSetMap = { + {"harmonyos", DEFAULT_OPTION_SET_HARMONY}, + }; + + auto it = optionSetMap.find(argValue); + if (it == optionSetMap.end()) { + HMFS_INFO("Invalid option set: %s", argValue.c_str()); + } + cmdPara_.defaultOptionSet = it->second; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessHelp(const std::string& argValue) +{ + (void)argValue; + ShowCmdUsage(); + return ArgParseResult::FINISH; +} + +ArgParseResult MkfsCmdParser::ProcessVolumeLabel(const std::string& argValue) +{ + if (argValue.length() > VOLUME_NAME_MAX_LEN) { + HMFS_ERROR("Volume Label should be less than %u characters.", VOLUME_NAME_MAX_LEN); + return ArgParseResult::ERROR; + } + cmdPara_.volume = argValue; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessZonedMode(const std::string& argValue) +{ + (void)argValue; + cmdPara_.zonedMode = true; + cmdPara_.features |= HMFS_FEATURE_BLKZONED; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessQuietMode(const std::string& argValue) +{ + (void)argValue; + cmdPara_.debugLevel = -1; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessSrandSeed(const std::string& argValue) +{ + (void)argValue; + cmdPara_.fakeSeed = true; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessRootOwner(const std::string& argValue) +{ + std::vector extList = HmfsCommon::GetInstance().SplitStringList(argValue, ':'); + if (extList.size() != 2) { + return ArgParseResult::ERROR; + } + + cmdPara_.rootUid = atoi(extList[0].c_str()); + cmdPara_.rootGid = atoi(extList[1].c_str()); + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessSegsPerSection(const std::string& argValue) +{ + int32_t value = atoi(argValue.c_str()); + if (value <= 0) { + HMFS_ERROR("Invalid argument"); + return ArgParseResult::ERROR; + } + cmdPara_.segsPerSection = value; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessSparseMode(const std::string& argValue) +{ + int64_t value = atoll(argValue.c_str()); + if (value <= 0) { + HMFS_ERROR("Invalid argument"); + return ArgParseResult::ERROR; + } + cmdPara_.deviceSize = value & (~((uint64_t)(HMFS_BLOCK_SIZE - 1))); + cmdPara_.sparseMode = true; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessDiscardPolicy(const std::string& argValue) +{ + int32_t value = atoi(argValue.c_str()); + cmdPara_.trim = (value != 0); + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessTimestamp(const std::string& argValue) +{ + cmdPara_.timeStamp = strtoul(optarg, nullptr, 0); + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessUuid(const std::string& argValue) +{ + cmdPara_.uuid = argValue; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessWantedSectorSize(const std::string& argValue) +{ + int32_t value = atoi(argValue.c_str()); + if (value <= 0) { + HMFS_ERROR("Invalid argument"); + return ArgParseResult::ERROR; + } + cmdPara_.wantedSectorSize = value; + return ArgParseResult::OK; +} + +ArgParseResult MkfsCmdParser::ProcessSectionsPerZone(const std::string& argValue) +{ + int32_t value = atoi(argValue.c_str()); + if (value <= 0) { + HMFS_ERROR("Invalid argument"); + return ArgParseResult::ERROR; + } + cmdPara_.sectionsPerZone = value; + return ArgParseResult::OK; +} + +int32_t MkfsCmdParser::Parse(int32_t argc, char *argv[]) +{ + cmdPara_.func = MKFS; + if (ParseOption(argc, argv)) { + return -1; + } + + if (optind >= argc) { + HMFS_ERROR("Device not specified"); + ShowCmdUsage(); + return -1; + } + cmdPara_.deviceList[0] = argv[optind]; + + if ((optind + 1) < argc) { + if (cmdPara_.deviceList.size() > 1) { + HMFS_ERROR("Not support custom size on multi-devices"); + ShowCmdUsage(); + return -1; + } + cmdPara_.wantedSectorCount = atoll(argv[optind + 1]); + } + + ConfigOptionPacket(); + + ConfigDefaultOption(); + + if (!CheckOptions()) { + return -1; + } + + ShowCmdInfo(); + return 0; +} + +void MkfsCmdParser::ConfigOptionPacket(void) +{ + switch (cmdPara_.defaultOptionSet) { + case DEFAULT_OPTION_SET_HARMONY: + /* -d1 -f -w 4096 -R 0:0 */ + cmdPara_.debugLevel = 1; + cmdPara_.forceOverwrite = true; + cmdPara_.wantedSectorSize = 4096; + cmdPara_.rootUid = 0; + cmdPara_.rootGid = 0; + + /* RO doesn't need any other features */ + if (cmdPara_.features & HMFS_FEATURE_RO) { + break; + } + + /* -O encrypt -O project_quota,extra_attr,{quota} -O verity */ + cmdPara_.features |= HMFS_FEATURE_ENCRYPT; + cmdPara_.features |= HMFS_FEATURE_PRJQUOTA; + cmdPara_.features |= HMFS_FEATURE_EXTRA_ATTR; + cmdPara_.features |= HMFS_FEATURE_VERITY; + if (!HmfsCommon::GetInstance().KernelVersionOver(4, 14)) { + cmdPara_.features |= HMFS_FEATURE_QUOTA_INO; + } + break; + default: + break; + } +} + +void MkfsCmdParser::ConfigDefaultOption(void) +{ + /* RO doesn't need any other features */ + if ((cmdPara_.features & HMFS_FEATURE_RO) && (cmdPara_.defaultOptionSet == DEFAULT_OPTION_SET_HARMONY)) { + return; + } + +#ifdef CONF_CASEFOLD + c.encoding = HMFS_ENC_UTF8_12_1; + cmdPara_.features |= HMFS_FEATURE_CASEFOLD; +#endif +#ifdef CONF_PROJID + cmdPara_.features |= HMFS_FEATURE_QUOTA_INO; + cmdPara_.features |= HMFS_FEATURE_PRJQUOTA; + cmdPara_.features |= HMFS_FEATURE_EXTRA_ATTR; +#endif + + if (cmdPara_.features & HMFS_FEATURE_QUOTA_INO) { + cmdPara_.quotaBits = QUOTA_USR_BIT | QUOTA_GRP_BIT; + } + + if (cmdPara_.features & HMFS_FEATURE_PRJQUOTA) { + cmdPara_.features |= HMFS_FEATURE_QUOTA_INO; + cmdPara_.quotaBits |= QUOTA_PRJ_BIT; + } +} + +bool MkfsCmdParser::CheckOptions(void) +{ + + if (!(cmdPara_.features & HMFS_FEATURE_EXTRA_ATTR)) { + if (cmdPara_.features & HMFS_FEATURE_PRJQUOTA) { + HMFS_ERROR("project quota feature should always be enabled with extra attr feature"); + return false; + } + if (cmdPara_.features & HMFS_FEATURE_INODE_CHKSUM) { + HMFS_ERROR("inode checksum feature should always be enabled with extra attr feature"); + return false; + } + if (cmdPara_.features & HMFS_FEATURE_FLEXIBLE_INLINE_XATTR) { + HMFS_ERROR("flexible inline xattr feature should always be enabled with extra attr feature"); + return false; + } + if (cmdPara_.features & HMFS_FEATURE_INODE_CRTIME) { + HMFS_ERROR("inode crtime feature should always be enabled with extra attr feature"); + return false; + } + if (cmdPara_.features & HMFS_FEATURE_COMPRESSION) { + HMFS_ERROR("compression feature should always be enabled with extra attr feature"); + return false; + } + } + + if (cfgPara_.zonedMode && !cfgPara_.trim) { + HMFS_ERROR("Trim is required for zoned block devices."); + return false; + } + + return true; +} + +void MkfsCmdParser::ShowCmdUsage() +{ + HMFS_PRINT("\nUsage: mkfs.hmfs [options] device [sectors]"); + HMFS_PRINT("[options]:"); + HMFS_PRINT(" -a heap-based allocation [default:0]"); + HMFS_PRINT(" -c device1[,device2,...] up to 7 additional devices, except meta device"); + HMFS_PRINT(" -d debug level [default:0]"); + HMFS_PRINT(" -e [cold file ext list] e.g. \"mp3,gif,mov\""); + HMFS_PRINT(" -E [hot file ext list] e.g. \"db\""); + HMFS_PRINT(" -f force overwrite of the existing filesystem"); + HMFS_PRINT(" -g add default options"); + HMFS_PRINT(" -i extended node bitmap, node ratio is 20%% by default"); + HMFS_PRINT(" -l label"); + HMFS_PRINT(" -U uuid"); + HMFS_PRINT(" -m support zoned block device [default:0]"); + HMFS_PRINT(" -o overprovision percentage [default:auto]"); + HMFS_PRINT(" -O feature1[,feature2,...] e.g. \"encrypt\""); + HMFS_PRINT(" -C [encoding[:flag1,...]] Support casefolding with optional flags"); + HMFS_PRINT(" -q quiet mode"); + HMFS_PRINT(" -r set checkpointing seed (srand()) to 0"); + HMFS_PRINT(" -R root_owner [default: 0:0]"); + HMFS_PRINT(" -s # of segments per section [default:1]"); + HMFS_PRINT(" -S sparse mode"); + HMFS_PRINT(" -t 0: nodiscard, 1: discard [default:1]"); + HMFS_PRINT(" -T timestamps"); + HMFS_PRINT(" -w wanted sector size"); + HMFS_PRINT(" -z # of sections per zone [default:1]"); + HMFS_PRINT(" -V print the version number and exit"); + HMFS_PRINT("sectors: number of sectors [default: determined by device size]"); +} + +void MkfsCmdParser::ShowCmdInfo() +{ + HMFS_PRINT(" HMFS-tools: mkfs.hmfs Ver: %s (%s)", HMFS_TOOLS_VERSION, HMFS_TOOLS_DATE); + + if (cfgPara_.heapBasedAllocation) { + HMFS_INFO("Enable heap-based policy"); + } + + HMFS_INFO("Debug level = %d", cfgPara_.debugLevel); + if (!cfgPara_.coldExtList.empty()) { + HMFS_INFO("Add new cold file extension list"); + } + if (!cfgPara_.hotExtList.empty()) { + HMFS_INFO("Add new hot file extension list"); + } + + if (!cfgPara_.volume.empty()) { + HMFS_INFO("Volume label = %s", cfgPara_.volume.c_str()); + } + + HMFS_INFO("Trim is %s", cfgPara_.trim ? "enabled": "disabled"); + + if (cfgPara_.defaultOptionSet == DEFAULT_OPTION_SET_HARMONY) { + HMFS_INFO("Set conf for harmonyos"); + } + + if (cfgPara_.features & HMFS_FEATURE_CASEFOLD) { + std::string str; + if (!EncodingValueToStr(cfgPara_.sEncoding, str)) { + HMFS_INFO("Enable %s with casefolding", str.c_str()); + } + } + + if (cfgPara_.features & HMFS_FEATURE_PRJQUOTA) { + HMFS_INFO("Enable Project quota"); + } + + if (cfgPara_.features & HMFS_FEATURE_COMPRESSION) { + HMFS_INFO("Enable Compression"); + } +} + +} // namespace Hmfs +} // namespace OHOS \ No newline at end of file diff --git a/tools/hmfs-tools/tools/mkfs/src/mkfs_format.cpp b/tools/hmfs-tools/tools/mkfs/src/mkfs_format.cpp new file mode 100755 index 0000000..b99fb62 --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/mkfs_format.cpp @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mkfs_format.h" + +#include +#include +#include +#include +#include + +#include "securec.h" +#include "hmfs_utils.h" +#include "cp_writer.h" +#include "main_writer.h" +#include "sit_writer.h" +#include "nat_writer.h" +#include "super_block_writer.h" +#include "hmfs_define.h" +#include "device_manager.h" +#include "mkfs_command.h" +#include "hmfs_io.h" +#include "hmfs_common.h" +#include "hmfs_encoding.h" +#include "hmfs_zoned.h" + +namespace OHOS { +namespace Hmfs { + +HmfsMkfs::HmfsMkfs(CmdConfig &cfgPara) : cfgPara_(cfgPara) +{ + HmfsIo::CreateInstance(cfgPara); + HmfsCommon::CreateInstance(cfgPara); + DeviceManager::CreateInstance(cfgPara); +} + +int32_t HmfsMkfs::GetDeviceSectorInfo() +{ + uint32_t segmentSize = HMFS_BLOCK_SIZE * BLOCKS_PER_SEGMENT; + + hmfsData_.sectorCount = DeviceManager::GetInstance().GetTotalSectors(); + for (uint32_t i = 0; i < cfgPara_.deviceList.size(); i++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(i); + ASSERT(deviceInfo != nullptr); + + if (i == 0) { + hmfsData_.sectorSize = deviceInfo->sectorSize; + hmfsData_.sectorsPerBlk = HMFS_BLOCK_SIZE / hmfsData_.sectorSize; + + if (cfgPara_.wantedSectorCount < hmfsData_.sectorCount) { + HMFS_INFO("total device sectors = %" PRIu64 " (in %u bytes)\n", + hmfsData_.sectorCount, hmfsData_.sectorSize); + hmfsData_.sectorCount = cfgPara_.wantedSectorCount; + deviceInfo->sectorCount = hmfsData_.sectorCount; + } + if (hmfsData_.sectorCount * hmfsData_.sectorSize > HMFS_MAX_DISK_SIZE) { + HMFS_ERROR("HMFS can support 16TB at most."); + return -1; + } + + deviceInfo->segmentCount = + (deviceInfo->sectorCount * hmfsData_.sectorSize - hmfsData_.zoneAlignStartOffset) / segmentSize; + deviceInfo->startBlkId = 0; + deviceInfo->endBlkId = deviceInfo->segmentCount * BLOCKS_PER_SEGMENT - 1 + hmfsData_.segment0BlkId; + } else { + DeviceInfo *prevDevice = DeviceManager::GetInstance().GetDeviceInfo(i - 1); + ASSERT(prevDevice != nullptr); + + deviceInfo->segmentCount = deviceInfo->sectorCount / (hmfsData_.sectorsPerBlk * BLOCKS_PER_SEGMENT); + deviceInfo->startBlkId = prevDevice->endBlkId + 1; + deviceInfo->endBlkId = deviceInfo->startBlkId + deviceInfo->segmentCount * BLOCKS_PER_SEGMENT - 1; + } + + hmfsData_.segmentCount += deviceInfo->segmentCount; + } + + if (hmfsData_.segmentCount < HMFS_MIN_SEGMENT_COUNT) { + HMFS_ERROR("Device size is not sufficient for HMFS volume."); + return -1; + } + + return 0; +} + +int32_t HmfsMkfs::GetZoneInfo() +{ + /* + * Check device types and determine the final volume operation mode: + * - If all devices are regular block devices, default operation. + * - If at least one HM device is found, operate in HM mode (BLKZONED + * feature will be enabled by mkfs). + * - If an HA device is found, let mkfs decide based on the -m option + * setting by the user. + */ + hmfsData_.zonedModel = HMFS_ZONED_NONE; + for (uint32_t id = 0; id < cfgPara_.deviceList.size(); id++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(id); + if (deviceInfo && (deviceInfo->zonedModel > hmfsData_.zonedModel)) { + hmfsData_.zonedModel = deviceInfo->zonedModel; + } + } + + if ((hmfsData_.zonedModel != HMFS_ZONED_NONE) && !cfgPara_.zonedMode) { + HMFS_ERROR("Zoned block device feature is required."); + return -1; + } + + if (hmfsData_.zonedModel != HMFS_ZONED_NONE) { + /* + * For zoned model, the zones sizes of all zoned devices must + * be equal. + */ + for (uint32_t id = 0; id < cfgPara_.deviceList.size(); id++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(id); + if ((deviceInfo == nullptr) || (deviceInfo->zonedModel == HMFS_ZONED_NONE)) { + continue; + } + + if (id == 0) { + hmfsData_.blocksPerZone = deviceInfo->zoneBlocks; + } else if (deviceInfo->zoneBlocks != hmfsData_.blocksPerZone) { + HMFS_ERROR("zones of different size are not supported"); + return -1; + } + } + + /* + * Align sections to the device zone size and align F2FS zones + * to the device zones. For HMFS_ZONED_HA model without the + * BLKZONED feature set at format time, this is only an + * optimization as sequential writes will not be enforced. + */ + cfgPara_.segsPerSection = hmfsData_.blocksPerZone / BLOCKS_PER_SEGMENT; + cfgPara_.sectionsPerZone = 1; + } else { + if (cfgPara_.zonedMode) { + HMFS_ERROR("%s may not be a zoned block device.", cfgPara_.deviceList[0].c_str()); + return -1; + } + } + + hmfsData_.segsPerZone = cfgPara_.segsPerSection * cfgPara_.sectionsPerZone; + + HMFS_INFO("Segments per section = %d", cfgPara_.segsPerSection); + HMFS_INFO("Sections per zone = %d", cfgPara_.sectionsPerZone); + HMFS_INFO("sector size = %u", hmfsData_.sectorSize); + HMFS_INFO("total sectors = %" PRIu64 " (%" PRIu64" MB)", + hmfsData_.sectorCount, (hmfsData_.sectorCount * (hmfsData_.sectorSize >> 9)) >> 11); + return 0; +} + +int32_t HmfsMkfs::ClacHmfsData() +{ + uint32_t segmentSize = HMFS_BLOCK_SIZE * BLOCKS_PER_SEGMENT; + uint32_t zoneSize = cfgPara_.sectionsPerZone * cfgPara_.segsPerSection * segmentSize; + + if (cfgPara_.features & HMFS_FEATURE_RO) { + hmfsData_.zoneAlignStartOffset = HMFS_BLOCK_SIZE * HMFS_SUPER_BLOCK_COUNT; + } else { + hmfsData_.zoneAlignStartOffset = AlignUpCount(HMFS_BLOCK_SIZE * HMFS_SUPER_BLOCK_COUNT, zoneSize) * zoneSize; + } + + if (cfgPara_.zonedMode && cfgPara_.deviceList.size() > 1) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(0); + if (deviceInfo != nullptr) { + hmfsData_.zoneAlignStartOffset += (deviceInfo->sectorCount * deviceInfo->sectorSize) % zoneSize; + } + } + + hmfsData_.segment0BlkId = hmfsData_.zoneAlignStartOffset / HMFS_BLOCK_SIZE; + HMFS_INFO("zone aligned segment0 blkaddr = %u", hmfsData_.segment0BlkId); + + if (GetDeviceSectorInfo()) { + return -1; + } + + if (GetZoneInfo()) { + return -1; + } + + if (cfgPara_.zonedMode && + ((cfgPara_.deviceList.size() == 1 && (hmfsData_.segment0BlkId + hmfsData_.startSector / DEFAULT_SECTORS_PER_BLOCK) % hmfsData_.blocksPerZone) || + (cfgPara_.deviceList.size() > 1 && DeviceManager::GetInstance().GetDeviceInfo(1)->startBlkId % hmfsData_.blocksPerZone))) { + HMFS_ERROR("Unaligned segment0 block address %u", hmfsData_.segment0BlkId); + return -1; + } + + hmfsData_.zoneAlignedSegCount = hmfsData_.segmentCount / hmfsData_.segsPerZone * hmfsData_.segsPerZone; + + hmfsData_.sitStartBlkId = hmfsData_.segment0BlkId + hmfsData_.segmentCountInCP * BLOCKS_PER_SEGMENT; + + uint32_t sitBlockCount = AlignUpCount(hmfsData_.zoneAlignedSegCount, SIT_ENTRIES_PER_BLOCK); + hmfsData_.segmentCountInSIT = AlignUpCount(sitBlockCount, BLOCKS_PER_SEGMENT) * HMFS_SIT_COUNT; + + hmfsData_.natStartBlkId = hmfsData_.sitStartBlkId + hmfsData_.segmentCountInSIT * BLOCKS_PER_SEGMENT; + + uint32_t validBlksRemaind = (hmfsData_.zoneAlignedSegCount - hmfsData_.segmentCountInCP - + hmfsData_.segmentCountInSIT) * BLOCKS_PER_SEGMENT; + uint32_t natBlockCount = AlignUpCount(validBlksRemaind, NAT_ENTRIES_PER_BLOCK); + + uint32_t sitBitmapSize = (hmfsData_.segmentCountInSIT / HMFS_SIT_COUNT) / BLOCKS_PER_SEGMENT / BITS_PER_BYTE; + uint32_t sitMaxBitmapSize = (sitBitmapSize > SIT_MAX_BITMAP_SIZE) ? SIT_MAX_BITMAP_SIZE : sitBitmapSize; + + if (cfgPara_.largeNatBitmap) { + uint32_t natSegments = AlignUpCount(natBlockCount, BLOCKS_PER_SEGMENT) * DEFAULT_NAT_ENTRY_RATIO / 100; + hmfsData_.segmentCountInNAT = natSegments ? natSegments : 1; + uint32_t natMaxBitmapSize = hmfsData_.segmentCountInNAT * BLOCKS_PER_SEGMENT / BITS_PER_BYTE; + + /* use cp_payload if free space of f2fs_checkpoint is not enough */ + if (sitMaxBitmapSize + natMaxBitmapSize > CP_MAX_BITMAP_SIZE) { + uint32_t diff = sitMaxBitmapSize + natMaxBitmapSize - CP_MAX_BITMAP_SIZE; + hmfsData_.cpPayload = AlignUpCount(diff, HMFS_BLOCK_SIZE); + } else { + hmfsData_.cpPayload = 0; + } + } else { + uint32_t natMaxBitmapSize; + if (sitMaxBitmapSize > CP_MAX_SIT_BITMAP_SIZE) { + natMaxBitmapSize = CP_MAX_BITMAP_SIZE; + hmfsData_.cpPayload = AlignUpCount(sitMaxBitmapSize, HMFS_BLOCK_SIZE); + } else { + natMaxBitmapSize = CP_MAX_BITMAP_SIZE - sitMaxBitmapSize; + hmfsData_.cpPayload = 0; + } + + uint32_t natMaxSegments = (natMaxBitmapSize * 8) / BLOCKS_PER_SEGMENT; + hmfsData_.segmentCountInNAT = AlignUpCount(natBlockCount, BLOCKS_PER_SEGMENT); + if (hmfsData_.segmentCountInNAT > natMaxSegments) { + hmfsData_.segmentCountInNAT = natMaxSegments; + } + } + hmfsData_.segmentCountInNAT *= HMFS_NAT_COUNT; + + validBlksRemaind -= hmfsData_.segmentCountInNAT * BLOCKS_PER_SEGMENT; + uint32_t ssaBlockCount = (cfgPara_.features & HMFS_FEATURE_RO) ? 0 : (validBlksRemaind / BLOCKS_PER_SEGMENT + 1); + hmfsData_.segmentCountInSSA = AlignUpCount(ssaBlockCount, BLOCKS_PER_SEGMENT); + + uint32_t metaSegmentCount = hmfsData_.segmentCountInCP + hmfsData_.segmentCountInSIT + + hmfsData_.segmentCountInNAT + hmfsData_.segmentCountInSSA; + uint32_t remainder = metaSegmentCount % hmfsData_.segsPerZone; + if (remainder) { + hmfsData_.segmentCountInSSA += hmfsData_.segsPerZone - remainder; + } + + uint64_t metaZoneCount = AlignUpCount(metaSegmentCount, hmfsData_.segsPerZone); + hmfsData_.mainStartBlkId = hmfsData_.segment0BlkId + metaZoneCount * hmfsData_.segsPerZone * BLOCKS_PER_SEGMENT; + + if (cfgPara_.zonedMode) { + /* + * Make sure there is enough randomly writeable + * space at the beginning of the disk. + */ + uint32_t mainBlkZone = hmfsData_.mainStartBlkId / hmfsData_.blocksPerZone; + for (uint32_t id = 0; id < cfgPara_.deviceList.size(); id++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(id); + if (id == 0) { + if ((deviceInfo->zonedModel == HMFS_ZONED_HM) && (deviceInfo->nrRndZones < mainBlkZone)) { + HMFS_ERROR("Device does not have enough random write zones (%u needed)", mainBlkZone); + return -1; + } + } else if ((deviceInfo->zonedModel != HMFS_ZONED_NONE) && (deviceInfo->startBlkId < hmfsData_.mainStartBlkId)) { + HMFS_ERROR("Conventional device is too small, %" PRIu64 " MiB needed.", + (hmfsData_.mainStartBlkId - deviceInfo->startBlkId) >> 8); + return -1; + } + } + } + + uint32_t mainZoneCount = hmfsData_.zoneAlignedSegCount / hmfsData_.segsPerZone - metaZoneCount; + if (mainZoneCount == 0) { + HMFS_ERROR("device size is not sufficient for HMFS volume"); + return -1; + } + + hmfsData_.sectionCount = mainZoneCount * cfgPara_.sectionsPerZone; + hmfsData_.segmentCountInMain = hmfsData_.sectionCount * cfgPara_.segsPerSection; + + uint32_t availZones = (cfgPara_.features & HMFS_FEATURE_RO) ? 2 : 6; + if (mainZoneCount <= availZones) { + HMFS_ERROR("%d zones: Need more zones by shrinking zone size", mainZoneCount); + return -1; + } + + if (cfgPara_.features & HMFS_FEATURE_RO) { + hmfsData_.curSeg[CURSEG_NODE_HOT] = LastSection(LastZone(mainZoneCount)); + hmfsData_.curSeg[CURSEG_NODE_WARM] = 0; + hmfsData_.curSeg[CURSEG_NODE_COLD] = 0; + hmfsData_.curSeg[CURSEG_DATA_HOT] = 0; + hmfsData_.curSeg[CURSEG_DATA_COLD] = 0; + hmfsData_.curSeg[CURSEG_DATA_WARM] = 0; + } else if (cfgPara_.heapBasedAllocation) { + hmfsData_.curSeg[CURSEG_NODE_HOT] = LastSection(LastZone(mainZoneCount)); + hmfsData_.curSeg[CURSEG_NODE_WARM] = PreviousZone(CURSEG_NODE_HOT); + hmfsData_.curSeg[CURSEG_NODE_COLD] = PreviousZone(CURSEG_NODE_WARM); + hmfsData_.curSeg[CURSEG_DATA_HOT] = PreviousZone(CURSEG_NODE_COLD); + hmfsData_.curSeg[CURSEG_DATA_COLD] = 0; + hmfsData_.curSeg[CURSEG_DATA_WARM] = NextZone(CURSEG_DATA_COLD); + } else if (cfgPara_.zonedMode) { + hmfsData_.curSeg[CURSEG_NODE_HOT] = 0; + hmfsData_.curSeg[CURSEG_NODE_WARM] = NextZone(CURSEG_NODE_HOT); + hmfsData_.curSeg[CURSEG_NODE_COLD] = NextZone(CURSEG_NODE_WARM); + hmfsData_.curSeg[CURSEG_DATA_HOT] = NextZone(CURSEG_NODE_COLD); + hmfsData_.curSeg[CURSEG_DATA_WARM] = NextZone(CURSEG_DATA_HOT); + hmfsData_.curSeg[CURSEG_DATA_COLD] = NextZone(CURSEG_DATA_WARM); + } else { + hmfsData_.curSeg[CURSEG_NODE_HOT] = 0; + hmfsData_.curSeg[CURSEG_NODE_WARM] = NextZone(CURSEG_NODE_HOT); + hmfsData_.curSeg[CURSEG_NODE_COLD] = NextZone(CURSEG_NODE_WARM); + hmfsData_.curSeg[CURSEG_DATA_HOT] = NextZone(CURSEG_NODE_COLD); + hmfsData_.curSeg[CURSEG_DATA_COLD] = std::max(LastZone(mainZoneCount >> 2), NextZone(CURSEG_DATA_HOT)); + hmfsData_.curSeg[CURSEG_DATA_WARM] = std::max(LastZone(mainZoneCount >> 1), NextZone(CURSEG_DATA_COLD)); + } + VerifyCurSegData(); + + if (HmfsCommon::GetInstance().GetKernelVersion(hmfsData_.version, sizeof(hmfsData_.version))) { + return -1; + } + + return 0; +} + + +void HmfsMkfs::VerifyCurSegData(void) +{ + if (cfgPara_.features & HMFS_FEATURE_RO) { + return; + } + + bool needReorder = false; + for (int32_t i = 0; i < CURSEG_TYPE_MAX; i++) { + for (int32_t j = i + 1; j < CURSEG_TYPE_MAX; j++) { + if (hmfsData_.curSeg[i] == hmfsData_.curSeg[j]) { + needReorder = true; + break; + } + } + } + + if (needReorder) { + hmfsData_.curSeg[0] = 0; + for (int32_t i = 1; i < CURSEG_TYPE_MAX; i++) { + hmfsData_.curSeg[i] = NextZone(i - 1); + } + } +} + + +int32_t HmfsMkfs::CreateDeviceInfo() +{ + for (size_t i = 0; i < cfgPara_.deviceList.size(); i++) { + if (DeviceManager::GetInstance().CreateDeviceInfo(cfgPara_.deviceList[i], i == 0)) { + return -1; + } + } + + return 0; +} + + +void HmfsMkfs::CreateFormaters() +{ + //super block must be first + areaFormaters_.emplace_back(std::make_unique(this)); + areaFormaters_.emplace_back(std::make_unique(this)); + areaFormaters_.emplace_back(std::make_unique(this)); + areaFormaters_.emplace_back(std::make_unique(this)); + areaFormaters_.emplace_back(std::make_unique(this)); +} + +SuperBlockData* HmfsMkfs::GetSuperBlockData() +{ + if (areaFormaters_.size() == 0) { + return nullptr; + } + return &static_cast(areaFormaters_[0].get())->superBlock_->superBlock; +} + +int32_t HmfsMkfs::Format() +{ + CreateFormaters(); + for (auto& formater : areaFormaters_) { + if (formater->Prepare()) { + return -1; + } + } + for (auto& formater : areaFormaters_) { + if (formater->Write()) { + return -1; + } + } + + if (HmfsIo::GetInstance().HmfsFinalizeDevice()) { + return -1; + } + + return 0; +} + +int32_t HmfsMkfs::OverwriteDevices() +{ + if (!DeviceManager::GetInstance().CheckDeviceFormated()) { + return 0; + } + + if (!cfgPara_.forceOverwrite) { + HMFS_INFO("Use the -f option to force overwrite."); + return -1; + } + + auto buf = std::make_unique(HMFS_BLOCK_SIZE); + if (buf == nullptr) { + HMFS_ERROR("not enough memory to overwrite"); + return -1; + } + memset_s(buf.get(), HMFS_BLOCK_SIZE, 0, HMFS_BLOCK_SIZE); + + constexpr uint64_t OVERWRITE_BLOCK_COUNT = 1024; + for (uint64_t blkId = 0; blkId < OVERWRITE_BLOCK_COUNT; blkId++) { + if (HmfsIo::GetInstance().DevFillBlock(buf.get(), blkId)) { + HMFS_ERROR("Fail to fill zeros at block id %" PRIu64 ".", blkId); + return -1; + } + } + if (HmfsIo::GetInstance().HmfsFsyncDevice()) { + return -1; + } + + return 0; +} + +int32_t HmfsMkfs::Process() +{ + if (CreateDeviceInfo()) { + return -1; + } + + if (OverwriteDevices()) { + return -1; + } + + if (ClacHmfsData()) { + return -1; + } + + if (cfgPara_.trim && DeviceManager::GetInstance().TrimDevices()) { + return -1; + } + + if (Format()) { + HMFS_ERROR("Failed to format the device."); + return -1; + } + + HMFS_INFO("Format successful."); + return 0; +} + +} // namespace Hmfs +} // namespace OHOS + +int32_t main(int32_t argc, char* argv[]) +{ + if (OHOS::Hmfs::MkfsCmdParser::GetInstance().Parse(argc, argv)) { + return -1; + } + auto cfgPara = OHOS::Hmfs::MkfsCmdParser::GetInstance().GetCmdConfig(); + OHOS::Hmfs::HmfsMkfs mkfs(cfgPara); + return mkfs.Process(); +} diff --git a/tools/hmfs-tools/tools/mkfs/src/nat_writer.cpp b/tools/hmfs-tools/tools/mkfs/src/nat_writer.cpp new file mode 100755 index 0000000..4b8284a --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/nat_writer.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "nat_writer.h" + +#include +#include +#include + +#include "hmfs_utils.h" +#include "mkfs_format.h" +#include "securec.h" +#include "device_manager.h" +#include "hmfs_io.h" +#include "hmfs_common.h" +#include "hmfs_quota.h" + +namespace OHOS { +namespace Hmfs { + +NatWriter::NatWriter(HmfsMkfs *mkfs) : mkfs_(mkfs) +{ +} + +int32_t NatWriter::Prepare() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + CmdConfig& cfgPara = mkfs_->cfgPara_; + struct SuperBlockData* superBlock = mkfs_->GetSuperBlockData(); + if (superBlock == nullptr) { + return -1; + } + + natBlock_ = std::make_unique(); + if (natBlock_ == nullptr) { + HMFS_ERROR("not enough memory for nat block"); + return -1; + } + struct natBlockData* natBlock = &natBlock_->natBlock; + memset_s(natBlock, sizeof(NatBlockOnDisk), 0, sizeof(NatBlockOnDisk)); + + + /* quota inode */ + uint32_t id = 1; + for (int32_t qtype = 0; qtype < HMFS_MAX_QUOTAS; qtype++) { + if (!((1 << qtype) & cfgPara.quotaBits)) { + continue; + } + + SetLeValue(natBlock->entries[GetLeValue(superBlock->qfInodeId[qtype])].blockId, + hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_HOT_NODE] * BLOCKS_PER_SEGMENT + id++); + natBlock->entries[GetLeValue(superBlock->qfInodeId[qtype])].inodeNo = superBlock->qfInodeId[qtype]; + } + + /* root inode */ + SetLeValue(natBlock->entries[hmfsData.rootInode].blockId, + hmfsData.mainStartBlkId + hmfsData.curSeg[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT); + SetLeValue(natBlock->entries[hmfsData.rootInode].inodeNo, hmfsData.rootInode); + + /* update node nat */ + SetLeValue(natBlock->entries[hmfsData.nodeInode].blockId, 1); + SetLeValue(natBlock->entries[hmfsData.nodeInode].inodeNo, hmfsData.nodeInode); + + /* update meta nat */ + SetLeValue(natBlock->entries[hmfsData.metaInode].blockId, 1); + SetLeValue(natBlock->entries[hmfsData.metaInode].inodeNo, hmfsData.metaInode); + + return 0; +} + +int32_t NatWriter::Write() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + uint32_t segmentSize = BLOCKS_PER_SEGMENT * HMFS_BLOCK_SIZE; + auto buf = std::make_unique(segmentSize); + if (buf == nullptr) { + HMFS_ERROR("not enough memory for nat segment"); + return -1; + } + memset_s(buf.get(), segmentSize, 0, segmentSize); + + uint64_t offset = hmfsData.natStartBlkId * HMFS_BLOCK_SIZE; + uint32_t segmentWriteCount = hmfsData.segmentCountInNAT / 2; + for (uint32_t i = 0; i < segmentWriteCount; i++) { + if (HmfsIo::GetInstance().DevFill(buf.get(), offset, segmentSize)) { + HMFS_ERROR("failed to write nat segment"); + return -1; + } + offset += (segmentSize * 2); + } + + uint64_t bolckId = hmfsData.natStartBlkId; + HMFS_DEBUG("write nat root at block 0x%08" PRIx64 "", bolckId); + if (HmfsIo::GetInstance().DevWriteBlock(natBlock_.get(), bolckId)) { + HMFS_ERROR("failed to write nat block 0 to disk"); + return -1; + } + + return 0; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/mkfs/src/sit_writer.cpp b/tools/hmfs-tools/tools/mkfs/src/sit_writer.cpp new file mode 100755 index 0000000..848a93d --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/sit_writer.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "sit_writer.h" + +#include +#include +#include + +#include "hmfs_utils.h" +#include "mkfs_format.h" +#include "securec.h" +#include "device_manager.h" +#include "hmfs_io.h" +#include "hmfs_common.h" + +namespace OHOS { +namespace Hmfs { + +SitWriter::SitWriter(HmfsMkfs *mkfs) : mkfs_(mkfs) +{ +} + +int32_t SitWriter::Prepare() +{ + return 0; +} + +int32_t SitWriter::Write() +{ + HmfsData& hmfsData = mkfs_->hmfsData_; + uint32_t segmentSize = BLOCKS_PER_SEGMENT * HMFS_BLOCK_SIZE; + auto buf = std::make_unique(segmentSize); + if (buf == nullptr) { + HMFS_ERROR("not enough memory for sit segment!"); + return -1; + } + memset_s(buf.get(), segmentSize, 0, segmentSize); + + uint64_t offset = hmfsData.sitStartBlkId * HMFS_BLOCK_SIZE; + for (uint32_t i = 0; i < (hmfsData.segmentCountInSIT / 2); i++) { + if (HmfsIo::GetInstance().DevFill(buf.get(), offset, segmentSize)) { + HMFS_ERROR("failed to write sit segment!"); + return -1; + } + offset += segmentSize; + } + + return 0; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/mkfs/src/super_block_writer.cpp b/tools/hmfs-tools/tools/mkfs/src/super_block_writer.cpp new file mode 100755 index 0000000..ef5647e --- /dev/null +++ b/tools/hmfs-tools/tools/mkfs/src/super_block_writer.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "super_block_writer.h" + +#include +#include +#include +#include + +#ifdef HAVE_UUID_UUID_H +#include +#endif +#ifndef HAVE_LIBUUID +#define uuid_parse(a, b) -1 +#define uuid_generate(a) +#endif + +#include "securec.h" +#include "hmfs_utils.h" +#include "mkfs_format.h" +#include "device_manager.h" +#include "hmfs_define.h" +#include "hmfs_io.h" +#include "hmfs_common.h" +#include "hmfs_zoned.h" +#include "hmfs_encoding.h" + +namespace OHOS { +namespace Hmfs { + +namespace { +const std::vector defaultColdExtList = { + /* common prefix */ + "mp", // Covers mp3, mp4, mpeg, mpg + "wm", // Covers wma, wmb, wmv + "og", // Covers oga, ogg, ogm, ogv + "jp", // Covers jpg, jpeg, jp2 + + /* video */ + "avi", + "m4v", + "m4p", + "mkv", + "mov", + "webm", + + /* audio */ + "wav", + "m4a", + "3gp", + "opus", + "flac", + + /* image */ + "gif", + "png", + "svg", + "webp", + + /* archives */ + "jar", + "deb", + "iso", + "gz", + "xz", + "zst", + + /* others */ + "pdf", + "pyc", // Python bytecode + "ttc", + "ttf", + "exe", + + "apk", + "cnt", // Image alias + "exo", // YouTube + "odex", // Android RunTime + "vdex", // Android RunTime + "so", +}; +const std::vector defaultHotExtList = { + "db", + "vmdk", // VMware or VirtualBox + "vdi", // VirtualBox + "qcow2", // QEMU +}; +} + +SuperBlockWriter::SuperBlockWriter(HmfsMkfs *mkfs) : mkfs_(mkfs) +{ + +} + +int32_t SuperBlockWriter::Prepare() +{ + superBlock_ = std::make_unique(); + if (superBlock_ == nullptr) { + return -1; + } + memset_s(superBlock_.get(), sizeof(SuperBlockOnDisk), 0, sizeof(SuperBlockOnDisk)); + + if (FillSuperBlockData()) { + return -1; + } + + if (UpdateHmfsData()) { + return -1; + } + + return 0; +} + +bool NearlyEqual(double a, double b, double epsilon = 0.000001) { + return std::fabs(a - b) < epsilon; +} + +int32_t SuperBlockWriter::UpdateHmfsData() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + HmfsData& hmfsData = mkfs_->hmfsData_; + struct SuperBlockData* superBlock = &superBlock_->superBlock; + + if (cfgPara.features & HMFS_FEATURE_RO) { + cfgPara.overProvision = 0; + hmfsData.reservedSegments = 0; + } else { + uint32_t usableSegs = HmfsZoned::GetInstance().HmfsGetUsableSegments(superBlock); + if (NearlyEqual(cfgPara.overProvision, 0.0)) { + cfgPara.overProvision = HmfsCommon::GetInstance().GetBestOverProvision(superBlock); + } + if (NearlyEqual(cfgPara.overProvision, 0.0)) { + HMFS_ERROR("device size is not sufficient for HMFS volume"); + return -1; + } + + hmfsData.reservedSegments = (2 * (100 / cfgPara.overProvision + 1) + CURSEG_TYPE_MAX) * + AlignUpCount(usableSegs, hmfsData.sectionCount); + } + + if ((!(cfgPara.features & HMFS_FEATURE_RO) && cfgPara.overProvision == 0) || + // (hmfsData.devices[0].sectorCount * hmfsData.sectorSize < hmfsData.zoneAlignStartOffset) || + ((hmfsData.segmentCountInMain - CURSEG_TYPE_MAX) < hmfsData.reservedSegments)) { + HMFS_ERROR("device size is not sufficient for HMFS volume"); + HMFS_DEBUG("cfgPara.overProvision = %f", cfgPara.overProvision); + HMFS_DEBUG("hmfsData.segmentCount = %u", hmfsData.segmentCount); + HMFS_DEBUG("hmfsData.segmentCountInMain = %u, CURSEG_TYPE_MAX = %u, hmfsData.reservedSegments = %u", + hmfsData.segmentCountInMain, CURSEG_TYPE_MAX, hmfsData.reservedSegments); + return -1; + } + + return 0; +} + +int32_t SuperBlockWriter::FillSuperBlockData() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + HmfsData& hmfsData = mkfs_->hmfsData_; + struct SuperBlockData* superBlock = &superBlock_->superBlock; + + SetLeValue(superBlock->magicNo, HMFS_MAGIC_NUMBER); + SetLeValue(superBlock->majorVersion, HMFS_MAJOR_VERSION); + SetLeValue(superBlock->minorVersion, HMFS_MINOR_VERSION); + + uint32_t log_sectorsize = HmfsCommon::GetInstance().LogBase2(hmfsData.sectorSize); + uint32_t log_sectors_per_block = HmfsCommon::GetInstance().LogBase2(hmfsData.sectorsPerBlk); + uint32_t log_blocksize = log_sectorsize + log_sectors_per_block; + uint32_t log_blks_per_seg = HmfsCommon::GetInstance().LogBase2(BLOCKS_PER_SEGMENT); + SetLeValue(superBlock->logSectorSize, log_sectorsize); + SetLeValue(superBlock->logSectorsPerBlk, log_sectors_per_block); + SetLeValue(superBlock->logBlockSize, log_blocksize); + SetLeValue(superBlock->logBlksPerSeg, log_blks_per_seg); + SetLeValue(superBlock->segsPerSection, cfgPara.segsPerSection); + SetLeValue(superBlock->sectionsPerZone, cfgPara.sectionsPerZone); + SetLeValue(superBlock->blockCount, hmfsData.sectorCount >> log_sectors_per_block); + SetLeValue(superBlock->sectionCount, hmfsData.sectionCount); + SetLeValue(superBlock->segmentCount, hmfsData.zoneAlignedSegCount); + SetLeValue(superBlock->segmentCountInCP, hmfsData.segmentCountInCP); + SetLeValue(superBlock->segmentCountInSIT, hmfsData.segmentCountInSIT); + SetLeValue(superBlock->segmentCountInNAT, hmfsData.segmentCountInNAT); + SetLeValue(superBlock->segmentCountInSSA, hmfsData.segmentCountInSSA); + SetLeValue(superBlock->segmentCountInMain, hmfsData.segmentCountInMain); + SetLeValue(superBlock->segment0BlkId, hmfsData.segment0BlkId); + superBlock->cpBlkId = superBlock->segment0BlkId; + SetLeValue(superBlock->sitBlkId, hmfsData.sitStartBlkId); + SetLeValue(superBlock->natBlkId, hmfsData.natStartBlkId); + SetLeValue(superBlock->ssaBlkId, hmfsData.natStartBlkId + hmfsData.segmentCountInNAT * BLOCKS_PER_SEGMENT); + SetLeValue(superBlock->mainBlkId, hmfsData.mainStartBlkId); + SetLeValue(superBlock->rootInodeId, hmfsData.rootInode); + SetLeValue(superBlock->nodeInodeId, hmfsData.nodeInode); + SetLeValue(superBlock->metaInodeId, hmfsData.metaInode); + + for (int32_t qtype = 0; qtype < MAXQUOTAS; qtype++) { + if (((1 << qtype) & cfgPara.quotaBits)) { + SetLeValue(superBlock->qfInodeId[qtype], hmfsData.nextFreeInodeId++); + HMFS_INFO("add quota type = %u => %u\n", qtype, hmfsData.nextFreeInodeId - 1); + } + } + + if (cfgPara.features & HMFS_FEATURE_LOST_FOUND) { + hmfsData.lpfIno = hmfsData.nextFreeInodeId++; + } + + SetLeValue(superBlock->cpPayload, hmfsData.cpPayload); + memcpy_s(superBlock->version, sizeof(superBlock->version), hmfsData.version, VERSION_TOTAL_LEN); + memcpy_s(superBlock->initVersion, sizeof(superBlock->initVersion), hmfsData.version, VERSION_TOTAL_LEN); + SetLeValue(superBlock->features, cfgPara.features); + + uint32_t deviceCount = DeviceManager::GetInstance().GetDeviceCount(); + if (deviceCount > 1) { + for (uint32_t id = 0; id < deviceCount; id++) { + DeviceInfo* deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(id); + if (deviceInfo == nullptr) { + HMFS_ERROR("failed to get device info, id %u", id); + return -1; + } + strcpy_s(superBlock->devices[id].path, DEVICE_PATH_MAX_LEN, deviceInfo->path.c_str()); + superBlock->devices[id].segmentCount = deviceInfo->segmentCount; + } + } + + if (cfgPara.uuid.empty()) { + uuid_generate(superBlock->uuid); + } else { + if (uuid_parse(cfgPara.uuid.c_str(), superBlock->uuid)) { + HMFS_ERROR("Supplied string is not a valid UUID."); + return -1; + } + } + + if (cfgPara.features & HMFS_FEATURE_INODE_CHKSUM) { + hmfsData.chksumSeed = HmfsCommon::GetInstance().HmfsCalCrc32(~0, superBlock->uuid, sizeof(superBlock->uuid)); + } + + Utf8ToUtf16(superBlock->volumeName, cfgPara.volume.c_str(), VOLUME_NAME_MAX_LEN, cfgPara.volume.length()); // TODO: check + + FillExtList(); + + if (cfgPara.features & HMFS_FEATURE_CASEFOLD) { + SetLeValue(superBlock->encoding, cfgPara.sEncoding); + SetLeValue(superBlock->encodingFlags, cfgPara.sEncodingFlags); + } + + return 0; +} + +void SuperBlockWriter::FillExtList() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + + struct SuperBlockData* superBlock = &superBlock_->superBlock; + std::vector, std::vector>> extList = { + std::make_pair(defaultColdExtList, cfgPara.coldExtList), + std::make_pair(defaultHotExtList, cfgPara.hotExtList), + }; + + uint32_t index = 0; + uint32_t coldExtCount = 0; + for (size_t i = 0; i < extList.size(); i++) { + for (auto &ext : extList[i].first) { + if (index >= EXTENSION_COUNT_MAX) { + break; + } + strcpy_s(superBlock->extensionList[index++], EXTENSION_LEN_MAX, ext.c_str()); + } + + for (auto &ext : extList[i].second) { + if (index >= EXTENSION_COUNT_MAX) { + break; + } + + if (!IsExtensionDuplicate(ext)) { + strcpy_s(superBlock->extensionList[index++], EXTENSION_LEN_MAX, ext.c_str()); + } + } + + if (i == 0) { + coldExtCount = index; + } + } + + uint32_t hotExtCount = index - coldExtCount; + SetLeValue(superBlock->hotExtensionCount, hotExtCount); + SetLeValue(superBlock->coldExtensionCount, coldExtCount); +} + +bool SuperBlockWriter::IsExtensionDuplicate(std::string& ext) +{ + struct SuperBlockData* superBlock = &superBlock_->superBlock; + for (uint32_t i = 0; i < EXTENSION_COUNT_MAX; i++) { + if (strcmp(superBlock->extensionList[i], ext.c_str()) == 0) { + return true; + } + } + return false; +} + +int32_t SuperBlockWriter::ClacCheckSum() +{ + CmdConfig& cfgPara = mkfs_->cfgPara_; + struct SuperBlockData* superBlock = &superBlock_->superBlock; + + if (cfgPara.features & HMFS_FEATURE_SB_CHKSUM) { + SetLeValue(superBlock->checksumOffset, SB_CHKSUM_OFFSET); + SetLeValue(superBlock->checksum, HmfsCommon::GetInstance().HmfsCalCrc32(HMFS_MAGIC_NUMBER, superBlock, SB_CHKSUM_OFFSET)); + HMFS_INFO("super block checksum is set: offset (%u), crc (0x%x)", + GetLeValue(superBlock->checksumOffset), GetLeValue(superBlock->checksum)); + } + + return 0; +} + +int32_t SuperBlockWriter::Write() +{ + ClacCheckSum(); + + for (uint64_t i = 0; i < HMFS_SUPER_BLOCK_COUNT; i++) { + if (HmfsIo::GetInstance().HmfsIo::GetInstance().DevWriteBlock(superBlock_.get(), i)) { + HMFS_ERROR("failed to write super block [%" PRIu64 "] on disk", i); + return -1; + } + } + return 0; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/BUILD.gn b/tools/hmfs-tools/tools/resize/BUILD.gn new file mode 100755 index 0000000..317d4d7 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/BUILD.gn @@ -0,0 +1,59 @@ +# Copyright (c) 2025 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//third_party/hmfs-tools/hmfs.gni") + +ohos_executable("resize.hmfs") { + cflags = [ + "-Wno-incompatible-pointer-types", + "-Wno-unused-function", + "-Wno-unused-parameter", + "-Wno-format", + ] + + sources = [ + "src/resize_command.cpp", + "src/resize_load.cpp", + "src/resize_main.cpp", + "src/resize_operator.cpp", + "src/resize_defrag.cpp", + "src/resize_load_sb.cpp", + "src/resize_load_cp.cpp", + "src/resize_load_sit.cpp", + "src/resize_load_nat.cpp", + ] + + include_dirs = [ + "include/", + "${hmfs_tools_path}/common", + ] + + deps = [ + "${hmfs_tools_path}/common:libhmfs", + ] + external_deps = [ + "bounds_checking_function:libsec_shared", + ] + public_external_deps = [ "e2fsprogs:libext2_uuid" ] + + defines = [ "HAVE_CONFIG_H" ] + + install_enable = true + install_images = [ + "system", + "updater", + ] + subsystem_name = "thirdparty" + part_name = "hmfs-tools" +} diff --git a/tools/hmfs-tools/tools/resize/include/node.h b/tools/hmfs-tools/tools/resize/include/node.h new file mode 100755 index 0000000..0088537 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/node.h @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HMFS_NODE_H +#define HMFS_NODE_H + +#include "hmfs_common.h" +#include "hmfs_data.h" +#include "hmfs_io.h" +#include "hmfs_utils.h" +#include "resize_data.h" + +namespace OHOS { +namespace Hmfs { + +enum { + COLD_BIT_SHIFT = 0, + FSYNC_BIT_SHIFT, + DENT_BIT_SHIFT, + OFFSET_BIT_SHIFT +}; + +#define XATTR_NODE_OFFSET ((((unsigned int)-1) << OFFSET_BIT_SHIFT) >> OFFSET_BIT_SHIFT) +#define IsFsyncDnode(nodeBlock) isNode(nodeBlock, FSYNC_BIT_SHIFT) +#define IsDentDnode(nodeBlock) isNode(nodeBlock, DENT_BIT_SHIFT) + +inline int32_t IsInode(struct NodeData *node) +{ + if (node == nullptr) { + HMFS_ERROR("node is nullptr"); + return -1; + } + return ((node)->footer.nid == (node)->footer.ino); +} + +inline unsigned long CurrentNatAddr(std::shared_ptr sbi, uint32_t start, int *pack) +{ + struct NodeAddressTable *nat = NM_I(sbi); + + unsigned long blockOff = NAT_BLOCK_OFFSET(start); + int32_t segOff = blockOff >> sbi->logBlksPerSeg; + unsigned long blockAddr = (unsigned long)(nat->natBlkaddr + + (segOff << sbi->logBlksPerSeg << 1) + + (blockOff & ((1 << sbi->logBlksPerSeg) - 1))); + if (pack) { + *pack = 1; + } + + if (HmfsCommon::GetInstance().HmfsTestBit(blockOff, nat->natBitmap)) { + blockAddr += sbi->blocksPerSeg; + if (pack) { + *pack = 2; + } + } + return blockAddr; +} + +inline int LookupNatInJournal(std::shared_ptr sbi, uint32_t nid, struct natEntry *raw_nat) +{ + struct CurSegmentInfo *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct JournalEntry *journal = &curseg->segSumBlk->journal; + for (int i = 0; i < nats_in_cursum(journal); i++) { + if (LE32_TO_NATIVE(nid_in_journal(journal, i)) == nid) { + memcpy(raw_nat, &nat_in_journal(journal, i), sizeof(struct natEntry)); + HMFS_INFO("==> Found nid [0x%x] in nat cache\n", nid); + return i; + } + } + return -1; +} + +inline void GetNatEntry(std::shared_ptr sbi, uint32_t nid, struct natEntry *rawNat) +{ + if (LookupNatInJournal(sbi, nid, rawNat) >= 0){ + return; + } + struct natBlockData *natBlock = (struct natBlockData *)calloc(BLOCK_SZ, 1); + ASSERT(natBlock); + + int entryOff = nid % NAT_ENTRY_PER_BLOCK; + unsigned long blockAddr = CurrentNatAddr(sbi, nid, NULL); + + int ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + + memcpy(rawNat, &natBlock->entries[entryOff], sizeof(struct natEntry)); + free(natBlock); +} + +inline void NodeInfoFromRawNat(struct NodeInfo *ni, struct natEntry *rawNat) +{ + ni->ino = LE32_TO_NATIVE(rawNat->inodeNo); + ni->blockAddr = LE32_TO_NATIVE(rawNat->blockId); + ni->version = rawNat->version; +} + +inline void GetNodeInfo(std::shared_ptr sbi, uint32_t nid, struct NodeInfo *ni) +{ + struct natEntry rawNat; + ni->nid = nid; + //FSCK command + // if (c.func == FSCK && F2FS_FSCK(sbi)->nr_nat_entries) { + // node_info_from_raw_nat(ni, &(F2FS_FSCK(sbi)->entries[nid])); + // if (ni->blkAddr) + // return; + // } + GetNatEntry(sbi, nid, &rawNat); + NodeInfoFromRawNat(ni, &rawNat); +} + +inline unsigned int ADDRS_PER_PAGE(std::shared_ptr sbi, struct NodeData *nodeBlock, + struct NodeData *inodeBlock) +{ + if (nodeBlock == nullptr || sbi == nullptr || inodeBlock == nullptr) { + HMFS_ERROR("nodeBlock or sbi or inodeBlock is nullptr"); + return 1; + } + + uint32_t ino = LE32_TO_NATIVE(nodeBlock->footer.ino); + if (IsInode(nodeBlock)) { + return HmfsCommon::GetInstance().AddrsPerInode(&nodeBlock->i); + } + unsigned int nblocks = 0; + if (inodeBlock == nullptr) { + inodeBlock = static_cast(calloc(BLOCK_SZ, 2)); + ASSERT(inodeBlock); + struct NodeInfo ni; + GetNodeInfo(sbi, ino, &ni); + ASSERT(HmfsIo::GetInstance().DevReadBlock(inodeBlock, ni.blockAddr) >= 0); + nblocks = HmfsCommon::GetInstance().AddrsPerBlock(&inodeBlock->i); + free(inodeBlock); + } else { + nblocks = HmfsCommon::GetInstance().AddrsPerBlock(&inodeBlock->i); + } + return nblocks; +} + +inline uint32_t *BlockAddressInINode(struct NodeData *node) +{ + if (node == nullptr) { + return nullptr; + } + return node->i.i_addr + HmfsCommon::GetInstance().GetExtraIsize(&node->i); +} + +inline uint32_t *BlockAddressInNode(struct NodeData *node) +{ + if (node == nullptr) { + return nullptr; + } + return IsInode(node) ? BlockAddressInINode(node) : node->dn.addr; +} + +inline uint32_t DatablockAddr(struct NodeData *nodePage, unsigned int offset) +{ + if (nodePage == nullptr) { + return 0; + } + uint32_t *addr_array = BlockAddressInNode(nodePage); + return LE32_TO_NATIVE(addr_array[offset]); +} + +enum { + ALLOC_NODE, /* allocate a new node page if needed */ + LOOKUP_NODE, /* lookup up a node without readahead */ + LOOKUP_NODE_RA, +}; + +inline unsigned int ofs_of_node(struct NodeData *nodeBlock) +{ + if (nodeBlock == nullptr) { + HMFS_ERROR("node_blk is nullptr"); + return 0; + } + unsigned flag = LE32_TO_NATIVE(nodeBlock->footer.flag); + return flag >> OFFSET_BIT_SHIFT; +} + +inline int IS_DNODE(struct NodeData *nodePage) +{ + if (nodePage == nullptr) { + return -1; + } + unsigned int ofs = ofs_of_node(nodePage); + + if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || ofs == 5 + 2 * NIDS_PER_BLOCK) { + return 0; + } + + if (ofs >= 6 + 2 * NIDS_PER_BLOCK) { + ofs -= 6 + 2 * NIDS_PER_BLOCK; + if (!((long int)ofs % (NIDS_PER_BLOCK + 1))) { + return 0; + } + } + return 1; +} + +inline uint32_t InoOfNode(struct NodeData *nodeBlock) +{ + if (nodeBlock == nullptr) { + return 0; + } + return LE32_TO_NATIVE(nodeBlock->footer.ino); +} + +inline unsigned int OfsOfNode(struct NodeData *nodeBlock) +{ + if (nodeBlock == nullptr) { + return 0; + } + unsigned flag = LE32_TO_NATIVE(nodeBlock->footer.flag); + return flag >> OFFSET_BIT_SHIFT; +} + +inline uint64_t GetNodeCheckPointVersion(struct NodeData *nodeBlock) +{ + if (nodeBlock == nullptr) { + return 0; + } + return LE64_TO_NATIVE(nodeBlock->footer.cpVer); +} + +inline unsigned long long GetCheckPointVersion(struct CheckPointData *cp) +{ + if (cp == nullptr) { + return 0; + } + return LE64_TO_NATIVE(cp->cpVersion); +} + +inline bool IsSetCheckPointFlagd(struct CheckPointData *cp, unsigned int f) +{ + if (cp == nullptr) { + return false; + } + unsigned int flag = LE32_TO_NATIVE(cp->cpFlags); + return flag & f ? 1 : 0; +} + +inline uint64_t cur_cp_crc(struct CheckPointData *cp) +{ + if (cp == nullptr) { + return 0; + } + size_t offset = LE32_TO_NATIVE(cp->checksumOffset); + return LE32_TO_NATIVE(*((uint32_t *)((unsigned char *)cp + offset))); +} + +inline bool IsRecoverableDnode(std::shared_ptr sbi, struct NodeData *nodeBlock) +{ + if (nodeBlock == nullptr || sbi == nullptr) { + HMFS_ERROR("nodeBlock or sbi is nullptr"); + return false; + } + + struct CheckPointData *checkPointData = F2FS_CKPT(sbi); + uint64_t checkpointVersion = GetCheckPointVersion(checkPointData); + + /* Don't care crc part, if fsck.f2fs sets it. */ + if (IsSetCheckPointFlagd(checkPointData, CP_NOCRC_RECOVERY_FLAG)) { + return (checkpointVersion << 32) == (GetNodeCheckPointVersion(nodeBlock) << 32); + } + + if (IsSetCheckPointFlagd(checkPointData, CP_CRC_RECOVERY_FLAG)) { + checkpointVersion |= (cur_cp_crc(checkPointData) << 32); + } + + return checkpointVersion == GetNodeCheckPointVersion(nodeBlock); +} + +inline uint32_t NextBlkAddrOfNode(struct NodeData *nodeBlock) +{ + if (nodeBlock == nullptr) { + return 0; + } + return LE32_TO_NATIVE(nodeBlock->footer.nextBlkaddr); +} + +inline int isNode(struct NodeData *nodeBlock, int type) +{ + if (nodeBlock == nullptr) { + return -1; + } + return LE32_TO_NATIVE(nodeBlock->footer.flag) & (1 << type); +} + +inline unsigned int StartBidxOfNode(unsigned int nodeOfs, struct NodeData *nodeBlk) +{ + unsigned int indirectBlks = 2 * NIDS_PER_BLOCK + 4; + unsigned int bidx; + if (nodeOfs == 0) { + return 0; + } + if (nodeOfs <= 2) { + bidx = nodeOfs - 1; + } else if (nodeOfs <= indirectBlks) { + int dec = (nodeOfs - 4) / (NIDS_PER_BLOCK + 1); + bidx = nodeOfs - 2 - dec; + } else { + int dec = (nodeOfs - indirectBlks - 3) / (NIDS_PER_BLOCK + 1); + bidx = nodeOfs - 5 - dec; + } + return bidx * HmfsCommon::GetInstance().AddrsPerBlock(&nodeBlk->i) + HmfsCommon::GetInstance().AddrsPerInode(&nodeBlk->i); +} + +} // namespace Hmfs +} // namespace OHOS +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_command.h b/tools/hmfs-tools/tools/resize/include/resize_command.h new file mode 100755 index 0000000..131f7b3 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_command.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_RESIZE_COMMAND_H +#define HMFS_RESIZE_COMMAND_H + +#include +#include +#include +#include +#include "hmfs_command.h" + +namespace OHOS { +namespace Hmfs { + +// struct ResizeConfig { +// int32_t debugLevel = 0; +// int32_t force = 0; +// int32_t safeResize = 0; +// uint64_t targetSectors = 0; +// int32_t largeNatBitmap = 0; +// uint16_t sEncoding = 0; +// uint16_t sEncodingFlags = 0; +// uint32_t features = 0; +// double newOverprovision; +// }; + +enum Option { + END = -1, + HELP = 'h', + DEBUG = 'd', + EXNODEBITMAP = 'i', + OVERPROVISION = 'o', + SAFE = 's', + TARGETSECTOR = 't', + FEATURELIST = 'O', + ENCODING = 'C', + RVERSION = 'V', + FORCEWRITE = 'f', + UNKNOWN = '?', + NO_ARGUMENT = ':', +}; + +class ResizeCmdParser : public CmdParser { +public: + ResizeCmdParser(CmdConfig &resizeConfig); + ~ResizeCmdParser() = default; + uint32_t Parse(int argc, char *argv[]); + void ShowCmdUsage(); + + // void SetTargetSectors(); + // void setDebugLevel(); + +private: + ArgParseResult OptionAProcess(const std::string& argValue); + + // void InitCommand(); + // uint32_t ParseCommand(int argc, char *argv[]); + // uint32_t CheckError(int argc, char *argv[], int c, int optIndex); + ArgParseResult PrintVersion(const std::string& argValue); + // uint32_t CheckParam() const; + // uint32_t HandleProcess(int c, const std::string& argValue); + ArgParseResult ShowHelp(const std::string& argValue); + // bool IsLongOpt(int argc, char *argv[]) const; + ArgParseResult SetDebugLevel(const std::string& argValue); + ArgParseResult SetForce(const std::string& argValue); + ArgParseResult SetSafe(const std::string& argValue); + ArgParseResult SetTargetSectors(const std::string& argValue); + ArgParseResult SetEncoding(const std::string& argValue); + ArgParseResult SetOverProvision(const std::string& argValue); + ArgParseResult SetExnodeBitmap(const std::string& argValue); + ArgParseResult SetFeatureList(const std::string& argValue); + std::vector SplitStringList(const std::string& srcString, char delimiter); + static const struct option CMD_OPTS[]; + static const std::string CMD_PARAMS; + CmdConfig &resizeConfig_; +}; + +} +} +#endif // HMFS_RESIZE_COMMAND_H diff --git a/tools/hmfs-tools/tools/resize/include/resize_data.h b/tools/hmfs-tools/tools/resize/include/resize_data.h new file mode 100755 index 0000000..4609062 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_data.h @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_RESIZE_DATA_H +#define HMFS_RESIZE_DATA_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif + +#include "hmfs_define.h" +#include "resize_list.h" +#include "device_manager.h" + +namespace OHOS { +namespace Hmfs { + +#define EXIT_ERR_CODE (-1) +#define SUCCESS_CODE (0) +template +bool ver_after(const T& a, const T& b) +{ + return (a > b); +} + +#define nats_in_cursum(jnl) (LE16_TO_NATIVE(jnl->nNats)) +#define sits_in_cursum(jnl) (LE16_TO_NATIVE(jnl->nSits)) + +#define nat_in_journal(jnl, i) (jnl->natJ.entries[i].ne) +#define nid_in_journal(jnl, i) (jnl->natJ.entries[i].nid) +#define sit_in_journal(jnl, i) (jnl->sitJ.entries[i].se) +#define segno_in_journal(jnl, i) (jnl->sitJ.entries[i].segno) +/* + * indicate meta/data type + */ +enum { + META_CP, + META_NAT, + META_SIT, + META_SSA, + META_MAX, + META_POR, +}; + +#define MAX_RA_BLOCKS 64 + +enum { + NAT_BITMAP, + SIT_BITMAP +}; + +enum { + LFS = 0, + SSR +}; + +struct NodeInfo { + uint32_t nid; + uint32_t ino; + uint32_t blockAddr; + unsigned char version; +}; + +/** zzx update */ +enum SB_ADDR { + SB0_ADDR = 0, + SB1_ADDR, + SB_MAX_ADDR, +}; + +#define DEVICE_NUM 1 + +struct HmfsConfigData { + /** init param */ + int nDevices; + uint32_t sectorsPerBlock; + uint32_t blocksPerSegment; + uint64_t wantedTotalSectors; + uint64_t wantedSectorSize; + int preserveLimits; + int noKernelCheck; + struct DeviceInfo devices[MAX_DEVICES]; + uint32_t segmentsPerSection; + uint32_t sectionsPerZone; + uint32_t segmentsPerZone; + char *volumeLabel; + int trim; + int32_t kd; + time_t fixedTime; + uint16_t fileEncoding; + uint16_t fileEncodingFlags; + uint32_t rootUid; + uint32_t rootGid; + /*--------------*/ + int debugLevel; + int force; + int safeResize; + uint64_t targetSectors; + uint64_t totalSectors; + int largeNatBitmap; + uint32_t feature; + double newOverprovision; + /** init param */ + uint8_t initVersion[VERSION_LEN + 1]; + uint8_t sbVersion[VERSION_LEN + 1]; + uint8_t version[VERSION_LEN + 1]; + int sparseMode; + int func; + int forceStop; + int abnormalStop; + int32_t hmfsErrors; + int quotaFix; + uint32_t newReservedSegments; + /* precomputed fs UUID checksum for seeding other checksums */ + uint32_t chksumSeed; + int zonedModel; + uint32_t sectorSize; + /** useful param */ + int bugOn; + int fixOn; + uint32_t reservedSegments; + int zonedMode; + uint32_t startSector; + size_t zoneBlocks; + double overprovision; + uint32_t curSeg[6]; + uint32_t totalSegments; + int32_t autoFix; + int32_t preenMode; + uint16_t encoding; + uint16_t encodingFlags; + int32_t layout; +}; + + +#define BLOCK_SZ 4096 +struct block { + unsigned char buf[BLOCK_SZ]; +}; + +#define ASSERT(exp) \ + do { \ + if (!(exp)) { \ + printf("[ASSERT] (%s:%4d) %s\n", \ + __func__, __LINE__, #exp); \ + exit(-1); \ + } \ + } while (0) + +#define SB_MASK(i) (1 << (i)) +#define SB_MASK_ALL (SB_MASK(SB0_ADDR) | SB_MASK(SB1_ADDR)) +#define SB_MASK_ONE (SB_MASK(SB0_ADDR)) + +enum seg_type { + SEG_TYPE_DATA, + SEG_TYPE_CUR_DATA, + SEG_TYPE_NODE, + SEG_TYPE_CUR_NODE, + SEG_TYPE_MAX, +}; + +/* summary block type, node or data, is stored to the SummaryFooter */ +#define IS_SUM_NODE_SEG(footer) (footer.entryType == SUM_TYPE_NODE) +#define IS_SUM_DATA_SEG(footer) (footer.entryType == SUM_TYPE_DATA) +struct NodeAddressTable { + uint32_t natBlkaddr; + uint32_t natBlocks; + uint32_t maxNid; + uint32_t initScanNid; + uint32_t nextScanNid; + + unsigned int natCnt; + unsigned int fcnt; + + char *natBitmap; + int bitmapSize; + char *nidBitmap; +}; + +struct SegEntry { + unsigned short validBlocks; /* # of valid blocks */ + unsigned short ckptValidBlocks; /* # of valid blocks last cp, for recovered data/node */ + unsigned char *curValidBitmap; /* validity bitmap of blocks */ + unsigned char *ckptValidBitmap; /* validity bitmap of blocks last cp, for recovered data/node */ + unsigned char type; /* segment type like CURSEG_XXX_TYPE */ + unsigned char origType; /* segment type like CURSEG_XXX_TYPE */ + unsigned char ckptType; /* segment type like CURSEG_XXX_TYPE , for recovered data/node */ + unsigned long long modTime; /* modification time of the segment */ + int dirty; +}; + +struct SecEntry { + unsigned int validBlocks; /* # of valid blocks in a section */ +}; + +struct SitInfo { + + uint32_t sitBaseAddr; /* start block address of SIT area */ + uint32_t sitBlocks; /* # of blocks used by SIT area */ + uint32_t writtenValidBlocks; /* # of valid blocks in main area */ + unsigned char *bitmap; /* all bitmaps pointer */ + char *sitBitmap; /* SIT bitmap pointer */ + unsigned int bitmapSize; /* SIT bitmap size */ + + unsigned long *dirtySentriesBitmap; /* bitmap for dirty sentries */ + unsigned int dirtySentries; /* # of dirty sentries */ + unsigned int sentsPerBlock; /* # of SIT entries per block */ + struct SegEntry *segEntries; /* SIT segment-level cache */ + struct SecEntry *secEntries; /* SIT section-level cache */ + + unsigned long long elapsedTime; /* elapsed time after mount */ + unsigned long long mountedTime; /* mount time */ + unsigned long long minModtime; /* min. modification time */ + unsigned long long maxModtime; /* max. modification time */ +}; + + +/* summary block type, node or data, is stored to the SummaryFooter */ +#define SUM_TYPE_NODE (1) +#define SUM_TYPE_DATA (0) +#define GET_SUM_BLKADDR(sbi, segno) \ + ((sbi->smInfoTable->ssaBlkaddr) + segno) + +/* + * For SIT entries + * + * Each segment is 2MB in size by default so that a bitmap for validity of + * there-in blocks should occupy 64 bytes, 512 bits. + * Not allow to change this. + */ +// #define SIT_VBLOCK_MAP_SIZE 64 + +struct CurSegmentInfo { + struct SummaryBlockData *segSumBlk; /* cached summary block */ + unsigned char allocType; /* current allocation type */ + unsigned int segNum; /* current segment number */ + unsigned short nextBlkOffset; /* next block offset to write */ + unsigned int zone; /* current zone number */ + unsigned int nextSegNum; /* preallocated segment */ +}; + +struct SegmentInfoTable { + struct SitInfo *sitInfo; + struct CurSegmentInfo *curSegmentArray; + + uint32_t seg0Blkaddr; + uint32_t mainBlkaddr; + uint32_t ssaBlkaddr; + + unsigned int segmentCount; + unsigned int mainSegments; + unsigned int reservedSegments; + unsigned int ovpSegments; +}; + + +struct HmfsSbInfo { + // struct f2fs_fsck *fsck; + struct SuperBlockData *rawSuper; //raw_super; + struct CheckPointData *ckptData; + struct SegmentInfoTable *smInfoTable; + struct NodeAddressTable *naTable; + + int curCpId; + + struct ListNode orphan_inode_list; + unsigned int n_orphans; + /* basic file system units */ + unsigned int logSectorsPerBlk; /* log2 sectors per block */ + unsigned int logBlockSize; /* log2 block size */ + unsigned int blockSize; /* block size */ + unsigned int rootInodeId; /* root inode number*/ + unsigned int nodeInodeId; /* node inode number*/ + unsigned int metaInodeId; /* meta inode number*/ + unsigned int logBlksPerSeg; /* log2 blocks per segment */ + unsigned int blocksPerSeg; /* blocks per segment */ + unsigned int segmentsPerSec; /* segments per section */ + unsigned int sectionsPerZone; /* sections per zone */ + unsigned int totalSections; /* total section count */ + unsigned int totalNodeCount; /* total node block count */ + unsigned int totalValidNodeCount; /* valid node block count */ + unsigned int totalValidInodeCount; /* valid inode count */ + int activeLogs; //active_logs; /* # of active logs */ + + uint32_t userBlockCount; /* # of user blocks */ + uint32_t totalValidBlockCount; /* # of valid blocks */ + uint32_t allocValidBlockCount; /* # of allocated blocks */ + uint32_t lastValidBlockCount; /* for recovery */ + uint32_t s_next_generation; /* for NFS support */ + unsigned int curVictimSec; /* current victim section num */ + uint32_t free_segments; + int cpBackuped; /* backup valid checkpoint */ + /* true if late_build_segment_manger() is called */ + bool segManagerDone; + /* keep track of hardlinks so we can recreate them */ + void *hardlink_cache; +}; + +inline struct SuperBlockData *F2FS_RAW_SUPER(std::shared_ptr sbi) +{ + if (sbi == nullptr) { + return nullptr; + } + return (struct SuperBlockData *)(sbi->rawSuper); +} + +inline struct CheckPointData *F2FS_CKPT(std::shared_ptr sbi) +{ + if (sbi == nullptr) { + return nullptr; + } + return (struct CheckPointData *)(sbi->ckptData); +} + +inline struct NodeAddressTable *NM_I(std::shared_ptr sbi) +{ + if (sbi == nullptr) { + return nullptr; + } + return (struct NodeAddressTable *)(sbi->naTable); +} + +inline struct SegmentInfoTable *SM_I(std::shared_ptr sbi) +{ + if (sbi == nullptr) { + return nullptr; + } + return (struct SegmentInfoTable *)(sbi->smInfoTable); +} + +inline struct SitInfo *SIT_I(std::shared_ptr sbi) +{ + if (sbi == nullptr) { + return nullptr; + } + return (struct SitInfo *)(SM_I(sbi)->sitInfo); +} + +inline bool IsSetCkptFlags(struct CheckPointData *cp, unsigned int f) +{ + if (cp == nullptr) { + return false; + } + unsigned int ckptFlags = LE32_TO_NATIVE(cp->cpFlags); + return ckptFlags & f ? 1 : 0; +} + +inline unsigned long GetBitmapSize(std::shared_ptr sbi, int flag) +{ + CheckPointData *cpData = sbi->ckptData; + /* return NAT or SIT bitmap */ + if (flag == NAT_BITMAP) { + return LE32_TO_NATIVE(cpData->natVersionBitmapSize); + } else if (flag == SIT_BITMAP) { + return LE32_TO_NATIVE(cpData->sitVersionBitmapSize); + } + return 0; +} + +/* + * For NAT entries + */ +inline bool IsValidNid(std::shared_ptr sbi, uint32_t nid) +{ + return (nid < (NAT_ENTRY_PER_BLOCK * LE32_TO_NATIVE(sbi->rawSuper->segmentCountInNAT) << + (sbi->logBlksPerSeg - 1))); +} + +inline bool IsValidBlkAddr(std::shared_ptr sbi, uint32_t addr) +{ + if (addr == NULL_ADDR || addr == NEW_ADDR) { + return 1; + } + + if (addr >= LE64_TO_NATIVE(sbi->rawSuper->blockCount) || addr < sbi->smInfoTable->mainBlkaddr) { + DBG(1, "block addr [0x%x]\n", addr); + return 0; + } + /* next block offset will be checked at the end of fsck. */ + return 1; +} + +#define BLOCK_SZ 4096 + +#define IS_DATASEG(t) \ + ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \ + (t == CURSEG_WARM_DATA)) + +#define IS_NODESEG(t) \ + ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \ + (t == CURSEG_WARM_NODE)) + +#define MAIN_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->mainBlkaddr : \ + LE32_TO_NATIVE(F2FS_RAW_SUPER(sbi)->mainBlkId)) +#define SEG0_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->seg0Blkaddr : \ + LE32_TO_NATIVE(F2FS_RAW_SUPER(sbi)->segment0BlkId)) + +#define MAIN_SEGS(sbi) (SM_I(sbi)->mainSegments) +#define TOTAL_SEGS(sbi) (SM_I(sbi)->segmentCount) +#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->logBlksPerSeg) +#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi)) + +#define START_BLOCK(sbi, segno) (SM_I(sbi)->mainBlkaddr + \ + ((segno) << sbi->logBlksPerSeg)) + +#define NEXT_FREE_BLKADDR(sbi, curseg) \ + (START_BLOCK(sbi, (curseg)->segNum) + (curseg)->nextBlkOffset) + +#define SIT_BLK_CNT(sbi) \ + ((MAIN_SEGS(sbi) + SIT_ENTRIES_PER_BLOCK - 1) / SIT_ENTRIES_PER_BLOCK) + +inline struct CurSegmentInfo *CURSEG_I(std::shared_ptr sbi, int type) +{ + return (struct CurSegmentInfo *)(SM_I(sbi)->curSegmentArray + type); +} + +/* for the list of fsync inodes, used only during recovery */ +struct FsyncInodeEntry { + struct ListNode list; /* list head */ + uint32_t ino; /* inode number */ + uint32_t blkaddr; /* block address locating the last fsync */ + uint32_t last_dentry; /* block address locating the last dentry */ +}; + +#define NatsInCursum(jnl) (LE16_TO_NATIVE(jnl->nNats)) +#define SitsInCursum(jnl) (LE16_TO_NATIVE(jnl->nSits)) + +#define NatInJournal(jnl, i) (jnl->natJ.entries[i].ne) +#define NidInJournal(jnl, i) (jnl->natJ.entries[i].nid) +#define SitInJournal(jnl, i) (jnl->sitJ.entries[i].se) +#define SegnoInJournal(jnl, i) (jnl->sitJ.entries[i].segno) + +#define SIT_ENTRY_OFFSET(sit_i, segno) \ + ((segno) % sit_i->sentsPerBlock) +#define SIT_BLOCK_OFFSET(sit_i, segno) \ + ((segno) / SIT_ENTRIES_PER_BLOCK) + +inline bool IsValidDataBlkAddr(uint32_t blkaddr) +{ + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR || blkaddr == COMPRESS_ADDR) { + return false; + } + return true; +} + +inline int32_t IS_CUR_SEGNO(std::shared_ptr sbi, uint32_t segno) +{ + if (sbi == nullptr) { + return -1; + } + for (int32_t i = 0; i < NO_CHECK_TYPE; i++) { + struct CurSegmentInfo *curseg = CURSEG_I(sbi, i); + if (segno == curseg->segNum) { + return 1; + } + } + return 0; +} + +// TODO 改成int32_t 来校验错误 +inline uint64_t BLKOFF_FROM_MAIN(std::shared_ptr sbi, uint64_t blkAddr) +{ + if (sbi == nullptr) { + return 1; + } + ASSERT(blkAddr >= SM_I(sbi)->mainBlkaddr); + return blkAddr - SM_I(sbi)->mainBlkaddr; +} + +// TODO 改成int32_t 来校验错误 +inline uint32_t GET_SEGNO(std::shared_ptr sbi, uint64_t blkAddr) +{ + if (sbi == nullptr) { + return 1; + } + return static_cast(BLKOFF_FROM_MAIN(sbi, blkAddr) >> sbi->logBlksPerSeg); +} + +inline uint32_t OFFSET_IN_SEG(std::shared_ptr sbi, uint64_t blkAddr) +{ + return (uint32_t)(BLKOFF_FROM_MAIN(sbi, blkAddr) + % (1 << sbi->logBlksPerSeg)); +} + +} // namespace Hmfs +} // namespace OHOS +#endif /* HMFS_RESIZE_DATA_H */ diff --git a/tools/hmfs-tools/tools/resize/include/resize_defrag.h b/tools/hmfs-tools/tools/resize/include/resize_defrag.h new file mode 100755 index 0000000..9ca843a --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_defrag.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESIZE_DEFRAG_H +#define OHOS_RESIZE_DEFRAG_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "hmfs_define.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_operator.h" + +namespace OHOS { +namespace Hmfs { + +class ResizeOperator; +class ResizeDefrag{ +public: + ResizeDefrag(ResizeOperator *optPtr, std::shared_ptr sbInfoPtr, std::shared_ptr configPtr); + ~ResizeDefrag() = default; + #ifdef HAVE_LINUX_BLKZONED_H + int GetDeviceIdx(std::shared_ptr sbi, uint32_t segno); + int GetZoneIdxFromDev(std::shared_ptr sbi, uint32_t segno, uint32_t devIdx); + bool IsUsableSegment(std::shared_ptr sbi, unsigned int segno); + bool WritePointerAtZoneStart(unsigned int zoneSegno); + #else + bool IsUsableSegment(std::shared_ptr sbi, unsigned int segno); + bool WritePointerAtZoneStart(unsigned int zone_segno); + #endif + unsigned char *GetSegBitmap(struct SegEntry *se); + unsigned char GetSegType(struct SegEntry *se); + void SetSectionType(unsigned int segno, int type); + int FindNextFreeBlock(uint64_t *to, int left, int wantType, bool newSec); + uint32_t GetFreeSegments(); + unsigned short GetSegVblocks(struct SegEntry *se); + void MoveOneCursegInfo(uint64_t from, int left, int i); + void MoveCursegInfo(uint64_t from, int left); + void ZeroJournalEntries(); + void WriteCursegInfo(); + void RewriteCurrentSitPage(unsigned int segno, struct sitBlockData *sitBlk); + void FlushSitEntries(); + void UpdateSumEntry(uint32_t blkAddr, struct SummaryEntry *sum); + int32_t HmfsMigrateBlock(uint64_t from, uint64_t to); + int32_t HmfsDefragment(uint64_t from, uint64_t len, uint64_t to, int left); +private: + ResizeOperator *opt_; + std::shared_ptr sbInfo_; /** sbi */ + std::shared_ptr config_; /** config */ +}; + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_list.h b/tools/hmfs-tools/tools/resize/include/resize_list.h new file mode 100755 index 0000000..a26df8a --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_list.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RESIZE_LIST_H +#define RESIZE_LIST_H + +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef struct ListNode { + struct ListNode *prev; /* Current node's pointer to the previous node */ + struct ListNode *next; /* Current node's pointer to the next node */ +} ListNode; + +/* list initialize */ +__attribute__((always_inline)) static inline void ListInit(ListNode *list) +{ + list->next = list; + list->prev = list; +} + +/* Get list head node */ +#define GET_LIST_HEAD(object) ((object)->next) + +/* Get list tail node */ +#define GET_LIST_TAIL(object) ((object)->prev) + +/* Insert a new node to list. */ +__attribute__((always_inline)) static inline void ListAdd(ListNode *list, ListNode *node) +{ + node->next = list->next; + node->prev = list; + list->next->prev = node; + list->next = node; +} + +/* Insert a node to the tail of a list. */ +__attribute__((always_inline)) static inline void ListTailInsert(ListNode *list, ListNode *node) +{ + ListAdd(list->prev, node); +} + +/* Insert a new node to list. */ +__attribute__((always_inline)) static inline void ListNodeInsert(ListNode *list, ListNode *node) +{ + ListAdd(list, node); +} + +/* Delete a specified node from list. */ +__attribute__((always_inline)) static inline void ListDelete(ListNode *node) +{ + if (node->next != 0 && node->prev != 0) { + node->next->prev = node->prev; + node->prev->next = node->next; + } + node->next = node; + node->prev = node; +} + +__attribute__((always_inline)) static inline bool IsListEmpty(const ListNode *node) +{ + return (bool)(node->next == node); +} + +/* + * @brief Obtain the pointer to a list in a structure + * + * @param type [IN] Structure name. + * @param member [IN] Member name of the list in the structure. + */ +#define OFF_SET_OF(type, member) ((size_t)&(((type *)0)->member)) + +#ifndef CONTAINER_OF +#define CONTAINER_OF(ptr, type, member) \ + (type *)((char *)(ptr) - (char *) &((type *)0)->member) +#endif + +/* + * @brief Obtain the pointer to a structure that contains a list. + * @param item [IN] Current node's pointer to the next node. + * @param type [IN] Structure name. + * @param member [IN] Member name of the list in the structure. + */ +#define LIST_ENTRY(item, type, member) \ + ((type *)(void *)((char *)(item) - OFF_SET_OF(type, member))) \ + +/* Iterate over a list of given type. */ +#define LIST_FOR_EACH_ENTRY(item, list, type, member) \ + for ((item) = LIST_ENTRY((list)->next, type, member); \ + ((item) != NULL) && (&(item)->member != (list)); \ + (item) = LIST_ENTRY((item)->member.next, type, member)) + +/* Iterate over a list safe against removal of list entry. */ +#define LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, list, type, member) \ + for ((item) = LIST_ENTRY((list)->next, type, member), \ + (nextItem) = LIST_ENTRY((item)->member.next, type, member); \ + &((item)->member) != (list); \ + (item) = (nextItem), (nextItem) = LIST_ENTRY((item)->member.next, type, member)) + +__attribute__((always_inline)) static inline void ListDel(ListNode *prevNode, ListNode *nextNode) +{ + nextNode->prev = prevNode; + prevNode->next = nextNode; +} + +/* Delete node and initialize list */ +__attribute__((always_inline)) static inline void ListDelInit(ListNode *list) +{ + ListDel(list->prev, list->next); + ListInit(list); +} + +/* Iterate over a list. */ +#define LIST_FOR_EACH(item, list) \ + for ((item) = (list)->next; (item) != (list); (item) = (item)->next) + +/* Iterate over a list safe against removal of list entry. */ +#define LIST_FOR_EACH_SAFE(item, nextItem, list) \ + for ((item) = (list)->next, (nextItem) = (item)->next; (item) != (list); \ + (item) = (nextItem), (nextItem) = (item)->next) + +/* Initialize a list. */ +#define LIST_HEAD(list) ListNode list = { &(list), &(list) } + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* RESIZE_LIST_H */ diff --git a/tools/hmfs-tools/tools/resize/include/resize_load.h b/tools/hmfs-tools/tools/resize/include/resize_load.h new file mode 100755 index 0000000..914c405 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_load.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_HMFS_RESIZE_LOAD_H +#define OHOS_HMFS_RESIZE_LOAD_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_load_sb.h" +#include "resize_load_cp.h" +#include "resize_load_sit.h" +#include "resize_load_nat.h" + +namespace OHOS { +namespace Hmfs { +class ResizeLoadSb; +class ResizeLoadCp; +class ResizeLoadSit; +class ResizeLoadNat; +class ResizeLoad{ +public: + ResizeLoad(std::shared_ptr configPtr, std::shared_ptr sbInfoPtr); + ~ResizeLoad() = default; + void UpdateSuperBlock(struct SuperBlockData *superBlock, int sbMask); + int32_t InitSbInfo(); + int32_t HmfsShouldProceed(struct SuperBlockData *sbData, uint32_t flag); + int32_t UpdateSbFeatures(); + void *GetBitmapPtr(int flag); + uint32_t GetStartCpAddr(); + uint32_t GetNextFreeBlkAddr(struct CurSegmentInfo * curseg); + bool HmfsIsValidBlkaddr(uint32_t blkaddr, int type); + struct FsyncInodeEntry* GetFsyncInode(struct ListNode *head, uint32_t ino); + struct FsyncInodeEntry* AddFsyncinode(struct ListNode *head, uint32_t ino); + int32_t FindFsyncInode(struct ListNode *head); + int32_t HmfsRaMetaPages(uint32_t start, int nrpages, int type); + int32_t DoRecordFsyncData(struct NodeData *node_blk, uint32_t blkaddr); + void DelFsyncInode(struct FsyncInodeEntry *entry); + int32_t TraverseDnodes(struct ListNode *inode_list); + void DestroyFsyncDnodes(struct ListNode *head); + int32_t RecordFsyncData(ResizeLoadSit &loadSit); + int32_t HmfsLoadData(); + void HmfsUnLoadData(); + std::shared_ptr GetConfig(); + std::shared_ptr GetSbInfo(); +private: + std::shared_ptr config_; /** config */ + std::shared_ptr sbInfo_; /** sbi */ +}; + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_load_cp.h b/tools/hmfs-tools/tools/resize/include/resize_load_cp.h new file mode 100755 index 0000000..a82f4c7 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_load_cp.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_HMFS_RESIZE_LOAD_CP_H +#define OHOS_HMFS_RESIZE_LOAD_CP_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_load.h" + +namespace OHOS { +namespace Hmfs { +class ResizeLoad; +class ResizeLoadCp{ +public: + ResizeLoadCp(ResizeLoad *loadPtr); + ~ResizeLoadCp() = default; + uint32_t HmfsCheckpointChksum(struct CheckPointData *cpData); + int32_t verifyCpchecksum(struct CheckPointData *cpData); + void *GetCheckpoint(uint32_t cpStartBlkId); + void *ValidateCheckpoint(uint32_t cpStartBlkId, unsigned long long *version); + int32_t GetAvailCheckpoint(); + int32_t HmfsCheckCheckPoint(); + int32_t HmfsLoadCpData(); +private: + ResizeLoad *load_; + std::shared_ptr config_; /** config */ + std::shared_ptr sbInfo_; /** sbi */ +}; + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_load_nat.h b/tools/hmfs-tools/tools/resize/include/resize_load_nat.h new file mode 100755 index 0000000..dde5d30 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_load_nat.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_HMFS_RESIZE_LOAD_NAT_H +#define OHOS_HMFS_RESIZE_LOAD_NAT_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_load.h" + +namespace OHOS { +namespace Hmfs { +class ResizeLoad; +class ResizeLoadNat{ +public: + ResizeLoadNat(ResizeLoad *loadPtr); + ~ResizeLoadNat() = default; + int32_t InitNidBitmapBegin(); + int32_t InitNodeManager(); + int32_t BuildNodeManager(); + int32_t HmfsLateInitNidBitmap(); +private: + ResizeLoad *load_; + std::shared_ptr config_; /** config */ + std::shared_ptr sbInfo_; /** sbi */ +}; + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_load_sb.h b/tools/hmfs-tools/tools/resize/include/resize_load_sb.h new file mode 100755 index 0000000..ac96382 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_load_sb.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_HMFS_RESIZE_LOAD_SB_H +#define OHOS_HMFS_RESIZE_LOAD_SB_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_load.h" + +namespace OHOS { +namespace Hmfs { +class ResizeLoad; +class ResizeLoadSb{ +public: + ResizeLoadSb(ResizeLoad *loadPtr); + ~ResizeLoadSb() = default; + int32_t SetFeature(int32_t feature); + void CheckSetFeatures(SB_ADDR sb_addr); + int32_t CheckAddrBoundary(struct SuperBlockData *superBlock, enum SB_ADDR sbAddr); + int32_t VerifySbChecksum(struct SuperBlockData *superBlock); + int32_t CheckSuperBlock(struct SuperBlockData *superBlock, enum SB_ADDR sbAddr); + bool isCheckpointStop(struct SuperBlockData *superBlock, bool abnormal); + bool isInconsistentError(struct SuperBlockData *superBlock); + int32_t ValidateSuperBlock(SB_ADDR sbAddr); + int32_t CheckSectorSize(struct SuperBlockData *superBlock); + int32_t HmfsLoadSbData(); +private: + ResizeLoad *load_; + std::shared_ptr config_; /** config */ + std::shared_ptr sbInfo_; /** sbi */ +}; + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_load_sit.h b/tools/hmfs-tools/tools/resize/include/resize_load_sit.h new file mode 100755 index 0000000..86bf83a --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_load_sit.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_HMFS_RESIZE_LOAD_SIT_H +#define OHOS_HMFS_RESIZE_LOAD_SIT_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_load.h" + +namespace OHOS { +namespace Hmfs { +class ResizeLoad; +class ResizeLoadSit{ +public: + ResizeLoadSit(ResizeLoad *loadPtr); + ~ResizeLoadSit() = default; + bool IsSyncDataRecord(); + int32_t BuildSitInfo(); + uint32_t GetStartSumBlock(); + uint32_t GetSumBlkAddr(int base, int type); + void ReadCompactSummaries(); + void RestoreNodeSummary(unsigned int segno, struct SummaryBlockData *sumblk); + void ReadNormalSummaries(int type); + void UpdateCurSegSummaries(); + int32_t BuildCurSegment(); + int32_t BuildSegmentBegin(); + int32_t BuildSitEntries(); + void InsideSegInfoFromRawSit(struct SegEntry *se, struct sitEntry *rawSit); + void SegInfoFromRawSit(struct SegEntry *se, struct sitEntry *rawSit); + void CheckBlockCount(unsigned int segno, struct sitEntry *rawSit); + int32_t LateBuildSegmentManager(); +private: + ResizeLoad *load_; + std::shared_ptr config_; /** config */ + std::shared_ptr sbInfo_; /** sbi */ +}; + +// template +// class ResizeOperator : public Singleton> { +// public: +// T &GetResizeOperator(); +// private: +// T resizeOperator_; +// }; + +// template +// T &ResizeOperator::GetResizeOperator() +// { +// return resizeOperator_; +// } + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_operator.h b/tools/hmfs-tools/tools/resize/include/resize_operator.h new file mode 100755 index 0000000..b7a9524 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_operator.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_HMFS_RESIZE_OPERATOR_H +#define OHOS_HMFS_RESIZE_OPERATOR_H + +#include +#include "hmfs_data.h" +#include "hmfs_utils.h" +#include "resize_command.h" +#include "resize_data.h" +#include "resize_utils.h" +#include "resize_defrag.h" + +namespace OHOS { +namespace Hmfs { +class ResizeDefrag; +class ResizeOperator { +public: + ResizeOperator(CmdConfig &resizeConfig); + ~ResizeOperator() = default; + void InitConfig(); + int32_t GetNewSuperBlock(struct SuperBlockData *sbData); + int32_t ShrinkNats(struct SuperBlockData *newSbData); + int32_t GetSumEntry(uint32_t blkAddr, struct SummaryEntry *sumEntry); + struct SummaryBlockData* GetSumBlock(unsigned int segno, int *ret_type); + int32_t MigrateMainArea(unsigned int offset); + void MoveSsa(unsigned int segno, uint32_t newSumBlkAddr); + void UpdateDataBlkaddr(uint32_t nid, uint16_t ofsInNode, uint32_t newAddr); + void UpdateNatBlkaddr(uint32_t ino, uint32_t nid, uint32_t newaddr); + int32_t MigrateSsa(struct SuperBlockData *newSbData, unsigned int offset); + int32_t MigrateNat(struct SuperBlockData *newSbData); + int32_t MigrateSit(struct SuperBlockData *newSbData, unsigned int offset); + int32_t RebuildCheckpoint(struct SuperBlockData *newSbData, unsigned int offset); + int32_t HmfsResizeCheck(struct SuperBlockData *newSbData); + int32_t FlushNatJournalEntries(); + void RewriteCurrentSitPage(unsigned int segno, struct sitBlockData *sitBlk); + int32_t FlushSitJournalEntries(); + void DuplicateCheckpoint(); + uint32_t GetFreeSegments(); + uint32_t UpdateNatBitsFlags(struct SuperBlockData *sbData, struct CheckPointData *cpData, uint32_t flags); + uint32_t HmfsCheckpointChksum(struct CheckPointData *cpData); + uint64_t GetCpCrc(struct CheckPointData *cpData); + void WriteNatBits(struct SuperBlockData *sbData, struct CheckPointData *cpData, int set); + int HmfsFsyncDevice(); + void WriteCheckpoint(); + void DupWriteCheckpoints(); + void FlushJournalEntries(); + void UpdateSuperBlock(struct SuperBlockData *superBlock, int sbMask); + int32_t HmfsResizeExpand(); + int32_t HmfsResizeShrink(); + int32_t HmfsResize(); + int32_t CreateDeviceInfo(); + int32_t InitDeviceInfoToConfig(); + +private: + CmdConfig &resizeConfig_; /** resize param */ + std::shared_ptr config_; /** config */ + std::shared_ptr sbInfo_; /** sbi */ + std::unique_ptr reDefrag_; +}; + +// template +// class ResizeOperator : public Singleton> { +// public: +// T &GetResizeOperator(); +// private: +// T resizeOperator_; +// }; + +// template +// T &ResizeOperator::GetResizeOperator() +// { +// return resizeOperator_; +// } + +} +} +#endif diff --git a/tools/hmfs-tools/tools/resize/include/resize_utils.h b/tools/hmfs-tools/tools/resize/include/resize_utils.h new file mode 100755 index 0000000..9218e36 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/include/resize_utils.h @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HMFS_RESIZE_UTILS_H +#define HMFS_RESIZE_UTILS_H + +#include +#include + +#include "hmfs_common.h" +#include "hmfs_io.h" +#include "hmfs_zoned.h" +#include "resize_data.h" + +namespace OHOS { +namespace Hmfs { + +inline bool IsCheckpointFlags(struct CheckPointData *cpData, unsigned int flag) +{ + unsigned int ckptFlags = LE32_TO_NATIVE(cpData->cpFlags); + return ckptFlags & flag ? 1 : 0; +} + +inline bool NeedFsyncDataRecord(std::shared_ptr sbInfo_, std::shared_ptr config_) +{ + return !IsCheckpointFlags(sbInfo_->ckptData, CP_UMOUNT_FLAG) || + config_->zonedModel == HMFS_ZONED_HM; +} + +inline uint32_t EndBlockAddr(std::shared_ptr sbInfo_) +{ + return SM_I(sbInfo_)->mainBlkaddr + + (LE32_TO_NATIVE(F2FS_RAW_SUPER(sbInfo_)->segmentCountInMain) << + sbInfo_->logBlksPerSeg); +} + +inline int ExistQfIno(struct SuperBlockData *superBlock) +{ + int i; + for (i = 0; i < HMFS_MAX_QUOTAS; i++) { + if (superBlock->qfInodeId[i]) { + return 1; + } + } + return 0; +} + +inline void CheckSegRange(std::shared_ptr sbInfo_, unsigned int segno) +{ + unsigned int endSegno = sbInfo_->smInfoTable->segmentCount - 1; + ASSERT(segno <= endSegno); +} + +inline uint32_t CurrentSitAddr(std::shared_ptr sbInfo_,unsigned int segno) +{ + SegmentInfoTable * smInfo = sbInfo_->smInfoTable; + struct SitInfo *sitInfo = smInfo->sitInfo; + unsigned int offset = SIT_BLOCK_OFFSET(sitInfo, segno); + uint32_t blkAddr = sitInfo->sitBaseAddr + offset; + + CheckSegRange(sbInfo_, segno); + + /* calculate sit block address */ + if (HmfsCommon::GetInstance().HmfsTestBit(offset, sitInfo->sitBitmap)) { + blkAddr += sitInfo->sitBlocks; + } + return blkAddr; +} + +inline void GetCurrentSitPage(std::shared_ptr sbInfo_, unsigned int segno, struct sitBlockData *sitBlk) +{ + uint32_t blkAddr = CurrentSitAddr(sbInfo_, segno); + ASSERT(HmfsIo::GetInstance().DevReadBlock(sitBlk, blkAddr) >= 0); +} + +inline struct SegEntry* GetSegEntry(std::shared_ptr sbInfo_, unsigned int segno) +{ + struct SitInfo *sitInfo = sbInfo_->smInfoTable->sitInfo; + return &sitInfo->segEntries[segno]; +} + +inline void ResetCurSegment(std::shared_ptr sbInfo_, int32_t type) +{ + struct CurSegmentInfo *curseg = static_cast(sbInfo_->smInfoTable->curSegmentArray + type); + + struct SummaryFooter *sumFooter = &(curseg->segSumBlk->footer); + memset(sumFooter, 0, sizeof(struct SummaryFooter)); + if (IS_DATASEG(type)) { + SET_SUM_TYPE(sumFooter, SUM_TYPE_DATA); + } + if (IS_NODESEG(type)) { + SET_SUM_TYPE(sumFooter, SUM_TYPE_NODE); + } + struct SegEntry *se = GetSegEntry(sbInfo_, curseg->segNum); + se->type = type; + se->dirty = 1; +} + +inline void PrintSbDataFeature(struct SuperBlockData *sbData) +{ + uint32_t f = sbData->features; + HMFS_DEBUG("superblock features = %x : ", f); + if (f & NATIVE_TO_LE32(HMFS_FEATURE_ENCRYPT)) { + HMFS_DEBUG("%s", " encrypt"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_VERITY)) { + HMFS_DEBUG("%s", " verity"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_BLKZONED)) { + HMFS_DEBUG("%s", " blkzoned"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_EXTRA_ATTR)) { + HMFS_DEBUG("%s", " extra_attr"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_PRJQUOTA)) { + HMFS_DEBUG("%s", " project_quota"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_INODE_CHKSUM)) { + HMFS_DEBUG("%s", " inode_checksum"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_FLEXIBLE_INLINE_XATTR)) { + HMFS_DEBUG("%s", " flexible_inline_xattr"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_QUOTA_INO)) { + HMFS_DEBUG("%s", " quota_ino"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_INODE_CRTIME)) { + HMFS_DEBUG("%s", " inode_crtime"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_LOST_FOUND)) { + HMFS_DEBUG("%s", " lost_found"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_SB_CHKSUM)) { + HMFS_DEBUG("%s", " sb_checksum"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_CASEFOLD)) { + HMFS_DEBUG("%s", " casefold"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_COMPRESSION)) { + HMFS_DEBUG("%s", " compression"); + } + if (f & NATIVE_TO_LE32(HMFS_FEATURE_RO)) { + HMFS_DEBUG("%s", " ro"); + } + HMFS_DEBUG("\n"); + HMFS_DEBUG("superblock encrypt level = %d, salt = ", sbData->encryptionLevel); + for (int i = 0; i < 16; i++) { + HMFS_DEBUG("%02x", sbData->encryptPwSalt[i]); + } +} + +inline void PrintSbDataStopReason(struct SuperBlockData *sbData, int forceStop) +{ + if(!forceStop) { + return; + } + uint8_t *reason = sbData->stopReason; + HMFS_DEBUG("checkpoint stop reason: "); + std::string stopReasonStr[] = { + [STOP_CP_REASON_SHUTDOWN] = "shutdown", + [STOP_CP_REASON_FAULT_INJECT] = "fault_inject", + [STOP_CP_REASON_META_PAGE] = "meta_page", + [STOP_CP_REASON_WRITE_FAIL] = "write_fail", + [STOP_CP_REASON_CORRUPTED_SUMMARY] = "corrupted_summary", + [STOP_CP_REASON_UPDATE_INODE] = "update_inode", + [STOP_CP_REASON_FLUSH_FAIL] = "flush_fail", + }; + for (int i = 0; i < STOP_CP_REASON_MAX; i++) { + if (reason[i]) + HMFS_DEBUG("%s(%d) ", stopReasonStr[i].c_str(), reason[i]); + } +} + +inline int TestBitLe(uint32_t nr, const uint8_t *addr) +{ + return ((1 << (nr & 7)) & (addr[nr >> 3])); +} + +enum f2fs_error { + ERROR_CORRUPTED_CLUSTER, + ERROR_FAIL_DECOMPRESSION, + ERROR_INVALID_BLKADDR, + ERROR_CORRUPTED_DIRENT, + ERROR_CORRUPTED_INODE, + ERROR_INCONSISTENT_SUMMARY, + ERROR_INCONSISTENT_FOOTER, + ERROR_INCONSISTENT_SUM_TYPE, + ERROR_CORRUPTED_JOURNAL, + ERROR_INCONSISTENT_NODE_COUNT, + ERROR_INCONSISTENT_BLOCK_COUNT, + ERROR_INVALID_CURSEG, + ERROR_INCONSISTENT_SIT, + ERROR_CORRUPTED_VERITY_XATTR, + ERROR_CORRUPTED_XATTR, + ERROR_MAX, +}; + +inline void PrintSbDataErrors(struct SuperBlockData *sbData, int32_t hmfsErrors) +{ + if (!hmfsErrors) { + return; + } + std::string errorsStr[] = { + [ERROR_CORRUPTED_CLUSTER] = "corrupted_cluster", + [ERROR_FAIL_DECOMPRESSION] = "fail_decompression", + [ERROR_INVALID_BLKADDR] = "invalid_blkaddr", + [ERROR_CORRUPTED_DIRENT] = "corrupted_dirent", + [ERROR_CORRUPTED_INODE] = "corrupted_inode", + [ERROR_INCONSISTENT_SUMMARY] = "inconsistent_summary", + [ERROR_INCONSISTENT_FOOTER] = "inconsistent_footer", + [ERROR_INCONSISTENT_SUM_TYPE] = "inconsistent_sum_type", + [ERROR_CORRUPTED_JOURNAL] = "corrupted_journal", + [ERROR_INCONSISTENT_NODE_COUNT] = "inconsistent_node_count", + [ERROR_INCONSISTENT_BLOCK_COUNT] = "inconsistent_block_count", + [ERROR_INVALID_CURSEG] = "invalid_curseg", + [ERROR_INCONSISTENT_SIT] = "inconsistent_sit", + [ERROR_CORRUPTED_VERITY_XATTR] = "corrupted_verity_xattr", + [ERROR_CORRUPTED_XATTR] = "corrupted_xattr", + }; + uint8_t *errors = sbData->errors; + HMFS_DEBUG("hmfs errors: "); + for (int i = 0; i < ERROR_MAX; i++) { + if (TestBitLe(i, errors)) + HMFS_DEBUG("%s ", errorsStr[i].c_str()); + } +} + +inline void PrintRawSbInfo(struct SuperBlockData *sb, int debugLevel, int32_t layout) +{ + if (!debugLevel) { + return; + } + if(layout) { + printf("\n"); + printf("+--------------------------------------------------------+\n"); + printf("| Super block |\n"); + printf("+--------------------------------------------------------+\n"); + } + PRINT_TO_COLSOLE(sb, magicNo); + PRINT_TO_COLSOLE(sb, majorVersion); + // DISP_label(sb->volumeName); + PRINT_TO_COLSOLE(sb, minorVersion); + PRINT_TO_COLSOLE(sb, logSectorSize); + PRINT_TO_COLSOLE(sb, logSectorsPerBlk); + + PRINT_TO_COLSOLE(sb, logBlockSize); + PRINT_TO_COLSOLE(sb, logBlksPerSeg); + PRINT_TO_COLSOLE(sb, segsPerSection); + PRINT_TO_COLSOLE(sb, sectionsPerZone); + PRINT_TO_COLSOLE(sb, checksumOffset); + PRINT_TO_COLSOLE(sb, blockCount); + + PRINT_TO_COLSOLE(sb, sectionCount); + PRINT_TO_COLSOLE(sb, segmentCount); + PRINT_TO_COLSOLE(sb, segmentCountInCP); + PRINT_TO_COLSOLE(sb, segmentCountInSIT); + PRINT_TO_COLSOLE(sb, segmentCountInNAT); + + PRINT_TO_COLSOLE(sb, segmentCountInSSA); + PRINT_TO_COLSOLE(sb, segmentCountInMain); + PRINT_TO_COLSOLE(sb, segment0BlkId); + + PRINT_TO_COLSOLE(sb, cpBlkId); + PRINT_TO_COLSOLE(sb, sitBlkId); + PRINT_TO_COLSOLE(sb, natBlkId); + PRINT_TO_COLSOLE(sb, ssaBlkId); + PRINT_TO_COLSOLE(sb, mainBlkId); + + PRINT_TO_COLSOLE(sb, rootInodeId); + PRINT_TO_COLSOLE(sb, nodeInodeId); + PRINT_TO_COLSOLE(sb, metaInodeId); + PRINT_TO_COLSOLE(sb, cpPayload); + // PRINT_TO_COLSOLE(sb, crc); + printf("%-25s%-.255s", "version", sb->version); + printf("\n"); +} + +inline void PrintCheckpointInfo(struct CheckPointData *cp, int debugLevel, int32_t layout) +{ + if (!debugLevel) { + return; + } + if(layout) { + printf("\n"); + printf("+--------------------------------------------------------+\n"); + printf("| Checkpoint |\n"); + printf("+--------------------------------------------------------+\n"); + } + PRINT_TO_COLSOLE(cp, cpVersion); + PRINT_TO_COLSOLE(cp, userBlockCount); + PRINT_TO_COLSOLE(cp, validBlockCount); + PRINT_TO_COLSOLE(cp, rsvdSegmentCount); + PRINT_TO_COLSOLE(cp, overprovSegmentCount); + PRINT_TO_COLSOLE(cp, freeSegmentCount); + + PRINT_TO_COLSOLE(cp, allocType[CURSEG_HOT_NODE]); + PRINT_TO_COLSOLE(cp, allocType[CURSEG_WARM_NODE]); + PRINT_TO_COLSOLE(cp, allocType[CURSEG_COLD_NODE]); + PRINT_TO_COLSOLE(cp, curNodeSegNo[0]); + PRINT_TO_COLSOLE(cp, curNodeSegNo[1]); + PRINT_TO_COLSOLE(cp, curNodeSegNo[2]); + + PRINT_TO_COLSOLE(cp, curNodeBlkOffset[0]); + PRINT_TO_COLSOLE(cp, curNodeBlkOffset[1]); + PRINT_TO_COLSOLE(cp, curNodeBlkOffset[2]); + + + PRINT_TO_COLSOLE(cp, allocType[CURSEG_HOT_DATA]); + PRINT_TO_COLSOLE(cp, allocType[CURSEG_WARM_DATA]); + PRINT_TO_COLSOLE(cp, allocType[CURSEG_COLD_DATA]); + PRINT_TO_COLSOLE(cp, curDataSegNo[0]); + PRINT_TO_COLSOLE(cp, curDataSegNo[1]); + PRINT_TO_COLSOLE(cp, curDataSegNo[2]); + + PRINT_TO_COLSOLE(cp, curDataBlkOffset[0]); + PRINT_TO_COLSOLE(cp, curDataBlkOffset[1]); + PRINT_TO_COLSOLE(cp, curDataBlkOffset[2]); + + PRINT_TO_COLSOLE(cp, cpFlags); + PRINT_TO_COLSOLE(cp, cpPackBlockCount); + PRINT_TO_COLSOLE(cp, cpPackStartSum); + PRINT_TO_COLSOLE(cp, validNodeCount); + PRINT_TO_COLSOLE(cp, validInodeCount); + PRINT_TO_COLSOLE(cp, nextFreeNodeId); + PRINT_TO_COLSOLE(cp, sitVersionBitmapSize); + PRINT_TO_COLSOLE(cp, natVersionBitmapSize); + PRINT_TO_COLSOLE(cp, checksumOffset); + PRINT_TO_COLSOLE(cp, elapsedTime); + + PRINT_TO_COLSOLE(cp, sitNatVersionBitmap[0]); + printf("\n\n"); +} + +} // namespace Hmfs +} // namespace OHOS + +#endif // HMFS_RESIZE_UTILS_H \ No newline at end of file diff --git a/tools/hmfs-tools/tools/resize/src/resize_command.cpp b/tools/hmfs-tools/tools/resize/src/resize_command.cpp new file mode 100755 index 0000000..696bed5 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_command.cpp @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_command.h" + +#include +#include +#include +#include +#include +#include +#include "hmfs_utils.h" +#include "hmfs_common.h" +#include "hmfs_encoding.h" +namespace OHOS { +namespace Hmfs { +const struct option ResizeCmdParser::CMD_OPTS[] = { + { "d", required_argument, nullptr, Option::DEBUG }, + { "V", no_argument, nullptr, Option::RVERSION}, + { "h", no_argument, nullptr, Option::HELP}, + { "f", no_argument, nullptr, Option::FORCEWRITE }, + { "t", required_argument, nullptr, Option::TARGETSECTOR}, + { "i", no_argument, nullptr, Option::EXNODEBITMAP}, + { "o", required_argument, nullptr, Option::OVERPROVISION}, + { "s", no_argument, nullptr, Option::SAFE}, + { "O", required_argument, nullptr, Option::FEATURELIST}, + { "C", required_argument, nullptr, Option::ENCODING}, + { 0, 0, 0, 0}, +}; + +const std::string ResizeCmdParser::CMD_PARAMS = "d:fst:O:C:io:V"; + +ResizeCmdParser::ResizeCmdParser(CmdConfig &resizeConfig) : CmdParser(resizeConfig), resizeConfig_(resizeConfig) +{ + resizeConfig_.deviceList.resize(1); + using namespace std::placeholders; + RegCmdOption(Option::RVERSION, false, std::bind(&ResizeCmdParser::PrintVersion, this, _1)); + RegCmdOption(Option::HELP, false, std::bind(&ResizeCmdParser::ShowHelp, this, _1)); + // RegCmdOption(Option::RVERSION, false, [this](const std::string &) -> uint32_t { return PrintVersion(); }); + // RegCmdOption(Option::HELP, false, [this](const std::string &) -> uint32_t { return ShowHelp(); }); + RegCmdOption(Option::DEBUG, true, std::bind(&ResizeCmdParser::SetDebugLevel, this, _1)); + RegCmdOption(Option::TARGETSECTOR, true, std::bind(&ResizeCmdParser::SetTargetSectors, this, _1)); + RegCmdOption(Option::SAFE, false, std::bind(&ResizeCmdParser::SetSafe, this, _1)); + RegCmdOption(Option::FORCEWRITE, false, std::bind(&ResizeCmdParser::SetForce, this, _1)); + RegCmdOption(Option::ENCODING, true, std::bind(&ResizeCmdParser::SetEncoding, this, _1)); + RegCmdOption(Option::EXNODEBITMAP, false, std::bind(&ResizeCmdParser::SetExnodeBitmap, this, _1)); + RegCmdOption(Option::OVERPROVISION, true, std::bind(&ResizeCmdParser::SetOverProvision, this, _1)); + RegCmdOption(Option::FEATURELIST, true, std::bind(&ResizeCmdParser::SetFeatureList, this, _1)); + + RegisterSingleton(this); +} + +uint32_t ResizeCmdParser::Parse(int argc, char *argv[]) +{ + if (ParseOption(argc, argv)) { + return -1; + } + + if (optind >= argc) { + HMFS_ERROR("Device not specified"); + ShowCmdUsage(); + return -1; + } + resizeConfig_.deviceList[0] = argv[optind]; + // resizeConfig_.deviceList[0] = argv[optind]; + // if ((optind + 1) < argc) { + // if (resizeConfig_.deviceList.size() > 1) { + // HMFS_ERROR("Not support custom size on multi-devs"); + // ShowCmdUsage(); + // return -1; + // } + // resizeConfig_.totalSectors = atoll(argv[optind + 1]); + // } + + // InitCommand(); + // if (ParseCommand(argc, argv) != RESTOOL_SUCCESS) { + // return RESTOOL_ERROR; + // } + // if (CheckParam() != RESTOOL_SUCCESS) { + // return RESTOOL_ERROR; + // } + + return 0; +} + +void ResizeCmdParser::ShowCmdUsage() +{ + std::cout << "\nUsage: resize.hmfs [options] device\n"; + std::cout << "[options]:\n"; + std::cout << " -d debug level [default:0]\n"; + std::cout << " -i extended node bitmap, node ratio is 20%% by default\n"; + std::cout << " -o overprovision percentage [default:auto]\n"; + std::cout << " -s safe resize (Does not resize metadata)\n"; + std::cout << " -t target sectors [default: device size]\n"; + std::cout << " -O feature1[,feature2,...] e.g. \"fsprojquota,fscasefold\"\n"; + std::cout << " -C [encoding[:flag1,...]] Support casefolding with optional flags\n"; + std::cout << " -V print the version number and exit\n"; +} + +ArgParseResult ResizeCmdParser::SetDebugLevel(const std::string &argValue) +{ + resizeConfig_.debugLevel = std::stoi(argValue); + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::SetForce(const std::string &argValue) +{ + (void)argValue; + resizeConfig_.force = 1; + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::SetSafe(const std::string &argValue) +{ + (void)argValue; + resizeConfig_.safeResize = 1; + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::SetTargetSectors(const std::string &argValue) +{ + if (strncmp(argValue.c_str(), "0x", 2)) { + sscanf(argValue.c_str(), "%" PRIu64"", &resizeConfig_.targetSectors); + } else { + sscanf(argValue.c_str(), "%" PRIu64"", &resizeConfig_.targetSectors); + } + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::PrintVersion(const std::string& argValue) +{ + (void)argValue; + std::cout << "Info: Hmfstool version= " << "1.0" << std::endl; + exit(0); + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::ShowHelp(const std::string& argValue) +{ + (void)argValue; + ShowCmdUsage(); + exit(0); + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::SetEncoding(const std::string &argValue) +{ + std::stringstream input(argValue); + std::string encodingStr; + std::getline(input, encodingStr, ':'); + if (EncodingStrToValue(encodingStr, resizeConfig_.sEncoding)) { + HMFS_ERROR("Unknown encoding : %s", encodingStr.c_str()); + return ArgParseResult::ERROR; + } + std::string flagStr; + if (std::getline(input, flagStr, ':')) { + if (EncodingFlagStrToValue(flagStr, resizeConfig_.sEncodingFlags)) { + HMFS_ERROR("Unknown flag : %s", flagStr.c_str()); + return ArgParseResult::ERROR; + } + } else { + resizeConfig_.sEncodingFlags = GetDefaultEncodingFlag(resizeConfig_.sEncoding); + } + resizeConfig_.features |= HMFS_FEATURE_CASEFOLD; + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::SetOverProvision(const std::string &argValue) +{ + resizeConfig_.newOverprovision = std::stod(argValue); + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::SetExnodeBitmap(const std::string &argValue) +{ + (void)argValue; + resizeConfig_.largeNatBitmap = 1; + return ArgParseResult::OK; +} + +std::vector ResizeCmdParser::SplitStringList(const std::string& srcString, char delimiter) +{ + std::vector list; + std::stringstream strStream(srcString); + std::string subString; + while (std::getline(strStream, subString, delimiter)) { + size_t start = subString.find_first_not_of(" "); + if (start == std::string::npos) { + continue; + } + size_t end = subString.find_last_not_of(" "); + list.emplace_back(subString.substr(start, end - start + 1)); + } + return list; +} + +ArgParseResult ResizeCmdParser::SetFeatureList(const std::string &argValue) +{ + std::unordered_map featureTable = { + {"encrypt", HMFS_FEATURE_ENCRYPT}, + {"extra_attr", HMFS_FEATURE_EXTRA_ATTR}, + {"project_quota", HMFS_FEATURE_PRJQUOTA}, + {"inode_checksum", HMFS_FEATURE_INODE_CHKSUM}, + {"flexible_inline_xattr", HMFS_FEATURE_FLEXIBLE_INLINE_XATTR}, + {"quota", HMFS_FEATURE_QUOTA_INO}, + {"inode_crtime", HMFS_FEATURE_INODE_CRTIME}, + {"lost_found", HMFS_FEATURE_LOST_FOUND}, + {"verity", HMFS_FEATURE_VERITY}, + {"sb_checksum", HMFS_FEATURE_SB_CHKSUM}, + {"casefold", HMFS_FEATURE_CASEFOLD}, + {"compression", HMFS_FEATURE_COMPRESSION}, + {"ro", HMFS_FEATURE_RO}, + }; + + std::vector featureList = SplitStringList(argValue, ','); + for (auto& feature : featureList) { + HMFS_DEBUG("-O featureTrim: %s", feature.c_str()); + auto it = featureTable.find(feature); + if (it == featureTable.end()) { + HMFS_ERROR("Wrong features: %s", feature.c_str()); + return ArgParseResult::ERROR; + } + resizeConfig_.features |= it->second; + } + return ArgParseResult::OK; +} + +ArgParseResult ResizeCmdParser::OptionAProcess(const std::string &argValue) +{ + auto value = std::stoi(argValue); + resizeConfig_.heapBasedAllocation = (value != 0); + return ArgParseResult::OK; +} + +// void ResizeCmdParser::InitCommand() +// { +// using namespace placeholders; +// handles_.emplace(Option::VERSION, [this](const std::string &) -> uint32_t { return PrintVersion(); }); +// handles_.emplace(Option::HELP, [this](const std::string &) -> uint32_t { return ShowHelp(); }); +// handles_.emplace(Option::DEBUG, bind(&ResizeCmdParser::SetDebugLevel, this, _1)); +// handles_.emplace(Option::TARGETSECTOR, bind(&ResizeCmdParser::SetTargetSectors, this, _1)); +// } + +// uint32_t ResizeCmdParser::HandleProcess(int c, const std::string &argValue) +// { +// auto handler = handles_.find(c); +// if (handler == handles_.end()) { +// cerr << "Error: unsupport " << c << endl; +// return -1; +// } +// return handler->second(argValue); +// } + +// uint32_t ResizeCmdParser::CheckError(int argc, char *argv[], int c, int optIndex) +// { +// if (optIndex != -1) { +// if ((optarg == nullptr && (optind - 1 < 0 || optind - 1 >= argc)) || +// (optarg != nullptr && (optind - 2 < 0 || optind - 2 >= argc))) { // 1 or 2 menas optind offset value +// return -1; +// } +// std::string curOpt = (optarg == nullptr) ? argv[optind - 1] : argv[optind - 2]; +// if (curOpt != ("--" + string(CMD_OPTS[optIndex].name))) { +// cerr << "Error: unknown option " << curOpt << endl; +// return -1; +// } +// } +// if (c == Option::UNKNOWN) { +// if (optopt == 0 && (optind - 1 < 0 || optind - 1 >= argc)) { +// return -1; +// } +// std::string optUnknown = (optopt == 0) ? argv[optind - 1] : ("-" + std::string(1, optopt)); +// cerr << "Error: unknown option " << optUnknown << endl; +// return -1; +// } +// if (c == Option::NO_ARGUMENT) { +// if (optind - 1 < 0 || optind - 1 >= argc) { +// return -1; +// } +// if (IsLongOpt(argc, argv)) { +// cerr << "Error: option " << argv[optind - 1] << " must have argument" << endl; +// } else { +// cerr << "Error: unknown option " << argv[optind - 1] << endl; +// } +// return -1; +// } +// return RESTOOL_SUCCESS; +// } + +// uint32_t ResizeCmdParser::ParseCommand(int argc, char *argv[]) +// { +// restoolPath_ = std::string(argv[0]); +// while (true) { +// int optIndex = -1; +// int c = getopt_long(argc, argv, CMD_PARAMS.c_str(), CMD_OPTS, &optIndex); +// if (CheckError(argc, argv, c, optIndex) != 0) { +// return -1; +// } +// if (c == Option::END) { +// if (argc == optind) { +// break; +// } +// std::string errmsg = "Error: invalid arguments : "; +// for (int i = optind; i < argc; i++) { +// errmsg.append(argv[i]).append(" "); +// } +// cerr << errmsg << endl; +// return -1; +// } + +// std::string argValue = (optarg != nullptr) ? optarg : ""; +// if (HandleProcess(c, argValue) != 0) { +// return -1; +// } +// } +// return 0; +// } + +// bool ResizeCmdParser::IsLongOpt(int argc, char *argv[]) const +// { +// if (optind - 1 < 0 || optind - 1 >= argc) { +// return false; +// } +// for (auto iter : CMD_OPTS) { +// if (optopt == iter.val && argv[optind - 1] == ("--" + std::string(iter.name))) { +// return true; +// } +// } +// return false; +// } + +} +} diff --git a/tools/hmfs-tools/tools/resize/src/resize_defrag.cpp b/tools/hmfs-tools/tools/resize/src/resize_defrag.cpp new file mode 100755 index 0000000..948c8b5 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_defrag.cpp @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_defrag.h" +#include "hmfs_define.h" +#include "hmfs_common.h" +#include "resize_data.h" +#include "resize_data.h" +#include "hmfs_zoned.h" + +namespace OHOS { +namespace Hmfs { +ResizeDefrag::ResizeDefrag(ResizeOperator *optPtr, std::shared_ptr sbInfoPtr, std::shared_ptr configPtr) + : opt_(optPtr), sbInfo_(sbInfoPtr), config_(configPtr) +{ + +} + +#ifdef HAVE_LINUX_BLKZONED_H +int ResizeDefrag::GetDeviceIdx(std::shared_ptr sbi, uint32_t segno) +{ + uint32_t segStartBlkaddr = SM_I(sbi)->mainBlkaddr + segno * DEFAULT_BLOCKS_PER_SEGMENT; + for (int i = 0; i < config_->nDevices; i++) { + if (config_->devices[i].startBlkId <= segStartBlkaddr && + config_->devices[i].endBlkId > segStartBlkaddr) { + return i; + } + } + return 0; +} + +int ResizeDefrag::GetZoneIdxFromDev(std::shared_ptr sbi, uint32_t segno, uint32_t devIdx) +{ + uint32_t segStartBlkaddr = START_BLOCK(sbi, segno); + + return (segStartBlkaddr - config_->devices[devIdx].startBlkId) >> + HmfsCommon::GetInstance().LogBase2(sbi->segmentsPerSec * sbi->blocksPerSeg); +} + +bool ResizeDefrag::IsUsableSegment(std::shared_ptr sbi, unsigned int segno) +{ + unsigned int secno = segno / sbi->segmentsPerSec; + uint32_t segStart = START_BLOCK(sbi, segno); + uint32_t blocksPerSec = sbi->blocksPerSeg * sbi->segmentsPerSec; + unsigned int devIdx = GetDeviceIdx(sbi, segno); + unsigned int zoneIdx = GetZoneIdxFromDev(sbi, segno, devIdx); + unsigned int secOff = SM_I(sbi)->mainBlkaddr >> + HmfsCommon::GetInstance().LogBase2(blocksPerSec); + + if (zoneIdx < config_->devices[devIdx].nrRndZones) { + return true; + } + if (config_->devices[devIdx].zonedModel != HMFS_ZONED_HM) { + return true; + } + return segStart < ((secOff + secno) * blocksPerSec) + + config_->devices[devIdx].zoneCapBlocks[zoneIdx]; +} + +#else + +bool ResizeDefrag::IsUsableSegment(std::shared_ptr sbi, unsigned int segno) +{ + return true; +} + +#endif + +uint32_t ResizeDefrag::GetFreeSegments() +{ + uint32_t freeSegs = 0; + for (uint32_t i = 0; i < MAIN_SEGS(sbInfo_); i++) { + struct SegEntry *se = GetSegEntry(sbInfo_, i); + if (se->validBlocks == 0x0 && !IS_CUR_SEGNO(sbInfo_, i) && IsUsableSegment(sbInfo_,i)) { + freeSegs++; + } + } + return freeSegs; +} + +unsigned short ResizeDefrag::GetSegVblocks(struct SegEntry *se) +{ + if (!NeedFsyncDataRecord(sbInfo_, config_)) { + return se->validBlocks; + } else { + return se->ckptValidBlocks; + } +} + +unsigned char* ResizeDefrag::GetSegBitmap(struct SegEntry *se) +{ + if (!NeedFsyncDataRecord(sbInfo_, config_)) { + return se->curValidBitmap; + } else { + return se->ckptValidBitmap; + } +} + +unsigned char ResizeDefrag::GetSegType(struct SegEntry *se) +{ + if (!NeedFsyncDataRecord(sbInfo_, config_)) { + return se->type; + } else { + return se->ckptType; + } +} + +void ResizeDefrag::SetSectionType(unsigned int segno, int type) +{ + if (sbInfo_->segmentsPerSec == 1) { + return; + } + for (unsigned int i = 0; i < sbInfo_->segmentsPerSec; i++) { + struct SegEntry *se = GetSegEntry(sbInfo_, segno + i); + se->type = type; + } +} + +#ifdef HAVE_LINUX_BLKZONED_H + +bool ResizeDefrag::WritePointerAtZoneStart(unsigned int zoneSegno) +{ + struct BlockZone blkz; + uint32_t block = START_BLOCK(sbInfo_, zoneSegno); + int logSectorsPerBlock = sbInfo_->logBlockSize - SECTOR_SHIFT; + int j; + + if (config_->zonedModel != HMFS_ZONED_HM) { + return true; + } + for (j = 0; j < MAX_DEVICES; j++) { + if (!config_->devices[j].path.c_str()) + break; + if (config_->devices[j].startBlkId <= block && + block <= config_->devices[j].endBlkId) + break; + } + + if (j >= MAX_DEVICES) { + return false; + } + uint64_t sector = (block - config_->devices[j].startBlkId) << logSectorsPerBlock; + int ret = HmfsZoned::GetInstance().HmfsReportZone(j, sector, &blkz); + if (ret) { + return false; + } + if (BLK_ZONE_TYPE(&blkz) != BLK_ZONE_TYPE_SEQWRITE_REQ) + return true; + + return BLK_ZONE_SECTOR(&blkz) == BLK_ZONE_WP_SECTOR(&blkz); +} + +#else + +bool ResizeDefrag::WritePointerAtZoneStart(unsigned int zone_segno) +{ + return true; +} + +#endif + +int ResizeDefrag::FindNextFreeBlock(uint64_t *to, int left, int wantType, bool newSec) +{ + struct SuperBlockData *sbData = F2FS_RAW_SUPER(sbInfo_); + struct SegEntry *se; + uint32_t segno; + uint32_t offset; + int notEnough = 0; + uint64_t endBlkaddr = (GetLeValue(sbData->segmentCountInMain) << + GetLeValue(sbData->logBlksPerSeg)) + GetLeValue(sbData->mainBlkId); + + if (*to > 0) { + *to -= left; + } + if (GetFreeSegments() <= SM_I(sbInfo_)->reservedSegments + 1) { + notEnough = 1; + } + while (*to >= SM_I(sbInfo_)->mainBlkaddr && *to < endBlkaddr) { + unsigned short vblocks; + unsigned char *bitmap; + unsigned char type; + + segno = GET_SEGNO(sbInfo_, *to); + offset = OFFSET_IN_SEG(sbInfo_, *to); + + se = GetSegEntry(sbInfo_, segno); + + vblocks = GetSegVblocks(se); + bitmap = GetSegBitmap(se); + type = GetSegType(se); + + if (vblocks == sbInfo_->blocksPerSeg) { + *to = left ? START_BLOCK(sbInfo_, segno) - 1 : START_BLOCK(sbInfo_, segno + 1); + continue; + } + if (!(GetLeValue(sbData->features) & NATIVE_TO_LE32(HMFS_FEATURE_RO)) && IS_CUR_SEGNO(sbInfo_, segno)) { + *to = left ? START_BLOCK(sbInfo_, segno) - 1 : START_BLOCK(sbInfo_, segno + 1); + continue; + } + if (vblocks == 0 && notEnough) { + *to = left ? START_BLOCK(sbInfo_, segno) - 1 : START_BLOCK(sbInfo_, segno + 1); + continue; + } + if (vblocks == 0 && !(segno % sbInfo_->segmentsPerSec)) { + struct SegEntry *se2; + unsigned int i; + + for (i = 1; i < sbInfo_->segmentsPerSec; i++) { + se2 = GetSegEntry(sbInfo_, segno + i); + if (GetSegVblocks(se2)) { + break; + } + } + + if (i == sbInfo_->segmentsPerSec && + WritePointerAtZoneStart(segno)) { + HMFS_DEBUG("SetSectionType"); + SetSectionType(segno, wantType); + return 0; + } + } + + if (type == wantType && !newSec && + !HmfsCommon::GetInstance().HmfsTestBit(offset, (const char *)bitmap)) { + HMFS_DEBUG("type == wantType"); + return 0; + } + *to = left ? *to - 1: *to + 1; + } + return -1; +} + +void ResizeDefrag::MoveOneCursegInfo(uint64_t from, int left, int i) +{ + struct SuperBlockData *sbData = F2FS_RAW_SUPER(sbInfo_); + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, i); + struct SummaryBlockData buf; + int ret; + uint64_t ssaBlk; + if ((GetLeValue(sbData->features) & NATIVE_TO_LE32(HMFS_FEATURE_RO))) { + if (i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE) { + return; + } + if (i == CURSEG_HOT_DATA) { + left = 0; + from = SM_I(sbInfo_)->mainBlkaddr; + } else { + left = 1; + from = EndBlockAddr(sbInfo_); + } + } else { //TODO 待调试 + /* update original SSA too */ + ssaBlk = GET_SUM_BLKADDR(sbInfo_, curseg->segNum); + ret = HmfsIo::GetInstance().DevWriteBlock(curseg->segSumBlk, ssaBlk); + ASSERT(ret >= 0); + } + uint64_t to = from; + ret = FindNextFreeBlock(&to, left, i, config_->zonedModel == HMFS_ZONED_HM); + ASSERT(ret == 0); + + // uint32_t oldSegno = curseg->segNum; + curseg->segNum = GET_SEGNO(sbInfo_, to); + curseg->nextBlkOffset = OFFSET_IN_SEG(sbInfo_, to); + curseg->allocType = config_->zonedModel == HMFS_ZONED_HM ? LFS : SSR; + + /* update new segno */ + ssaBlk = GET_SUM_BLKADDR(sbInfo_, curseg->segNum); + ret = HmfsIo::GetInstance().DevReadBlock(&buf, ssaBlk); + ASSERT(ret >= 0); + + memcpy(curseg->segSumBlk, &buf, SUM_ENTRIES_SIZE); + + /* update se->types */ + ResetCurSegment(sbInfo_, i); + + // FIX_MSG("Move curseg[%d] %x -> %x after %"PRIx64"\n", + // i, oldSegno, curseg->segNum, from); +} + +void ResizeDefrag::MoveCursegInfo(uint64_t from, int left) +{ + /* update summary blocks having nullified journal entries */ + for (int i = 0; i < NO_CHECK_TYPE; i++) { + MoveOneCursegInfo(from, left, i); + } +} + + +void ResizeDefrag::ZeroJournalEntries() +{ + for (int i = 0; i < NO_CHECK_TYPE; i++) { + CURSEG_I(sbInfo_, i)->segSumBlk->journal.nNats = 0; + } +} + +void ResizeDefrag::WriteCursegInfo() +{ + struct CheckPointData *cpData = F2FS_CKPT(sbInfo_); + for (int i = 0; i < NO_CHECK_TYPE; i++) { + cpData->allocType[i] = CURSEG_I(sbInfo_, i)->allocType; + if (i < CURSEG_HOT_NODE) { + SetLeValue(cpData->curDataSegNo[i], CURSEG_I(sbInfo_, i)->segNum); + SetLeValue(cpData->curDataBlkOffset[i], CURSEG_I(sbInfo_, i)->nextBlkOffset); + } else { + int n = i - CURSEG_HOT_NODE; + SetLeValue(cpData->curNodeSegNo[n], CURSEG_I(sbInfo_, i)->segNum); + SetLeValue(cpData->curNodeBlkOffset[n], CURSEG_I(sbInfo_, i)->nextBlkOffset); + } + } +} + +void ResizeDefrag::RewriteCurrentSitPage(unsigned int segno, struct sitBlockData *sitBlk) +{ + uint32_t blkAddr = CurrentSitAddr(sbInfo_, segno); + ASSERT(HmfsIo::GetInstance().DevWriteBlock(sitBlk, blkAddr) >= 0); +} + +void ResizeDefrag::FlushSitEntries() +{ + struct SitInfo *sitInfo = SIT_I(sbInfo_); + struct sitBlockData *sitBlk = (sitBlockData *)calloc(BLOCK_SZ, 1); + ASSERT(sitBlk); + /* update free segments */ + for (unsigned int segno = 0; segno < MAIN_SEGS(sbInfo_); segno++) { + struct SegEntry *se = GetSegEntry(sbInfo_, segno); + if (!se->dirty) { + continue; + } + GetCurrentSitPage(sbInfo_, segno, sitBlk); + struct sitEntry *sit = &sitBlk->entries[SIT_ENTRY_OFFSET(sitInfo, segno)]; + memcpy(sit->blockBitmap, se->curValidBitmap, SIT_VBLOCK_MAP_SIZE); + sit->usedBlockCount = NATIVE_TO_LE16((se->type << SIT_VBLOCKS_SHIFT) | + se->validBlocks); + RewriteCurrentSitPage(segno, sitBlk); + } + + free(sitBlk); +} + + +void ResizeDefrag::UpdateSumEntry(uint32_t blkAddr, struct SummaryEntry *sum) +{ + struct SuperBlockData *sbData = F2FS_RAW_SUPER(sbInfo_); + int type; + if (GetLeValue(sbData->features) & NATIVE_TO_LE32(HMFS_FEATURE_RO)) { + return; + } + uint32_t segno = GET_SEGNO(sbInfo_, blkAddr); + uint32_t offset = OFFSET_IN_SEG(sbInfo_, blkAddr); + struct SitInfo *sitInfo = sbInfo_->smInfoTable->sitInfo; + struct SegEntry *se = &sitInfo->segEntries[segno]; + + struct SummaryBlockData *sumBlk = opt_->GetSumBlock(segno, &type); + memcpy(&sumBlk->entries[offset], sum, sizeof(*sum)); + sumBlk->footer.entryType = IS_NODESEG(se->type) ? SUM_TYPE_NODE : SUM_TYPE_DATA; + + /* write SSA all the time */ + uint32_t getSumblkAddr = (sbInfo_->smInfoTable->ssaBlkaddr) + segno; + int ret = HmfsIo::GetInstance().DevWriteBlock(sumBlk, getSumblkAddr); + ASSERT(ret >= 0); + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sumBlk); +} + +int32_t ResizeDefrag::HmfsMigrateBlock(uint64_t from, uint64_t to) +{ + void *raw = calloc(BLOCK_SZ, 1); + ASSERT(raw != NULL); + int ret = HmfsIo::GetInstance().DevReadBlock(raw, from); + ASSERT(ret >= 0); + ret = HmfsIo::GetInstance().DevWriteBlock(raw, to); + ASSERT(ret >= 0); + /* update sit bitmap & valid_blocks && se->type */ + struct SitInfo *sitInfo = sbInfo_->smInfoTable->sitInfo; + struct SegEntry *se = &sitInfo->segEntries[GET_SEGNO(sbInfo_, from)]; + uint64_t offset = OFFSET_IN_SEG(sbInfo_, from); + int type = se->type; + se->validBlocks--; + HmfsCommon::GetInstance().HmfsClearBit(offset, (char *)se->curValidBitmap); + se->dirty = 1; + + se = &sitInfo->segEntries[GET_SEGNO(sbInfo_, to)]; + offset = OFFSET_IN_SEG(sbInfo_, to); + se->type = type; + se->validBlocks++; + HmfsCommon::GetInstance().HmfsSetBit(offset, (char *)se->curValidBitmap); + se->dirty = 1; + + struct SummaryEntry sum; + /* read/write SSA */ + opt_->GetSumEntry(from, &sum); + UpdateSumEntry(to, &sum); + + /* if data block, read node and update node block */ + if (IS_DATASEG(type)) { + opt_->UpdateDataBlkaddr(LE32_TO_NATIVE(sum.nid), LE16_TO_NATIVE(sum.ofsInNode), to); + } else { + opt_->UpdateNatBlkaddr(0, LE32_TO_NATIVE(sum.nid), to); + } + // HMFS_INFO("Migrate %s block %"PRIx64" -> %"PRIx64"\n", IS_DATASEG(type) ? "data" : "node", from, to); + free(raw); + return 0; +} + +int32_t ResizeDefrag::HmfsDefragment(uint64_t from, uint64_t len, uint64_t to, int left) +{ + struct SitInfo *sitInfo; + struct SegEntry *se; + uint64_t offset; + /* flush NAT/SIT journal entries */ + opt_->FlushJournalEntries(); + + for (uint64_t idx = from; idx < from + len; idx++) { + uint64_t target = to; + sitInfo = sbInfo_->smInfoTable->sitInfo; + se = &sitInfo->segEntries[GET_SEGNO(sbInfo_, idx)]; + offset = OFFSET_IN_SEG(sbInfo_, idx); + + if (!HmfsCommon::GetInstance().HmfsTestBit(offset, (const char *)se->curValidBitmap)) { + continue; + } + if (FindNextFreeBlock(&target, left, se->type, false)) { + MSG(0, "Not enough space to migrate blocks"); + return -1; + } + if (HmfsMigrateBlock(idx, target)) { + MSG(0, "Found inconsistency: please run FSCK"); + return -1; + } + } + + /* update curseg info; can update sit->types */ + MoveCursegInfo(to, left); + ZeroJournalEntries(); + WriteCursegInfo(); + /* flush dirty sit entries */ + FlushSitEntries(); + opt_->WriteCheckpoint(); + return 0; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/src/resize_load.cpp b/tools/hmfs-tools/tools/resize/src/resize_load.cpp new file mode 100755 index 0000000..f5d351e --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_load.cpp @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_load.h" + +#include +#include +#include + +#include "node.h" +#include "device_manager.h" +#include "hmfs_common.h" +#include "resize_load_sb.h" +#include "resize_load_cp.h" +#include "resize_load_sit.h" +#include "resize_load_nat.h" + +namespace OHOS { +namespace Hmfs { +ResizeLoad::ResizeLoad(std::shared_ptr configPtr, std::shared_ptr sbInfoPtr) + : config_(configPtr), sbInfo_(sbInfoPtr) +{ +} + +void ResizeLoad::UpdateSuperBlock(struct SuperBlockData *superBlock, int sbMask) +{ + uint8_t *buf = static_cast(calloc(BLOCK_SZ, 1)); + ASSERT(buf); + if (GetLeValue(superBlock->features) & HMFS_FEATURE_SB_CHKSUM) { + uint32_t oldCrc = GetLeValue(superBlock->checksum); + uint32_t newCrc = HmfsCommon::GetInstance().HmfsCalCrc32(HMFS_SUPER_MAGIC, superBlock, SB_CHKSUM_OFFSET); + SetLeValue(superBlock->checksum, newCrc); + HMFS_INFO("SuperBlock CRC is updated (0x%x -> 0x%x)", oldCrc, newCrc); + } + + memcpy(buf + HMFS_SUPER_OFFSET, superBlock, sizeof(*superBlock)); + for (int32_t addr = SB0_ADDR; addr < SB_MAX_ADDR; addr++) { + if (SB_MASK(addr) & sbMask) { + int ret = HmfsIo::GetInstance().DevWriteBlock(buf, addr); + ASSERT(ret >= 0); + } + } + free(buf); + HMFS_INFO("Done to update superblock"); +} + +int32_t ResizeLoad::InitSbInfo() +{ + HMFS_DEBUG("Enter InitSbInfo"); + struct SuperBlockData *superB = sbInfo_->rawSuper; + sbInfo_->logSectorsPerBlk = GetLeValue(superB->logSectorsPerBlk); + sbInfo_->logBlockSize = GetLeValue(superB->logBlockSize);; + sbInfo_->blockSize = 1 << sbInfo_->logBlockSize; + sbInfo_->logBlksPerSeg = GetLeValue(superB->logBlksPerSeg); + sbInfo_->blocksPerSeg = 1 << sbInfo_->logBlksPerSeg; + sbInfo_->segmentsPerSec = GetLeValue(superB->segsPerSection); + sbInfo_->sectionsPerZone = GetLeValue(superB->sectionsPerZone); + sbInfo_->totalSections = GetLeValue(superB->sectionCount); + sbInfo_->totalNodeCount = (GetLeValue(superB->segmentCountInNAT) / 2) * + sbInfo_->blocksPerSeg * NAT_ENTRY_PER_BLOCK; + sbInfo_->rootInodeId = GetLeValue(superB->rootInodeId); + sbInfo_->nodeInodeId = GetLeValue(superB->nodeInodeId); + sbInfo_->metaInodeId = GetLeValue(superB->metaInodeId); + sbInfo_->curVictimSec = NULL_SEGNO; + + for (int32_t i = 0; i < MAX_DEVICES; i++) { + if (!superB->devices[i].path[0]) { + HMFS_ERROR("superB->devices[i].path[0] = %s",(char *)superB->devices[i].path); + break; + } + if (i != 0 ) { + config_->devices[i].path = strdup((char *)superB->devices[i].path); + // if (DeviceManager::GetInstance().GetDeviceInfo(i)) //TODO modify + // ASSERT(0); + } else { + ASSERT(!strcmp((char *)superB->devices[i].path, config_->devices[i].path.c_str())); + } + + config_->devices[i].segmentCount = LE32_TO_NATIVE(superB->devices[i].segmentCount); // superB->devices[i].totalSegments换成了 segmentCount。TODO 确认是否正确 + if (i != 0) { + config_->devices[i].startBlkId = config_->devices[i - 1].endBlkId + 1; + } + config_->devices[i].endBlkId = config_->devices[i].startBlkId + config_->devices[i].segmentCount * + config_->blocksPerSegment - 1; + if (i == 0) { + config_->devices[i].endBlkId += GetLeValue(superB->segment0BlkId); + } + if (config_->zonedModel == HMFS_ZONED_NONE) { + if (config_->devices[i].zonedModel == HMFS_ZONED_HM) { + config_->zonedModel = HMFS_ZONED_HM; + } else if (config_->devices[i].zonedModel == HMFS_ZONED_HA && config_->zonedModel != HMFS_ZONED_HM) { + config_->zonedModel = HMFS_ZONED_HA; + } + } + + config_->nDevices = i + 1; + HMFS_INFO("Device[%d] : %s blkaddr = %" PRIx64"--%" PRIx64"", + i, config_->devices[i].path.c_str(), config_->devices[i].startBlkId, config_->devices[i].endBlkId); + } + if(DeviceManager::GetInstance().GetDeviceCount() == 1) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(0); + config_->devices[0].segmentCount = LE32_TO_NATIVE(superB->segmentCount);//TODO device.segmentCount? + deviceInfo->segmentCount = LE32_TO_NATIVE(superB->segmentCount); + config_->devices[0].endBlkId = config_->devices[0].startBlkId + config_->devices[0].segmentCount * config_->blocksPerSegment - 1; + config_->devices[0].endBlkId += GetLeValue(superB->segment0BlkId); + deviceInfo->endBlkId = config_->devices[0].endBlkId; + if (config_->zonedModel == HMFS_ZONED_NONE) { + if (deviceInfo->zonedModel == HMFS_ZONED_HM) { + config_->zonedModel = HMFS_ZONED_HM; + } else if (deviceInfo->zonedModel == HMFS_ZONED_HA && config_->zonedModel != HMFS_ZONED_HM) { + config_->zonedModel = HMFS_ZONED_HA; + } + } + } + uint64_t totalSectors = GetLeValue(superB->blockCount) << sbInfo_->logSectorsPerBlk; + HMFS_INFO("Segments per section = %d", sbInfo_->segmentsPerSec); + HMFS_INFO("Sections per zone = %d", sbInfo_->sectionsPerZone); + HMFS_INFO("total FS sectors = %" PRIu64" (%" PRIu64" MB)", + totalSectors, totalSectors >> (20 - GetLeValue(superB->logSectorSize))); + return SUCCESS_CODE; +} + +int32_t ResizeLoad::HmfsShouldProceed(struct SuperBlockData *sbData, uint32_t flag) +{ + HMFS_DEBUG("Enter HmfsShouldProceed"); + if (sbData == nullptr) { + return EXIT_ERR_CODE; + } + if (!config_->fixOn && (config_->autoFix || config_->preenMode)) { + if (flag & CP_FSCK_FLAG || flag & CP_QUOTA_NEED_FSCK_FLAG || config_->abnormalStop || + config_->hmfsErrors || (ExistQfIno(sbData) && (flag & CP_ERROR_FLAG))) { + config_->fixOn = 1; + } else if (!config_->preenMode) { + //print_cp_state(flag); + return EXIT_ERR_CODE; + } + } + return SUCCESS_CODE; +} + +int32_t ResizeLoad::UpdateSbFeatures() +{ + int sbIschanged = 0; + struct SuperBlockData *sbData = sbInfo_->rawSuper; + + if (!(sbData->features & NATIVE_TO_LE32(HMFS_FEATURE_ENCRYPT)) && + config_->feature & NATIVE_TO_LE32(HMFS_FEATURE_ENCRYPT)) { + sbData->features |= NATIVE_TO_LE32(HMFS_FEATURE_ENCRYPT); + HMFS_INFO("Set Encryption feature"); + sbIschanged = 1; + } + if (!(sbData->features & NATIVE_TO_LE32(HMFS_FEATURE_CASEFOLD)) && + config_->feature & NATIVE_TO_LE32(HMFS_FEATURE_CASEFOLD)) { + if (!config_->encoding) { + HMFS_ERROR("ERROR: Must specify encoding to enable casefolding."); + return EXIT_ERR_CODE; + } + sbData->features |= NATIVE_TO_LE32(HMFS_FEATURE_CASEFOLD); + HMFS_INFO("Set Casefold feature"); + sbIschanged = 1; + } + /* TODO: quota needs to allocate inode numbers */ + + config_->feature = sbData->features; + if (!sbIschanged) { + return SUCCESS_CODE; + } + UpdateSuperBlock(sbData, SB_MASK_ALL); + return SUCCESS_CODE; +} + +void *ResizeLoad::GetBitmapPtr(int flag) +{ + if (sbInfo_ == nullptr) { + return nullptr; + } + CheckPointData *ckpt = sbInfo_->ckptData; + SuperBlockData *sbData = sbInfo_->rawSuper; + int32_t offset; + + if (IsSetCkptFlags(ckpt, CP_LARGE_NAT_BITMAP_FLAG)) { + unsigned int chksumSize = 0; + offset = (flag == SIT_BITMAP) ? + LE32_TO_NATIVE(ckpt->natVersionBitmapSize) : 0; + if (LE32_TO_NATIVE(ckpt->checksumOffset) == + CP_MIN_CHKSUM_OFFSET) + chksumSize = sizeof(uint32_t); + + return &ckpt->sitNatVersionBitmap[offset + chksumSize]; + } + if (LE32_TO_NATIVE(sbData->cpPayload) > 0) { + if (flag == NAT_BITMAP) { + return &ckpt->sitNatVersionBitmap; + } else { + return ((char *)ckpt + HMFS_BLKSIZE); + } + } else { + offset = (flag == NAT_BITMAP) ? LE32_TO_NATIVE(ckpt->sitVersionBitmapSize) : 0; + return &ckpt->sitNatVersionBitmap[offset]; + } +} + +uint32_t ResizeLoad::GetStartCpAddr() +{ + uint32_t startCpAddr = LE32_TO_NATIVE(sbInfo_->rawSuper->cpBlkId); + if(sbInfo_->curCpId == 2) { + startCpAddr += sbInfo_->blocksPerSeg; + } + return startCpAddr; +} + +uint32_t ResizeLoad::GetNextFreeBlkAddr(struct CurSegmentInfo * curseg) +{ + uint32_t segNum = curseg->segNum; + return sbInfo_->smInfoTable->mainBlkaddr + (segNum << sbInfo_->logBlksPerSeg) + + curseg->nextBlkOffset; +} + +bool ResizeLoad::HmfsIsValidBlkaddr(uint32_t blkaddr, int type) +{ + switch (type) { + case META_NAT: + break; + case META_SIT: { + if (blkaddr >= SIT_BLK_CNT(sbInfo_)) { + return SUCCESS_CODE; + } + break; + } + case META_SSA: { + if (blkaddr >= MAIN_BLKADDR(sbInfo_) || blkaddr < SM_I(sbInfo_)->ssaBlkaddr) { + return SUCCESS_CODE; + } + break; + } + case META_CP: { + if (blkaddr >= SIT_I(sbInfo_)->sitBaseAddr || blkaddr < GetStartCpAddr()) { + return SUCCESS_CODE; + } + break; + } + case META_POR: { + if (blkaddr >= MAX_BLKADDR(sbInfo_) || blkaddr < MAIN_BLKADDR(sbInfo_)) { + return SUCCESS_CODE; + } + break; + } + default: + ASSERT(SUCCESS_CODE); + } + return EXIT_ERR_CODE; +} + +struct FsyncInodeEntry* ResizeLoad::GetFsyncInode(struct ListNode *head, uint32_t ino) +{ + struct FsyncInodeEntry *entry; + LIST_FOR_EACH_ENTRY(entry, head, FsyncInodeEntry, list) { + if (entry->ino == ino) { + return entry; + } + } + return nullptr; +} + +struct FsyncInodeEntry* ResizeLoad::AddFsyncinode(struct ListNode *head, uint32_t ino) +{ + struct FsyncInodeEntry *entry = static_cast(calloc(sizeof(struct FsyncInodeEntry), 1)); + if (!entry) { + return nullptr; + } + entry->ino = ino; + ListTailInsert(head, &entry->list); + return entry; +} + +int32_t ResizeLoad::FindFsyncInode(struct ListNode *head) +{ + unsigned int loopCnt = 0; + SegmentInfoTable * smInfo = sbInfo_->smInfoTable; + unsigned int freeBlocks = smInfo->mainSegments * sbInfo_->blocksPerSeg - + sbInfo_->totalValidBlockCount; + int err = 0; + + /* get node pages in the current segment */ + struct CurSegmentInfo *curseg = (struct CurSegmentInfo *) (smInfo->curSegmentArray + CURSEG_WARM_NODE); + uint32_t blkaddr = GetNextFreeBlkAddr(curseg); + + struct NodeData *nodeBlk = static_cast(calloc(HMFS_BLKSIZE, 1)); + ASSERT(nodeBlk); + + while (1) { + struct FsyncInodeEntry *entry; + + if (!HmfsIsValidBlkaddr(blkaddr, META_POR)) { + break; + } + err = HmfsIo::GetInstance().DevReadBlock(nodeBlk, blkaddr); + if (err) { + break; + } + if (!IsRecoverableDnode(sbInfo_, nodeBlk)) { + break; + } + if (!IsFsyncDnode(nodeBlk)) { + if (++loopCnt >= freeBlocks || blkaddr == NextBlkAddrOfNode(nodeBlk)) { + HMFS_ERROR("\tdetect looped node chain, blkaddr"); + err = -1; + break; + } + blkaddr = NextBlkAddrOfNode(nodeBlk); + continue; + } + entry = GetFsyncInode(head, InoOfNode(nodeBlk)); + if (!entry) { + entry = AddFsyncinode(head, InoOfNode(nodeBlk)); + if (!entry) { + err = -1; + break; + } + } + entry->blkaddr = blkaddr; + + if (IsInode(nodeBlk) && IsDentDnode(nodeBlk)) + entry->last_dentry = blkaddr; + + /* sanity check in order to detect looped node chain */ + if (++loopCnt >= freeBlocks || + blkaddr == NextBlkAddrOfNode(nodeBlk)) { + HMFS_ERROR("\tdetect looped node chain, blkaddr:%u, next:%u", blkaddr, + NextBlkAddrOfNode(nodeBlk)); + err = -1; + break; + } + blkaddr = NextBlkAddrOfNode(nodeBlk); + } + + free(nodeBlk); + return err; +} + +/* + * Readahead CP/NAT/SIT/SSA pages + */ +int32_t ResizeLoad::HmfsRaMetaPages(uint32_t start, int nrpages, int type) +{ + uint32_t blkno = start; + uint32_t blkaddr; + uint32_t startBlk = 0; + uint32_t len = 0; + for (; nrpages-- > 0; blkno++) { + + if (!HmfsIsValidBlkaddr(blkno, type)) { + break; + } + + switch (type) { + case META_NAT: + if (blkno >= NAT_BLOCK_OFFSET(NM_I(sbInfo_)->maxNid)) + blkno = 0; + /* get nat block addr */ + blkaddr = CurrentNatAddr(sbInfo_, blkno * NAT_ENTRY_PER_BLOCK, nullptr); + break; + case META_SIT: + /* get sit block addr */ + blkaddr = CurrentSitAddr(sbInfo_, blkno * SIT_ENTRIES_PER_BLOCK); + break; + case META_SSA: + case META_CP: + case META_POR: + blkaddr = blkno; + break; + default: + ASSERT(0); + } + + if (!len) { + startBlk = blkaddr; + len = 1; + } else if (startBlk + len == blkaddr) { + len++; + } else { + HmfsIo::GetInstance().DevReadAhead(startBlk << HMFS_BLKSIZE_BITS); + } + } + + if (len) { + HmfsIo::GetInstance().DevReadAhead(startBlk << HMFS_BLKSIZE_BITS); + } + return blkno - start; +} + +int32_t ResizeLoad::DoRecordFsyncData(struct NodeData *node_blk, uint32_t blkaddr) +{ + unsigned int ofsInNode = 0; + unsigned int start = 0; + int err = 0; + int recorded = 0; + unsigned int segno = GET_SEGNO(sbInfo_, blkaddr); + struct SegEntry *se = GetSegEntry(sbInfo_, segno); + unsigned int offset = OFFSET_IN_SEG(sbInfo_, blkaddr); + if (HmfsCommon::GetInstance().HmfsTestBit(offset, (char *)se->curValidBitmap)) { + ASSERT(0); + return EXIT_ERR_CODE; + } + if (HmfsCommon::GetInstance().HmfsTestBit(offset, (char *)se->ckptValidBitmap)) { + ASSERT(0); + return EXIT_ERR_CODE; + } + + if (!se->ckptValidBlocks) { + se->ckptType = CURSEG_WARM_NODE; + } + se->ckptValidBlocks++; + HmfsCommon::GetInstance().HmfsSetBit(offset, (char *)se->ckptValidBitmap); + + HMFS_INFO("do_record_fsync_data: [node] ino = %u, nid = %u, blkaddr = %u", + InoOfNode(node_blk), OfsOfNode(node_blk), blkaddr); + + /* inline data */ + if (IsInode(node_blk) && (node_blk->i.iInline & HMFS_INLINE_DATA)) { + return SUCCESS_CODE; + } + /* xattr node */ + if (OfsOfNode(node_blk) == XATTR_NODE_OFFSET) { + return SUCCESS_CODE; + } + /* step 3: recover data indices */ + start = StartBidxOfNode(OfsOfNode(node_blk), node_blk); + unsigned int end = start + ADDRS_PER_PAGE(sbInfo_, node_blk, nullptr); + + for (; start < end; start++, ofsInNode++) { + blkaddr = DatablockAddr(node_blk, ofsInNode); + + if (!IsValidDataBlkAddr(blkaddr)) { + continue; + } + if (!HmfsIsValidBlkaddr(blkaddr, META_POR)) { + err = EXIT_ERR_CODE; + HMFS_ERROR("It is invalid blkaddr!"); + return err; + } + + segno = GET_SEGNO(sbInfo_, blkaddr); + se = GetSegEntry(sbInfo_, segno); + offset = OFFSET_IN_SEG(sbInfo_, blkaddr); + if (HmfsCommon::GetInstance().HmfsTestBit(offset, (char *)se->curValidBitmap)) { + continue; + } + if (HmfsCommon::GetInstance().HmfsTestBit(offset, (char *)se->ckptValidBitmap)) { + continue; + } + if (!se->ckptValidBlocks) { + se->ckptType = CURSEG_WARM_DATA; + } + se->ckptValidBlocks++; + HmfsCommon::GetInstance().HmfsSetBit(offset, (char *)se->ckptValidBitmap); + HMFS_INFO("do_record_fsync_data: [data] ino = %u, nid = %u, blkaddr = %u", + InoOfNode(node_blk), OfsOfNode(node_blk), blkaddr); + recorded++; + } + + HMFS_INFO("recover_data: ino = %u, nid = %u, recorded = %d, err = %d", + InoOfNode(node_blk), OfsOfNode(node_blk), recorded, err); + return err; +} + +void ResizeLoad::DelFsyncInode(struct FsyncInodeEntry *entry) +{ + ListDelete(&entry->list); + free(entry); +} + +int32_t ResizeLoad::TraverseDnodes(struct ListNode *inode_list) +{ + int32_t err = 0; + /* get node pages in the current segment */ + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, CURSEG_WARM_NODE); + uint32_t blkaddr = NEXT_FREE_BLKADDR(sbInfo_, curseg); + + struct NodeData *node_blk = static_cast(calloc(HMFS_BLKSIZE, 1)); + ASSERT(node_blk); + + while (1) { + struct FsyncInodeEntry *entry; + + if (!HmfsIsValidBlkaddr(blkaddr, META_POR)) { + break; + } + err = HmfsIo::GetInstance().DevReadBlock(node_blk, blkaddr); + if (err) { + break; + } + if (!IsRecoverableDnode(sbInfo_, node_blk)) { + break; + } + entry = GetFsyncInode(inode_list, InoOfNode(node_blk)); + if (!entry) { + blkaddr = NextBlkAddrOfNode(node_blk); + continue; + } + err = DoRecordFsyncData(node_blk, blkaddr); + if (err) { + break; + } + if (entry->blkaddr == blkaddr){ + DelFsyncInode(entry); + } + + blkaddr = NextBlkAddrOfNode(node_blk); + } + + free(node_blk); + return err; +} + +void ResizeLoad::DestroyFsyncDnodes(struct ListNode *head) +{ + struct FsyncInodeEntry *entry; + struct FsyncInodeEntry *tmp; + LIST_FOR_EACH_ENTRY_SAFE(entry, tmp, head, FsyncInodeEntry, list) { + DelFsyncInode(entry); + } +} + +int32_t ResizeLoad::RecordFsyncData(ResizeLoadSit &loadSit) +{ + HMFS_DEBUG("Enter RecordFsyncData"); + struct ListNode iNodeList = { &iNodeList, &iNodeList }; + if (!NeedFsyncDataRecord(sbInfo_, config_)) { + return SUCCESS_CODE; + } + uint32_t ret = FindFsyncInode(&iNodeList); + if (ret) { + HMFS_ERROR("Failed to find fsync inode"); + DestroyFsyncDnodes(&iNodeList); + return ret; + } + + ret = loadSit.LateBuildSegmentManager(); + if (ret != SUCCESS_CODE) { + HMFS_ERROR("Failed to build segment manager"); + DestroyFsyncDnodes(&iNodeList); + return ret; + } + + ret = TraverseDnodes(&iNodeList); + + DestroyFsyncDnodes(&iNodeList); + return ret; +} + +int32_t ResizeLoad::HmfsLoadData() +{ + HMFS_DEBUG("Enter HmfsLoadData"); + if (sbInfo_ == nullptr) { + return EXIT_ERR_CODE; + } + struct CheckPointData *cpData = nullptr; + struct SuperBlockData *sbData = nullptr; + sbInfo_->activeLogs = NR_CURSEG_TYPE; + + ResizeLoadSb loadSb(this); + int32_t ret = loadSb.HmfsLoadSbData(); + if(ret != SUCCESS_CODE) { + return EXIT_ERR_CODE; + } + sbData = sbInfo_->rawSuper; + + InitSbInfo(); + + ResizeLoadCp loadCp(this); + ret = loadCp.HmfsLoadCpData(); + if(ret != SUCCESS_CODE) { + return EXIT_ERR_CODE; + } + + cpData = sbInfo_->ckptData; + if (config_->quotaFix) { + if (GetLeValue(cpData->cpFlags) & CP_QUOTA_NEED_FSCK_FLAG) + config_->fixOn = 1; + } + if (config_->layout) { + return 1; + } + + if (UpdateSbFeatures() != SUCCESS_CODE) { + HMFS_ERROR("Failed to update superblock features"); + return EXIT_ERR_CODE; + } + + /* precompute checksum seed for metadata */ + if (config_->feature & NATIVE_TO_LE32(HMFS_FEATURE_INODE_CHKSUM)) { + config_->chksumSeed = HmfsCommon::GetInstance().HmfsCalCrc32(~0, sbData->uuid, sizeof(sbData->uuid)); + } + sbInfo_->totalValidNodeCount = GetLeValue(cpData->validNodeCount); + sbInfo_->totalValidInodeCount = GetLeValue(cpData->validInodeCount); + sbInfo_->userBlockCount = GetLeValue(cpData->userBlockCount); + sbInfo_->totalValidBlockCount = GetLeValue(cpData->validBlockCount); + sbInfo_->lastValidBlockCount = sbInfo_->totalValidBlockCount; + sbInfo_->allocValidBlockCount = 0; + + ResizeLoadSit loadSit(this); + ResizeLoadNat loadNat(this); + if (loadSit.BuildSegmentBegin() != SUCCESS_CODE) { + HMFS_ERROR("Failed to build segment begin"); + return EXIT_ERR_CODE; + } + if (loadNat.BuildNodeManager() != SUCCESS_CODE) { + HMFS_ERROR("Failed to build node manager"); + return EXIT_ERR_CODE; + } + if (RecordFsyncData(loadSit) != SUCCESS_CODE) { + HMFS_ERROR("Failed to record fsync data"); + return EXIT_ERR_CODE; + } + if (HmfsShouldProceed(sbData, GetLeValue(cpData->cpFlags)) != SUCCESS_CODE) { + HMFS_ERROR("Failed to proceed"); + return EXIT_ERR_CODE; + } + if (loadSit.LateBuildSegmentManager() != SUCCESS_CODE) { + HMFS_ERROR("Failed to build segment manager"); + return EXIT_ERR_CODE; + } + if (loadNat.HmfsLateInitNidBitmap() != SUCCESS_CODE) { + HMFS_ERROR("Failed to init nid bitmap"); + return EXIT_ERR_CODE; + } + return SUCCESS_CODE; +} + +void ResizeLoad::HmfsUnLoadData() +{ + struct SitInfo *sitInfo = SIT_I(sbInfo_); + struct SegmentInfoTable *smI = SM_I(sbInfo_); + struct NodeAddressTable *nmI = NM_I(sbInfo_); + /* free nm_info */ + // if (c.func == SLOAD || c.func == FSCK) + // free(nm_i->nid_bitmap); + free(nmI->natBitmap); + free(sbInfo_->naTable); + /* free sit_info */ + free(sitInfo->bitmap); + free(sitInfo->sitBitmap); + free(sitInfo->segEntries); + free(smI->sitInfo); + /* free sm_info */ + for (uint32_t i = 0; i < NR_CURSEG_TYPE; i++) { + free(smI->curSegmentArray[i].segSumBlk); + } + free(smI->curSegmentArray); + free(sbInfo_->smInfoTable); + free(sbInfo_->ckptData); + free(sbInfo_->rawSuper); +} + +std::shared_ptr ResizeLoad::GetConfig() +{ + return config_; +} + +std::shared_ptr ResizeLoad::GetSbInfo() +{ + return sbInfo_; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/src/resize_load_cp.cpp b/tools/hmfs-tools/tools/resize/src/resize_load_cp.cpp new file mode 100755 index 0000000..51ac99b --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_load_cp.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_load_cp.h" + +#include +#include +#include + +#include "node.h" +#include "device_manager.h" +#include "hmfs_common.h" + +namespace OHOS { +namespace Hmfs { +ResizeLoadCp::ResizeLoadCp(ResizeLoad *loadPtr) : load_(loadPtr) +{ + config_ = load_->GetConfig(); + sbInfo_ = load_->GetSbInfo(); +} + +uint32_t ResizeLoadCp::HmfsCheckpointChksum(struct CheckPointData *cpData) +{ + if (cpData == nullptr) { + return EXIT_ERR_CODE; + } + unsigned int chksumOffset = LE32_TO_NATIVE(cpData->checksumOffset); + uint32_t chksum = HmfsCommon::GetInstance().HmfsCalCrc32(HMFS_SUPER_MAGIC, cpData, chksumOffset); + if (chksumOffset < CP_CHKSUM_OFFSET) { + chksumOffset += sizeof(chksum); + chksum = HmfsCommon::GetInstance().HmfsCalCrc32(chksum, (__u8 *)cpData + chksumOffset, HMFS_BLKSIZE - chksumOffset); + } + return chksum; +} + +int32_t ResizeLoadCp::verifyCpchecksum(struct CheckPointData *cpData) +{ + if (cpData == nullptr) { + return EXIT_ERR_CODE; + } + + unsigned int chksumOffset = GetLeValue(cpData->checksumOffset); + if (chksumOffset < CP_MIN_CHKSUM_OFFSET || chksumOffset > CP_CHKSUM_OFFSET) { + HMFS_ERROR("\tInvalid CP CRC offset: %u", chksumOffset); + return EXIT_ERR_CODE; + } + + unsigned int crc = LE32_TO_NATIVE(*(uint32_t *)((unsigned char *)cpData + chksumOffset)); + unsigned int calCrc = HmfsCheckpointChksum(cpData); + if (calCrc != crc) { + HMFS_ERROR("\tInvalid CP CRC: offset:%u, crc:0x%x, calc:0x%x", chksumOffset, crc, calCrc); + return EXIT_ERR_CODE; + } + return SUCCESS_CODE; +} + +void* ResizeLoadCp::GetCheckpoint(uint32_t cpStartBlkId) +{ + void *checkPoint = malloc(HMFS_BLKSIZE); + ASSERT(checkPoint); + + if (HmfsIo::GetInstance().DevReadBlock(checkPoint, cpStartBlkId) < 0) { + ASSERT(0); + } + if (verifyCpchecksum((struct CheckPointData *)checkPoint) == -1) { + HMFS_ERROR("verifyCpchecksum fail!"); + PrintCheckpointInfo((struct CheckPointData *)checkPoint, config_->debugLevel, config_->layout); + free(checkPoint); + return nullptr; + } + return checkPoint; +} + +void* ResizeLoadCp::ValidateCheckpoint(uint32_t cpStartBlkId, unsigned long long *version) +{ + if (version == nullptr) { + return nullptr; + } + /* Read the 1st cp block in this CP pack */ + void *checkPoint1 = GetCheckpoint(cpStartBlkId); + if (!checkPoint1) { + return nullptr; + } + struct CheckPointData *cpData = static_cast(checkPoint1); + if (GetLeValue(cpData->cpPackBlockCount) > sbInfo_->blocksPerSeg) { + free(checkPoint1); + return nullptr; + } + unsigned long long preVersion = GetLeValue(cpData->cpVersion); + + /* Read the 2nd cp block in this CP pack */ + cpStartBlkId += GetLeValue(cpData->cpPackBlockCount) - 1; + void *checkPoint2 = GetCheckpoint(cpStartBlkId); + if (!checkPoint2) { + free(checkPoint1); + return nullptr; + } + cpData = (struct CheckPointData *)checkPoint2; + unsigned long long curVersion = GetLeValue(cpData->cpVersion); + + if (curVersion == preVersion) { + *version = curVersion; + free(checkPoint2); + return checkPoint1; + } + free(checkPoint2); + free(checkPoint1); + return nullptr; +} + +int32_t ResizeLoadCp::GetAvailCheckpoint() +{ + HMFS_DEBUG("Enter GetAvailCheckpoint"); + struct SuperBlockData *superB = sbInfo_->rawSuper; + void *curCp; + unsigned long blkSize = sbInfo_->blockSize; + unsigned long long cp1Version = 0; + unsigned long long cp2Version = 0; + unsigned long long version; + + unsigned int cpPayload = GetLeValue(superB->cpPayload); + if (cpPayload > HMFS_BLK_ALIGN(MAX_CP_PAYLOAD)) { + return -EINVAL; + } + unsigned int cpBlks = 1 + cpPayload; + sbInfo_->ckptData = static_cast(malloc(cpBlks * blkSize)); + if (!sbInfo_->ckptData) { + return -ENOMEM; + } + /* + * Finding out valid cp block involves read both + * sets( cp pack1 and cp pack 2) + */ + unsigned long long cpStartBlkId = GetLeValue(superB->cpBlkId); + void *checkPoint1 = ValidateCheckpoint(cpStartBlkId, &cp1Version); + + /* The second checkpoint pack should start at the next segment */ + cpStartBlkId += 1 << GetLeValue(superB->logBlksPerSeg); + void *checkPoint2 = ValidateCheckpoint(cpStartBlkId, &cp2Version); + + if (checkPoint1 && checkPoint2) { + if (ver_after(cp2Version, cp1Version)) { + curCp = checkPoint2; + sbInfo_->curCpId = 2; + version = cp2Version; + } else { + curCp = checkPoint1; + sbInfo_->curCpId = 1; + version = cp1Version; + } + } else if (checkPoint1) { + curCp = checkPoint1; + sbInfo_->curCpId = 1; + version = cp1Version; + } else if (checkPoint2) { + curCp = checkPoint2; + sbInfo_->curCpId = 2; + version = cp2Version; + } else { + free(sbInfo_->ckptData); + sbInfo_->ckptData = nullptr; + return -EINVAL; + } + + HMFS_INFO("CKPT version = %llx", version); + + memcpy(sbInfo_->ckptData, curCp, blkSize); + + if (cpBlks > 1) { + unsigned long long cpBlkNo = GetLeValue(superB->cpBlkId); + if (curCp == checkPoint2) { + cpBlkNo += 1 << GetLeValue(superB->logBlksPerSeg); + } + + /* copy sit bitmap */ + for (uint32_t i = 1; i < cpBlks; i++) { + unsigned char *ckpt = (unsigned char *)sbInfo_->ckptData; + int32_t ret = HmfsIo::GetInstance().DevReadBlock(curCp, cpBlkNo + i); + ASSERT(ret >= 0); + memcpy(ckpt + i * blkSize, curCp, blkSize); + } + } + if (checkPoint1) { + free(checkPoint1); + } + if (checkPoint2) { + free(checkPoint2); + } + return SUCCESS_CODE; + +} + +int32_t ResizeLoadCp::HmfsCheckCheckPoint() +{ + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct CheckPointData *cpData = sbInfo_->ckptData; + unsigned int flag = GetLeValue(cpData->cpFlags); + int i; + uint32_t total = GetLeValue(sbData->segmentCount); + uint32_t fsmeta = GetLeValue(sbData->segmentCountInCP); + uint32_t sitSegments = GetLeValue(sbData->segmentCountInSIT); + fsmeta += sitSegments; + uint32_t natSegments = GetLeValue(sbData->segmentCountInNAT); + fsmeta += natSegments; + fsmeta += GetLeValue(cpData->rsvdSegmentCount); + fsmeta += GetLeValue(sbData->segmentCountInSSA); + + if (fsmeta >= total) { + return EXIT_ERR_CODE; + } + uint32_t ovpSegments = GetLeValue(cpData->overprovSegmentCount); + uint32_t reservedSegments = GetLeValue(cpData->rsvdSegmentCount); + + if (!(GetLeValue(sbData->features) & NATIVE_TO_LE32(HMFS_FEATURE_RO)) && + (fsmeta < HMFS_MIN_SEGMENT || ovpSegments == 0 || reservedSegments == 0)) { + HMFS_ERROR("\tWrong layout: check mkfs.hmfs version"); + return EXIT_ERR_CODE; + } + + uint32_t userBlockCount = GetLeValue(cpData->userBlockCount); + uint32_t segmentCountMain = GetLeValue(sbData->segmentCountInMain) + (NATIVE_TO_LE32(HMFS_FEATURE_RO) ? 1 : 0); + uint32_t logBlocksPerSeg = GetLeValue(sbData->logBlksPerSeg); + if (!userBlockCount || userBlockCount >= segmentCountMain << logBlocksPerSeg) { + HMFS_ERROR("\tWrong userBlockCount(%u)", userBlockCount); + + if (load_->HmfsShouldProceed(sbData, flag) != EXIT_ERR_CODE) { + return EXIT_ERR_CODE; + } + if (!config_->fixOn) { + return EXIT_ERR_CODE; + } + if (flag & (CP_FSCK_FLAG | CP_RESIZEFS_FLAG)) { + uint32_t seg_cnt_main = GetLeValue(sbData->segmentCount) - (GetLeValue(sbData->segmentCountInCP) + + GetLeValue(sbData->segmentCountInSIT) + GetLeValue(sbData->segmentCountInNAT) + + GetLeValue(sbData->segmentCountInSSA)); + + /* validate segment_count_main in sb first */ + if (seg_cnt_main != GetLeValue(sbData->segmentCountInMain)) { + HMFS_ERROR("Inconsistent segment_cnt_main %u in sb", segmentCountMain << logBlocksPerSeg); + return EXIT_ERR_CODE; + } + uint32_t validUserBlocks = ((GetLeValue(sbData->segmentCountInMain) - + GetLeValue(cpData->overprovSegmentCount)) * config_->blocksPerSegment); + HMFS_INFO("Fix wrong userBlockCount in CP: (%u) -> (%u)", userBlockCount, validUserBlocks); + SetLeValue(cpData->userBlockCount, validUserBlocks); + config_->bugOn = 1; + } + } + + uint32_t mainSegmentss = GetLeValue(sbData->segmentCountInMain); + uint32_t blocksPerSeg = sbInfo_->blocksPerSeg; + for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { + if (GetLeValue(cpData->curNodeSegNo[i]) >= mainSegmentss || + GetLeValue(cpData->curNodeBlkOffset[i]) >= blocksPerSeg) + return EXIT_ERR_CODE; + } + for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { + if (GetLeValue(cpData->curDataSegNo[i]) >= mainSegmentss || + GetLeValue(cpData->curDataBlkOffset[i]) >= blocksPerSeg) + return EXIT_ERR_CODE; + } + + uint32_t sitBitmapSize = GetLeValue(cpData->sitVersionBitmapSize); + uint32_t natBitmapSize = GetLeValue(cpData->natVersionBitmapSize); + + if (sitBitmapSize != ((sitSegments / 2) << logBlocksPerSeg) / 8 || + natBitmapSize != ((natSegments / 2) << logBlocksPerSeg) / 8) { + HMFS_ERROR("\tWrong bitmap size: sit(%u), nat(%u)", sitBitmapSize, natBitmapSize); + return EXIT_ERR_CODE; + } + + // cpStartSum = __start_sum_addr(sbInfo_); + // cpPayload = __cp_payload(sbInfo_); + uint32_t cpStartSum = LE32_TO_NATIVE(cpData->cpPackStartSum); + uint32_t cpPayload = LE32_TO_NATIVE(sbData->cpPayload); + if (cpStartSum < cpPayload + 1 || cpStartSum > blocksPerSeg - 1 - NR_CURSEG_TYPE) { + HMFS_ERROR("\tWrong cpStartSum(%u) or cpPayload(%u)", cpStartSum, cpPayload); + if ((GetLeValue(sbData->features) & HMFS_FEATURE_SB_CHKSUM)) { + return EXIT_ERR_CODE; + } + SetLeValue(sbData->cpPayload, cpStartSum - 1); + load_->UpdateSuperBlock(sbData, SB_MASK_ALL); + } + + return SUCCESS_CODE; +} + +int32_t ResizeLoadCp::HmfsLoadCpData() +{ + HMFS_DEBUG("Enter HmfsLoadCpData"); + int32_t ret = GetAvailCheckpoint(); + if (ret != SUCCESS_CODE) { + HMFS_ERROR("Failed to find valid checkpoint"); + //dump_sbi_info(sbInfo_); + PrintCheckpointInfo(F2FS_CKPT(sbInfo_), config_->debugLevel, config_->layout); + return EXIT_ERR_CODE; + } + config_->bugOn = 0; + if (HmfsCheckCheckPoint() != SUCCESS_CODE) { + HMFS_ERROR("Failed to check checkpoint"); + //dump_sbi_info(sbInfo_); + PrintCheckpointInfo(F2FS_CKPT(sbInfo_), config_->debugLevel, config_->layout); + return EXIT_ERR_CODE; + } + + PrintCheckpointInfo(F2FS_CKPT(sbInfo_), config_->debugLevel, config_->layout); + + if (config_->func != FSCK && config_->func != DUMP && + !IsCheckpointFlags(sbInfo_->ckptData, CP_UMOUNT_FLAG)) { + HMFS_ERROR("Mount unclean image to replay log first"); + return EXIT_ERR_CODE; + } + + return SUCCESS_CODE; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/src/resize_load_nat.cpp b/tools/hmfs-tools/tools/resize/src/resize_load_nat.cpp new file mode 100755 index 0000000..5c01eba --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_load_nat.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_load_nat.h" + +#include +#include +#include + +#include "node.h" +#include "device_manager.h" +#include "hmfs_common.h" + +namespace OHOS { +namespace Hmfs { +ResizeLoadNat::ResizeLoadNat(ResizeLoad *loadPtr) : load_(loadPtr) +{ + config_ = load_->GetConfig(); + sbInfo_ = load_->GetSbInfo(); +} + +int32_t ResizeLoadNat::InitNidBitmapBegin() +{ + struct NodeAddressTable *nat = sbInfo_->naTable; + int nidBitmapSize = (nat->maxNid + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + struct CurSegmentInfo *curseg = (struct CurSegmentInfo *) (sbInfo_->smInfoTable->curSegmentArray + CURSEG_HOT_DATA); + struct SummaryBlockData *sum = curseg->segSumBlk; + struct JournalEntry *journal = &sum->journal; + + nat->nidBitmap = static_cast(calloc(nidBitmapSize, 1)); + if (!nat->nidBitmap) { + return -ENOMEM; + } + /* arbitrarily set 0 bit */ + HmfsCommon::GetInstance().HmfsSetBit(0, nat->nidBitmap); + + uint16_t nNats = LE16_TO_NATIVE(journal->nNats); + if (nNats > NAT_JOURNAL_ENTRIES) { + HMFS_ERROR("\tError: hmfs_init_nid_bitmap truncate nNats(%u) to NAT_JOURNAL_ENTRIES(%zu)", + nNats, NAT_JOURNAL_ENTRIES); + journal->nNats = NATIVE_TO_LE16(NAT_JOURNAL_ENTRIES); + config_->fixOn = 1; + } + + for (int32_t i = 0; i < nNats; i++) { + uint32_t addr = LE32_TO_NATIVE(journal->natJ.entries[i].ne.blockId); + if (!IsValidBlkAddr(sbInfo_, addr)) { + HMFS_ERROR("\tError: hmfs_init_nid_bitmap: addr(%u) is invalid!!!", addr); + journal->nNats = NATIVE_TO_LE16(i); + config_->fixOn = 1; + continue; + } + + uint32_t nid = LE32_TO_NATIVE(journal->natJ.entries[i].nid); + if (!IsValidNid(sbInfo_, nid)) { + HMFS_ERROR("\tError: hmfs_init_nid_bitmap: nid(%u) is invalid!!!", nid); + journal->nNats = NATIVE_TO_LE16(i); + config_->fixOn = 1; + continue; + } + if (addr != NULL_ADDR) + HmfsCommon::GetInstance().HmfsSetBit(nid, nat->nidBitmap); + } + return SUCCESS_CODE; +} + +int32_t ResizeLoadNat::InitNodeManager() +{ + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct CheckPointData *cpData = sbInfo_->ckptData; + struct NodeAddressTable *nat = sbInfo_->naTable; + + nat->natBlkaddr = GetLeValue(sbData->natBlkId); + + /* segment_count_nat includes pair segment so divide to 2. */ + unsigned int natSegs = GetLeValue(sbData->segmentCountInNAT) >> 1; + nat->natBlocks = natSegs << GetLeValue(sbData->logBlksPerSeg); + nat->maxNid = NAT_ENTRY_PER_BLOCK * nat->natBlocks; + nat->fcnt = 0; + nat->natCnt = 0; + nat->initScanNid = GetLeValue(cpData->nextFreeNodeId); + nat->nextScanNid = GetLeValue(cpData->nextFreeNodeId); + + nat->bitmapSize = GetBitmapSize(sbInfo_, NAT_BITMAP); + + nat->natBitmap = static_cast(malloc(nat->bitmapSize)); + if (!nat->natBitmap) { + return -ENOMEM; + } + unsigned char *versionBitmap = (unsigned char *)load_->GetBitmapPtr(NAT_BITMAP); + if (!versionBitmap) { + return -EFAULT; + } + /* copy version bitmap */ + memcpy(nat->natBitmap, versionBitmap, nat->bitmapSize); + return InitNidBitmapBegin(); +} + +int32_t ResizeLoadNat::BuildNodeManager() +{ + HMFS_DEBUG("Enter BuildNodeManager"); + sbInfo_->naTable = static_cast(malloc(sizeof(struct NodeAddressTable))); + if (!sbInfo_->naTable) { + return -ENOMEM; + } + int err = InitNodeManager(); + if (err != SUCCESS_CODE) { + return err; + } + return SUCCESS_CODE; +} + +int32_t ResizeLoadNat::HmfsLateInitNidBitmap() +{ + HMFS_DEBUG("Enter HmfsLateInitNidBitmap"); + struct NodeAddressTable *nat = NM_I(sbInfo_); + uint32_t startBlk; + if (!(config_->func == SLOAD || config_->func == FSCK)) { + return 0; + } + struct natBlockData *natBlock = static_cast(malloc(HMFS_BLKSIZE)); + if (!natBlock) { + free(nat->nidBitmap); + return -ENOMEM; + } + + load_->HmfsRaMetaPages(0, NAT_BLOCK_OFFSET(nat->maxNid), META_NAT); + for (uint32_t nid = 0; nid < nat->maxNid; nid++) { + if (!(nid % NAT_ENTRY_PER_BLOCK)) { + int ret; + startBlk = CurrentNatAddr(sbInfo_, nid, nullptr); + ret = HmfsIo::GetInstance().DevReadBlock(natBlock, startBlk); + ASSERT(ret >= 0); + } + + if (natBlock->entries[nid % NAT_ENTRY_PER_BLOCK].blockId) + HmfsCommon::GetInstance().HmfsSetBit(nid, nat->nidBitmap); + } + free(natBlock); + return 0; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/src/resize_load_sb.cpp b/tools/hmfs-tools/tools/resize/src/resize_load_sb.cpp new file mode 100755 index 0000000..00aa76b --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_load_sb.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_load_sb.h" + +#include +#include +#include + +#include "node.h" +#include "device_manager.h" +#include "hmfs_common.h" + +namespace OHOS { +namespace Hmfs { +ResizeLoadSb::ResizeLoadSb(ResizeLoad *loadPtr) : load_(loadPtr) +{ + config_ = load_->GetConfig(); + sbInfo_ = load_->GetSbInfo(); +} + +int32_t ResizeLoadSb::SetFeature(int32_t feature) +{ + if (config_->feature & NATIVE_TO_LE32(feature)) { + if (!(sbInfo_->rawSuper->features & NATIVE_TO_LE32(feature))) { + sbInfo_->rawSuper->features |= NATIVE_TO_LE32(feature); + return EXIT_ERR_CODE; + } + } + return SUCCESS_CODE; +} + +void ResizeLoadSb::CheckSetFeatures(enum SB_ADDR sb_addr) +{ + bool requiresUpdate = false; + if (SetFeature(HMFS_FEATURE_EXTRA_ATTR)) { + HMFS_INFO("Fix set feature: extra_attr"); + requiresUpdate = true; + } + + if (SetFeature(HMFS_FEATURE_PRJQUOTA)) { + HMFS_INFO("Fix set feature: project_quota"); + requiresUpdate = true; + } + + if (SetFeature(HMFS_FEATURE_CASEFOLD)) { + struct SuperBlockData *superBlock = sbInfo_->rawSuper; + SetLeValue(superBlock->encoding, config_->fileEncoding); + SetLeValue(superBlock->encodingFlags, config_->fileEncodingFlags); + HMFS_INFO("Fix set feature: casefold, encoding: %d, encodingFlags: %d", + config_->fileEncoding, config_->fileEncodingFlags); + requiresUpdate = true; + } + + if (requiresUpdate) { + load_->UpdateSuperBlock(sbInfo_->rawSuper, SB_MASK(sb_addr)); + } +} + +int32_t ResizeLoadSb::CheckAddrBoundary(struct SuperBlockData *superBlock, enum SB_ADDR sbAddr) +{ + uint32_t segment0BlkId = GetLeValue(superBlock->segment0BlkId); + uint32_t cpBlkId = GetLeValue(superBlock->cpBlkId); + uint32_t sitBlkId = GetLeValue(superBlock->sitBlkId); + uint32_t natBlkId = GetLeValue(superBlock->natBlkId); + uint32_t ssaBlkId = GetLeValue(superBlock->ssaBlkId);; + uint32_t mainBlkId = GetLeValue(superBlock->mainBlkId); + uint32_t segmentCountInCP = GetLeValue(superBlock->segmentCountInCP);; + uint32_t segmentCountInSIT = GetLeValue(superBlock->segmentCountInSIT); + uint32_t segmentCountInNAT = GetLeValue(superBlock->segmentCountInNAT); + uint32_t segmentCountInSSA = GetLeValue(superBlock->segmentCountInSSA); + uint32_t segmentCountInMain = GetLeValue(superBlock->segmentCountInMain); + uint32_t segmentCount = GetLeValue(superBlock->segmentCount); + uint32_t logBlksPerSeg = GetLeValue(superBlock->logBlksPerSeg); + uint64_t mainEndBlkAddr = mainBlkId + (segmentCountInMain << logBlksPerSeg); + uint64_t segEndBlkAddr = segment0BlkId + (segmentCount << logBlksPerSeg); + + if (segment0BlkId != cpBlkId) { + HMFS_ERROR("\tMismatch segment0(%u) cp_blkaddr(%u)", segment0BlkId, cpBlkId); + return EXIT_ERR_CODE; + } + + if (cpBlkId + (segmentCountInCP << logBlksPerSeg) != sitBlkId) { + HMFS_ERROR("\tWrong CP boundary, start(%u) end(%u) blocks(%u)", cpBlkId, sitBlkId, + segmentCountInCP << logBlksPerSeg); + return EXIT_ERR_CODE; + } + + if (sitBlkId + (segmentCountInSIT << logBlksPerSeg) != natBlkId) { + HMFS_ERROR("\tWrong SIT boundary, start(%u) end(%u) blocks(%u)", + sitBlkId, natBlkId, segmentCountInSIT << logBlksPerSeg); + return EXIT_ERR_CODE; + } + + if (natBlkId + (segmentCountInNAT << logBlksPerSeg) != ssaBlkId) { + HMFS_ERROR("\tWrong NAT boundary, start(%u) end(%u) blocks(%u)", + natBlkId, ssaBlkId, segmentCountInNAT << logBlksPerSeg); + return EXIT_ERR_CODE; + } + + if (ssaBlkId + (segmentCountInSSA << logBlksPerSeg) != mainBlkId) { + HMFS_ERROR("\tWrong SSA boundary, start(%u) end(%u) blocks(%u)", + ssaBlkId, mainBlkId, segmentCountInSSA << logBlksPerSeg); + return EXIT_ERR_CODE; + } + + if (mainEndBlkAddr > segEndBlkAddr) { + HMFS_ERROR("\tWrong MAIN_AREA, start(%u) end(%u) block(%u)", + mainBlkId, segment0BlkId + (segmentCount << logBlksPerSeg), segmentCountInMain << logBlksPerSeg); + return EXIT_ERR_CODE; + } else if (mainEndBlkAddr < segEndBlkAddr) { + SetLeValue(superBlock->segmentCount, (mainEndBlkAddr - segment0BlkId) >> logBlksPerSeg); + + load_->UpdateSuperBlock(superBlock, SB_MASK(sbAddr)); + HMFS_ERROR("Fix alignment: start(%u) end(%u) block(%u)", mainBlkId, + segment0BlkId + (segmentCount << logBlksPerSeg), segmentCountInMain << logBlksPerSeg); + } + return SUCCESS_CODE; +} + +int32_t ResizeLoadSb::VerifySbChecksum(struct SuperBlockData *superBlock) +{ + if (SB_CHKSUM_OFFSET != GetLeValue(superBlock->checksumOffset)) { + HMFS_ERROR("\tInvalid SB CRC offset: %u", + GetLeValue(superBlock->checksumOffset)); + return EXIT_ERR_CODE; + } + if (HmfsCommon::GetInstance().HmfsCrcValid(GetLeValue(superBlock->checksum), superBlock, + GetLeValue(superBlock->checksumOffset))) { + HMFS_ERROR("\tInvalid SB CRC: 0x%x", GetLeValue(superBlock->checksum)); + return EXIT_ERR_CODE; + } + return SUCCESS_CODE; +} + +int32_t ResizeLoadSb::CheckSuperBlock(struct SuperBlockData *superBlock, enum SB_ADDR sbAddr) +{ + if (superBlock == nullptr) { + return EXIT_ERR_CODE; + } + + if (HMFS_SUPER_MAGIC != GetLeValue(superBlock->magicNo)) { + HMFS_ERROR("Magic Mismatch, valid(0x%x) - read(0x%x)", + HMFS_SUPER_MAGIC, GetLeValue(superBlock->magicNo)); + return EXIT_ERR_CODE; + } + + if ((GetLeValue(superBlock->features) & HMFS_FEATURE_SB_CHKSUM) && VerifySbChecksum(superBlock)) + return EXIT_ERR_CODE; + + uint32_t blockSize = 1 << GetLeValue(superBlock->logBlockSize); + if (HMFS_BLKSIZE != blockSize) { + HMFS_ERROR("Invalid blocksize (%u), supports only 4KB", + blockSize); + return EXIT_ERR_CODE; + } + + /* check log blocks per segment */ + if (GetLeValue(superBlock->logBlksPerSeg) != 9) { + HMFS_ERROR("Invalid log blocks per segment (%u)", + GetLeValue(superBlock->logBlksPerSeg)); + return EXIT_ERR_CODE; + } + + /* Currently, support 512/1024/2048/4096 bytes sector size */ + if (GetLeValue(superBlock->logSectorSize) > HMFS_MAX_LOG_SECTOR_SIZE || + GetLeValue(superBlock->logSectorSize) < HMFS_MIN_LOG_SECTOR_SIZE) { + HMFS_ERROR("Invalid log sectorsize (%u)", GetLeValue(superBlock->logSectorSize)); + return EXIT_ERR_CODE; + } + + if (GetLeValue(superBlock->logSectorsPerBlk) + GetLeValue(superBlock->logSectorSize) != + HMFS_MAX_LOG_SECTOR_SIZE) { + HMFS_ERROR("Invalid log sectors per block(%u) log sectorsize(%u)", + GetLeValue(superBlock->logSectorsPerBlk), GetLeValue(superBlock->logSectorSize)); + return EXIT_ERR_CODE; + } + + uint32_t segmentCount = GetLeValue(superBlock->segmentCount); + uint32_t segsPerSec = GetLeValue(superBlock->segsPerSection); + uint32_t secsPerZone = GetLeValue(superBlock->sectionsPerZone); + uint32_t totalSections = GetLeValue(superBlock->sectionCount); + uint32_t segsPerZone = segsPerSec * secsPerZone; + + /* blocks_per_seg should be 512, given the above check */ + uint32_t blocksPerSeg = 1 << GetLeValue(superBlock->logBlksPerSeg); + + if (segmentCount > HMFS_MAX_SEGMENT || segmentCount < HMFS_MIN_SEGMENTS) { + HMFS_ERROR("\tInvalid segment count (%u)", segmentCount); + return EXIT_ERR_CODE; + } + + if (!(GetLeValue(superBlock->features) & NATIVE_TO_LE32(HMFS_FEATURE_RO)) && (totalSections > segmentCount || + totalSections < HMFS_MIN_SEGMENTS || segsPerSec > segmentCount || !segsPerSec)) { + HMFS_ERROR("\tInvalid segment/section count (%u, %u x %u)", + segmentCount, totalSections, segsPerSec); + return EXIT_ERR_CODE; + } + + if ((segmentCount / segsPerSec) < totalSections) { + HMFS_ERROR("Small segmentCount (%u < %u * %u)", + segmentCount, segsPerSec, totalSections); + return EXIT_ERR_CODE; + } + + if (segmentCount > (GetLeValue(superBlock->blockCount) >> 9)) { + HMFS_ERROR("Wrong segmentCount / block_count (%u > %" PRIu64 ")", + segmentCount, GetLeValue(superBlock->blockCount)); + return EXIT_ERR_CODE; + } + + if (superBlock->devices[0].path[0]) { //TODO modify + uint32_t dev_segs = LE32_TO_NATIVE(superBlock->devices[0].segmentCount); + uint32_t i = 1; + while (i < MAX_DEVICES && superBlock->devices[i].path[0]) { + dev_segs += LE32_TO_NATIVE(superBlock->devices[i].segmentCount); + i++; + } + if (segmentCount != dev_segs / segsPerZone * segsPerZone) { + HMFS_ERROR("Segment count (%u) mismatch with total segments from devices (%u)", + segmentCount, dev_segs); + return EXIT_ERR_CODE; + } + } + + if (secsPerZone > totalSections || !secsPerZone) { + HMFS_ERROR("Wrong secsPerZone / total_sections (%u, %u)", secsPerZone, totalSections); + return EXIT_ERR_CODE; + } + if (GetLeValue(superBlock->coldExtensionCount) > HMFS_MAX_EXTENSION || superBlock->hotExtensionCount > + HMFS_MAX_EXTENSION || GetLeValue(superBlock->coldExtensionCount) + superBlock->hotExtensionCount > + HMFS_MAX_EXTENSION) { + HMFS_ERROR("Corrupted extension count (%u + %u > %u)", GetLeValue(superBlock->coldExtensionCount), + superBlock->hotExtensionCount, HMFS_MAX_EXTENSION); + return EXIT_ERR_CODE; + } + + if (GetLeValue(superBlock->cpPayload) > (blocksPerSeg - HMFS_CP_PACKS)) { + HMFS_ERROR("Insane cp_payload (%u > %u)", + GetLeValue(superBlock->cpPayload), blocksPerSeg - HMFS_CP_PACKS); + return EXIT_ERR_CODE; + } + + /* check reserved ino info */ + if (GetLeValue(superBlock->nodeInodeId) != 1 || GetLeValue(superBlock->metaInodeId) != 2 || + GetLeValue(superBlock->rootInodeId) != 3) { + HMFS_ERROR("Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)", + GetLeValue(superBlock->nodeInodeId), GetLeValue(superBlock->metaInodeId), GetLeValue(superBlock->rootInodeId)); + return EXIT_ERR_CODE; + } + + /* Check zoned block device feature */ + if (config_->devices[0].zonedModel != HMFS_ZONED_NONE && !(superBlock->features & + NATIVE_TO_LE32(HMFS_FEATURE_BLKZONED))) { + HMFS_ERROR("\tMissing zoned block device feature"); + return EXIT_ERR_CODE; + } + + if (CheckAddrBoundary(superBlock, sbAddr)) { + return EXIT_ERR_CODE; + } + return SUCCESS_CODE; +} + +bool ResizeLoadSb::isCheckpointStop(struct SuperBlockData *superBlock, bool abnormal) +{ + for (int32_t i = 0; i < STOP_CP_REASON_MAX; i++) { + if (abnormal && i == STOP_CP_REASON_SHUTDOWN) { + continue; + } + if (superBlock->stopReason[i]) { + return true; + } + } + return false; +} + +bool ResizeLoadSb::isInconsistentError(struct SuperBlockData *superBlock) +{ + if (superBlock == nullptr) { + return false; + } + for (int32_t i = 0; i < MAX_HMFS_ERRORS; i++) { + if (superBlock->errors[i]) { + return true; + } + } + return false; +} + +int32_t ResizeLoadSb::ValidateSuperBlock(enum SB_ADDR sbAddr) +{ + HMFS_DEBUG("Enter ValidateSuperBlock"); + char buf[HMFS_BLKSIZE]; + sbInfo_->rawSuper = static_cast(malloc(sizeof(struct SuperBlockData))); + if (!sbInfo_->rawSuper) { + return EXIT_ERR_CODE; + } + if (HmfsIo::GetInstance().DevReadBlock(buf, sbAddr)) { + HMFS_ERROR("failed to read superblock!"); + return EXIT_ERR_CODE; + } + memcpy(sbInfo_->rawSuper, buf + HMFS_SUPER_OFFSET, sizeof(struct SuperBlockData)); + if (!CheckSuperBlock(sbInfo_->rawSuper, sbAddr)) { + CheckSetFeatures(sbAddr); + /* get kernel version */ + if (config_->kd >= 0) { + HmfsIo::GetInstance().DevReadVersion(config_->version, 0, VERSION_NAME_LEN); + HmfsCommon::GetInstance().GetKernelVersion(config_->version); + } else { + HmfsCommon::GetInstance().GetKernelUnameVersion(config_->version); + } + /* build sb version */ + memcpy(config_->sbVersion, sbInfo_->rawSuper->version, VERSION_NAME_LEN); + HmfsCommon::GetInstance().GetKernelVersion(config_->sbVersion); + memcpy(config_->initVersion, sbInfo_->rawSuper->initVersion, VERSION_NAME_LEN); + HmfsCommon::GetInstance().GetKernelVersion(config_->initVersion); + config_->forceStop = isCheckpointStop(sbInfo_->rawSuper, false); + config_->abnormalStop = isCheckpointStop(sbInfo_->rawSuper, true); + config_->hmfsErrors = isInconsistentError(sbInfo_->rawSuper); + + HMFS_INFO("RESIZE version\n \"%s\"", config_->initVersion); + HMFS_INFO("FSCK version\n from \"%s\"\n to \"%s\"", config_->sbVersion, config_->version); + PrintSbDataFeature(sbInfo_->rawSuper); + PrintSbDataStopReason(sbInfo_->rawSuper, config_->forceStop); + PrintSbDataErrors(sbInfo_->rawSuper, config_->hmfsErrors); + return SUCCESS_CODE; + } + + free(sbInfo_->rawSuper); + sbInfo_->rawSuper = nullptr; + HMFS_ERROR("\tCan't find a valid F2FS superblock at 0x%x", sbAddr); + return -EINVAL; +} + +int32_t ResizeLoadSb::CheckSectorSize(struct SuperBlockData *superBlock) +{ + if (superBlock == nullptr) { + return EXIT_ERR_CODE; + } + uint32_t logSectorSize = HmfsCommon::GetInstance().LogBase2(config_->sectorSize); + uint32_t logSectorsPerBlock = HmfsCommon::GetInstance().LogBase2(config_->sectorsPerBlock); + //TODO 相等了?待调试 + if (logSectorSize == GetLeValue(superBlock->logSectorSize) && + logSectorsPerBlock == GetLeValue(superBlock->logSectorsPerBlk)) { + return SUCCESS_CODE; + } + HMFS_INFO("RESIZE version\n \"%s\"", config_->initVersion); + SetLeValue(superBlock->logSectorSize, logSectorSize); + SetLeValue(superBlock->logSectorsPerBlk, logSectorsPerBlock); + + load_->UpdateSuperBlock(superBlock, SB_MASK_ALL); + return SUCCESS_CODE; +} + +int32_t ResizeLoadSb::HmfsLoadSbData() +{ + HMFS_DEBUG("Enter HmfsLoadSbData"); + if (sbInfo_ == nullptr) { + return EXIT_ERR_CODE; + } + int32_t ret = ValidateSuperBlock(SB0_ADDR); + if (ret) { + ret = ValidateSuperBlock(SB1_ADDR); + if (ret) { + //dump_sbi_info(sbInfo_); //TODO modify + return EXIT_ERR_CODE; + } + } + SuperBlockData *sbData = sbInfo_->rawSuper; + ret = CheckSectorSize(sbData); + if (ret) { + return EXIT_ERR_CODE; + } + PrintRawSbInfo(sbData, config_->debugLevel, config_->layout); + return SUCCESS_CODE; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/src/resize_load_sit.cpp b/tools/hmfs-tools/tools/resize/src/resize_load_sit.cpp new file mode 100755 index 0000000..3e3cd5b --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_load_sit.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_load_sit.h" + +#include +#include +#include + +#include "node.h" +#include "device_manager.h" +#include "hmfs_common.h" + +namespace OHOS { +namespace Hmfs { +ResizeLoadSit::ResizeLoadSit(ResizeLoad *loadPtr) : load_(loadPtr) +{ + config_ = load_->GetConfig(); + sbInfo_ = load_->GetSbInfo(); +} + +bool ResizeLoadSit::IsSyncDataRecord() +{ + return !IsCheckpointFlags(sbInfo_->ckptData, CP_UMOUNT_FLAG) || + config_->zonedModel == HMFS_ZONED_HM; +} + +int32_t ResizeLoadSit::BuildSitInfo() +{ + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct CheckPointData *cpData = sbInfo_->ckptData; + + struct SitInfo *sitInfo = static_cast(malloc(sizeof(struct SitInfo))); + if (sitInfo == nullptr) { + HMFS_ERROR("\tError: Malloc failed for build_sit_info!"); + return -ENOMEM; + } + + sbInfo_->smInfoTable->sitInfo = sitInfo; + unsigned int mainSegments = sbInfo_->smInfoTable->mainSegments; + sitInfo->segEntries = static_cast(calloc(mainSegments * sizeof(struct SegEntry), 1)); + if (sitInfo->segEntries == nullptr) { + HMFS_ERROR("\tError: Calloc failed for build_sit_info!"); + free(sitInfo); + return -ENOMEM; + } + + unsigned int bitmapSize = mainSegments * SIT_VBLOCK_MAP_SIZE; + if (IsSyncDataRecord()) { + bitmapSize += bitmapSize; + } + sitInfo->bitmap = static_cast(calloc(bitmapSize, 1)); + if (sitInfo->bitmap == nullptr) { + HMFS_ERROR("\tError: Calloc failed for build_sit_info!!"); + free(sitInfo->segEntries); + free(sitInfo); + return -ENOMEM; + } + + unsigned char *bitmap = sitInfo->bitmap; + for (unsigned int start = 0; start < mainSegments; start++) { + sitInfo->segEntries[start].curValidBitmap = bitmap; + bitmap += SIT_VBLOCK_MAP_SIZE; + if (IsSyncDataRecord()) { + sitInfo->segEntries[start].ckptValidBitmap = bitmap; + bitmap += SIT_VBLOCK_MAP_SIZE; + } + } + + unsigned int sitSegments = GetLeValue(sbData->segmentCountInSIT) >> 1; + bitmapSize = LE32_TO_NATIVE(cpData->sitVersionBitmapSize); + char *srcBitmap = static_cast(load_->GetBitmapPtr(SIT_BITMAP)); + char *dstBitmap = static_cast(malloc(bitmapSize)); + if (dstBitmap == nullptr) { + HMFS_ERROR("\tError: Malloc failed for build_sit_info!!"); + free(sitInfo->bitmap); + free(sitInfo->segEntries); + free(sitInfo); + return -ENOMEM; + } + + memcpy(dstBitmap, srcBitmap, bitmapSize); + + sitInfo->sitBaseAddr = GetLeValue(sbData->sitBlkId); + sitInfo->sitBlocks = sitSegments << sbInfo_->logBlksPerSeg; + sitInfo->writtenValidBlocks = GetLeValue(cpData->validBlockCount); + sitInfo->sitBitmap = dstBitmap; + sitInfo->bitmapSize = bitmapSize; + sitInfo->dirtySentries = 0; + sitInfo->sentsPerBlock = SIT_ENTRIES_PER_BLOCK; + sitInfo->elapsedTime = GetLeValue(cpData->elapsedTime); + return SUCCESS_CODE; +} + +uint32_t ResizeLoadSit::GetStartSumBlock() +{ + uint32_t cpPackStartSum = sbInfo_->ckptData->cpPackStartSum; + return load_->GetStartCpAddr() + LE32_TO_NATIVE(cpPackStartSum); +} + +uint32_t ResizeLoadSit::GetSumBlkAddr(int base, int type) +{ + uint32_t cpPackTotalBlockCount = sbInfo_->ckptData->cpPackBlockCount; + return load_->GetStartCpAddr() + LE32_TO_NATIVE(cpPackTotalBlockCount) - (base + 1) + type; +} + +void ResizeLoadSit::ReadCompactSummaries() +{ + uint32_t start = GetStartSumBlock(); + char *kaddr = static_cast(malloc(HMFS_BLKSIZE)); + ASSERT(kaddr); + + int32_t ret = HmfsIo::GetInstance().DevReadBlock(kaddr, start++); + ASSERT(ret >= 0); + struct CurSegmentInfo *curSeg = (struct CurSegmentInfo *)(sbInfo_->smInfoTable->curSegmentArray + CURSEG_HOT_DATA); + memcpy(&curSeg->segSumBlk->journal.nNats, kaddr, SUM_JOURNAL_SIZE); + + curSeg = (struct CurSegmentInfo *)(sbInfo_->smInfoTable->curSegmentArray + CURSEG_COLD_DATA); + memcpy(&curSeg->segSumBlk->journal.nSits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); + + unsigned int offset = 2 * SUM_JOURNAL_SIZE; + for (uint32_t i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + unsigned short blk_off; + struct CurSegmentInfo *cursegInfo = static_cast(sbInfo_->smInfoTable->curSegmentArray + i); + ResetCurSegment(sbInfo_, i); + + if (cursegInfo->allocType == SSR) { + blk_off = sbInfo_->blocksPerSeg; + } else { + blk_off = cursegInfo->nextBlkOffset; + } + ASSERT(blk_off <= ENTRIES_IN_SUM); + + for (uint32_t j = 0; j < blk_off; j++) { + struct SummaryEntry *s; + s = (struct SummaryEntry *)(kaddr + offset); + cursegInfo->segSumBlk->entries[j] = *s; + offset += SUMMARY_SIZE; + if (offset + SUMMARY_SIZE <= + HMFS_BLKSIZE - SUM_FOOTER_SIZE) + continue; + memset(kaddr, 0, HMFS_BLKSIZE); + ret = HmfsIo::GetInstance().DevReadBlock(kaddr, start++); + ASSERT(ret >= 0); + offset = 0; + } + } + free(kaddr); +} + +void ResizeLoadSit::RestoreNodeSummary(unsigned int segno, struct SummaryBlockData *sumblk) +{ + if (sumblk == nullptr) { + HMFS_ERROR("sumblk is nullptr"); + return; + } + struct NodeData *nodeBlk = static_cast(malloc(HMFS_BLKSIZE)); + ASSERT(nodeBlk); + + /* scan the node segment */ + uint32_t addr = sbInfo_->smInfoTable->mainBlkaddr + ((segno) << sbInfo_->logBlksPerSeg); + struct SummaryEntry *sumEntry = &sumblk->entries[0]; + for (uint32_t i = 0; i < sbInfo_->blocksPerSeg; i++, sumEntry++) { + int32_t ret = HmfsIo::GetInstance().DevReadBlock(nodeBlk, addr); + ASSERT(ret >= 0); + sumEntry->nid = nodeBlk->footer.nid; + addr++; + } + free(nodeBlk); +} + +void ResizeLoadSit::ReadNormalSummaries(int type) +{ + struct CheckPointData *cpData = sbInfo_->ckptData; + unsigned int segno = 0; + uint32_t blkAddr = 0; + int ret; + + if (IS_DATASEG(type)) { + segno = GetLeValue(cpData->curDataSegNo[type]); + if (IsCheckpointFlags(cpData, CP_UMOUNT_FLAG)) { + blkAddr = GetSumBlkAddr(NR_CURSEG_TYPE, type); + } else { + blkAddr = GetSumBlkAddr(NR_CURSEG_DATA_TYPE, type); + } + } else { + segno = GetLeValue(cpData->curNodeSegNo[type - CURSEG_HOT_NODE]); + if (IsCheckpointFlags(cpData, CP_UMOUNT_FLAG)) { + blkAddr = GetSumBlkAddr( NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE); + } else { + blkAddr = sbInfo_->smInfoTable->ssaBlkaddr + segno; + } + } + + struct SummaryBlockData *sumBlk = static_cast(malloc(sizeof(*sumBlk))); + ASSERT(sumBlk); + + ret = HmfsIo::GetInstance().DevReadBlock(sumBlk, blkAddr); + ASSERT(ret >= 0); + + if (IS_NODESEG(type) && !IsCheckpointFlags(cpData, CP_UMOUNT_FLAG)) { + RestoreNodeSummary(segno, sumBlk); + } + struct CurSegmentInfo *curSeg = CURSEG_I(sbInfo_, type); + memcpy(curSeg->segSumBlk, sumBlk, sizeof(*sumBlk)); + ResetCurSegment(sbInfo_, type); + free(sumBlk); +} + +void ResizeLoadSit::UpdateCurSegSummaries() +{ + int type = CURSEG_HOT_DATA; + + if (IsCheckpointFlags(sbInfo_->ckptData, CP_COMPACT_SUM_FLAG)) { + ReadCompactSummaries(); + type = CURSEG_HOT_NODE; + } + + for (; type <= CURSEG_COLD_NODE; type++) { + ReadNormalSummaries(type); + } +} + +int32_t ResizeLoadSit::BuildCurSegment() +{ + struct CheckPointData *cpData = sbInfo_->ckptData; + unsigned short blkOffset; + unsigned int segNum; + int i; + + struct CurSegmentInfo *array = static_cast(malloc(sizeof(*array) * NR_CURSEG_TYPE)); + if (!array) { + HMFS_ERROR("\tError: Malloc failed for build_curseg!"); + return -ENOMEM; + } + sbInfo_->smInfoTable->curSegmentArray = array; + + for (i = 0; i < NR_CURSEG_TYPE; i++) { + array[i].segSumBlk = static_cast(calloc(sizeof(*(array[i].segSumBlk)), 1)); + if (!array[i].segSumBlk) { + HMFS_ERROR("\tError: Calloc failed for build_curseg!!"); + for(--i ; i >= 0; --i) { + free(array[i].segSumBlk); + } + free(array); + return -ENOMEM; + } + + if (i <= CURSEG_COLD_DATA) { + blkOffset = GetLeValue(cpData->curDataBlkOffset[i]); + segNum = GetLeValue(cpData->curDataSegNo[i]); + } + if (i > CURSEG_COLD_DATA) { + blkOffset = GetLeValue(cpData->curNodeBlkOffset[i - CURSEG_HOT_NODE]); + segNum = GetLeValue(cpData->curNodeSegNo[i - CURSEG_HOT_NODE]); + } + ASSERT(segNum < sbInfo_->smInfoTable->mainSegments); + ASSERT(blkOffset < DEFAULT_BLOCKS_PER_SEGMENT); + + array[i].segNum = segNum; + array[i].zone = (segNum / sbInfo_->segmentsPerSec) / sbInfo_->sectionsPerZone; + array[i].nextSegNum = NULL_SEGNO; + array[i].nextBlkOffset = blkOffset; + array[i].allocType = cpData->allocType[i]; + } + UpdateCurSegSummaries(); + return SUCCESS_CODE; +} + +int32_t ResizeLoadSit::BuildSegmentBegin() +{ + HMFS_DEBUG("Enter BuildSegmentBegin"); + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct CheckPointData *cpData = sbInfo_->ckptData; + struct SegmentInfoTable *smInfoTable = + static_cast(malloc(sizeof(struct SegmentInfoTable))); + if (!smInfoTable) { + HMFS_ERROR("\tError: Malloc failed for build_segment_manager!"); + return -ENOMEM; + } + + /* init sm info table */ + sbInfo_->smInfoTable = smInfoTable; + smInfoTable->seg0Blkaddr = GetLeValue(sbData->segment0BlkId); + smInfoTable->mainBlkaddr = GetLeValue(sbData->mainBlkId); + smInfoTable->segmentCount = GetLeValue(sbData->segmentCount); + smInfoTable->reservedSegments = GetLeValue(cpData->rsvdSegmentCount); + smInfoTable->ovpSegments = GetLeValue(cpData->overprovSegmentCount); + smInfoTable->mainSegments = GetLeValue(sbData->segmentCountInMain); + smInfoTable->ssaBlkaddr = GetLeValue(sbData->ssaBlkId); + + if (BuildSitInfo() != SUCCESS_CODE || BuildCurSegment() != SUCCESS_CODE) { + free(smInfoTable); + return -ENOMEM; + } + return 0; +} + +int32_t ResizeLoadSit::BuildSitEntries() +{ + struct SitInfo *sitInfo = SIT_I(sbInfo_); + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, CURSEG_COLD_DATA); + struct JournalEntry *journal = &curseg->segSumBlk->journal; + struct SegEntry *se; + struct sitEntry sit; + int sitBlkCnt = SIT_BLK_CNT(sbInfo_); + unsigned int segno; + unsigned int startBlk = 0; + struct sitBlockData *sitBlk = static_cast(calloc(BLOCK_SZ, 1)); + if (!sitBlk) { + HMFS_ERROR("\tError: Calloc failed for build_sit_entries!"); + return -ENOMEM; + } + + do { + unsigned int readed = load_->HmfsRaMetaPages(startBlk, MAX_RA_BLOCKS, META_SIT); + segno = startBlk * sitInfo->sentsPerBlock; + unsigned int end = (startBlk + readed) * sitInfo->sentsPerBlock; + + for (; segno < end && segno < MAIN_SEGS(sbInfo_); segno++) { + se = &sitInfo->segEntries[segno]; + GetCurrentSitPage(sbInfo_, segno, sitBlk); + sit = sitBlk->entries[SIT_ENTRY_OFFSET(sitInfo, segno)]; + CheckBlockCount(segno, &sit); + SegInfoFromRawSit(se, &sit); + } + startBlk += readed; + } while (startBlk < sitBlkCnt); + + free(sitBlk); + + if (SitsInCursum(journal) > SIT_JOURNAL_ENTRIES) { + HMFS_ERROR("\tError: build_sit_entries truncate nSits(%u) to SIT_JOURNAL_ENTRIES(%zu)", + SitsInCursum(journal), SIT_JOURNAL_ENTRIES); + journal->nSits = NATIVE_TO_LE16(SIT_JOURNAL_ENTRIES); + config_->fixOn = 1; + } + + for (uint32_t i = 0; i < SitsInCursum(journal); i++) { + segno = LE32_TO_NATIVE(SegnoInJournal(journal, i)); + if (segno >= MAIN_SEGS(sbInfo_)) { + HMFS_ERROR("\tError: build_sit_entries: segno(%u) is invalid!!!", segno); + journal->nSits = NATIVE_TO_LE16(i); + config_->fixOn = 1; + continue; + } + + se = &sitInfo->segEntries[segno]; + sit = SitInJournal(journal, i); + + CheckBlockCount(segno, &sit); + SegInfoFromRawSit(se, &sit); + } + return SUCCESS_CODE; +} + +void ResizeLoadSit::InsideSegInfoFromRawSit(struct SegEntry *se, struct sitEntry *rawSit) +{ + se->validBlocks = GET_SIT_VBLOCKS(rawSit); + memcpy(se->curValidBitmap, rawSit->blockBitmap, SIT_VBLOCK_MAP_SIZE); + se->type = GET_SIT_TYPE(rawSit); + se->origType = GET_SIT_TYPE(rawSit); + se->modTime = LE64_TO_NATIVE(rawSit->modTime); +} + +void ResizeLoadSit::SegInfoFromRawSit(struct SegEntry *se, struct sitEntry *rawSit) +{ + InsideSegInfoFromRawSit(se, rawSit); + if (!NeedFsyncDataRecord(sbInfo_, config_)) { + return; + } + se->ckptValidBlocks = se->validBlocks; + memcpy(se->ckptValidBitmap, se->curValidBitmap, SIT_VBLOCK_MAP_SIZE); + se->ckptType = se->type; +} + +void ResizeLoadSit::CheckBlockCount(unsigned int segno, struct sitEntry *rawSit) +{ + struct SegmentInfoTable *smInfo = SM_I(sbInfo_); + unsigned int end_segno = smInfo->segmentCount - 1; + int validBlocks = 0; + + /* check segment usage */ + if (GET_SIT_VBLOCKS(rawSit) > sbInfo_->blocksPerSeg) + HMFS_ERROR("Invalid SIT vblocks: segno=0x%x, %u", + segno, GET_SIT_VBLOCKS(rawSit)); + + /* check boundary of a given segment number */ + if (segno > end_segno) + HMFS_ERROR("Invalid SEGNO: 0x%x", segno); + + /* check bitmap with valid block count */ + for (uint32_t i = 0; i < SIT_VBLOCK_MAP_SIZE; i++) { + validBlocks += HmfsCommon::GetInstance().GetBitsInByte(rawSit->blockBitmap[i]); + } + if (GET_SIT_VBLOCKS(rawSit) != validBlocks) + HMFS_ERROR("Wrong SIT valid blocks: segno=0x%x, %u vs. %u", + segno, GET_SIT_VBLOCKS(rawSit), validBlocks); + + if (GET_SIT_TYPE(rawSit) >= NO_CHECK_TYPE) + HMFS_ERROR("Wrong SIT type: segno=0x%x, %u", + segno, GET_SIT_TYPE(rawSit)); +} + +int32_t ResizeLoadSit::LateBuildSegmentManager() +{ + HMFS_DEBUG("Enter LateBuildSegmentManager"); + if (sbInfo_->segManagerDone) { + return EXIT_ERR_CODE; /* this function was already called */ + } + sbInfo_->segManagerDone = true; + if (BuildSitEntries()) { + free (sbInfo_->smInfoTable); + return -ENOMEM; + } + return SUCCESS_CODE; +} + +} // namespace Hmfs +} // namespace OHOS diff --git a/tools/hmfs-tools/tools/resize/src/resize_main.cpp b/tools/hmfs-tools/tools/resize/src/resize_main.cpp new file mode 100755 index 0000000..4c8e16c --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_main.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "hmfs_command.h" +#include "resize_operator.h" + +int main(int argc, char* argv[]) +{ + + if (argv == nullptr) { + std::cerr << "Error: argv null" << std::endl; + return -1; + } + OHOS::Hmfs::CmdConfig resizeConfig; + OHOS::Hmfs::ResizeCmdParser resizeParser(resizeConfig); + if (resizeParser.Parse(argc, argv) != 0) { + resizeParser.ShowCmdUsage(); + return -1; + } + OHOS::Hmfs::ResizeOperator resizeOperator(resizeConfig); + return resizeOperator.HmfsResize(); +} diff --git a/tools/hmfs-tools/tools/resize/src/resize_operator.cpp b/tools/hmfs-tools/tools/resize/src/resize_operator.cpp new file mode 100755 index 0000000..01b9da1 --- /dev/null +++ b/tools/hmfs-tools/tools/resize/src/resize_operator.cpp @@ -0,0 +1,1338 @@ +/* + * Copyright (c) 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resize_operator.h" + +#include +#include +#include +#include +#include +#include "securec.h" +#include "hmfs_common.h" +#include "device_manager.h" +#include "hmfs_io.h" +#include "node.h" +#include "resize_load.h" +#include "resize_defrag.h" + +namespace OHOS { +namespace Hmfs { +using namespace std; + +ResizeOperator::ResizeOperator(CmdConfig &resizeConfig) : resizeConfig_(resizeConfig) +{ + config_ = std::make_shared(); + sbInfo_ = std::make_shared(); + memset_s(config_.get(), sizeof(HmfsConfigData), 0, sizeof(HmfsConfigData)); + memset_s(sbInfo_.get(), sizeof(HmfsSbInfo), 0, sizeof(HmfsSbInfo)); + HmfsIo::CreateInstance(resizeConfig); + HmfsCommon::CreateInstance(resizeConfig); + DeviceManager::CreateInstance(resizeConfig); + InitConfig(); + reDefrag_ = std::make_unique(this, sbInfo_, config_); +} + +void ResizeOperator::InitConfig() +{ + //init default values + config_->nDevices = 1; + config_->sectorsPerBlock = 8; + config_->blocksPerSegment = 512; + config_->wantedTotalSectors = -1; + config_->wantedSectorSize = -1; + config_->preserveLimits = 1; + config_->noKernelCheck = 1; + // struct device_info devices[MAX_DEVICES]; + for (int32_t i = 0; i < MAX_DEVICES; i++) { + config_->devices[i].fd = -1; + config_->devices[i].sectorSize = DEFAULT_SECTOR_SIZE; + config_->devices[i].endBlkId = -1; + config_->devices[i].zonedModel = HMFS_ZONED_NONE; + } + config_->segmentsPerSection = 1; + config_->sectionsPerZone = 1; + config_->segmentsPerZone = 1; + // config_->volumeLabel = ""; + config_->trim = 1; + config_->kd = 1; + config_->fixedTime = -1; + config_->fileEncoding = 0; + config_->fileEncodingFlags = 0; + config_->rootUid = getuid(); + config_->rootGid = getgid(); + //command parameter values + config_->debugLevel = resizeConfig_.debugLevel; + config_->force = resizeConfig_.force; + config_->safeResize = resizeConfig_.safeResize; + config_->targetSectors = resizeConfig_.targetSectors; + config_->largeNatBitmap = resizeConfig_.largeNatBitmap; + config_->fileEncoding = resizeConfig_.sEncoding; + config_->fileEncodingFlags = resizeConfig_.sEncodingFlags; + config_->feature = resizeConfig_.features; + config_->newOverprovision = resizeConfig_.newOverprovision; + + config_->sectorSize = 512; + config_->sectorsPerBlock = HMFS_BLKSIZE / 512; + /* Get device */ + //if (f2fs_get_device_info() < 0 || f2fs_get_f2fs_info() < 0) { } +} + +int32_t ResizeOperator::GetNewSuperBlock(struct SuperBlockData *sbData) +{ + HMFS_DEBUG("Enter GetNewSuperBlock"); + uint32_t zoneSizeBytes; + uint64_t zoneAlignStartOffset; + uint32_t blocksForSit, blocksForNat, blocksForSsa; + uint32_t sitSegments, natSegments, diff, totalMetaSegments; + uint32_t totalValidBlksAvailable; + uint32_t sitBitmapSize, maxSitBitmapSize; + uint32_t maxNatBitmapSize, maxNatSegments; + uint32_t segmentSizeBytes = 1 << (GetLeValue(sbData->logBlockSize) + GetLeValue(sbData->logBlksPerSeg)); + uint32_t blksPerSeg = 1 << GetLeValue(sbData->logBlksPerSeg); + uint32_t segsPerZone = GetLeValue(sbData->segsPerSection) * GetLeValue(sbData->sectionsPerZone); + + SetLeValue(sbData->blockCount, config_->targetSectors >> GetLeValue(sbData->logSectorsPerBlk)); + + zoneSizeBytes = segmentSizeBytes * segsPerZone; + zoneAlignStartOffset = ((uint64_t) config_->startSector * DEFAULT_SECTOR_SIZE + + 2 * HMFS_BLKSIZE + zoneSizeBytes - 1) / zoneSizeBytes * zoneSizeBytes - + (uint64_t) config_->startSector * DEFAULT_SECTOR_SIZE; + + SetLeValue(sbData->segmentCount, (config_->targetSectors * config_->sectorSize - zoneAlignStartOffset) / + segmentSizeBytes / config_->segmentsPerSection * config_->segmentsPerSection); + + if (!config_->safeResize) { + blocksForSit = SIZE_ALIGN(GetLeValue(sbData->segmentCount), SIT_ENTRY_PER_BLOCK); + sitSegments = SIZE_ALIGN(blocksForSit, config_->blocksPerSegment); + SetLeValue(sbData->segmentCountInSIT, sitSegments * 2); + SetLeValue(sbData->natBlkId, GetLeValue(sbData->sitBlkId) + GetLeValue(sbData->segmentCountInSIT) * blksPerSeg); + + totalValidBlksAvailable = (GetLeValue(sbData->segmentCount) -(GetLeValue(sbData->segmentCountInCP) + + GetLeValue(sbData->segmentCountInSIT))) * blksPerSeg; + blocksForNat = SIZE_ALIGN(totalValidBlksAvailable, NAT_ENTRY_PER_BLOCK); + + if (config_->largeNatBitmap) { + natSegments = SIZE_ALIGN(blocksForNat, config_->blocksPerSegment) * DEFAULT_NAT_ENTRY_RATIO / 100; + SetLeValue(sbData->segmentCountInNAT, natSegments ? natSegments : 1); + + maxNatBitmapSize = (GetLeValue(sbData->segmentCountInNAT) << GetLeValue(sbData->logBlksPerSeg)) / 8; + SetLeValue(sbData->segmentCountInNAT, GetLeValue(sbData->segmentCountInNAT) * 2); + } else { + SetLeValue(sbData->segmentCountInNAT, SIZE_ALIGN(blocksForNat, config_->blocksPerSegment)); + maxNatBitmapSize = 0; + } + + sitBitmapSize = ((GetLeValue(sbData->segmentCountInSIT) / 2) << GetLeValue(sbData->logBlksPerSeg)) / 8; + if (sitBitmapSize > MAX_SIT_BITMAP_SIZE) { + maxSitBitmapSize = MAX_SIT_BITMAP_SIZE; + } else { + maxSitBitmapSize = sitBitmapSize; + } + if (config_->largeNatBitmap) { + /* use cp_payload if free space of f2fs_checkpoint is not enough */ + if (maxSitBitmapSize + maxNatBitmapSize > MAX_BITMAP_SIZE_IN_CKPT) { + uint32_t diff = maxSitBitmapSize + maxNatBitmapSize - MAX_BITMAP_SIZE_IN_CKPT; + SetLeValue(sbData->cpPayload, HMFS_BLK_ALIGN(diff)); + } else { + SetLeValue(sbData->cpPayload, 0); + } + } else { + /* + * It should be reserved minimum 1 segment for nat. + * When sit is too large, we should expand cp area. + * It requires more pages for cp. + */ + if (maxSitBitmapSize > MAX_SIT_BITMAP_SIZE_IN_CKPT) { + maxNatBitmapSize = MAX_BITMAP_SIZE_IN_CKPT; + SetLeValue(sbData->cpPayload, HMFS_BLK_ALIGN(maxSitBitmapSize)); + } else { + maxNatBitmapSize = MAX_BITMAP_SIZE_IN_CKPT - maxSitBitmapSize; + SetLeValue(sbData->cpPayload, 0); + } + + maxNatSegments = (maxNatBitmapSize * 8) >> GetLeValue(sbData->logBlksPerSeg); + if (GetLeValue(sbData->segmentCountInNAT) > maxNatSegments) { + SetLeValue(sbData->segmentCountInNAT, maxNatSegments); + } + SetLeValue(sbData->segmentCountInNAT, GetLeValue(sbData->segmentCountInNAT) * 2); + } + + SetLeValue(sbData->ssaBlkId, GetLeValue(sbData->natBlkId) + GetLeValue(sbData->segmentCountInNAT) * blksPerSeg); + + totalValidBlksAvailable = (GetLeValue(sbData->segmentCount) - (GetLeValue(sbData->segmentCountInCP) + + GetLeValue(sbData->segmentCountInSIT) + GetLeValue(sbData->segmentCountInNAT))) * blksPerSeg; + + blocksForSsa = totalValidBlksAvailable / blksPerSeg + 1; + + SetLeValue(sbData->segmentCountInSSA, SIZE_ALIGN(blocksForSsa, config_->blocksPerSegment)); + + totalMetaSegments = GetLeValue(sbData->segmentCountInCP) + GetLeValue(sbData->segmentCountInSIT) + + GetLeValue(sbData->segmentCountInNAT) + GetLeValue(sbData->segmentCountInSSA); + + diff = totalMetaSegments % segsPerZone; + if (diff) { + SetLeValue(sbData->segmentCountInSSA, GetLeValue(sbData->segmentCountInSSA) + (segsPerZone - diff)); + } + + SetLeValue(sbData->mainBlkId, GetLeValue(sbData->ssaBlkId) + GetLeValue(sbData->segmentCountInSSA) * blksPerSeg); + } + + SetLeValue(sbData->segmentCountInMain, GetLeValue(sbData->segmentCount) - (GetLeValue(sbData->segmentCountInCP) + + GetLeValue(sbData->segmentCountInSIT) + GetLeValue(sbData->segmentCountInNAT) + + GetLeValue(sbData->segmentCountInSSA))); + + SetLeValue(sbData->sectionCount, GetLeValue(sbData->segmentCountInMain) / GetLeValue(sbData->segsPerSection)); + + SetLeValue(sbData->segmentCountInMain, GetLeValue(sbData->sectionCount) * GetLeValue(sbData->segsPerSection)); + + /* Let's determine the best reserved and overprovisioned space ifdef HAVE_BLK_ZONE_REP_V2*/ + if (config_->newOverprovision == 0) { + config_->newOverprovision = HmfsCommon::GetInstance().GetBestOverProvision(sbData); + } + config_->newReservedSegments = (2 * (100 / config_->newOverprovision + 1) + 6) * + GetLeValue(sbData->segsPerSection); + + if ((GetLeValue(sbData->segmentCountInMain) - 2) < config_->newReservedSegments || + GetLeValue(sbData->segmentCountInMain) * blksPerSeg > GetLeValue(sbData->blockCount)) { + HMFS_ERROR("\tError: Device size is not sufficient for F2FS volume, more segment needed =%u", + config_->newReservedSegments - (GetLeValue(sbData->segmentCountInMain) - 2)); + return -1; + } + return 0; +} + +int32_t ResizeOperator::ShrinkNats(struct SuperBlockData *newSbData) +{ + HMFS_DEBUG("Enter ShrinkNats"); + if (newSbData == nullptr) { + return -1; + } + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct NodeAddressTable *nat = sbInfo_->naTable; + uint32_t oldNatBlkaddr = GetLeValue(sbData->natBlkId); + int32_t ret = 0; + void *natBlock = malloc(BLOCK_SZ); + ASSERT(natBlock); + void *zeroBlock = calloc(BLOCK_SZ, 1); + ASSERT(zeroBlock); + + unsigned int natBlocks = GetLeValue(newSbData->segmentCountInNAT) >> 1; + natBlocks = natBlocks << GetLeValue(sbData->logBlksPerSeg); + int32_t newMaxNid = NAT_ENTRY_PER_BLOCK * natBlocks; + + for (int32_t nid = nat->maxNid - 1; nid > newMaxNid; nid -= NAT_ENTRY_PER_BLOCK) { + unsigned long blockOff = nid / NAT_ENTRY_PER_BLOCK; + int32_t segOff = blockOff >> sbInfo_->logBlksPerSeg; + unsigned long blockAddr = (unsigned long)(oldNatBlkaddr + + (segOff << sbInfo_->logBlksPerSeg << 1) + + (blockOff & ((1 << sbInfo_->logBlksPerSeg) - 1))); + + if (HmfsCommon::GetInstance().HmfsTestBit(blockOff, nat->natBitmap)) + blockAddr += sbInfo_->blocksPerSeg; + + ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + + if (memcmp(zeroBlock, natBlock, BLOCK_SZ)) { + free(natBlock); + free(zeroBlock); + return -1; + } + } + ret = 0; + nat->maxNid = newMaxNid; + free(natBlock); + free(zeroBlock); + return ret; +} + +int32_t ResizeOperator::GetSumEntry(uint32_t blkAddr, struct SummaryEntry *sumEntry) +{ + if (sumEntry == nullptr) { + return -1; + } + int32_t type = 0; + uint32_t segno = GET_SEGNO(sbInfo_, blkAddr); + uint32_t blkOffFromMain = blkAddr - SM_I(sbInfo_)->mainBlkaddr; + uint32_t offset = blkOffFromMain % (1 << sbInfo_->logBlksPerSeg); + + struct SummaryBlockData *sumBlk = GetSumBlock(segno, &type); + memcpy(sumEntry, &(sumBlk->entries[offset]), sizeof(struct SummaryEntry)); + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || type == SEG_TYPE_MAX) { + free(sumBlk); + } + return type; +} + +struct SummaryBlockData* ResizeOperator::GetSumBlock(unsigned int segno, int *ret_type) +{ + if (ret_type == nullptr) { + return nullptr; + } + struct CheckPointData *cpData = sbInfo_->ckptData; + struct CurSegmentInfo *curseg; + *ret_type= SEG_TYPE_MAX; + + uint64_t ssaBlk = sbInfo_->smInfoTable->ssaBlkaddr + segno; + for (int32_t type = 0; type < NR_CURSEG_NODE_TYPE; type++) { + if (segno == GetLeValue(cpData->curNodeSegNo[type])) { + curseg = CURSEG_I(sbInfo_, CURSEG_HOT_NODE + type); + if (!IS_SUM_NODE_SEG(curseg->segSumBlk->footer)) { + HMFS_ERROR("segno [0x%x] indicates a data " + "segment, but should be node", + segno); + *ret_type = -SEG_TYPE_CUR_NODE; + } else { + *ret_type = SEG_TYPE_CUR_NODE; + } + return curseg->segSumBlk; + } + } + + for (int32_t type = 0; type < NR_CURSEG_DATA_TYPE; type++) { + if (segno == GetLeValue(cpData->curDataSegNo[type])) { + curseg = CURSEG_I(sbInfo_, type); + if (IS_SUM_NODE_SEG(curseg->segSumBlk->footer)) { + HMFS_ERROR("segno [0x%x] indicates a node segment, but should be data", segno); + *ret_type = -SEG_TYPE_CUR_DATA; + } else { + *ret_type = SEG_TYPE_CUR_DATA; + } + return curseg->segSumBlk; + } + } + struct SummaryBlockData *sumBlk = static_cast(calloc(BLOCK_SZ, 1)); + ASSERT(sumBlk); + + int32_t ret = HmfsIo::GetInstance().DevReadBlock(sumBlk, ssaBlk); + ASSERT(ret >= 0); + + if (IS_SUM_NODE_SEG(sumBlk->footer)) { + *ret_type = SEG_TYPE_NODE; + } else if (IS_SUM_DATA_SEG(sumBlk->footer)) { + *ret_type = SEG_TYPE_DATA; + } + return sumBlk; +} + +void ResizeOperator::UpdateDataBlkaddr(uint32_t nid, uint16_t ofsInNode, uint32_t newAddr) +{ + struct NodeInfo ni; + uint32_t oldaddr; + + struct NodeData *nodeBlk = static_cast(calloc(BLOCK_SZ, 1)); + ASSERT(nodeBlk); + + GetNodeInfo(sbInfo_, nid, &ni); + + /* read node_block */ + int ret = HmfsIo::GetInstance().DevReadBlock(nodeBlk, ni.blockAddr); + ASSERT(ret >= 0); + + /* check its block address */ + if (nodeBlk->footer.nid == nodeBlk->footer.ino) { + int ofs = HmfsCommon::GetInstance().GetExtraIsize(&nodeBlk->i); + + oldaddr = LE32_TO_NATIVE(nodeBlk->i.i_addr[ofs + ofsInNode]); + nodeBlk->i.i_addr[ofs + ofsInNode] = NATIVE_TO_LE32(newAddr); + ret = HmfsCommon::GetInstance().WriteInode(nodeBlk, ni.blockAddr, config_->chksumSeed); + ASSERT(ret >= 0); + } else { + oldaddr = LE32_TO_NATIVE(nodeBlk->dn.addr[ofsInNode]); + nodeBlk->dn.addr[ofsInNode] = NATIVE_TO_LE32(newAddr); + ret = HmfsIo::GetInstance().DevWriteBlock(nodeBlk, ni.blockAddr); + ASSERT(ret >= 0); + } + + /* check extent cache entry */ + if (nodeBlk->footer.nid != nodeBlk->footer.ino) { + GetNodeInfo(sbInfo_, LE32_TO_NATIVE(nodeBlk->footer.ino), &ni); + + /* read inode block */ + ret = HmfsIo::GetInstance().DevReadBlock(nodeBlk, ni.blockAddr); + ASSERT(ret >= 0); + } + + uint32_t startaddr = LE32_TO_NATIVE(nodeBlk->i.iExt.blkAddr); + uint32_t endaddr = startaddr + LE32_TO_NATIVE(nodeBlk->i.iExt.len); + if (oldaddr >= startaddr && oldaddr < endaddr) { + nodeBlk->i.iExt.len = 0; + + /* update inode block */ + ASSERT(HmfsCommon::GetInstance().WriteInode(nodeBlk, ni.blockAddr, config_->chksumSeed) >= 0); + } + free(nodeBlk); +} + +void ResizeOperator::UpdateNatBlkaddr(uint32_t ino, uint32_t nid, uint32_t newaddr) +{ + struct natBlockData *natBlock = (struct natBlockData *)calloc(BLOCK_SZ, 1); + ASSERT(natBlock); + + int entryOff = nid % NAT_ENTRY_PER_BLOCK; + unsigned long blockAddr = CurrentNatAddr(sbInfo_, nid, NULL); + int ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + + if (ino) + natBlock->entries[entryOff].inodeNo = NATIVE_TO_LE32(ino); + natBlock->entries[entryOff].blockId = NATIVE_TO_LE32(newaddr); + // if (c.func == FSCK) + // F2FS_FSCK(sbi)->entries[nid] = natBlock->entries[entryOff]; + + ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + free(natBlock); +} + +int32_t ResizeOperator::MigrateMainArea(unsigned int offset) +{ + HMFS_DEBUG("Enter MigrateMainArea"); + void *raw = calloc(BLOCK_SZ, 1); + if (raw == nullptr) { + return -1; + } + SegmentInfoTable *smInfo = sbInfo_->smInfoTable; + uint32_t smMainSeg = smInfo->mainSegments; + ASSERT(raw != nullptr); + + for (int32_t i = smMainSeg - 1; i >= 0; i--) { + struct SegEntry *se = GetSegEntry(sbInfo_, i); + if (!se->validBlocks) { + continue; + } + for (int32_t j = sbInfo_->blocksPerSeg - 1; j >= 0; j--) { + if (!HmfsCommon::GetInstance().HmfsTestBit(j, (const char *)se->curValidBitmap)) { + continue; + } + uint32_t from = START_BLOCK(sbInfo_, i) + j; + int32_t ret = HmfsIo::GetInstance().DevReadBlock(raw, from); + ASSERT(ret >= 0); + + uint32_t to = from + offset; + ret = HmfsIo::GetInstance().DevWriteBlock(raw, to); + ASSERT(ret >= 0); + struct SummaryEntry sum = {}; + GetSumEntry(from, &sum); + + if (IS_DATASEG(se->type)) { + UpdateDataBlkaddr(LE32_TO_NATIVE(sum.nid), LE16_TO_NATIVE(sum.ofsInNode), to); + } else { + UpdateNatBlkaddr(0, LE32_TO_NATIVE(sum.nid), to); + } + } + } + free(raw); + HMFS_INFO("Done to migrate Main area: main_blkaddr = 0x%x -> 0x%x\n", + START_BLOCK(sbInfo_, 0), START_BLOCK(sbInfo_, 0) + offset); + return SUCCESS_CODE; +} + +void ResizeOperator::MoveSsa(unsigned int segno, uint32_t newSumBlkAddr) +{ + int32_t type = 0; + struct SummaryBlockData *sumBlk = GetSumBlock(segno, &type); + if (type < SEG_TYPE_MAX) { + int32_t ret = HmfsIo::GetInstance().DevWriteBlock(sumBlk, newSumBlkAddr); + ASSERT(ret >= 0); + // HMFS_INFO("Write summary block: (%d) segno=%x/%x --> (%d) %x\n", + // type, segno, GET_SUM_BLKADDR(sbInfo_, segno), + // IS_SUM_NODE_SEG(sumBlk->footer), newSumBlkAddr); + } + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || type == SEG_TYPE_MAX) { + free(sumBlk); + } + HMFS_INFO("Done to migrate SSA blocks\n"); +} + +int32_t ResizeOperator::MigrateSsa(struct SuperBlockData *newSbData, unsigned int offset) +{ + HMFS_DEBUG("Enter MigrateSsa"); + if (newSbData == nullptr) { + return EXIT_ERR_CODE; + } + struct SuperBlockData *sbData = sbInfo_->rawSuper; + uint32_t oldSumBlkaddr = GetLeValue(sbData->ssaBlkId); + uint32_t newSumBlkaddr = GetLeValue(newSbData->ssaBlkId); + uint32_t endSumBlkaddr = GetLeValue(newSbData->mainBlkId); + uint32_t expandSumBlkaddr = newSumBlkaddr + MAIN_SEGS(sbInfo_) - offset; + uint32_t blkaddr = 0; + int32_t ret = -1; + void *zero_block = calloc(BLOCK_SZ, 1); + ASSERT(zero_block); + + if (offset && newSumBlkaddr < oldSumBlkaddr + offset) { + blkaddr = newSumBlkaddr; + while (blkaddr < endSumBlkaddr) { + if (blkaddr < expandSumBlkaddr) { + MoveSsa(offset++, blkaddr++); + } else { + ret = HmfsIo::GetInstance().DevWriteBlock(zero_block, blkaddr++); + ASSERT(ret >=0); + } + } + } else { + blkaddr = endSumBlkaddr - 1; + offset = MAIN_SEGS(sbInfo_) - 1; + while (blkaddr >= newSumBlkaddr) { + if (blkaddr >= expandSumBlkaddr) { + ret = HmfsIo::GetInstance().DevWriteBlock(zero_block, blkaddr--); + ASSERT(ret >=0); + } else { + MoveSsa(offset--, blkaddr--); + } + } + } + + HMFS_INFO("Done to migrate SSA blocks: sum_blkaddr = 0x%x -> 0x%x\n", + oldSumBlkaddr, newSumBlkaddr); + free(zero_block); + return SUCCESS_CODE; +} + +int32_t ResizeOperator::MigrateNat(struct SuperBlockData *newSbData) +{ + HMFS_DEBUG("Enter MigrateNat"); + if (newSbData == nullptr) { + return EXIT_ERR_CODE; + } + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct NodeAddressTable *nat = sbInfo_->naTable; + uint32_t oldNatBlkaddr = GetLeValue(sbData->natBlkId); + uint32_t newNatBlkaddr = GetLeValue(newSbData->natBlkId); + int32_t ret = -1; + unsigned long blockOff = 0; + unsigned long blockAddr = 0; + int32_t segOff = -1; + + void *natBlock = malloc(BLOCK_SZ); + ASSERT(natBlock); + for (int32_t nid = nat->maxNid - 1; nid >= 0; nid -= NAT_ENTRY_PER_BLOCK) { + blockOff = nid / NAT_ENTRY_PER_BLOCK; + segOff = blockOff >> sbInfo_->logBlksPerSeg; + blockAddr = (unsigned long)(oldNatBlkaddr + (segOff << sbInfo_->logBlksPerSeg << 1) + + (blockOff & ((1 << sbInfo_->logBlksPerSeg) - 1))); + + /* move to set #0 */ + if (HmfsCommon::GetInstance().HmfsTestBit(blockOff, nat->natBitmap)) { + blockAddr += sbInfo_->blocksPerSeg; + HmfsCommon::GetInstance().HmfsClearBit(blockOff, nat->natBitmap); + } + + ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + + blockAddr = (unsigned long)(newNatBlkaddr + (segOff << sbInfo_->logBlksPerSeg << 1) + + (blockOff & ((1 << sbInfo_->logBlksPerSeg) - 1))); + + /* new bitmap should be zeros */ + ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + } + /* zero out newly assigned nids */ + memset(natBlock, 0, BLOCK_SZ); + unsigned int natBlocks = GetLeValue(newSbData->segmentCountInNAT) >> 1; + natBlocks = natBlocks << GetLeValue(sbData->logBlksPerSeg); + int32_t newMaxNid = NAT_ENTRY_PER_BLOCK * natBlocks; + + HMFS_INFO("Write NAT block: %x->%x, max_nid=%x->%x\n", + oldNatBlkaddr, newNatBlkaddr, + GetLeValue(sbData->segmentCountInNAT), + GetLeValue(newSbData->segmentCountInNAT)); + + for (int32_t nid = nat->maxNid; nid < newMaxNid; nid += NAT_ENTRY_PER_BLOCK) { + blockOff = nid / NAT_ENTRY_PER_BLOCK; + segOff = blockOff >> sbInfo_->logBlksPerSeg; + blockAddr = (unsigned long)(newNatBlkaddr + (segOff << sbInfo_->logBlksPerSeg << 1) + + (blockOff & ((1 << sbInfo_->logBlksPerSeg) - 1))); + ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + HMFS_INFO("Write NAT: %lx\n", blockAddr); + } + free(natBlock); + HMFS_INFO("Done to migrate NAT blocks: nat_blkaddr = 0x%x -> 0x%x\n", + oldNatBlkaddr, newNatBlkaddr); + return SUCCESS_CODE; +} + +int32_t ResizeOperator::MigrateSit(struct SuperBlockData *newSbData, unsigned int offset) +{ + HMFS_DEBUG("Enter MigrateSit"); + if (newSbData == nullptr) { + return EXIT_ERR_CODE; + } + struct SitInfo *sitInfo = SIT_I(sbInfo_); + unsigned int ofs = 0; + unsigned int preOfs = 0; + struct sitBlockData *sitBlk = static_cast(calloc(BLOCK_SZ, 1)); + uint32_t sitBlks = GetLeValue(newSbData->segmentCountInSIT) << (sbInfo_->logBlksPerSeg - 1); + uint32_t blkAddr = 0; + int32_t ret = 0; + ASSERT(sitBlk); + + /* initialize with zeros */ + for (unsigned int index = 0; index < sitBlks; index++) { + ret = HmfsIo::GetInstance().DevWriteBlock(sitBlk, GetLeValue(newSbData->sitBlkId) + index); + ASSERT(ret >= 0); + HMFS_INFO("Write zero sit: %x\n", GetLeValue(newSbData->sitBlkId) + index); + } + + for (unsigned int segno = 0; segno < MAIN_SEGS(sbInfo_); segno++) { + struct SegEntry *se = GetSegEntry(sbInfo_, segno); + if (segno < offset) { + ASSERT(se->validBlocks == 0); + continue; + } + + ofs = SIT_BLOCK_OFFSET(sitInfo, segno - offset); + + if (ofs != preOfs) { + blkAddr = GetLeValue(newSbData->sitBlkId) + preOfs; + ret = HmfsIo::GetInstance().DevWriteBlock(sitBlk, blkAddr); + ASSERT(ret >= 0); + HMFS_INFO("Write valid sit: %x\n", blkAddr); + + preOfs = ofs; + memset(sitBlk, 0, BLOCK_SZ); + } + unsigned int sitEntryOffSet = (segno - offset) % sitInfo->sentsPerBlock; + struct sitEntry *sit = &sitBlk->entries[sitEntryOffSet]; + memcpy(sit->blockBitmap, se->curValidBitmap, SIT_VBLOCK_MAP_SIZE); + sit->usedBlockCount = NATIVE_TO_LE16((se->type << SIT_VBLOCKS_SHIFT) | se->validBlocks); + } + blkAddr = GetLeValue(newSbData->sitBlkId) + ofs; + ret = HmfsIo::GetInstance().DevWriteBlock(sitBlk, blkAddr); + HMFS_INFO("Write valid sit: %x\n", blkAddr); + ASSERT(ret >= 0); + + free(sitBlk); + HMFS_INFO("Done to restore new SIT blocks: 0x%x\n", GetLeValue(newSbData->sitBlkId)); + return SUCCESS_CODE; +} + +int32_t ResizeOperator::RebuildCheckpoint(struct SuperBlockData *newSbData, unsigned int offset) +{ + HMFS_DEBUG("Enter RebuildCheckpoint"); + if (newSbData == nullptr) { + return EXIT_ERR_CODE; + } + struct CheckPointData *cpData = sbInfo_->ckptData; + unsigned long long cpVer = GetLeValue(cpData->cpVersion); + struct SuperBlockData *sbData = sbInfo_->rawSuper; + unsigned int freeSegmentCount, newSegmentCount; + uint32_t newCpBlks = 1 + GetLeValue(newSbData->cpPayload); + uint32_t orphanBlks = 0; + uint32_t newCpBlkId, oldCpBlkId; + uint32_t crc = 0; + int32_t ret = 0; + struct CheckPointData *newCp = static_cast(calloc(newCpBlks * BLOCK_SZ, 1)); + ASSERT(newCp); + + void *buf = malloc(BLOCK_SZ); + ASSERT(buf); + + /* ovp / free segments */ + SetLeValue(cpData->rsvdSegmentCount, config_->newReservedSegments); + SetLeValue(cpData->overprovSegmentCount, (GetLeValue(newSbData->segmentCountInMain) - + GetLeValue(cpData->rsvdSegmentCount)) * config_->newOverprovision / 100); + SetLeValue(cpData->overprovSegmentCount, GetLeValue(cpData->overprovSegmentCount) + + GetLeValue(cpData->rsvdSegmentCount)); + + HMFS_INFO("Overprovision ratio = %.3lf%%\n", config_->newOverprovision); + HMFS_INFO("Overprovision segments = %u (GC reserved = %u)\n", + GetLeValue(cpData->overprovSegmentCount), config_->newReservedSegments); + + freeSegmentCount = GetFreeSegments(); + newSegmentCount = GetLeValue(newSbData->segmentCountInMain) - + GetLeValue(sbData->segmentCountInMain); + + SetLeValue(cpData->freeSegmentCount, freeSegmentCount + newSegmentCount); + SetLeValue(cpData->userBlockCount, ((GetLeValue(newSbData->segmentCountInMain) - + GetLeValue(cpData->overprovSegmentCount)) * config_->blocksPerSegment)); + + if (IsCheckpointFlags(cpData, CP_ORPHAN_PRESENT_FLAG)){ + orphanBlks = LE32_TO_NATIVE(cpData->cpPackStartSum) - 1; + } + SetLeValue(cpData->cpPackStartSum, 1 + GetLeValue(newSbData->cpPayload)); + SetLeValue(cpData->cpPackBlockCount, 8 + orphanBlks + GetLeValue(newSbData->cpPayload)); + + /* cur->segno - offset */ + for (int32_t i = 0; i < NO_CHECK_TYPE; i++) { + if (i < CURSEG_HOT_NODE) { + SetLeValue(cpData->curDataSegNo[i], CURSEG_I(sbInfo_, i)->segNum - offset); + } else { + int32_t n = i - CURSEG_HOT_NODE; + SetLeValue(cpData->curNodeSegNo[n], CURSEG_I(sbInfo_, i)->segNum - offset); + } + } + + /* sit / nat ver bitmap bytesize */ + SetLeValue(cpData->sitVersionBitmapSize, ((GetLeValue(newSbData->segmentCountInSIT) / 2) << + GetLeValue(newSbData->logBlksPerSeg)) / 8); + SetLeValue(cpData->natVersionBitmapSize, ((GetLeValue(newSbData->segmentCountInNAT) / 2) << + GetLeValue(newSbData->logBlksPerSeg)) / 8); + + /* update nat_bits flag */ + uint32_t flags = UpdateNatBitsFlags(newSbData, cpData, GetLeValue(cpData->cpFlags)); + if (config_->largeNatBitmap) { + flags |= CP_LARGE_NAT_BITMAP_FLAG; + } + if (flags & CP_COMPACT_SUM_FLAG) { + flags &= ~CP_COMPACT_SUM_FLAG; + } + if (flags & CP_LARGE_NAT_BITMAP_FLAG) { + SetLeValue(cpData->checksumOffset, CP_MIN_CHKSUM_OFFSET); + } else { + SetLeValue(cpData->checksumOffset, CP_CHKSUM_OFFSET); + } + SetLeValue(cpData->cpFlags, flags); + HMFS_DEBUG("memcpy new checkpoint begin"); + memcpy(newCp, cpData, (unsigned char *)cpData->sitNatVersionBitmap - (unsigned char *)cpData); + if (config_->safeResize) { + HMFS_DEBUG("memcpy new checkpoint in safe"); + memcpy(reinterpret_cast(newCp) + CP_BITMAP_OFFSET, reinterpret_cast(cpData) + CP_BITMAP_OFFSET, HMFS_BLKSIZE - CP_BITMAP_OFFSET); + } + newCp->cpVersion = NATIVE_TO_LE64(cpVer + 1); + crc = HmfsCheckpointChksum(newCp); + *(reinterpret_cast((reinterpret_cast(newCp) + GetLeValue(cpData->checksumOffset)))) = NATIVE_TO_LE32(crc); + + /* Write a new checkpoint in the other set */ + newCpBlkId = oldCpBlkId = GetLeValue(sbData->cpBlkId); + if (sbInfo_->curCpId == 2) { + oldCpBlkId += 1 << GetLeValue(sbData->logBlksPerSeg); + } else { + newCpBlkId += 1 << GetLeValue(sbData->logBlksPerSeg); + } + /* write first cp */ + ret = HmfsIo::GetInstance().DevWriteBlock(newCp, newCpBlkId++); + ASSERT(ret >= 0); + + memset(buf, 0, BLOCK_SZ); + for (int32_t i = 0; i < GetLeValue(newSbData->cpPayload); i++) { + ret = HmfsIo::GetInstance().DevWriteBlock(buf, newCpBlkId++); + ASSERT(ret >= 0); + } + + for (int32_t i = 0; i < orphanBlks; i++) { + uint32_t orphan_blk_no = oldCpBlkId + 1 + GetLeValue(sbData->cpPayload); + ret = HmfsIo::GetInstance().DevReadBlock(buf, orphan_blk_no++); + ASSERT(ret >= 0); + ret = HmfsIo::GetInstance().DevWriteBlock(buf, newCpBlkId++); + ASSERT(ret >= 0); + } + + /* update summary blocks having nullified journal entries */ + for (int32_t i = 0; i < NO_CHECK_TYPE; i++) { + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, i); + ret = HmfsIo::GetInstance().DevWriteBlock(curseg->segSumBlk, newCpBlkId++); + ASSERT(ret >= 0); + } + + /* write the last cp */ + ret = HmfsIo::GetInstance().DevWriteBlock(newCp, newCpBlkId++); + ASSERT(ret >= 0); + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) { + WriteNatBits(newSbData, newCp, sbInfo_->curCpId == 1 ? 2 : 1); + } + /* disable old checkpoint */ + memset(buf, 0, BLOCK_SZ); + ret = HmfsIo::GetInstance().DevWriteBlock(buf, oldCpBlkId); + ASSERT(ret >= 0); + + free(buf); + free(newCp); + HMFS_INFO("Done to rebuild checkpoint blocks\n"); + return SUCCESS_CODE; +} + +int32_t ResizeOperator::HmfsResizeCheck(struct SuperBlockData *newSbData) +{ + if (newSbData == nullptr) { + return EXIT_ERR_CODE; + } + struct CheckPointData *cpData = sbInfo_->ckptData; + unsigned int overprovSegmentCount = (GetLeValue(newSbData->segmentCountInMain) - + config_->newReservedSegments) * config_->newOverprovision / 100; + overprovSegmentCount += config_->newReservedSegments; + + uint32_t userBlockCount = (GetLeValue(newSbData->segmentCountInMain) - + overprovSegmentCount) * config_->blocksPerSegment; + + if (GetLeValue(cpData->validBlockCount) > userBlockCount) { + return EXIT_ERR_CODE; + } + return SUCCESS_CODE; +} + +int32_t ResizeOperator::FlushNatJournalEntries() +{ + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, CURSEG_HOT_DATA); + struct JournalEntry *journal = &curseg->segSumBlk->journal; + int32_t ret = 0; + int32_t i = 0; + struct natBlockData *natBlock = static_cast(calloc(BLOCK_SZ, 1)); + ASSERT(natBlock); + + uint16_t natsSum = NatsInCursum(journal); + + for(; i < natsSum; i++) { + uint32_t nid = LE32_TO_NATIVE(NidInJournal(journal, i)); + + int32_t entryOff = nid % NAT_ENTRY_PER_BLOCK; + unsigned long blockAddr = CurrentNatAddr(sbInfo_, nid, nullptr); + ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + + memcpy(&natBlock->entries[entryOff], &NatInJournal(journal, i), sizeof(struct natEntry)); + + ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr); + ASSERT(ret >= 0); + } + + free(natBlock); + journal->nNats = 0; + return i; +} + +void ResizeOperator::RewriteCurrentSitPage(unsigned int segno, struct sitBlockData *sitBlk) +{ + if (sitBlk == nullptr) { + return; + } + uint32_t blkAddr = CurrentSitAddr(sbInfo_, segno); + ASSERT(HmfsIo::GetInstance().DevWriteBlock(sitBlk, blkAddr) >= 0); +} + +int32_t ResizeOperator::FlushSitJournalEntries() +{ + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, CURSEG_COLD_DATA); + struct JournalEntry *journal = &curseg->segSumBlk->journal; + struct SitInfo *sitInfo = SIT_I(sbInfo_); + int32_t i; + + struct sitBlockData *sitBlk = static_cast(calloc(BLOCK_SZ, 1)); + ASSERT(sitBlk); + for (i = 0; i < SitsInCursum(journal); i++) { + struct sitEntry *sit; + struct SegEntry *se; + + unsigned int segno = SegnoInJournal(journal, i); + se = GetSegEntry(sbInfo_, segno); + + GetCurrentSitPage(sbInfo_, segno, sitBlk); + unsigned int sitEntryOffSet = segno % sitInfo->sentsPerBlock; + sit = &sitBlk->entries[sitEntryOffSet]; + + memcpy(sit->blockBitmap, se->curValidBitmap, SIT_VBLOCK_MAP_SIZE); + sit->usedBlockCount = NATIVE_TO_LE16((se->type << SIT_VBLOCKS_SHIFT) | se->validBlocks); + sit->modTime = NATIVE_TO_LE64(se->modTime); + RewriteCurrentSitPage(segno, sitBlk); + } + free(sitBlk); + journal->nSits = 0; + return i; +} + +void ResizeOperator::DuplicateCheckpoint() +{ + HMFS_DEBUG("Enter DuplicateCheckpoint"); + struct SuperBlockData *sbData = sbInfo_->rawSuper; + unsigned long long dst; + unsigned long long src; + unsigned int segSize = 1 << GetLeValue(sbData->logBlksPerSeg); + int32_t ret; + + if (sbInfo_->cpBackuped) { + return; + } + void *buf = malloc(HMFS_BLKSIZE * segSize); + ASSERT(buf); + + if (sbInfo_->curCpId == 1) { + src = GetLeValue(sbData->cpBlkId); + dst = src + segSize; + } else { + dst = GetLeValue(sbData->cpBlkId); + src = dst + segSize; + } + + ret = HmfsIo::GetInstance().DevRead(buf, src << HMFS_BLKSIZE_BITS, segSize << HMFS_BLKSIZE_BITS); + ASSERT(ret >= 0); + + ret = HmfsIo::GetInstance().DevWrite(buf, dst << HMFS_BLKSIZE_BITS, segSize << HMFS_BLKSIZE_BITS); + ASSERT(ret >= 0); + + free(buf); + + ret = HmfsFsyncDevice(); + ASSERT(ret >= 0); + + sbInfo_->cpBackuped = 1; + HMFS_INFO("Duplicate valid checkpoint to mirror position " + "%llu -> %llu\n", src, dst); +} + +uint32_t ResizeOperator::GetFreeSegments() +{ + uint32_t freeSegs = 0; + unsigned int mainSegments = sbInfo_->smInfoTable->mainSegments; + for (uint32_t i = 0; i < mainSegments; i++) { + struct SegEntry *se = GetSegEntry(sbInfo_, i); + if (se->validBlocks == 0x0 && !IS_CUR_SEGNO(sbInfo_, i)) { //&&is_usable_seg(sbInfo_, i) + freeSegs++; + } + } + return freeSegs; +} + +uint32_t ResizeOperator::UpdateNatBitsFlags(struct SuperBlockData *sbData, + struct CheckPointData *cpData, uint32_t flags) +{ + if (sbData == nullptr || cpData == nullptr) { + return 1; + } + + uint32_t natBitsBytes =GetLeValue(sbData->segmentCountInNAT) << 5; + uint32_t natBitsBlocks = HMFS_BYTES_TO_BLK((natBitsBytes << 1) + 8 + HMFS_BLKSIZE - 1); + if (GetLeValue(cpData->cpPackBlockCount) <= (1 << GetLeValue(sbData->logBlksPerSeg)) - natBitsBlocks) { + flags |= CP_NAT_BITS_FLAG; + } else { + flags &= (~CP_NAT_BITS_FLAG); + } + return flags; +} + +uint32_t ResizeOperator::HmfsCheckpointChksum(struct CheckPointData *cpData) +{ + if (cpData == nullptr) { + return 1; + } + unsigned int chksumOffset = LE32_TO_NATIVE(cpData->checksumOffset); + uint32_t chksum = HmfsCommon::GetInstance().HmfsCalCrc32(HMFS_SUPER_MAGIC, cpData, chksumOffset); + if (chksumOffset < CP_CHKSUM_OFFSET) { + chksumOffset += sizeof(chksum); + chksum = HmfsCommon::GetInstance().HmfsCalCrc32(chksum, (uint8_t *)cpData + chksumOffset, HMFS_BLKSIZE - chksumOffset); + } + return chksum; +} + +uint64_t ResizeOperator::GetCpCrc(struct CheckPointData *cpData) +{ + if (cpData == nullptr) { + return 1; + } + uint64_t cpVer = GetLeValue(cpData->cpVersion); + size_t crcOffset = GetLeValue(cpData->checksumOffset); + uint32_t crc = LE32_TO_NATIVE(*(uint32_t *)((unsigned char *)cpData + crcOffset)); + cpVer |= ((uint64_t)crc << 32); + return NATIVE_TO_LE64(cpVer); +} + +void ResizeOperator::WriteNatBits(struct SuperBlockData *sbData, struct CheckPointData *cpData, int set) +{ + if (sbData == nullptr || cpData == nullptr) { + return; + } + struct NodeAddressTable *nat = NM_I(sbInfo_); + uint32_t natBlocks = GetLeValue(sbData->segmentCountInNAT) << (GetLeValue(sbData->logBlksPerSeg) - 1); + uint32_t natBitsBytes = natBlocks >> 3; + uint32_t natBitsBlocks = HMFS_BYTES_TO_BLK((natBitsBytes << 1) + 8 + HMFS_BLKSIZE - 1); + uint32_t blkaddr; + int32_t ret; + + unsigned char *natBits = static_cast(calloc(HMFS_BLKSIZE, natBitsBlocks)); + ASSERT(natBits); + + struct natBlockData *natBlock = static_cast(malloc(HMFS_BLKSIZE)); + ASSERT(natBlock); + + unsigned char *fullNatBits = natBits + 8; + unsigned char *emptyNatBits = fullNatBits + natBitsBytes; + + memset(fullNatBits, 0, natBitsBytes); + memset(emptyNatBits, 0, natBitsBytes); + + for (uint32_t i = 0; i < natBlocks; i++) { + int seg_off = i >> GetLeValue(sbData->logBlksPerSeg); + int valid = 0; + + blkaddr = (unsigned long)(GetLeValue(sbData->natBlkId) + + (seg_off << GetLeValue(sbData->logBlksPerSeg) << 1) + + (i & ((1 << GetLeValue(sbData->logBlksPerSeg)) - 1))); + + /* + * Should consider new nat_blocks is larger than old + * nm_i->nat_blocks, since nm_i->nat_bitmap is based on + * old one. + */ + if (i < nat->natBlocks && HmfsCommon::GetInstance().HmfsTestBit(i, nat->natBitmap)) { + blkaddr += (1 << GetLeValue(sbData->logBlksPerSeg)); + } + + ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blkaddr); + ASSERT(ret >= 0); + + for (uint32_t j = 0; j < NAT_ENTRY_PER_BLOCK; j++) { + if ((i == 0 && j == 0) || natBlock->entries[j].blockId != NULL_ADDR) { + valid++; + } + } + if (valid == 0) { + HmfsCommon::GetInstance().TestAndSetBitLe(i, emptyNatBits); + } else if (valid == NAT_ENTRY_PER_BLOCK) { + HmfsCommon::GetInstance().TestAndSetBitLe(i, fullNatBits); + } + } + *(uint64_t *)natBits = GetCpCrc(cpData); + free(natBlock); + + blkaddr = GetLeValue(sbData->segment0BlkId) + (set << + GetLeValue(sbData->logBlksPerSeg)) - natBitsBlocks; + + HMFS_INFO("\tWriting NAT bits pages, at offset 0x%08x\n", blkaddr); + + for (uint32_t i = 0; i < natBitsBlocks; i++) { + if (HmfsIo::GetInstance().DevWriteBlock(natBits + i * HMFS_BLKSIZE, blkaddr + i)) + HMFS_ERROR("\tError: write NAT bits to disk!!!\n"); + } + HMFS_INFO("Write valid nat_bits in checkpoint\n"); + + free(natBits); +} + +int ResizeOperator::HmfsFsyncDevice() +{ +#ifdef HAVE_FSYNC + for (int i = 0; i < config_->nDevices; i++) { + if (fsync(config_->devices[i].fd) < 0) { + HMFS_ERROR("\tError: Could not conduct fsync!!!\n"); + return -1; + } + } +#endif + return 0; +} + +void ResizeOperator::WriteCheckpoint() +{ + HMFS_DEBUG("Enter WriteCheckpoint"); + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct CheckPointData *cpData = sbInfo_->ckptData; + uint32_t orphanBlks = 0; + uint32_t flags = CP_UMOUNT_FLAG; + int32_t ret; + if (IsCheckpointFlags(cpData, CP_ORPHAN_PRESENT_FLAG)) { + orphanBlks = LE32_TO_NATIVE(cpData->cpPackStartSum) - 1; + flags |= CP_ORPHAN_PRESENT_FLAG; + } + if (IsCheckpointFlags(cpData, CP_TRIMMED_FLAG)) { + flags |= CP_TRIMMED_FLAG; + } + if (IsCheckpointFlags(cpData, CP_DISABLED_FLAG)) { + flags |= CP_DISABLED_FLAG; + } + if (IsCheckpointFlags(cpData, CP_LARGE_NAT_BITMAP_FLAG)) { + flags |= CP_LARGE_NAT_BITMAP_FLAG; + SetLeValue(cpData->checksumOffset, CP_MIN_CHKSUM_OFFSET); + } else { + SetLeValue(cpData->checksumOffset, CP_CHKSUM_OFFSET); + } + SetLeValue(cpData->freeSegmentCount, GetFreeSegments()); + SetLeValue(cpData->validBlockCount, sbInfo_->totalValidBlockCount); + SetLeValue(cpData->validNodeCount, sbInfo_->totalValidNodeCount); + SetLeValue(cpData->validInodeCount, sbInfo_->totalValidInodeCount); + SetLeValue(cpData->cpPackBlockCount, 8 + orphanBlks + GetLeValue(sbData->cpPayload)); + + flags = UpdateNatBitsFlags(sbData, cpData, flags); + SetLeValue(cpData->cpFlags, flags); + + uint32_t crc = HmfsCheckpointChksum(cpData); + *((uint32_t *)((unsigned char *)cpData + GetLeValue(cpData->checksumOffset))) = NATIVE_TO_LE32(crc); + + unsigned long long cpBlkNo = GetLeValue(sbData->cpBlkId); + if (sbInfo_->curCpId == 2) { + cpBlkNo += 1 << GetLeValue(sbData->logBlksPerSeg); + } + /* write the first cpData */ + ret = HmfsIo::GetInstance().DevWriteBlock(cpData, cpBlkNo++); + ASSERT(ret >= 0); + + /* skip payload */ + cpBlkNo += GetLeValue(sbData->cpPayload); + /* skip orphan blocks */ + cpBlkNo += orphanBlks; + + /* update summary blocks having nullified journal entries */ + for (int32_t i = 0; i < NO_CHECK_TYPE; i++) { + struct CurSegmentInfo *curseg = CURSEG_I(sbInfo_, i); + ret = HmfsIo::GetInstance().DevWriteBlock(curseg->segSumBlk, cpBlkNo++); + ASSERT(ret >= 0); + + if (!(GetLeValue(sbData->features) & NATIVE_TO_LE32(HMFS_FEATURE_RO))) { + /* update original SSA too */ + uint64_t ssaBlk = sbInfo_->smInfoTable->ssaBlkaddr + curseg->segNum; + ret = HmfsIo::GetInstance().DevWriteBlock(curseg->segSumBlk, ssaBlk); + ASSERT(ret >= 0); + } + } + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) { + WriteNatBits(sbData, cpData, sbInfo_->curCpId); + } + /* in case of sudden power off */ + ret = HmfsFsyncDevice(); + ASSERT(ret >= 0); + // /* write the last cpData */ + ret = HmfsIo::GetInstance().DevWriteBlock(cpData, cpBlkNo++); + ASSERT(ret >= 0); + ret = HmfsFsyncDevice(); + ASSERT(ret >= 0); +} + +void ResizeOperator::DupWriteCheckpoints() +{ + /* copy valid checkpoint to its mirror position */ + DuplicateCheckpoint(); + /* repair checkpoint at CP #0 position */ + sbInfo_->curCpId = 1; + WriteCheckpoint(); +} + +void ResizeOperator::FlushJournalEntries() +{ + HMFS_DEBUG("Enter FlushJournalEntries"); + int32_t nNats = FlushNatJournalEntries(); + int32_t nSits = FlushSitJournalEntries(); + if (nNats || nSits) { + DupWriteCheckpoints(); + } +} + +void ResizeOperator::UpdateSuperBlock(struct SuperBlockData *superBlock, int sbMask) +{ + HMFS_DEBUG("Enter UpdateSuperBlock"); + if (superBlock == nullptr) { + return; + } + uint8_t *buf = static_cast(calloc(BLOCK_SZ, 1)); + ASSERT(buf); + if (GetLeValue(superBlock->features) & HMFS_FEATURE_SB_CHKSUM) { + uint32_t oldCrc = GetLeValue(superBlock->checksum); + uint32_t newCrc = HmfsCommon::GetInstance().HmfsCalCrc32(HMFS_SUPER_MAGIC, superBlock, SB_CHKSUM_OFFSET); + SetLeValue(superBlock->checksum, newCrc); + HMFS_INFO("SueprBlock CRC is updated (0x%x -> 0x%x)\n", oldCrc, newCrc); + } + + memcpy(buf + HMFS_SUPER_OFFSET, superBlock, sizeof(*superBlock)); + for (int addr = SB0_ADDR; addr < SB_MAX_ADDR; addr++) { + if (SB_MASK(addr) & sbMask) { + int ret = HmfsIo::GetInstance().DevWriteBlock(buf, addr); + ASSERT(ret >= 0); + } + } + free(buf); + HMFS_INFO("Done to update superblock\n"); +} + +int32_t ResizeOperator::HmfsResizeExpand() +{ + HMFS_DEBUG("Enter HmfsResizeExpand"); + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct SuperBlockData newSbRaw; + struct SuperBlockData *newSb = &newSbRaw; + unsigned int offsetSeg = 0; + int32_t err = -1; + + FlushJournalEntries(); + + memcpy(newSb, sbData, sizeof(*newSb)); + if (GetNewSuperBlock(newSb)) { + return -1; + } + if (HmfsResizeCheck(newSb) < 0) { + return -1; + } + /* check nat availability */ + if (GetLeValue(sbData->segmentCountInNAT) > GetLeValue(newSb->segmentCountInNAT)) { + err = ShrinkNats(newSb); + if (err) { + HMFS_ERROR("\tError: Failed to shrink NATs\n"); + return err; + } + } + + uint64_t oldMainBlkaddr = GetLeValue(sbData->mainBlkId); + uint64_t newMainBlkaddr = GetLeValue(newSb->mainBlkId); + uint64_t offset = newMainBlkaddr - oldMainBlkaddr; + uint32_t endBlkaddr = (GetLeValue(sbData->segmentCountInMain) << + GetLeValue(sbData->logBlksPerSeg)) + GetLeValue(sbData->mainBlkId); + + err = -EAGAIN; + if (newMainBlkaddr < endBlkaddr) { + err = reDefrag_->HmfsDefragment(oldMainBlkaddr, offset, newMainBlkaddr, 0); + if (!err) { + offsetSeg = offset >> GetLeValue(sbData->logBlksPerSeg); + } + HMFS_INFO("Try to do defragement: %s\n", err ? "Skip": "Done"); + } + /* move whole data region */ + if (err) { + MigrateMainArea(offset); + } + MigrateSsa(newSb, offsetSeg); + MigrateNat(newSb); + MigrateSit(newSb, offsetSeg); + RebuildCheckpoint(newSb, offsetSeg); + UpdateSuperBlock(newSb, SB_MASK_ALL); + // print_raw_sb_info(sb); + // print_raw_sb_info(newSb); + return SUCCESS_CODE; +} + +int32_t ResizeOperator::HmfsResizeShrink() +{ + HMFS_DEBUG("Enter HmfsResizeShrink"); + struct SuperBlockData *sbData = sbInfo_->rawSuper; + struct SuperBlockData newSbRaw; + struct SuperBlockData *newSb = &newSbRaw; + int32_t err = -1; + + /* flush NAT/SIT journal entries */ + FlushJournalEntries(); + + memcpy(newSb, sbData, sizeof(*newSb)); + if (GetNewSuperBlock(newSb)){ + return -1; + } + if (HmfsResizeCheck(newSb) < 0) { + return -1; + } + /* check nat availability */ + if (GetLeValue(sbData->segmentCountInNAT) > GetLeValue(newSb->segmentCountInNAT)) { + err = ShrinkNats(newSb); + if (err) { + HMFS_ERROR("\tError: Failed to shrink NATs\n"); + return err; + } + } + + uint32_t oldMainBlkaddr = GetLeValue(sbData->mainBlkId); + uint32_t newMainBlkaddr = GetLeValue(newSb->mainBlkId); + unsigned int offset = oldMainBlkaddr - newMainBlkaddr; + uint64_t oldEndBlkaddr = (GetLeValue(sbData->segmentCountInMain) << + GetLeValue(sbData->logBlksPerSeg)) + GetLeValue(sbData->mainBlkId); + uint32_t newEndBlkaddr = (GetLeValue(newSb->segmentCountInMain) << + GetLeValue(newSb->logBlksPerSeg)) + GetLeValue(newSb->mainBlkId); + + uint64_t tmpEndBlkaddr = newEndBlkaddr + offset; + err = reDefrag_->HmfsDefragment(tmpEndBlkaddr, oldEndBlkaddr - tmpEndBlkaddr, tmpEndBlkaddr, 1); + HMFS_INFO("Try to do defragement: %s\n", err ? "Insufficient Space": "Done"); + + if (err) { + return -ENOSPC; + } + + UpdateSuperBlock(newSb, SB_MASK_ALL); + RebuildCheckpoint(newSb, 0); + + return SUCCESS_CODE; +} + +int32_t ResizeOperator::HmfsResize() +{ + HMFS_DEBUG("Enter HmfsResize"); + if (CreateDeviceInfo()) { + HMFS_ERROR("CreateDeviceInfo fail"); + return -1; + } + if(InitDeviceInfoToConfig()) { + HMFS_ERROR("InitDeviceInfoToConfig fail"); + return -1; + } + ResizeLoad resizeLoad(config_, sbInfo_); + int32_t ret = resizeLoad.HmfsLoadData(); + if(ret) { + return EXIT_ERR_CODE; + } + if (!config_->targetSectors) { + config_->targetSectors = config_->totalSectors; + } + if (config_->targetSectors > config_->totalSectors) { + HMFS_ERROR("Out-of-range Target=0x%" PRIx64 " / 0x%" PRIx64 "", config_->targetSectors, config_->totalSectors); + return EXIT_ERR_CODE; + } + struct SuperBlockData *sbData = sbInfo_->rawSuper; + uint64_t configBlockCount = config_->targetSectors * config_->sectorSize >> GetLeValue(sbData->logBlockSize); + uint64_t curBlockCount = GetLeValue(sbData->blockCount); + if (configBlockCount < curBlockCount) { + if (!config_->safeResize) { + HMFS_ERROR("Nothing to resize, now only supports resizing with safe resize flag\n"); + return EXIT_ERR_CODE; + } else { + return HmfsResizeShrink(); + } + } else if ((configBlockCount > curBlockCount) || config_->force) { + return HmfsResizeExpand(); + } else { + HMFS_INFO("Nothing to resize.\n"); + return SUCCESS_CODE; + } + resizeLoad.HmfsUnLoadData(); +} + +int32_t ResizeOperator::CreateDeviceInfo() +{ + for (auto i = 0; i < resizeConfig_.deviceList.size(); i++) { + if (DeviceManager::GetInstance().CreateDeviceInfo(resizeConfig_.deviceList[i], i == 0)) { + return -1; + } + } + return 0; +} + +int32_t ResizeOperator::InitDeviceInfoToConfig() +{ + for (uint32_t i = 0; i < resizeConfig_.deviceList.size(); i++) { + DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(i); + if (deviceInfo == nullptr) { + HMFS_DEBUG("failed to get device info of %s", resizeConfig_.deviceList[i].c_str()); + continue; + } + config_->devices[i].path = deviceInfo->path; + config_->devices[i].fd = deviceInfo->fd; + if (i == 0) { + config_->sectorSize = deviceInfo->sectorSize; + config_->sectorsPerBlock = HMFS_BLOCK_SIZE / config_->sectorSize; + } else { + if (deviceInfo->sectorSize != config_->sectorSize) { + HMFS_ERROR("different sector sizes"); + return -1; + } + } + config_->totalSectors += deviceInfo->sectorCount; + } + config_->nDevices = DeviceManager::GetInstance().GetDeviceCount(); + if(config_->totalSectors == 0) { + return -1; + } + return 0; +} + +} +} -- Gitee