// Copyright 2019 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/minfs/inspector/inspector.h"

#include <lib/syslog/cpp/macros.h>
#include <sys/stat.h>

#include <disk_inspector/common_types.h>
#include <fbl/unique_fd.h>
#include <safemath/safe_conversions.h>

#include "src/storage/lib/block_client/cpp/block_device.h"
#include "src/storage/lib/vfs/cpp/journal/inspector_journal.h"
#include "src/storage/minfs/bcache.h"
#include "src/storage/minfs/inspector/inspector_inode_table.h"
#include "src/storage/minfs/inspector/inspector_private.h"
#include "src/storage/minfs/inspector/inspector_superblock.h"

namespace minfs {

std::unique_ptr<disk_inspector::DiskObjectUint64> CreateUint64DiskObj(fbl::String fieldName,
                                                                      const uint64_t* value) {
  return std::make_unique<disk_inspector::DiskObjectUint64>(std::move(fieldName), value);
}

std::unique_ptr<disk_inspector::DiskObjectUint32> CreateUint32DiskObj(fbl::String fieldName,
                                                                      const uint32_t* value) {
  return std::make_unique<disk_inspector::DiskObjectUint32>(std::move(fieldName), value);
}

std::unique_ptr<disk_inspector::DiskObjectUint64Array> CreateUint64ArrayDiskObj(
    fbl::String fieldName, const uint64_t* value, size_t size) {
  return std::make_unique<disk_inspector::DiskObjectUint64Array>(std::move(fieldName), value, size);
}

std::unique_ptr<disk_inspector::DiskObjectUint32Array> CreateUint32ArrayDiskObj(
    fbl::String fieldName, const uint32_t* value, size_t size) {
  return std::make_unique<disk_inspector::DiskObjectUint32Array>(std::move(fieldName), value, size);
}

zx_status_t Inspector::GetRoot(std::unique_ptr<disk_inspector::DiskObject>* out) {
  auto bc_or = CreateBcache(std::move(device_));
  if (bc_or.is_error()) {
    FX_LOGS(ERROR) << "cannot create block cache";
    return bc_or.error_value();
  }
  auto [bc, _] = std::move(bc_or.value());

  auto root_or = CreateRoot(std::move(bc));
  if (root_or.is_error()) {
    FX_LOGS(ERROR) << "cannot create root object";
    return root_or.error_value();
  }

  *out = std::move(root_or.value());
  return ZX_OK;
}

zx::result<std::unique_ptr<disk_inspector::DiskObject>> Inspector::CreateRoot(
    std::unique_ptr<Bcache> bc) {
  MountOptions options = {};
  options.writability = minfs::Writability::ReadOnlyFilesystem;
  options.repair_filesystem = false;

  auto fs = Runner::Create(dispatcher_, std::move(bc), options);
  if (fs.is_error()) {
    FX_LOGS(ERROR) << "minfsInspector: Create Failed to Create Minfs: " << fs.error_value();
    return fs.take_error();
  }

  return zx::ok(std::make_unique<RootObject>(*std::move(fs)));
}

std::unique_ptr<disk_inspector::DiskObject> RootObject::GetSuperBlock() const {
  return std::unique_ptr<disk_inspector::DiskObject>(
      new SuperBlockObject(fs_.Info(), SuperblockType::kPrimary));
}

std::unique_ptr<disk_inspector::DiskObject> RootObject::GetInodeTable() const {
  return std::unique_ptr<disk_inspector::DiskObject>(new InodeTableObject(
      fs_.GetInodeManager(), fs_.Info().alloc_inode_count, fs_.Info().inode_count));
}

std::unique_ptr<disk_inspector::DiskObject> RootObject::GetJournal() const {
  char data[kMinfsBlockSize];

  const Superblock& superblock = fs_.Info();
  uint64_t start_block = JournalStartBlock(superblock);
  uint64_t length = JournalBlocks(superblock);
  if (fs_.ReadBlock(static_cast<blk_t>(start_block), data) < 0) {
    FX_LOGS(ERROR) << "minfsInspector: could not read journal block";
    return nullptr;
  }
  fs::JournalInfo* info = reinterpret_cast<fs::JournalInfo*>(data);
  auto block_reader = [&fs = fs_](uint64_t start, void* data) {
    return fs.ReadBlock(safemath::checked_cast<blk_t>(start), data);
  };
  return std::unique_ptr<disk_inspector::DiskObject>(
      new fs::JournalObject(*info, start_block, length, std::move(block_reader)));
}

std::unique_ptr<disk_inspector::DiskObject> RootObject::GetBackupSuperBlock() const {
  char data[kMinfsBlockSize];
  const Superblock& info = fs_.Info();

  uint64_t location =
      ((info.flags & kMinfsFlagFVM) == 0) ? kNonFvmSuperblockBackup : kFvmSuperblockBackup;
  if (fs_.ReadBlock(static_cast<blk_t>(location), &data) < 0) {
    FX_LOGS(ERROR) << "minfsInspector: could not read backup superblock";
    return nullptr;
  }
  auto backup_info = reinterpret_cast<Superblock&>(data);
  return std::unique_ptr<disk_inspector::DiskObject>(
      new SuperBlockObject(backup_info, SuperblockType::kBackup));
}

void RootObject::GetValue(const void** out_buffer, size_t* out_buffer_size) const {
  ZX_DEBUG_ASSERT_MSG(false, "Invalid GetValue call for non primitive data type.");
}

std::unique_ptr<disk_inspector::DiskObject> RootObject::GetElementAt(uint32_t index) const {
  switch (index) {
    case 0: {
      // Super Block
      return GetSuperBlock();
    }
    case 1: {
      // Inode Table
      return GetInodeTable();
    }
    case 2: {
      // Journal
      return GetJournal();
    }
    case 3: {
      // Backup Superblock
      return GetBackupSuperBlock();
    }
  };
  return nullptr;
}

}  // namespace minfs
