// Copyright 2016 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 "devfs.h"

#include <fcntl.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/async/cpp/wait.h>
#include <lib/ddk/driver.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/coding.h>
#include <lib/fidl/cpp/message_part.h>
#include <lib/fidl/txn_header.h>
#include <lib/zx/channel.h>
#include <stdio.h>
#include <string.h>
#include <zircon/types.h>

#include <memory>

#include <fbl/ref_ptr.h>
#include <fbl/string_buffer.h>

#include "coordinator.h"
#include "src/devices/bin/driver_manager/builtin_devices.h"
#include "src/devices/lib/log/log.h"

namespace {

namespace fio = fuchsia_io;

async_dispatcher_t* g_dispatcher = nullptr;
uint64_t next_ino = 2;

std::unique_ptr<Devnode> class_devnode;

std::unique_ptr<Devnode> devfs_mkdir(Devnode* parent, std::string_view name);

// Dummy node to represent dev/diagnostics directory.
std::unique_ptr<Devnode> diagnostics_devnode;

// Dummy node to represent dev/null directory.
std::unique_ptr<Devnode> null_devnode;

// Dummy node to represent dev/zero directory.
std::unique_ptr<Devnode> zero_devnode;

// Connection to diagnostics VFS server. Channel is owned by inspect manager.
std::optional<fidl::UnownedClientEnd<fuchsia_io::Directory>> diagnostics_channel;

const char kDiagnosticsDirName[] = "diagnostics";
const size_t kDiagnosticsDirLen = strlen(kDiagnosticsDirName);

zx::channel g_devfs_root;

}  // namespace

struct Watcher : fbl::DoublyLinkedListable<std::unique_ptr<Watcher>,
                                           fbl::NodeOptions::AllowRemoveFromContainer> {
  Watcher(Devnode* dn, fidl::ServerEnd<fuchsia_io::DirectoryWatcher> server_end,
          fio::wire::WatchMask mask)
      : devnode(dn), server_end(std::move(server_end)), mask(mask) {}

  Watcher(const Watcher&) = delete;
  Watcher& operator=(const Watcher&) = delete;

  Watcher(Watcher&&) = delete;
  Watcher& operator=(Watcher&&) = delete;

  void HandleChannelClose(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
                          const zx_packet_signal_t* signal);

  Devnode* devnode = nullptr;
  fidl::ServerEnd<fuchsia_io::DirectoryWatcher> server_end;
  fio::wire::WatchMask mask;
  async::WaitMethod<Watcher, &Watcher::HandleChannelClose> channel_close_wait{this};
};

void Watcher::HandleChannelClose(async_dispatcher_t* dispatcher, async::WaitBase* wait,
                                 zx_status_t status, const zx_packet_signal_t* signal) {
  if (status == ZX_OK) {
    if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
      RemoveFromContainer();
    }
  }
}

