/* * Copyright (C) 2020 The Android Open Source Project * * 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. */ #pragma once #include #include #include #include #include "incfs.h" #include "path.h" namespace android::incfs { static bool exists(std::string_view path) { return access(path.data(), F_OK) == 0; } class IncFsTestBase : public ::testing::Test { protected: virtual void SetUp() { tmp_dir_for_mount_.emplace(); mount_dir_path_ = tmp_dir_for_mount_->path; tmp_dir_for_image_.emplace(); image_dir_path_ = tmp_dir_for_image_->path; ASSERT_TRUE(exists(image_dir_path_)); ASSERT_TRUE(exists(mount_dir_path_)); if (!enabled()) { GTEST_SKIP() << "test not supported: IncFS is not enabled"; } else { metrics_key_ = path::baseName(image_dir_path_); control_ = mount(image_dir_path_, mount_dir_path_, MountOptions{.readLogBufferPages = 4, .defaultReadTimeoutMs = getReadTimeout(), .sysfsName = metrics_key_.c_str()}); ASSERT_TRUE(control_.cmd() >= 0) << "Expected >= 0 got " << control_.cmd(); ASSERT_TRUE(control_.pendingReads() >= 0); ASSERT_TRUE(control_.logs() >= 0); checkRestoreconResult(mountPath(INCFS_PENDING_READS_FILENAME)); checkRestoreconResult(mountPath(INCFS_LOG_FILENAME)); } } virtual void TearDown() { unmount(mount_dir_path_); tmp_dir_for_image_.reset(); tmp_dir_for_mount_.reset(); EXPECT_FALSE(exists(image_dir_path_)); EXPECT_FALSE(exists(mount_dir_path_)); } static void checkRestoreconResult(std::string_view path) { char* ctx = nullptr; ASSERT_NE(-1, getfilecon(path.data(), &ctx)); ASSERT_EQ("u:object_r:shell_data_file:s0", std::string(ctx)); freecon(ctx); } static IncFsFileId fileId(uint64_t i) { IncFsFileId id = {}; static_assert(sizeof(id) >= sizeof(i)); memcpy(&id, &i, sizeof(i)); return id; } virtual int32_t getReadTimeout() { return std::chrono::duration_cast(kDefaultReadTimeout).count(); } template std::string mountPath(Paths&&... paths) const { return path::join(mount_dir_path_, std::forward(paths)...); } virtual int makeFileWithHash(int id) { // calculate the required size for two leaf hash blocks constexpr auto size = (INCFS_DATA_FILE_BLOCK_SIZE / INCFS_MAX_HASH_SIZE + 1) * INCFS_DATA_FILE_BLOCK_SIZE; // assemble a signature/hashing data for it struct __attribute__((packed)) Signature { uint32_t version = INCFS_SIGNATURE_VERSION; uint32_t hashingSize = sizeof(hashing); struct __attribute__((packed)) Hashing { uint32_t algo = INCFS_HASH_TREE_SHA256; uint8_t log2Blocksize = 12; uint32_t saltSize = 0; uint32_t rootHashSize = INCFS_MAX_HASH_SIZE; char rootHash[INCFS_MAX_HASH_SIZE] = {}; } hashing; uint32_t signingSize = 0; } signature; int res = makeFile(control_, mountPath(test_file_name_), 0555, fileId(id), {.size = size, .signature = {.data = (char*)&signature, .size = sizeof(signature)}}); EXPECT_EQ(0, res); return res ? -1 : size; } std::string mount_dir_path_; std::optional tmp_dir_for_mount_; std::string image_dir_path_; std::optional tmp_dir_for_image_; inline static const std::string_view test_file_name_ = "test.txt"; inline static const std::string_view test_dir_name_ = "test_dir"; std::string metrics_key_; Control control_; }; } // namespace android::incfs