// 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 <lib/zbitl/vmo.h>

#include <cstddef>
#include <memory>

#include <fbl/alloc_checker.h>

namespace zbitl {

fitx::result<zx_status_t, uint32_t> StorageTraits<zx::vmo>::Capacity(const zx::vmo& vmo) {
  uint64_t size;
  zx_status_t status = vmo.get_size(&size);
  if (status == ZX_OK) {
    uint64_t content_size;
    status = vmo.get_property(ZX_PROP_VMO_CONTENT_SIZE, &content_size, sizeof(content_size));
    if (status == ZX_OK && content_size != 0) {
      size = content_size;
    }
  }
  if (status != ZX_OK) {
    return fitx::error{status};
  }
  return fitx::ok(static_cast<uint32_t>(
      std::min(static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()), size)));
}

fitx::result<zx_status_t> StorageTraits<zx::vmo>::EnsureCapacity(const zx::vmo& vmo,
                                                                 uint32_t capacity_bytes) {
  auto current = Capacity(vmo);
  if (current.is_error()) {
    return current.take_error();
  } else if (current.value() >= capacity_bytes) {
    return fitx::ok();  // Current capacity is sufficient.
  }

  uint64_t cap = static_cast<uint64_t>(capacity_bytes);
  if (auto status = vmo.set_size(cap); status != ZX_OK) {
    return fitx::error{status};
  }
  if (auto status = vmo.set_property(ZX_PROP_VMO_CONTENT_SIZE, &cap, sizeof(cap));
      status != ZX_OK) {
    return fitx::error{status};
  }
  return fitx::ok();
}

fitx::result<zx_status_t, zbi_header_t> StorageTraits<zx::vmo>::Header(const zx::vmo& vmo,
                                                                       uint32_t offset) {
  zbi_header_t header;
  zx_status_t status = vmo.read(&header, offset, sizeof(header));
  if (status != ZX_OK) {
    return fitx::error{status};
  }
  return fitx::ok(header);
}

fitx::result<zx_status_t> StorageTraits<zx::vmo>::Read(const zx::vmo& vmo, payload_type payload,
                                                       void* buffer, uint32_t length) {
  zx_status_t status = vmo.read(buffer, payload, length);
  if (status != ZX_OK) {
    return fitx::error{status};
  }
  return fitx::ok();
}

fitx::result<zx_status_t> StorageTraits<zx::vmo>::Write(const zx::vmo& vmo, uint32_t offset,
                                                        ByteView data) {
  zx_status_t status = vmo.write(data.data(), offset, data.size());
  if (status != ZX_OK) {
    return fitx::error{status};
  }
  return fitx::ok();
}

fitx::result<zx_status_t, zx::vmo> StorageTraits<zx::vmo>::Create(const zx::vmo&, uint32_t size,
                                                                  uint32_t initial_zero_size) {
  // While `initial_zero_size` is a required parameter for the creation trait,
  // it is unnecessary in the case of VMOs, as newly-created instances are
  // always zero-filled.
  zx::vmo vmo;
  if (zx_status_t status = zx::vmo::create(size, ZX_VMO_RESIZABLE, &vmo); status != ZX_OK) {
    return fitx::error{status};
  }
  // Setting ZX_PROP_VMO_CONTENT_SIZE expectes a 64-bit user-pointer.
  auto size64 = static_cast<uint64_t>(size);
  if (zx_status_t status = vmo.set_property(ZX_PROP_VMO_CONTENT_SIZE, &size64, sizeof(size64));
      status != ZX_OK) {
    return fitx::error{status};
  }
  return fitx::ok(std::move(vmo));
}

fitx::result<zx_status_t, std::optional<std::pair<zx::vmo, uint32_t>>>
StorageTraits<zx::vmo>::DoClone(const zx::vmo& original, uint32_t offset, uint32_t length) {
  const uint32_t slop = offset % uint32_t{ZX_PAGE_SIZE};
  const uint32_t clone_start = offset & -uint32_t{ZX_PAGE_SIZE};
  const uint32_t clone_size = slop + length;

  zx::vmo clone;
  zx_status_t status = original.create_child(ZX_VMO_CHILD_SNAPSHOT | ZX_VMO_CHILD_RESIZABLE,
                                             clone_start, clone_size, &clone);
  if (status == ZX_OK && slop > 0) {
    // Explicitly zero the partial page before the range so it remains unseen.
    status = clone.op_range(ZX_VMO_OP_ZERO, 0, slop, nullptr, 0);
  }
  if (status == ZX_OK && clone_size % ZX_PAGE_SIZE != 0) {
    // Explicitly zero the partial page after the range so it remains unseen.
    status = clone.op_range(ZX_VMO_OP_ZERO, clone_size, ZX_PAGE_SIZE - (clone_size % ZX_PAGE_SIZE),
                            nullptr, 0);
  }
  if (status == ZX_OK) {
    const uint64_t content_size = slop + length;
    status = clone.set_property(ZX_PROP_VMO_CONTENT_SIZE, &content_size, sizeof(content_size));
  }

  if (status != ZX_OK) {
    return fitx::error{status};
  }

  return fitx::ok(std::make_pair(std::move(clone), slop));
}

}  // namespace zbitl
