blob: c32b352135588170dd51b21d079d892a93a89fe2 [file] [log] [blame]
// Copyright 2018 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/svc/dir.h"
#include <fbl/string.h>
#include <fs/pseudo-dir.h>
#include <fs/service.h>
#include <fs/synchronous-vfs.h>
struct svc_dir {
explicit svc_dir(async_dispatcher_t* dispatcher) : vfs(dispatcher) {}
fs::SynchronousVfs vfs;
fbl::RefPtr<fs::PseudoDir> root;
};
zx_status_t svc_dir_create(async_dispatcher_t* dispatcher,
zx_handle_t dir_request, svc_dir_t** result) {
svc_dir_t* dir = new svc_dir_t(dispatcher);
dir->root = fbl::AdoptRef(new fs::PseudoDir());
zx_status_t status =
dir->vfs.ServeDirectory(dir->root, zx::channel(dir_request));
if (status != ZX_OK) {
delete dir;
return status;
}
*result = dir;
return ZX_OK;
}
zx_status_t svc_dir_add_service(svc_dir_t* dir, const char* type,
const char* service_name, void* context,
svc_connector_t handler) {
fbl::RefPtr<fs::Vnode> node = dir->root;
if (type != nullptr) {
zx_status_t status = dir->root->Lookup(&node, type);
if (status == ZX_ERR_NOT_FOUND) {
node = fbl::AdoptRef(new fs::PseudoDir());
status = dir->root->AddEntry(type, node);
}
if (status != ZX_OK)
return status;
}
fs::PseudoDir* node_dir = static_cast<fs::PseudoDir*>(node.get());
return node_dir->AddEntry(
service_name,
fbl::AdoptRef(new fs::Service([service_name = fbl::String(service_name),
context, handler](zx::channel channel) {
handler(context, service_name.c_str(), channel.release());
return ZX_OK;
})));
}
zx_status_t svc_dir_remove_service(svc_dir_t* dir, const char* type,
const char* service_name) {
fbl::RefPtr<fs::Vnode> node = dir->root;
if (type != nullptr) {
zx_status_t status = dir->root->Lookup(&node, type);
if (status != ZX_OK)
return status;
}
fs::PseudoDir* node_dir = static_cast<fs::PseudoDir*>(node.get());
return node_dir->RemoveEntry(service_name);
}
zx_status_t svc_dir_destroy(svc_dir_t* dir) {
delete dir;
return ZX_OK;
}