// 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 <fcntl.h>
#include <lib/fit/defer.h>
#include <lib/fpromise/result.h>
#include <sys/stat.h>
#include <unistd.h>

#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <iostream>
#include <memory>
#include <string>

#include <fbl/unique_fd.h>

#include "src/storage/volume_image/adapter/commands.h"
#include "src/storage/volume_image/fvm/fvm_image_extend.h"
#include "src/storage/volume_image/fvm/options.h"
#include "src/storage/volume_image/utils/fd_reader.h"
#include "src/storage/volume_image/utils/fd_writer.h"

namespace storage::volume_image {
namespace {

// A helper wrapping fstat.
fpromise::result<struct stat, std::string> GetBlockInfo(std::string_view path) {
  std::string str_path(path);
  fbl::unique_fd device(open(str_path.c_str(), O_RDONLY));

  if (!device.is_valid()) {
    auto err = std::string(strerror(errno));
    return fpromise::error("Failed to obtain FD for device at " + str_path +
                           ". More specifically: " + err + ".");
  }

  struct stat st = {};
  if (fstat(device.get(), &st) != 0) {
    auto err = std::string(strerror(errno));
    return fpromise::error("Failed to perform fstat on device. More specifically: " + err + ".");
  }

  return fpromise::ok(st);
}

}  // namespace

fpromise::result<void, std::string> Extend(const ExtendParams& params) {
  if (params.image_path.empty()) {
    return fpromise::error("Must provide a non empty |image_path| for extend.");
  }

  auto block_info_or = GetBlockInfo(params.image_path);
  if (block_info_or.is_error()) {
    return block_info_or.take_error_result();
  }

  if (params.length.value() < static_cast<uint64_t>(block_info_or.value().st_size)) {
    if (params.should_use_max_partition_size) {
      // Truncating an image is a NOP when this flag is set.
      return fpromise::ok();
    }
    return fpromise::error("|length|(" + std::to_string(params.length.value()) +
                           ") must be greater or equal than |disk_size|(" +
                           std::to_string(block_info_or.value().st_size) + " bytes)");
  }

  auto reader_or = FdReader::Create(params.image_path);
  if (reader_or.is_error()) {
    return reader_or.take_error_result();
  }
  auto image_reader = reader_or.take_value();

  auto image_size_or = FvmImageGetSize(image_reader);
  if (image_size_or.is_error()) {
    return image_size_or.take_error_result();
  }
  uint64_t image_size = image_size_or.value();

  uint64_t target_volume_size = params.length.value();
  if (params.should_use_max_partition_size && target_volume_size < image_size) {
    target_volume_size = image_size;
  }
  FvmOptions options;
  options.target_volume_size = target_volume_size;

  // We create a temporary file to protect source image from IO errors.
  std::string base =
      std::filesystem::path(params.image_path).parent_path().string() + "/tmp_XXXXXXX";

  fbl::unique_fd tmp_file(mkstemp(base.data()));
  if (!tmp_file.is_valid()) {
    return fpromise::error("Failed to create temporary file at " + base +
                           ". More specifically: " + strerror(errno));
  }
  auto cleanup = fit::defer([&]() { unlink(base.c_str()); });

  {
    // So writer is flushed.
    FdWriter writer(std::move(tmp_file));

    auto extend_or = FvmImageExtend(image_reader, options, writer);
    if (extend_or.is_error()) {
      return extend_or.take_error_result();
    }
  }

  uint64_t truncate_size = target_volume_size;
  if (params.should_trim) {
    auto trim_size_or = FvmImageGetTrimmedSize(image_reader);
    if (trim_size_or.is_error()) {
      return trim_size_or.take_error_result();
    }
    truncate_size = trim_size_or.value();
  }

  // Now truncate the image to target size. The target size is either the partition size,
  // the image is ready to me used or its trim size, that is the image has no trailing unallocated
  // slices.
  if (truncate(base.data(), static_cast<off_t>(truncate_size)) != 0) {
    std::string err(strerror(errno));
    return fpromise::error("Failed to trim image to " + std::to_string(truncate_size) +
                           ". More specifically " + err + ".");
  }

  if (rename(base.data(), params.image_path.c_str()) != 0) {
    std::string err(strerror(errno));
    return fpromise::error("Failed to move temporary image(working copy at " + base +
                           ") to final location(source image at " + params.image_path +
                           ". More specifically: " + err + ".");
  }

  return fpromise::ok();
}

}  // namespace storage::volume_image
