// 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 <fuchsia/io/c/fidl.h>
#include <lib/vfs/cpp/connection.h>
#include <lib/vfs/cpp/flags.h>
#include <lib/vfs/cpp/internal/node_connection.h>
#include <lib/vfs/cpp/node.h>
#include <zircon/assert.h>

#include <algorithm>
#include <mutex>

namespace vfs {
namespace {

constexpr uint32_t kCommonAllowedFlags =
    fuchsia::io::OPEN_FLAG_DESCRIBE | fuchsia::io::OPEN_FLAG_NODE_REFERENCE |
    fuchsia::io::OPEN_FLAG_POSIX | fuchsia::io::CLONE_FLAG_SAME_RIGHTS;

}  // namespace

bool IsValidName(const std::string& name) {
  return name.length() <= NAME_MAX &&
         memchr(name.data(), '/', name.length()) == nullptr && name != "." &&
         name != "..";
}

Node::Node() = default;

Node::~Node() = default;

std::unique_ptr<Connection> Node::Close(Connection* connection) {
  std::lock_guard<std::mutex> guard(mutex_);

  auto connection_iterator = std::find_if(
      connections_.begin(), connections_.end(),
      [connection](const auto& entry) { return entry.get() == connection; });
  auto ret = std::move(*connection_iterator);
  connections_.erase(connection_iterator);
  return ret;
}

zx_status_t Node::Sync() { return ZX_ERR_NOT_SUPPORTED; }

bool Node::IsRemote() const { return false; }

zx_status_t Node::GetAttr(fuchsia::io::NodeAttributes* out_attributes) const {
  return ZX_ERR_NOT_SUPPORTED;
}

void Node::Clone(uint32_t flags, uint32_t parent_flags, zx::channel request,
                 async_dispatcher_t* dispatcher) {
  if (!Flags::InputPrecondition(flags)) {
    SendOnOpenEventOnError(flags, std::move(request), ZX_ERR_INVALID_ARGS);
    return;
  }
  // If SAME_RIGHTS is specified, the client cannot request any specific rights.
  // TODO(yifeit): Start enforcing this after soft transition
  // if (Flags::ShouldCloneWithSameRights(flags) && (flags & Flags::kFsRights))
  // {
  //   SendOnOpenEventOnError(flags, std::move(request), ZX_ERR_INVALID_ARGS);
  //   return;
  // }
  flags |= (parent_flags & Flags::kStatusFlags);
  // If SAME_RIGHTS is requested, cloned connection will inherit the same rights
  // as those from the originating connection.
  if (Flags::ShouldCloneWithSameRights(flags)) {
    flags &= (~Flags::kFsRights);
    flags |= (parent_flags & Flags::kFsRights);
    flags &= ~fuchsia::io::CLONE_FLAG_SAME_RIGHTS;
  }
  // TODO(yifeit): Start enforcing hierarchical rights during clone
  // after soft transition
  // if (!Flags::StricterOrSameRights(flags, parent_flags)) {
  //   SendOnOpenEventOnError(flags, std::move(request), ZX_ERR_ACCESS_DENIED);
  //   return;
  // }
  Serve(flags, std::move(request), dispatcher);
}

zx_status_t Node::ValidateFlags(uint32_t flags) const {
  if (!Flags::InputPrecondition(flags)) {
    return ZX_ERR_INVALID_ARGS;
  }
  bool is_directory = IsDirectory();
  if (!is_directory && Flags::IsDirectory(flags)) {
    return ZX_ERR_NOT_DIR;
  }
  if (is_directory && Flags::IsNotDirectory(flags)) {
    return ZX_ERR_NOT_FILE;
  }

  uint32_t allowed_flags = kCommonAllowedFlags | GetAdditionalAllowedFlags();
  if (is_directory) {
    allowed_flags = allowed_flags | fuchsia::io::OPEN_FLAG_DIRECTORY;
  }

  uint32_t prohibitive_flags = GetProhibitiveFlags();

  if ((flags & prohibitive_flags) != 0) {
    return ZX_ERR_INVALID_ARGS;
  }
  if ((flags & ~allowed_flags) != 0) {
    return ZX_ERR_NOT_SUPPORTED;
  }
  return ZX_OK;
}

zx_status_t Node::ValidateMode(uint32_t mode) const {
  fuchsia::io::NodeAttributes attr;
  uint32_t mode_from_attr = 0;
  zx_status_t status = GetAttr(&attr);
  if (status == ZX_OK) {
    mode_from_attr = attr.mode & fuchsia::io::MODE_TYPE_MASK;
  }

  if (((mode & ~fuchsia::io::MODE_PROTECTION_MASK) & ~mode_from_attr) != 0) {
    return ZX_ERR_INVALID_ARGS;
  }
  return ZX_OK;
}

zx_status_t Node::Lookup(const std::string& name, Node** out_node) const {
  ZX_ASSERT(!IsDirectory());
  return ZX_ERR_NOT_DIR;
}

uint32_t Node::GetAdditionalAllowedFlags() const { return 0; }

uint32_t Node::GetProhibitiveFlags() const { return 0; }

zx_status_t Node::SetAttr(uint32_t flags,
                          const fuchsia::io::NodeAttributes& attributes) {
  return ZX_ERR_NOT_SUPPORTED;
}

uint32_t Node::FilterRefFlags(uint32_t flags) {
  if (Flags::IsNodeReference(flags)) {
    return flags & (kCommonAllowedFlags | fuchsia::io::OPEN_FLAG_DIRECTORY);
  }
  return flags;
}

zx_status_t Node::Serve(uint32_t flags, zx::channel request,
                        async_dispatcher_t* dispatcher) {
  flags = FilterRefFlags(flags);
  zx_status_t status = ValidateFlags(flags);
  if (status != ZX_OK) {
    SendOnOpenEventOnError(flags, std::move(request), status);
    return status;
  }
  return Connect(flags, std::move(request), dispatcher);
}

zx_status_t Node::Connect(uint32_t flags, zx::channel request,
                          async_dispatcher_t* dispatcher) {
  zx_status_t status;
  std::unique_ptr<Connection> connection;
  if (Flags::IsNodeReference(flags)) {
    status = Node::CreateConnection(flags, &connection);
  } else {
    status = CreateConnection(flags, &connection);
  }
  if (status != ZX_OK) {
    SendOnOpenEventOnError(flags, std::move(request), status);
    return status;
  }
  status = connection->Bind(std::move(request), dispatcher);
  if (status == ZX_OK) {
    AddConnection(std::move(connection));
  }
  return status;
}

zx_status_t Node::ServeWithMode(uint32_t flags, uint32_t mode,
                                zx::channel request,
                                async_dispatcher_t* dispatcher) {
  zx_status_t status = ValidateMode(mode);
  if (status != ZX_OK) {
    SendOnOpenEventOnError(flags, std::move(request), status);
    return status;
  }
  return Serve(flags, std::move(request), dispatcher);
}

void Node::SendOnOpenEventOnError(uint32_t flags, zx::channel request,
                                  zx_status_t status) {
  ZX_DEBUG_ASSERT(status != ZX_OK);

  if (!Flags::ShouldDescribe(flags)) {
    return;
  }

  fuchsia_io_NodeOnOpenEvent msg;
  memset(&msg, 0, sizeof(msg));
  msg.hdr.ordinal = fuchsia_io_NodeOnOpenOrdinal;
  msg.s = status;
  request.write(0, &msg, sizeof(msg), nullptr, 0);
}

uint64_t Node::GetConnectionCount() const {
  std::lock_guard<std::mutex> guard(mutex_);
  return connections_.size();
}

void Node::AddConnection(std::unique_ptr<Connection> connection) {
  std::lock_guard<std::mutex> guard(mutex_);
  connections_.push_back(std::move(connection));
}

zx_status_t Node::CreateConnection(uint32_t flags,
                                   std::unique_ptr<Connection>* connection) {
  *connection = std::make_unique<internal::NodeConnection>(flags, this);
  return ZX_OK;
}

}  // namespace vfs