class DcIostate : public fbl::DoublyLinkedListable<DcIostate*>,
                  public fidl::WireServer<fuchsia_io::Directory> {
 public:
  explicit DcIostate(Devnode* dn, async_dispatcher_t* dispatcher);
  ~DcIostate() override;

  static void Bind(std::unique_ptr<DcIostate> ios, fidl::ServerEnd<fio::Node> request);
  // Remove this DcIostate from its devnode
  void DetachFromDevnode();

  void AdvisoryLock(AdvisoryLockRequestView request,
                    AdvisoryLockCompleter::Sync& completer) override {
    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
  }
  void Clone(CloneRequestView request, CloneCompleter::Sync& completer) override;
  void Close(CloseRequestView request, CloseCompleter::Sync& completer) override;
  void Describe(DescribeRequestView request, DescribeCompleter::Sync& completer) override;
  void Describe2(Describe2RequestView request, Describe2Completer::Sync& completer) override;
  void Sync(SyncRequestView request, SyncCompleter::Sync& completer) override {
    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
  }
  void GetAttr(GetAttrRequestView request, GetAttrCompleter::Sync& completer) override;
  void SetAttr(SetAttrRequestView request, SetAttrCompleter::Sync& completer) override {
    completer.Reply(ZX_ERR_NOT_SUPPORTED);
  }

  void Open(OpenRequestView request, OpenCompleter::Sync& completer) override;
  void AddInotifyFilter(AddInotifyFilterRequestView request,
                        AddInotifyFilterCompleter::Sync& completer) override {}
  void Unlink(UnlinkRequestView request, UnlinkCompleter::Sync& completer) override {
    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
  }
  void ReadDirents(ReadDirentsRequestView request, ReadDirentsCompleter::Sync& completer) override;
  void Rewind(RewindRequestView request, RewindCompleter::Sync& completer) override;
  void GetToken(GetTokenRequestView request, GetTokenCompleter::Sync& completer) override {
    completer.Reply(ZX_ERR_NOT_SUPPORTED, zx::handle());
  }
  void Rename(RenameRequestView request, RenameCompleter::Sync& completer) override {
    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
  }
  void Link(LinkRequestView request, LinkCompleter::Sync& completer) override {
    completer.Reply(ZX_ERR_NOT_SUPPORTED);
  }
  void Watch(WatchRequestView request, WatchCompleter::Sync& completer) override;
  void GetFlags(GetFlagsRequestView request, GetFlagsCompleter::Sync& completer) override {
    completer.Reply(ZX_ERR_NOT_SUPPORTED, {});
  }
  void SetFlags(SetFlagsRequestView request, SetFlagsCompleter::Sync& completer) override {
    completer.Reply(ZX_ERR_NOT_SUPPORTED);
  }
  void QueryFilesystem(QueryFilesystemRequestView request,
                       QueryFilesystemCompleter::Sync& completer) override;

 private:
  // pointer to our devnode, nullptr if it has been removed
  Devnode* devnode_;

  std::optional<fidl::ServerBindingRef<fuchsia_io::Directory>> binding_;

  async_dispatcher_t* dispatcher_;

  uint64_t readdir_ino_ = 0;
};

namespace {

struct ProtocolInfo {
  const char* name;
  std::unique_ptr<Devnode> devnode;
  uint32_t id;
  uint32_t flags;
};

ProtocolInfo proto_infos[] = {
#define DDK_PROTOCOL_DEF(tag, val, name, flags) {name, nullptr, val, flags},
#include <lib/ddk/protodefs.h>
};

// A devnode is a directory (from stat's perspective) if
// it has children, or if it doesn't have a device, or if
// its device has no rpc handle
bool devnode_is_dir(const Devnode* dn) {
  if (dn->children.is_empty()) {
    return (dn->device == nullptr) || (!dn->device->device_controller().is_valid()) ||
           (!dn->device->coordinator_binding().has_value());
  }
  return true;
}

// Local devnodes are ones that we should not hand off OPEN
// RPCs to the underlying driver_host
bool devnode_is_local(Devnode* dn) {
  if (dn->service_dir) {
    return false;
  }
  if (dn->device == nullptr) {
    return true;
  }
  if (!dn->device->device_controller().is_valid()) {
    return true;
  }
  if (dn->device->flags & DEV_CTX_BUS_DEVICE || dn->device->flags & DEV_CTX_IMMORTAL) {
    return true;
  }
  return false;
}

// Notify a single watcher about the given operation and path.  On failure,
// frees the watcher.  This can only be called on a watcher that has not yet
// been added to a Devnode's watchers list.
void devfs_notify_single(std::unique_ptr<Watcher>* watcher, const fbl::String& name,
                         fio::wire::WatchEvent op) {
  size_t len = name.length();
  if (!*watcher || len > fio::wire::kMaxFilename) {
    return;
  }

  ZX_ASSERT(!(*watcher)->InContainer());

  uint8_t msg[fio::wire::kMaxFilename + 2];
  const uint32_t msg_len = static_cast<uint32_t>(len + 2);
  msg[0] = static_cast<uint8_t>(op);
  msg[1] = static_cast<uint8_t>(len);
  memcpy(msg + 2, name.c_str(), len);

  // convert to mask
  fio::wire::WatchMask mask = static_cast<fio::wire::WatchMask>(1u << static_cast<uint8_t>(op));

  if (!((*watcher)->mask & mask)) {
    return;
  }

  if ((*watcher)->server_end.channel().write(0, msg, msg_len, nullptr, 0) != ZX_OK) {
    watcher->reset();
  }
}

void devfs_notify(Devnode* dn, std::string_view name, fio::wire::WatchEvent op) {
  if (dn->watchers.is_empty()) {
    return;
  }

  size_t len = name.length();
  if (len > fio::wire::kMaxFilename) {
    return;
  }

  uint8_t msg[fio::wire::kMaxFilename + 2];
  const uint32_t msg_len = static_cast<uint32_t>(len + 2);
  msg[0] = static_cast<uint8_t>(op);
  msg[1] = static_cast<uint8_t>(len);
  memcpy(msg + 2, name.data(), len);

  // convert to mask
  fio::wire::WatchMask mask = static_cast<fio::wire::WatchMask>(1u << static_cast<uint8_t>(op));

  for (auto itr = dn->watchers.begin(); itr != dn->watchers.end();) {
    auto& cur = *itr;
    // Advance the iterator now instead of at the end of the loop because we
    // may erase the current element from the list.
    ++itr;

    if (!(cur.mask & mask)) {
      continue;
    }

    if (cur.server_end.channel().write(0, msg, msg_len, nullptr, 0) != ZX_OK) {
      dn->watchers.erase(cur);
      // The Watcher is free'd here
    }
  }
}

}  // namespace

