blob: cba15272e31120de49f676dc91374298b68e7a1c [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/storage/blobfs/fsck.h"
#include <gtest/gtest.h>
#include "src/storage/blobfs/blobfs.h"
#include "src/storage/blobfs/mkfs.h"
#include "src/storage/blobfs/test/unit/local_decompressor_creator.h"
#include "src/storage/blobfs/test/unit/utils.h"
#include "src/storage/lib/block_client/cpp/fake_block_device.h"
namespace blobfs {
namespace {
using block_client::FakeBlockDevice;
constexpr uint32_t kBlockSize = 512;
constexpr uint32_t kNumBlocks = 400 * kBlobfsBlockSize / kBlockSize;
class FsckTest : public testing::Test {
public:
void SetUp() final {
auto connector_or = LocalDecompressorCreator::Create();
ASSERT_TRUE(connector_or.is_ok());
decompressor_creator_ = std::move(connector_or.value());
}
MountOptions DefaultMountOptions() {
return {.decompression_connector = &decompressor_creator_->GetDecompressorConnector()};
}
private:
std::unique_ptr<LocalDecompressorCreator> decompressor_creator_;
};
TEST_F(FsckTest, TestEmpty) {
auto device = std::make_unique<FakeBlockDevice>(kNumBlocks, kBlockSize);
ASSERT_TRUE(device);
ASSERT_EQ(FormatFilesystem(device.get(), FilesystemOptions{}), ZX_OK);
ASSERT_EQ(Fsck(std::move(device), DefaultMountOptions()), ZX_OK);
}
TEST_F(FsckTest, TestUnmountable) {
auto device = std::make_unique<FakeBlockDevice>(kNumBlocks, kBlockSize);
ASSERT_TRUE(device);
ASSERT_EQ(Fsck(std::move(device), DefaultMountOptions()), ZX_ERR_INVALID_ARGS);
}
TEST_F(FsckTest, TestCorrupted) {
auto device = std::make_unique<FakeBlockDevice>(kNumBlocks, kBlockSize);
ASSERT_TRUE(device);
ASSERT_EQ(FormatFilesystem(device.get(), FilesystemOptions{}), ZX_OK);
char block[kBlobfsBlockSize];
DeviceBlockRead(device.get(), block, sizeof(block), kSuperblockOffset);
Superblock* info = reinterpret_cast<Superblock*>(block);
info->alloc_inode_count++;
DeviceBlockWrite(device.get(), block, sizeof(block), kSuperblockOffset);
ASSERT_EQ(Fsck(std::move(device), DefaultMountOptions()), ZX_ERR_IO_OVERRUN);
}
TEST_F(FsckTest, TestOverflow) {
auto device = std::make_unique<FakeBlockDevice>(kNumBlocks, kBlockSize);
ASSERT_TRUE(device);
ASSERT_EQ(FormatFilesystem(device.get(), FilesystemOptions{}), ZX_OK);
char block[kBlobfsBlockSize];
DeviceBlockRead(device.get(), block, sizeof(block), kSuperblockOffset);
Superblock* info = reinterpret_cast<Superblock*>(block);
info->inode_count = std::numeric_limits<uint64_t>::max();
DeviceBlockWrite(device.get(), block, sizeof(block), kSuperblockOffset);
ASSERT_EQ(Fsck(std::move(device), DefaultMountOptions()), ZX_ERR_OUT_OF_RANGE);
}
TEST_F(FsckTest, TestBadBackupSuperblock) {
auto device = std::make_unique<block_client::FakeFVMBlockDevice>(
400, kBlobfsBlockSize, /*slice_size=*/32768, /*slice_capacity=*/500);
ASSERT_TRUE(device);
ASSERT_EQ(FormatFilesystem(device.get(), FilesystemOptions{}), ZX_OK);
char block[kBlobfsBlockSize];
memset(block, 0xaf, sizeof(block));
DeviceBlockWrite(device.get(), block, sizeof(block), kBlobfsBlockSize);
ASSERT_NE(Fsck(std::move(device), DefaultMountOptions()), ZX_OK);
}
// This format is no longer supported for reading.
TEST_F(FsckTest, TestNoBackupSuperblockOnOldRevisionFailsFsck) {
auto device = std::make_unique<block_client::FakeFVMBlockDevice>(
400, kBlobfsBlockSize, /*slice_size=*/32768, /*slice_capacity=*/500);
ASSERT_TRUE(device);
ASSERT_EQ(FormatFilesystem(device.get(), FilesystemOptions{}), ZX_OK);
Superblock superblock;
DeviceBlockRead(device.get(), &superblock, sizeof(superblock), 0);
superblock.oldest_minor_version = kBlobfsMinorVersionBackupSuperblock - 1;
DeviceBlockWrite(device.get(), &superblock, sizeof(superblock), 0);
memset(&superblock, 0xaf, sizeof(superblock));
DeviceBlockWrite(device.get(), &superblock, sizeof(superblock), kBlobfsBlockSize);
MountOptions mount_options = DefaultMountOptions();
mount_options.writability = Writability::ReadOnlyDisk;
ASSERT_NE(Fsck(std::move(device), mount_options), ZX_OK);
}
} // namespace
} // namespace blobfs