// Copyright 2021 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/fs_test/json_filesystem.h"

#include "src/storage/fs_test/crypt_service.h"

namespace fs_test {

zx::status<std::unique_ptr<JsonFilesystem>> JsonFilesystem::NewFilesystem(
    const rapidjson::Document& config) {
  auto name = config["name"].GetString();

  auto iter = config.FindMember("binary_path");
  fs_management::DiskFormat format;
  if (iter == config.MemberEnd()) {
    format = static_cast<fs_management::DiskFormat>(config["disk_format"].GetInt64());
  } else {
    format = fs_management::CustomDiskFormat::Register(
        std::make_unique<fs_management::CustomDiskFormat>(name, config["binary_path"].GetString()));
  }
  iter = config.FindMember("sectors_per_cluster");
  const int sectors_per_cluster = iter == config.MemberEnd() ? 0 : iter->value.GetInt();
  return zx::ok(std::make_unique<JsonFilesystem>(
      Traits{
          .name = config["name"].GetString(),
          .timestamp_granularity = zx::nsec(config["timestamp_granularity"].GetInt64()),
          .supports_hard_links = ConfigGetOrDefault<bool>(config, "supports_hard_links", false),
          .supports_mmap = ConfigGetOrDefault<bool>(config, "supports_mmap", false),
          .supports_mmap_shared_write =
              ConfigGetOrDefault<bool>(config, "supports_mmap_shared_write", false),
          .supports_resize = ConfigGetOrDefault<bool>(config, "supports_resize", false),
          .max_file_size = ConfigGetOrDefault<int64_t>(config, "max_file_size",
                                                       std::numeric_limits<int64_t>::max()),
          .max_block_size = ConfigGetOrDefault<int64_t>(config, "max_block_size",
                                                        std::numeric_limits<int64_t>::max()),
          .in_memory = ConfigGetOrDefault<bool>(config, "in_memory", false),
          .is_case_sensitive = ConfigGetOrDefault<bool>(config, "is_case_sensitive", true),
          .supports_sparse_files = ConfigGetOrDefault<bool>(config, "supports_sparse_files", true),
          .is_slow = ConfigGetOrDefault<bool>(config, "is_slow", false),
          .supports_fsck_after_every_transaction =
              ConfigGetOrDefault<bool>(config, "supports_fsck_after_every_transaction", false),
          .has_directory_size_limit =
              ConfigGetOrDefault<bool>(config, "has_directory_size_limit", false),
          .is_journaled = ConfigGetOrDefault<bool>(config, "is_journaled", true),
          .supports_watch_event_deleted =
              ConfigGetOrDefault<bool>(config, "supports_watch_event_deleted", true),
          .supports_inspect = ConfigGetOrDefault<bool>(config, "supports_inspect", false),
          .supports_shutdown_on_no_connections =
              ConfigGetOrDefault<bool>(config, "supports_shutdown_on_no_connections", false),
          .uses_crypt = ConfigGetOrDefault<bool>(config, "uses_crypt", false),
      },
      format, sectors_per_cluster, ConfigGetOrDefault<bool>(config, "is_component", false)));
}

class JsonInstance : public FilesystemInstance {
 public:
  JsonInstance(const JsonFilesystem* filesystem, RamDevice device, std::string device_path)
      : filesystem_(*filesystem),
        device_(std::move(device)),
        device_path_(std::move(device_path)) {}

  virtual zx::status<> Format(const TestFilesystemOptions& options) override {
    fs_management::MkfsOptions mkfs_options;
    mkfs_options.sectors_per_cluster = filesystem_.sectors_per_cluster();
    if (filesystem_.GetTraits().uses_crypt) {
      mkfs_options.crypt_client = [] {
        if (auto service_or = GetCryptService(); service_or.is_error()) {
          return zx::channel();
        } else {
          return *std::move(service_or);
        }
      };
    }
    if (filesystem_.is_component()) {
      const std::string& name = filesystem_.GetTraits().name;
      mkfs_options.component_child_name = name.c_str();
      mkfs_options.component_url = "#meta/" + name;
    }
    return FsFormat(device_path_, filesystem_.format(), mkfs_options);
  }

  zx::status<> Mount(const std::string& mount_path,
                     const fs_management::MountOptions& options) override {
    fs_management::MountOptions mount_options = options;
    if (filesystem_.is_component()) {
      const std::string& name = filesystem_.GetTraits().name;
      mount_options.component_child_name = name.c_str();
      mount_options.component_url = "#meta/" + name;
    }
    auto export_root_or = FsMount(device_path_, mount_path, filesystem_.format(), mount_options);
    if (export_root_or.is_error())
      return export_root_or.take_error();
    outgoing_directory_ = std::move(*export_root_or);
    return zx::ok();
  }

  zx::status<> Fsck() override {
    fs_management::FsckOptions options{
        .verbose = false,
        .never_modify = true,
        .always_modify = false,
        .force = true,
    };
    if (filesystem_.is_component()) {
      const std::string& name = filesystem_.GetTraits().name;
      options.component_child_name = name.c_str();
      options.component_url = "#meta/" + name;
    }
    if (filesystem_.GetTraits().uses_crypt) {
      options.crypt_client = [] {
        if (auto service_or = GetCryptService(); service_or.is_error()) {
          return zx::channel();
        } else {
          return *std::move(service_or);
        }
      };
    }
    return zx::make_status(fs_management::Fsck(device_path_.c_str(), filesystem_.format(), options,
                                               fs_management::LaunchStdioSync));
  }

  zx::status<std::string> DevicePath() const override { return zx::ok(std::string(device_path_)); }

  storage::RamDisk* GetRamDisk() override { return std::get_if<storage::RamDisk>(&device_); }

  ramdevice_client::RamNand* GetRamNand() override {
    return std::get_if<ramdevice_client::RamNand>(&device_);
  }

  fidl::UnownedClientEnd<fuchsia_io::Directory> GetOutgoingDirectory() const override {
    return outgoing_directory_.borrow();
  }

  void ResetOutgoingDirectory() override { outgoing_directory_.reset(); }

 private:
  const JsonFilesystem& filesystem_;
  RamDevice device_;
  std::string device_path_;
  fidl::ClientEnd<fuchsia_io::Directory> outgoing_directory_;
};

std::unique_ptr<FilesystemInstance> JsonFilesystem::Create(RamDevice device,
                                                           std::string device_path) const {
  return std::make_unique<JsonInstance>(this, std::move(device), std::move(device_path));
}

zx::status<std::unique_ptr<FilesystemInstance>> JsonFilesystem::Open(
    const TestFilesystemOptions& options) const {
  auto result = OpenRamDevice(options);
  if (result.is_error()) {
    return result.take_error();
  }
  auto [ram_device, device_path] = std::move(result).value();
  return zx::ok(
      std::make_unique<JsonInstance>(this, std::move(ram_device), std::move(device_path)));
}

}  // namespace fs_test