void devfs_prepopulate_class(Devnode* dn) {
  for (auto& info : proto_infos) {
    if (!(info.flags & PF_NOPUB)) {
      info.devnode = devfs_mkdir(dn, info.name);
    }
  }
}

Devnode* devfs_proto_node(uint32_t protocol_id) {
  for (const auto& info : proto_infos) {
    if (info.id == protocol_id) {
      return info.devnode.get();
    }
  }
  return nullptr;
}

zx_status_t devfs_watch(Devnode* dn, fidl::ServerEnd<fio::DirectoryWatcher> server_end,
                        fio::wire::WatchMask mask) {
  auto watcher = std::make_unique<Watcher>(dn, std::move(server_end), mask);
  if (watcher == nullptr) {
    return ZX_ERR_NO_MEMORY;
  }

  // If the watcher has asked for all existing entries, send it all of them
  // followed by the end-of-existing marker (IDLE).
  if (mask & fio::wire::WatchMask::kExisting) {
    for (const auto& child : dn->children) {
      if (child.device && (child.device->flags & DEV_CTX_INVISIBLE)) {
        continue;
      }
      // TODO: send multiple per write
      devfs_notify_single(&watcher, child.name, fio::wire::WatchEvent::kExisting);
    }
    devfs_notify_single(&watcher, "", fio::wire::WatchEvent::kIdle);
  }

  // Watcher may have been freed by devfs_notify_single, so check before
  // adding.
  if (watcher) {
    dn->watchers.push_front(std::move(watcher));

    Watcher& watcher_ref = dn->watchers.front();
    watcher_ref.channel_close_wait.set_object(watcher_ref.server_end.channel().get());
    watcher_ref.channel_close_wait.set_trigger(ZX_CHANNEL_PEER_CLOSED);
    watcher_ref.channel_close_wait.Begin(g_dispatcher);
  }
  return ZX_OK;
}

bool devfs_has_watchers(Devnode* dn) { return !dn->watchers.is_empty(); }

