// 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/fvm/test_support.h"

#include <errno.h>
#include <fidl/fuchsia.device/cpp/wire.h>
#include <fidl/fuchsia.hardware.block.volume/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/device-watcher/cpp/device-watcher.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fidl/cpp/wire/sync_call.h>
#include <lib/fidl/cpp/wire/vector_view.h>
#include <lib/zx/time.h>
#include <zircon/status.h>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

#include <fbl/unique_fd.h>
#include <zxtest/zxtest.h>

#include "lib/fdio/directory.h"
#include "src/storage/lib/block_client/cpp/remote_block_device.h"
#include "src/storage/lib/fs_management/cpp/fvm.h"

namespace fvm {
namespace {

constexpr char kRamdiskCtlPath[] = "sys/platform/00:00:2d/ramctl";
constexpr zx::duration kDeviceWaitTime = zx::sec(30);

template <typename Protocol>
zx::result<fidl::ClientEnd<Protocol>> GetChannel(DeviceRef* device) {
  fdio_cpp::UnownedFdioCaller caller(device->devfs_root_fd());
  return component::ConnectAt<Protocol>(caller.directory(), device->path());
}

zx::result<fidl::ClientEnd<fuchsia_device::Controller>> GetController(DeviceRef* device) {
  fdio_cpp::UnownedFdioCaller caller(device->devfs_root_fd());
  std::string controller_path = std::string(device->path()).append("/device_controller");
  return component::ConnectAt<fuchsia_device::Controller>(caller.directory(), controller_path);
}

zx_status_t RebindBlockDevice(DeviceRef* device) {
  // We need to create a DirWatcher to wait for the block device's child to disappear.
  fdio_cpp::UnownedFdioCaller caller(device->devfs_root_fd());
  auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
  const fidl::OneWayStatus status =
      fidl::WireCall(caller.directory())
          ->Open(fuchsia_io::OpenFlags::kDirectory, {},
                 fidl::StringView::FromExternal(device->path()),
                 fidl::ServerEnd<fuchsia_io::Node>(server_end.TakeChannel()));
  EXPECT_OK(status);
  if (!status.ok()) {
    return status.status();
  }
  zx::result watcher = device_watcher::DirWatcher::Create(client_end);
  EXPECT_OK(watcher);
  if (watcher.is_error()) {
    return watcher.error_value();
  }

  zx::result channel = GetController(device);
  if (channel.is_error()) {
    return channel.status_value();
  }
  const fidl::WireResult result = fidl::WireCall(channel.value())->Rebind({});
  if (!result.ok()) {
    ADD_FAILURE("('%s').Rebind(): %s", device->path(), result.status_string());
    return result.status();
  }
  const fit::result response = result.value();
  if (response.is_error()) {
    ADD_FAILURE("('%s').Rebind(): %s", device->path(),
                zx_status_get_string(response.error_value()));
    return response.error_value();
  }
  if (zx_status_t status =
          watcher.value().WaitForRemoval(fbl::String() /* any file */, kDeviceWaitTime);
      status != ZX_OK) {
    ADD_FAILURE("Watcher('%s').WaitForRemoval: %s", device->path(), zx_status_get_string(status));
    return status;
  }
  return ZX_OK;
}

using FidlGuid = fuchsia_hardware_block_partition::wire::Guid;

}  // namespace

// namespace

DeviceRef::DeviceRef(const fbl::unique_fd& devfs_root, const std::string& path)
    : devfs_root_(devfs_root) {
  path_.append(path);
}

std::unique_ptr<DeviceRef> DeviceRef::Create(const fbl::unique_fd& devfs_root,
                                             const std::string& device_path) {
  return std::make_unique<DeviceRef>(devfs_root, device_path);
}

std::unique_ptr<RamdiskRef> RamdiskRef::Create(const fbl::unique_fd& devfs_root,
                                               uint64_t block_size, uint64_t block_count) {
  if (!devfs_root.is_valid()) {
    ADD_FAILURE("Bad devfs root handle.");
    return nullptr;
  }

  if (block_size == 0 || block_count == 0) {
    ADD_FAILURE("Attempting to create 0 sized ramdisk.");
    return nullptr;
  }

  if (zx::result channel =
          device_watcher::RecursiveWaitForFile(devfs_root.get(), kRamdiskCtlPath, kDeviceWaitTime);
      channel.is_error()) {
    ADD_FAILURE("Failed to wait for RamCtl. Reason: %s", channel.status_string());
    return nullptr;
  }

  RamdiskClient* client;
  if (zx_status_t status = ramdisk_create_at(devfs_root.get(), block_size, block_count, &client);
      status != ZX_OK) {
    ADD_FAILURE("Failed to create ramdisk. Reason: %s", zx_status_get_string(status));
    return nullptr;
  }
  const char* path = ramdisk_get_path(client);
  return std::make_unique<RamdiskRef>(devfs_root, path, client);
}

RamdiskRef::~RamdiskRef() { ramdisk_destroy(ramdisk_client_); }

zx_status_t RamdiskRef::Grow(uint64_t target_size) {
  return ramdisk_grow(ramdisk_client_, target_size);
}

void BlockDeviceAdapter::WriteAt(const fbl::Array<uint8_t>& data, uint64_t offset) {
  zx::result channel = GetChannel<fuchsia_hardware_block::Block>(device());
  ASSERT_OK(channel.status_value());
  ASSERT_OK(block_client::SingleWriteBytes(channel.value(), data.data(), data.size(), offset));
}

void BlockDeviceAdapter::ReadAt(uint64_t offset, fbl::Array<uint8_t>* out_data) {
  zx::result channel = GetChannel<fuchsia_hardware_block::Block>(device());
  ASSERT_OK(channel.status_value());
  ASSERT_OK(
      block_client::SingleReadBytes(channel.value(), out_data->data(), out_data->size(), offset));
}

void BlockDeviceAdapter::CheckContentsAt(const fbl::Array<uint8_t>& data, uint64_t offset) {
  ASSERT_GT(data.size(), 0, "data::size must be greater than 0.");
  fbl::Array<uint8_t> device_data(new uint8_t[data.size()], data.size());
  ASSERT_NO_FAILURES(ReadAt(offset, &device_data));
  ASSERT_BYTES_EQ(device_data.data(), data.data(), data.size());
}

zx_status_t BlockDeviceAdapter::WaitUntilVisible() const {
  zx::result channel =
      device_watcher::RecursiveWaitForFile(devfs_root_.get(), device()->path(), kDeviceWaitTime);
  if (channel.is_error()) {
    ADD_FAILURE("Block device did not become visible at %s: %s", device()->path(),
                channel.status_string());
  }
  return channel.status_value();
}

zx_status_t BlockDeviceAdapter::Rebind() {
  if (zx_status_t status = RebindBlockDevice(device()); status != ZX_OK) {
    return status;
  }

  // Block device is visible again.
  if (zx_status_t status = WaitUntilVisible(); status != ZX_OK) {
    return status;
  }

  return ZX_OK;
}

zx::result<fidl::ClientEnd<fuchsia_device::Controller>> VPartitionAdapter::GetController() {
  return fvm::GetController(device());
}

std::unique_ptr<VPartitionAdapter> VPartitionAdapter::Create(const fbl::unique_fd& devfs_root,
                                                             const std::string& name,
                                                             const Guid& guid, const Guid& type) {
  if (name.empty() || type.size() == 0 || guid.size() == 0) {
    ADD_FAILURE(
        "Partition name(size=%lu), type(size=%lu) and guid(size=%lu) must be non "
        "empty.\n"
        "Partition {\n"
        "    name: %s\n"
        "    type: %s\n"
        "    guid: %s\n"
        "}",
        name.size(), type.size(), guid.size(), name.c_str(), type.ToString().c_str(),
        guid.ToString().c_str());
    return nullptr;
  }

  fs_management::PartitionMatcher matcher{
      .type_guids = {uuid::Uuid(type.data())},
      .instance_guids = {uuid::Uuid(guid.data())},
  };
  fdio_cpp::UnownedFdioCaller devfs_root_caller(devfs_root.get());
  zx::result controller =
      fs_management::OpenPartitionWithDevfs(devfs_root_caller.directory(), matcher, true);
  if (controller.is_error()) {
    ADD_FAILURE("Unable to obtain handle for partition.");
    return nullptr;
  }
  fidl::WireResult topo_path = fidl::WireCall(controller.value())->GetTopologicalPath();
  if (!topo_path.ok()) {
    ADD_FAILURE("Failed to call topo path: %s", topo_path.status_string());
    return nullptr;
  }
  if (topo_path->is_error()) {
    ADD_FAILURE("Failed to get topo path: %d", topo_path->error_value());
    return nullptr;
  }
  std::string relative_path = std::string(topo_path.value()->path.get());
  constexpr std::string_view kDevPrefix = "/dev/";
  if (!cpp20::starts_with(std::string_view(relative_path), kDevPrefix)) {
    ADD_FAILURE("Bad topo path, doesn't start with /dev/: %s", relative_path.c_str());
    return nullptr;
  }
  relative_path.erase(0, kDevPrefix.size());

  return std::make_unique<VPartitionAdapter>(devfs_root, relative_path, name, guid, type);
}

VPartitionAdapter::~VPartitionAdapter() {
  ASSERT_OK(
      fs_management::DestroyPartitionWithDevfs(devfs_root_.get(),
                                               {
                                                   .type_guids = {uuid::Uuid(type_.data())},
                                                   .instance_guids = {uuid::Uuid(guid_.data())},
                                               },
                                               false));
}

zx_status_t VPartitionAdapter::Extend(uint64_t offset, uint64_t length) {
  zx::result channel = GetChannel<fuchsia_hardware_block_volume::Volume>(device());
  if (channel.is_error()) {
    return channel.error_value();
  }
  const fidl::WireResult result = fidl::WireCall(channel.value())->Extend(offset, length);
  if (!result.ok()) {
    return result.status();
  }
  const fidl::WireResponse response = result.value();
  return response.status;
}

std::unique_ptr<FvmAdapter> FvmAdapter::Create(const fbl::unique_fd& devfs_root,
                                               uint64_t block_size, uint64_t block_count,
                                               uint64_t slice_size, DeviceRef* device) {
  return CreateGrowable(devfs_root, block_size, block_count, block_count, slice_size, device);
}

std::unique_ptr<FvmAdapter> FvmAdapter::CreateGrowable(const fbl::unique_fd& devfs_root,
                                                       uint64_t block_size,
                                                       uint64_t initial_block_count,
                                                       uint64_t maximum_block_count,
                                                       uint64_t slice_size, DeviceRef* device) {
  if (device == nullptr) {
    ADD_FAILURE("Create requires non-null device pointer.");
    return nullptr;
  }

  {
    zx::result channel = GetChannel<fuchsia_hardware_block::Block>(device);
    if (channel.is_error()) {
      ADD_FAILURE("ConnectAt(%s): %s", device->path(), channel.status_string());
      return nullptr;
    }
    if (zx_status_t status =
            fs_management::FvmInitPreallocated(channel.value(), initial_block_count * block_size,
                                               maximum_block_count * block_size, slice_size);
        status != ZX_OK) {
      ADD_FAILURE("FvmInitPreallocated(%s): %s", device->path(), zx_status_get_string(status));
      return nullptr;
    }
  }

  {
    zx::result channel = GetController(device);
    if (channel.is_error()) {
      ADD_FAILURE("ConnectAt(%s): %s", device->path(), channel.status_string());
      return nullptr;
    }
    const fidl::WireResult result =
        fidl::WireCall(channel.value())->Bind(fidl::StringView(kFvmDriverLib));
    if (!result.ok()) {
      ADD_FAILURE("Binding FVM driver failed: %s", result.FormatDescription().c_str());
      return nullptr;
    }
    const fit::result response = result.value();
    if (response.is_error()) {
      ADD_FAILURE("Binding FVM driver failed: %s", zx_status_get_string(response.error_value()));
      return nullptr;
    }
  }

  fbl::StringBuffer<kPathMax> fvm_path;
  fvm_path.AppendPrintf("%s/fvm", device->path());

  if (zx::result channel =
          device_watcher::RecursiveWaitForFile(devfs_root.get(), fvm_path.c_str(), kDeviceWaitTime);
      channel.is_error()) {
    ADD_FAILURE("Loading FVM driver: %s", channel.status_string());
    return nullptr;
  }
  return std::make_unique<FvmAdapter>(devfs_root, fvm_path.c_str(), device);
}

FvmAdapter::~FvmAdapter() {
  fs_management::FvmDestroyWithDevfs(devfs_root_.get(), block_device_->path());
}

zx_status_t FvmAdapter::AddPartition(const fbl::unique_fd& devfs_root, const std::string& name,
                                     const Guid& guid, const Guid& type, uint64_t slice_count,
                                     std::unique_ptr<VPartitionAdapter>* out_vpartition) {
  FidlGuid fidl_guid, fidl_type;
  memcpy(fidl_guid.value.data(), guid.data(), guid.size());
  memcpy(fidl_type.value.data(), type.data(), type.size());

  zx::result channel = GetChannel<fuchsia_hardware_block_volume::VolumeManager>(this);
  if (channel.is_error()) {
    return channel.status_value();
  }
  const fidl::WireResult result = fidl::WireCall(channel.value())
                                      ->AllocatePartition(slice_count, fidl_type, fidl_guid,
                                                          fidl::StringView::FromExternal(name), 0u);
  if (!result.ok()) {
    return result.status();
  }
  const fidl::WireResponse response = result.value();
  if (zx_status_t status = response.status; status != ZX_OK) {
    return status;
  }

  auto vpartition = VPartitionAdapter::Create(devfs_root, name, guid, type);
  if (vpartition == nullptr) {
    return ZX_ERR_INVALID_ARGS;
  }
  if (zx_status_t status = vpartition->WaitUntilVisible(); status != ZX_OK) {
    return status;
  }

  if (out_vpartition != nullptr) {
    *out_vpartition = std::move(vpartition);
  }

  return ZX_OK;
}

zx_status_t FvmAdapter::Rebind(fbl::Vector<VPartitionAdapter*> vpartitions) {
  if (zx_status_t status = RebindBlockDevice(block_device_); status != ZX_OK) {
    ADD_FAILURE("FvmAdapter block device rebind failed.");
    return status;
  }

  // Bind the FVM to the block device.
  zx::result channel = GetController(block_device_);
  if (channel.is_error()) {
    return channel.status_value();
  }
  const fidl::WireResult result =
      fidl::WireCall(channel.value())->Bind(fidl::StringView(kFvmDriverLib));
  if (!result.ok()) {
    ADD_FAILURE("Rebinding FVM driver failed: %s", result.FormatDescription().c_str());
    return result.status();
  }
  const fit::result response = result.value();
  if (response.is_error()) {
    ADD_FAILURE("Rebinding FVM driver failed: %s", zx_status_get_string(response.error_value()));
    return response.error_value();
  }

  // Wait for FVM driver to become visible.
  if (zx::result channel =
          device_watcher::RecursiveWaitForFile(devfs_root_.get(), path(), kDeviceWaitTime);
      channel.is_error()) {
    ADD_FAILURE("Loading FVM driver: %s", channel.status_string());
    return channel.status_value();
  }

  for (auto* vpartition : vpartitions) {
    if (zx_status_t status = vpartition->WaitUntilVisible(); status != ZX_OK) {
      return status;
    }
  }
  return ZX_OK;
}

zx_status_t FvmAdapter::Query(VolumeManagerInfo* out_info) const {
  fdio_cpp::UnownedFdioCaller caller(devfs_root_.get());
  zx::result<fidl::ClientEnd<fuchsia_hardware_block_volume::VolumeManager>> volume_manager =
      component::ConnectAt<fuchsia_hardware_block_volume::VolumeManager>(caller.directory(),
                                                                         path());
  if (volume_manager.is_error()) {
    ADD_FAILURE("Could not open FVM Volume Manager: %s\n",
                zx_status_get_string(volume_manager.error_value()));
    return volume_manager.error_value();
  }
  zx::result info = fs_management::FvmQuery(volume_manager.value());
  if (info.is_error()) {
    return info.error_value();
  }
  *out_info = info.value();
  return ZX_OK;
}

fbl::Array<uint8_t> MakeRandomBuffer(size_t size, unsigned int* seed) {
  fbl::Array data(new uint8_t[size], size);

  for (size_t byte = 0; byte < size; ++byte) {
    data[byte] = static_cast<uint8_t>(rand_r(seed));
  }

  return data;
}

bool IsConsistentAfterGrowth(const VolumeManagerInfo& before, const VolumeManagerInfo& after) {
  // Frowing a FVM should not allocate any slices nor should it change the slice size.
  return before.slice_size == after.slice_size &&
         before.assigned_slice_count == after.assigned_slice_count;
}

}  // namespace fvm
