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

#include <lib/fidl-async/cpp/bind.h>

#include "src/storage/blobfs/blobfs.h"
#include "src/storage/blobfs/format.h"
#include "src/storage/blobfs/runner.h"

namespace fuchsia_fs = ::llcpp::fuchsia::fs;

namespace blobfs {

constexpr const char kFsName[] = "blobfs";

QueryService::QueryService(async_dispatcher_t* dispatcher, Blobfs* blobfs, Runner* runner)
    : fs::Service([dispatcher, this](zx::channel server_end) {
        return fidl::BindSingleInFlightOnly(dispatcher, std::move(server_end), this);
      }),
      blobfs_(blobfs),
      runner_(runner) {}

void QueryService::GetInfo(fuchsia_fs::FilesystemInfoQuery query,
                           GetInfoCompleter::Sync& completer) {
  static_assert(fbl::constexpr_strlen(kFsName) < fuchsia_fs::MAX_FS_NAME_LENGTH,
                "Blobfs name too long");

  fuchsia_fs::FilesystemInfo::UnownedBuilder builder;

  uint64_t total_bytes;
  if (query & fuchsia_fs::FilesystemInfoQuery::TOTAL_BYTES) {
    total_bytes = blobfs_->Info().data_block_count * blobfs_->Info().block_size;
    builder.set_total_bytes(fidl::unowned_ptr(&total_bytes));
  }

  uint64_t used_bytes;
  if (query & fuchsia_fs::FilesystemInfoQuery::USED_BYTES) {
    used_bytes = blobfs_->Info().alloc_block_count * blobfs_->Info().block_size;
    builder.set_used_bytes(fidl::unowned_ptr(&used_bytes));
  }

  uint64_t total_nodes;
  if (query & fuchsia_fs::FilesystemInfoQuery::TOTAL_NODES) {
    total_nodes = blobfs_->Info().inode_count;
    builder.set_total_nodes(fidl::unowned_ptr(&total_nodes));
  }

  uint64_t used_nodes;
  if (query & fuchsia_fs::FilesystemInfoQuery::USED_NODES) {
    used_nodes = blobfs_->Info().alloc_inode_count;
    builder.set_used_nodes(fidl::unowned_ptr(&used_nodes));
  }

  zx::event fs_id;
  if (query & fuchsia_fs::FilesystemInfoQuery::FS_ID) {
    zx_status_t status = blobfs_->GetFsId(&fs_id);
    if (status != ZX_OK) {
      completer.ReplyError(status);
      return;
    }
    builder.set_fs_id(fidl::unowned_ptr(&fs_id));
  }

  uint32_t block_size;
  if (query & fuchsia_fs::FilesystemInfoQuery::BLOCK_SIZE) {
    block_size = kBlobfsBlockSize;
    builder.set_block_size(fidl::unowned_ptr(&block_size));
  }

  uint32_t max_node_name_size;
  if (query & fuchsia_fs::FilesystemInfoQuery::MAX_NODE_NAME_SIZE) {
    max_node_name_size = digest::kSha256HexLength;
    builder.set_max_node_name_size(fidl::unowned_ptr(&max_node_name_size));
  }

  fuchsia_fs::FsType fs_type;
  if (query & fuchsia_fs::FilesystemInfoQuery::FS_TYPE) {
    fs_type = fuchsia_fs::FsType::BLOBFS;
    builder.set_fs_type(fidl::unowned_ptr(&fs_type));
  }

  fidl::StringView name;
  if (query & fuchsia_fs::FilesystemInfoQuery::NAME) {
    name = fidl::StringView(kFsName);
    builder.set_name(fidl::unowned_ptr(&name));
  }

  fidl::StringView device_path;
  char name_buf[llcpp::fuchsia::io2::MAX_PATH_LENGTH];
  size_t name_len;
  if (query & fuchsia_fs::FilesystemInfoQuery::DEVICE_PATH) {
    zx_status_t status =
        blobfs_->Device()->GetDevicePath(llcpp::fuchsia::io2::MAX_PATH_LENGTH, name_buf, &name_len);
    if (status != ZX_OK) {
      completer.ReplyError(status);
      return;
    }
    // It appears that the |name_len| returned by |GetDevicePath| includes a trailing NUL.
    ZX_ASSERT(name_buf[name_len - 1] == '\0');
    device_path = fidl::StringView(name_buf, name_len - 1);
    builder.set_device_path(fidl::unowned_ptr(&device_path));
  }

  completer.ReplySuccess(builder.build());
}

void QueryService::IsNodeInFilesystem(zx::event token,
                                      IsNodeInFilesystemCompleter::Sync& completer) {
  completer.Reply(runner_->IsTokenAssociatedWithVnode(std::move(token)));
}

}  // namespace blobfs