namespace {

std::unique_ptr<Devnode> devfs_mknode(const fbl::RefPtr<Device>& dev, std::string_view name) {
  auto dn = std::make_unique<Devnode>(name);
  if (!dn) {
    return nullptr;
  }
  dn->ino = next_ino++;
  // TODO(teisenbe): This should probably be refcounted
  dn->device = dev.get();
  return dn;
}

std::unique_ptr<Devnode> devfs_mkdir(Devnode* parent, std::string_view name) {
  std::unique_ptr<Devnode> dn = devfs_mknode(nullptr, name);
  if (dn == nullptr) {
    return nullptr;
  }
  dn->parent = parent;
  parent->children.push_back(dn.get());
  return dn;
}

Devnode* devfs_lookup(Devnode* parent, std::string_view name) {
  for (auto& child : parent->children) {
    if (name == static_cast<std::string_view>(child.name)) {
      return &child;
    }
  }
  return nullptr;
}

zx_status_t fill_dirent(vdirent_t* de, size_t delen, uint64_t ino, const fbl::String& name,
                        uint8_t type) {
  size_t len = name.length();
  size_t sz = sizeof(vdirent_t) + len;

  if (sz > delen || len > NAME_MAX) {
    return ZX_ERR_INVALID_ARGS;
  }
  de->ino = ino;
  de->size = static_cast<uint8_t>(len);
  de->type = type;
  memcpy(de->name, name.c_str(), len);
  return static_cast<zx_status_t>(sz);
}

zx_status_t devfs_readdir(Devnode* dn, uint64_t* ino_inout, void* data, size_t len) {
  char* ptr = static_cast<char*>(data);
  uint64_t ino = *ino_inout;

  for (const auto& child : dn->children) {
    if (child.ino <= ino) {
      continue;
    }
    if (child.device == nullptr) {
      // "pure" directories (like /dev/class/$NAME) do not show up
      // if they have no children, to avoid clutter and confusion.
      // They remain openable, so they can be watched.
      //
      // An exception being /dev/diagnostics which is served by different VFS
      // and should be listed even though it has no devnode children.
      //
      // Another exception is when the devnode is for a remote service.
      if (child.children.is_empty() && child.ino != diagnostics_devnode->ino &&
          child.ino != null_devnode->ino && child.ino != zero_devnode->ino && !child.service_dir) {
        continue;
      }
    } else {
      // invisible devices also do not show up
      if (child.device->flags & DEV_CTX_INVISIBLE) {
        continue;
      }
    }
    ino = child.ino;
    auto vdirent = reinterpret_cast<vdirent_t*>(ptr);
    zx_status_t r = fill_dirent(vdirent, len, ino, child.name, VTYPE_TO_DTYPE(V_TYPE_DIR));
    if (r < 0) {
      break;
    }
    ptr += r;
    len -= r;
  }

  *ino_inout = ino;
  return static_cast<zx_status_t>(ptr - static_cast<char*>(data));
}

zx_status_t devfs_walk(Devnode** dn_inout, char* path) {
  Devnode* dn = *dn_inout;

again:
  if ((path == nullptr) || (path[0] == 0)) {
    *dn_inout = dn;
    return ZX_OK;
  }
  char* name = path;
  if ((path = strchr(path, '/')) != nullptr) {
    *path++ = 0;
  }
  if (name[0] == 0) {
    return ZX_ERR_BAD_PATH;
  }
  for (auto& child : dn->children) {
    if (!strcmp(child.name.c_str(), name)) {
      if (child.device && (child.device->flags & DEV_CTX_INVISIBLE)) {
        continue;
      }
      dn = &child;
      goto again;
    }
  }
  // The path only partially matched.
  return ZX_ERR_NOT_FOUND;
}

void devfs_open(Devnode* dirdn, async_dispatcher_t* dispatcher, fidl::ServerEnd<fio::Node> ipc,
                char* path, fio::OpenFlags flags) {
  std::string_view path_view(path);
  // Filter requests for diagnostics path and pass it on to diagnostics vfs server.
  if (!strncmp(path, kDiagnosticsDirName, kDiagnosticsDirLen) &&
      (path[kDiagnosticsDirLen] == '\0' || path[kDiagnosticsDirLen] == '/')) {
    char* dir_path = path + kDiagnosticsDirLen;
    char current_dir[] = ".";
    if (dir_path[0] == '/') {
      dir_path++;
    } else {
      dir_path = current_dir;
    }
    // TODO(fxbug.dev/97955) Consider handling the error instead of ignoring it.
    (void)fidl::WireCall(*diagnostics_channel)
        ->Open(flags, 0, fidl::StringView::FromExternal(dir_path), std::move(ipc));
  } else if (path_view == kNullDevName || path_view == kZeroDevName) {
    BuiltinDevices::Get(dispatcher)->HandleOpen(flags, std::move(ipc), path_view);
  } else {
    if (!strcmp(path, ".")) {
      path = nullptr;
    }

    auto describe = [&ipc, describe = flags & fio::wire::OpenFlags::kDescribe](
                        zx::status<fio::wire::NodeInfo> node_info) {
      if (describe) {
        __UNUSED auto result = fidl::WireSendEvent(ipc)->OnOpen(
            node_info.status_value(),
            node_info.is_ok() ? std::move(node_info.value()) : fio::wire::NodeInfo());
      }
    };

    Devnode* dn = dirdn;
    if (zx_status_t status = devfs_walk(&dn, path); status != ZX_OK) {
      describe(zx::error(status));
      return;
    }

    // If we are a local-only node, or we are asked to open-as-a-directory, open locally:
    if (devnode_is_local(dn) || (flags & fio::wire::OpenFlags::kDirectory)) {
      auto ios = std::make_unique<DcIostate>(dn, dispatcher);
      if (ios == nullptr) {
        describe(zx::error(ZX_ERR_NO_MEMORY));
        return;
      }
      fio::wire::DirectoryObject directory;
      describe(zx::ok(fio::wire::NodeInfo::WithDirectory(directory)));
      DcIostate::Bind(std::move(ios), std::move(ipc));
    } else if (dn->service_dir) {
      // TODO(fxbug.dev/97955) Consider handling the error instead of ignoring it.
      (void)fidl::WireCall(dn->service_dir)
          ->Open(flags, 0, fidl::StringView::FromExternal(dn->service_path), std::move(ipc));
    } else {
      __UNUSED auto result = dn->device->device_controller()->Open(flags, 0, ".", std::move(ipc));
    }
  }
}

void devfs_remove(Devnode* dn) {
  if (dn->InContainer()) {
    dn->parent->children.erase(*dn);
  }

  // detach all connected iostates
  while (!dn->iostate.is_empty()) {
    dn->iostate.front().DetachFromDevnode();
  }

  // notify own file watcher
  if ((dn->device == nullptr) || !(dn->device->flags & DEV_CTX_INVISIBLE)) {
    devfs_notify(dn, "", fio::wire::WatchEvent::kDeleted);
  }

  // disconnect from device and notify parent/link directory watchers
  if (dn->device != nullptr) {
    if (dn->device->self == dn) {
      dn->device->self = nullptr;

      if ((dn->device->parent() != nullptr) && (dn->device->parent()->self != nullptr) &&
          !(dn->device->flags & DEV_CTX_INVISIBLE)) {
        devfs_notify(dn->device->parent()->self, dn->name, fio::wire::WatchEvent::kRemoved);
      }
    }
    if (dn->device->link == dn) {
      dn->device->link = nullptr;

      if (!(dn->device->flags & DEV_CTX_INVISIBLE)) {
        Devnode* dir = devfs_proto_node(dn->device->protocol_id());
        devfs_notify(dir, dn->name, fio::wire::WatchEvent::kRemoved);
      }
    }
    dn->device = nullptr;
  }

  // destroy all watchers
  dn->watchers.clear();

  // detach children
  // They will be unpublished when the devices they're associated with are
  // eventually destroyed.
  dn->children.clear();
}

}  // namespace

