// 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 <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fdio/directory.h>

#include <fbl/auto_lock.h>
#include <fbl/no_destructor.h>

#include "sdk/lib/fdio/directory_internal.h"
#include "sdk/lib/fdio/fdio_unistd.h"
#include "sdk/lib/fdio/internal.h"
#include "sdk/lib/fdio/unistd.h"

namespace fio = fuchsia_io;

__EXPORT
zx_status_t fdio_service_connect(const char* path, zx_handle_t h) {
  zx::handle handle{h};
  fdio_ns_t* ns;
  if (zx_status_t status = fdio_ns_get_installed(&ns); status != ZX_OK) {
    return status;
  }
  return fdio_ns_service_connect(ns, path, handle.release());
}

__EXPORT
zx_status_t fdio_service_connect_at(zx_handle_t dir, const char* path, zx_handle_t h) {
  return fdio_open_at(dir, path, 0, h);
}

__EXPORT
zx_status_t fdio_service_connect_by_name(const char* name, zx_handle_t request) {
  // We can't destroy |service_root| at static destruction time as some multithreaded programs call
  // exit() from one thread while other threads are calling in to fdio functions. Destroying
  // |service_root| in this scenario would result in crashes on those threads. See
  // https://fxbug.dev/42069066 for details.
  static fbl::NoDestructor<zx::result<zx::channel>> service_root = []() -> zx::result<zx::channel> {
    zx::channel client, request;
    zx_status_t status = zx::channel::create(0, &client, &request);
    if (status != ZX_OK) {
      return zx::error(status);
    }
    status = fdio_service_connect("/svc", request.release());
    if (status != ZX_OK) {
      return zx::error(status);
    }
    return zx::ok(std::move(client));
  }();

  if (service_root->is_error()) {
    return service_root->status_value();
  }

  return fdio_service_connect_at((*service_root)->get(), name, request);
}

__EXPORT
zx_status_t fdio_open(const char* path, uint32_t flags, zx_handle_t request) {
  zx::handle handle{request};
  fdio_ns_t* ns;
  if (zx_status_t status = fdio_ns_get_installed(&ns); status != ZX_OK) {
    return status;
  }
  return fdio_ns_open(ns, path, flags, handle.release());
}

namespace fdio_internal {

// TODO(https://fxbug.dev/42180154): This should reuse the logic used by openat().
zx_status_t fdio_open_at(fidl::UnownedClientEnd<fio::Directory> directory, std::string_view path,
                         fuchsia_io::wire::OpenFlags flags, fidl::ServerEnd<fio::Node> request) {
  if (!directory.is_valid()) {
    return ZX_ERR_UNAVAILABLE;
  }

  return fidl::WireCall(directory)
      ->Open(flags, {}, fidl::StringView::FromExternal(path), std::move(request))
      .status();
}

}  // namespace fdio_internal

__EXPORT
zx_status_t fdio_open_at(zx_handle_t dir, const char* path, uint32_t flags,
                         zx_handle_t raw_request) {
  size_t length;
  zx_status_t status = fdio_validate_path(path, &length);
  if (status != ZX_OK) {
    return status;
  }

  fidl::UnownedClientEnd<fio::Directory> directory(dir);
  fidl::ServerEnd<fio::Node> request((zx::channel(raw_request)));
  auto fio_flags = static_cast<fio::wire::OpenFlags>(flags);

  return fdio_internal::fdio_open_at(directory, std::string_view(path, length), fio_flags,
                                     std::move(request));
}

namespace {

zx_status_t fdio_open_fd_at_internal(int dirfd, const char* dirty_path, fio::wire::OpenFlags flags,
                                     bool allow_absolute_path, int* out_fd) {
  // We're opening a file descriptor rather than just a channel (like fdio_open), so we always
  // want to Describe (or listen for an OnOpen event on) the opened connection. This ensures that
  // the fd is valid before returning from here, and mimics how open() and openat() behave
  // (fdio_flags_to_zxio always add _FLAG_DESCRIBE).
  flags |= fio::wire::OpenFlags::kDescribe;

  zx::result io = fdio_internal::open_at_impl(dirfd, dirty_path, flags,
                                              {
                                                  .disallow_directory = false,
                                                  .allow_absolute_path = allow_absolute_path,
                                              });
  if (io.is_error()) {
    return io.status_value();
  }

  std::optional fd = bind_to_fd(io.value());
  if (!fd.has_value()) {
    return ZX_ERR_BAD_STATE;
  }
  *out_fd = fd.value();
  return ZX_OK;
}

}  // namespace

__EXPORT
zx_status_t fdio_open_fd(const char* path, uint32_t flags, int* out_fd) {
  return fdio_open_fd_at_internal(AT_FDCWD, path, static_cast<fio::wire::OpenFlags>(flags), true,
                                  out_fd);
}

__EXPORT
zx_status_t fdio_open_fd_at(int dirfd, const char* path, uint32_t flags, int* out_fd) {
  return fdio_open_fd_at_internal(dirfd, path, static_cast<fio::wire::OpenFlags>(flags), false,
                                  out_fd);
}

__EXPORT
zx_handle_t fdio_service_clone(zx_handle_t handle) {
  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
  if (endpoints.is_error()) {
    return ZX_HANDLE_INVALID;
  }
  zx_status_t status = fdio_service_clone_to(handle, endpoints->server.channel().release());
  if (status != ZX_OK) {
    return ZX_HANDLE_INVALID;
  }
  return endpoints->client.channel().release();
}

__EXPORT
zx_status_t fdio_service_clone_to(zx_handle_t handle, zx_handle_t request_raw) {
  auto request = fidl::ServerEnd<fio::Node>(zx::channel(request_raw));
  auto node = fidl::UnownedClientEnd<fio::Node>(handle);
  if (!node.is_valid()) {
    return ZX_ERR_INVALID_ARGS;
  }
  fio::wire::OpenFlags flags = fio::wire::OpenFlags::kCloneSameRights;
  return fidl::WireCall(node)->Clone(flags, std::move(request)).status();
}