Devnode::Devnode(fbl::String name) : name(std::move(name)) {}

Devnode::~Devnode() { devfs_remove(this); }

DcIostate::DcIostate(Devnode* dn, async_dispatcher_t* dispatcher)
    : devnode_(dn), dispatcher_(dispatcher) {
  devnode_->iostate.push_back(this);
}

DcIostate::~DcIostate() { DetachFromDevnode(); }

void DcIostate::Bind(std::unique_ptr<DcIostate> ios, fidl::ServerEnd<fio::Node> request) {
  std::optional<fidl::ServerBindingRef<fuchsia_io::Directory>>* binding = &ios->binding_;
  *binding = fidl::BindServer(ios->dispatcher_,
                              fidl::ServerEnd<fuchsia_io::Directory>(request.TakeChannel()),
                              std::move(ios));
}

void DcIostate::DetachFromDevnode() {
  if (devnode_ != nullptr) {
    devnode_->iostate.erase(*this);
    devnode_ = nullptr;
  }
  if (std::optional binding = std::exchange(binding_, std::nullopt); binding.has_value()) {
    binding.value().Unbind();
  }
}

void devfs_advertise(const fbl::RefPtr<Device>& dev) {
  if (dev->link) {
    Devnode* dir = devfs_proto_node(dev->protocol_id());
    devfs_notify(dir, dev->link->name, fio::wire::WatchEvent::kAdded);
  }
  if (dev->self->parent) {
    devfs_notify(dev->self->parent, dev->self->name, fio::wire::WatchEvent::kAdded);
  }
}

// TODO: generate a MODIFIED event rather than back to back REMOVED and ADDED
void devfs_advertise_modified(const fbl::RefPtr<Device>& dev) {
  if (dev->link) {
    Devnode* dir = devfs_proto_node(dev->protocol_id());
    devfs_notify(dir, dev->link->name, fio::wire::WatchEvent::kRemoved);
    devfs_notify(dir, dev->link->name, fio::wire::WatchEvent::kAdded);
  }
  if (dev->self->parent) {
    devfs_notify(dev->self->parent, dev->self->name, fio::wire::WatchEvent::kRemoved);
    devfs_notify(dev->self->parent, dev->self->name, fio::wire::WatchEvent::kAdded);
  }
}

zx_status_t devfs_seq_name(Devnode* dir, char* data, size_t size) {
  for (unsigned n = 0; n < 1000; n++) {
    snprintf(data, size, "%03u", (dir->seqcount++) % 1000);
    if (devfs_lookup(dir, data) == nullptr) {
      return ZX_OK;
    }
  }
  return ZX_ERR_ALREADY_EXISTS;
}

zx_status_t devfs_publish(const fbl::RefPtr<Device>& parent, const fbl::RefPtr<Device>& dev) {
  if ((parent->self == nullptr) || (dev->self != nullptr) || (dev->link != nullptr)) {
    return ZX_ERR_INTERNAL;
  }

  std::unique_ptr<Devnode> dnself = devfs_mknode(dev, dev->name());
  if (dnself == nullptr) {
    return ZX_ERR_NO_MEMORY;
  }

  if ((dev->protocol_id() == ZX_PROTOCOL_TEST_PARENT) || (dev->protocol_id() == ZX_PROTOCOL_MISC)) {
    // misc devices are singletons, not a class
    // in the sense of other device classes.
    // They do not get aliases in /dev/class/misc/...
    // instead they exist only under their parent
    // device.
    goto done;
  }

  // Create link in /dev/class/... if this id has a published class
  if (auto dir = devfs_proto_node(dev->protocol_id()); dir != nullptr) {
    char buf[4] = {};
    auto name = dev->name();

    if (dev->protocol_id() != ZX_PROTOCOL_CONSOLE) {
      zx_status_t status = devfs_seq_name(dir, buf, sizeof(buf));
      if (status != ZX_OK) {
        return status;
      }
      name = buf;
    }

    std::unique_ptr<Devnode> dnlink = devfs_mknode(dev, name);
    if (dnlink == nullptr) {
      return ZX_ERR_NO_MEMORY;
    }

    // add link node to class directory
    dnlink->parent = dir;
    dir->children.push_back(dnlink.get());
    dev->link = dnlink.release();
  }

done:
  // add self node to parent directory
  dnself->parent = parent->self;
  parent->self->children.push_back(dnself.get());
  dev->self = dnself.release();

  if (!(dev->flags & DEV_CTX_INVISIBLE)) {
    devfs_advertise(dev);
  }
  return ZX_OK;
}

// TODO(teisenbe): Ideally this would take a RefPtr, but currently this is
// invoked in the dtor for Device.
void devfs_unpublish(Device* dev) {
  if (dev->self != nullptr) {
    delete dev->self;
    dev->self = nullptr;
  }
  if (dev->link != nullptr) {
    delete dev->link;
    dev->link = nullptr;
  }
}

zx_status_t devfs_connect(const Device* dev, fidl::ServerEnd<fio::Node> client_remote) {
  if (!client_remote.is_valid()) {
    return ZX_ERR_BAD_HANDLE;
  }
  __UNUSED auto result = dev->device_controller()->Open({}, 0, ".", std::move(client_remote));
  return ZX_OK;
}

void devfs_connect_diagnostics(fidl::UnownedClientEnd<fio::Directory> h) {
  diagnostics_channel = std::make_optional<fidl::UnownedClientEnd<fio::Directory>>(h);
}

void DcIostate::Open(OpenRequestView request, OpenCompleter::Sync& completer) {
  if (request->path.size() <= fio::wire::kMaxPath) {
    fbl::StringBuffer<fio::wire::kMaxPath + 1> terminated_path;
    terminated_path.Append(request->path.data(), request->path.size());
    devfs_open(devnode_, dispatcher_, std::move(request->object), terminated_path.data(),
               request->flags);
  }
}

void DcIostate::Clone(CloneRequestView request, CloneCompleter::Sync& completer) {
  if (request->flags & fio::wire::OpenFlags::kCloneSameRights) {
    request->flags |= fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable;
  }
  char path[] = ".";
  devfs_open(devnode_, dispatcher_, std::move(request->object), path,
             request->flags | fio::wire::OpenFlags::kDirectory);
}

void DcIostate::QueryFilesystem(QueryFilesystemRequestView request,
                                QueryFilesystemCompleter::Sync& completer) {
  fuchsia_io::wire::FilesystemInfo info;
  strlcpy(reinterpret_cast<char*>(info.name.data()), "devfs", fuchsia_io::wire::kMaxFsNameBuffer);
  completer.Reply(ZX_OK, fidl::ObjectView<fuchsia_io::wire::FilesystemInfo>::FromExternal(&info));
}

void DcIostate::Watch(WatchRequestView request, WatchCompleter::Sync& completer) {
  zx_status_t status;
  if (!request->mask || request->options != 0) {
    status = ZX_ERR_INVALID_ARGS;
  } else {
    status = devfs_watch(devnode_, std::move(request->watcher), request->mask);
  }
  completer.Reply(status);
}

void DcIostate::Rewind(RewindRequestView request, RewindCompleter::Sync& completer) {
  readdir_ino_ = 0;
  completer.Reply(ZX_OK);
}

void DcIostate::ReadDirents(ReadDirentsRequestView request, ReadDirentsCompleter::Sync& completer) {
  if (request->max_bytes > fio::wire::kMaxBuf) {
    completer.Reply(ZX_ERR_INVALID_ARGS, fidl::VectorView<uint8_t>());
    return;
  }

  uint8_t data[fio::wire::kMaxBuf];
  size_t actual = 0;
  zx_status_t status = devfs_readdir(devnode_, &readdir_ino_, data, request->max_bytes);
  if (status >= 0) {
    actual = status;
    status = ZX_OK;
  }
  completer.Reply(status, fidl::VectorView<uint8_t>::FromExternal(data, actual));
}

void DcIostate::GetAttr(GetAttrRequestView request, GetAttrCompleter::Sync& completer) {
  uint32_t mode;
  if (devnode_is_dir(devnode_)) {
    mode = V_TYPE_DIR | V_IRUSR | V_IWUSR;
  } else {
    mode = V_TYPE_CDEV | V_IRUSR | V_IWUSR;
  }

  fio::wire::NodeAttributes attributes;
  attributes.mode = mode;
  attributes.content_size = 0;
  attributes.link_count = 1;
  attributes.id = devnode_->ino;
  completer.Reply(ZX_OK, attributes);
}

void DcIostate::Describe(DescribeRequestView request, DescribeCompleter::Sync& completer) {
  fio::wire::DirectoryObject directory;
  completer.Reply(fio::wire::NodeInfo::WithDirectory(directory));
}

void DcIostate::Describe2(Describe2RequestView request, Describe2Completer::Sync& completer) {
  fio::wire::DirectoryInfo directory_info;
  fio::wire::Representation representation = fio::wire::Representation::WithDirectory(
      fidl::ObjectView<decltype(directory_info)>::FromExternal(&directory_info));
  fio::wire::ConnectionInfo connection_info;
  connection_info.set_representation(
      fidl::ObjectView<decltype(representation)>::FromExternal(&representation));
  completer.Reply(connection_info);
}

void DcIostate::Close(CloseRequestView request, CloseCompleter::Sync& completer) {
  completer.ReplySuccess();
  completer.Close(ZX_OK);
}

zx::unowned_channel devfs_root_borrow() { return zx::unowned_channel(g_devfs_root); }

zx::channel devfs_root_clone() { return zx::channel(fdio_service_clone(g_devfs_root.get())); }

void devfs_init(const fbl::RefPtr<Device>& device, async_dispatcher_t* dispatcher) {
  g_dispatcher = dispatcher;
  auto root_devnode = std::make_unique<Devnode>("");
  if (!root_devnode) {
    return;
  }
  root_devnode->ino = 1;

  class_devnode = devfs_mkdir(root_devnode.get(), "class");
  if (!class_devnode) {
    return;
  }
  devfs_prepopulate_class(class_devnode.get());

  // Create dummy diagnostics devnode, so that the directory is listed.
  diagnostics_devnode = devfs_mkdir(root_devnode.get(), "diagnostics");
  // Create dummy null devnode, so that the directory is listed.
  null_devnode = devfs_mkdir(root_devnode.get(), "null");
  // Create dummy zero devnode, so that the directory is listed.
  zero_devnode = devfs_mkdir(root_devnode.get(), "zero");

  // TODO(teisenbe): Should this take a reference?
  root_devnode->device = device.get();
  root_devnode->device->self = root_devnode.get();

  auto endpoints = fidl::CreateEndpoints<fio::Node>();
  if (endpoints.is_error()) {
    return;
  }
  auto ios = std::make_unique<DcIostate>(root_devnode.get(), dispatcher);
  if (ios == nullptr) {
    return;
  }
  DcIostate::Bind(std::move(ios), std::move(endpoints->server));

  g_devfs_root = endpoints->client.TakeChannel();
  // This is actually owned by |device| and will be freed in unpublish
  __UNUSED auto ptr = root_devnode.release();
}

zx_status_t devfs_walk(Devnode* dn, const char* path, fbl::RefPtr<Device>* dev) {
  Devnode* inout = dn;

  char path_copy[PATH_MAX];
  if (strlen(path) + 1 > sizeof(path_copy)) {
    return ZX_ERR_BUFFER_TOO_SMALL;
  }
  strcpy(path_copy, path);

  zx_status_t status = devfs_walk(&inout, path_copy);
  if (status != ZX_OK) {
    return status;
  }
  *dev = fbl::RefPtr(inout->device);
  return ZX_OK;
}

zx_status_t devfs_export(Devnode* dn, fidl::ClientEnd<fuchsia_io::Directory> service_dir,
                         std::string_view service_path, std::string_view devfs_path,
                         uint32_t protocol_id, std::vector<std::unique_ptr<Devnode>>& out) {
  // Check if the `devfs_path` provided is valid.
  const auto is_valid_path = [](std::string_view path) {
    return !path.empty() && path.front() != '/' && path.back() != '/';
  };
  if (!is_valid_path(service_path) || !is_valid_path(devfs_path)) {
    return ZX_ERR_INVALID_ARGS;
  }

  // Walk the `devfs_path` and call `process` on each part of the path.
  //
  // e.g. If devfs_path is "platform/acpi/acpi-pwrbtn", then process will be
  // called with "platform", then "acpi", then "acpi-pwrbtn".
  std::string_view::size_type begin = 0, end = 0;
  const auto walk = [&devfs_path, &begin, &end](auto process) {
    do {
      // Consume excess separators.
      while (devfs_path[begin] == '/') {
        ++begin;
      }
      end = devfs_path.find('/', begin);
      auto size = end == std::string_view::npos ? end : end - begin;
      if (!process(devfs_path.substr(begin, size))) {
        break;
      }
      begin = end + 1;
    } while (end != std::string_view::npos);
  };

  // Walk `devfs_path` and find the last Devnode that exists, so we can create
  // the rest of the path underneath it.
  Devnode* prev_dn = nullptr;
  walk([&dn, &prev_dn](std::string_view name) {
    prev_dn = dn;
    dn = devfs_lookup(dn, name);
    return dn != nullptr;
  });

  // The full path described by `devfs_path` already exists.
  if (dn != nullptr) {
    return ZX_ERR_ALREADY_EXISTS;
  }

  // Create Devnodes for the remainder of the path, and set `service_dir` and
  // `service_path` on the leaf Devnode.
  dn = prev_dn;
  walk([&out, &dn](std::string_view name) {
    out.push_back(devfs_mkdir(dn, name));
    devfs_notify(dn, name, fio::wire::WatchEvent::kAdded);
    dn = out.back().get();
    return true;
  });
  dn->service_dir = std::move(service_dir);
  dn->service_path = service_path;

  // If a protocol directory exists for `protocol_id`, then create a Devnode
  // under the protocol directory too.
  if (auto dir = devfs_proto_node(protocol_id); dir != nullptr) {
    char name[4] = {};
    zx_status_t status = devfs_seq_name(dir, name, sizeof(name));
    if (status != ZX_OK) {
      return status;
    }
    out.push_back(devfs_mkdir(dir, name));
    devfs_notify(dir, name, fio::wire::WatchEvent::kAdded);

    // Clone the service node for the entry in the protocol directory.
    auto endpoints = fidl::CreateEndpoints<fio::Node>();
    if (endpoints.is_error()) {
      return endpoints.status_value();
    }
    auto result = fidl::WireCall(dn->service_dir)
                      ->Clone(fio::wire::OpenFlags::kCloneSameRights, std::move(endpoints->server));
    if (!result.ok()) {
      return result.status();
    }
    Devnode* class_dn = out.back().get();
    class_dn->service_dir.channel().swap(endpoints->client.channel());
    class_dn->service_path = service_path;
  }

  return ZX_OK;
}
