blob: 7e74df3889e27204243b1307063e7a72557f0a44 [file] [log] [blame] [edit]
// 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 "fdio.h"
#include <lib/fdio/directory.h>
#include <lib/fdio/namespace.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <iterator>
#include "src/developer/shell/josh/lib/qjs_util.h"
#include "src/developer/shell/josh/lib/zx.h"
#include "third_party/quickjs/quickjs.h"
namespace shell::fdio {
namespace {
// Wrapper around fdio_service_connect.
// argv[0] is a (string) path to the service.
// Returns a handle object that points to the client endpoint to this service.
JSValue ServiceConnect(JSContext *ctx, JSValueConst /*this_val*/, int argc, JSValueConst *argv) {
if (argc != 1) {
return JS_ThrowSyntaxError(ctx,
"Wrong number of arguments to fdio.serviceConnect(), "
"was %d, expected 1",
argc);
}
zx_handle_t out0, out1;
zx_status_t status;
status = zx_channel_create(0, &out0, &out1);
if (status != ZX_OK) {
return zx::ZxStatusToError(ctx, status);
}
CStringHolder path(ctx, argv[0]);
if (!path.get()) {
return JS_EXCEPTION;
}
status = fdio_service_connect(path.get(), out1);
if (status != ZX_OK) {
zx_handle_close(out0);
zx_handle_close(out1);
return zx::ZxStatusToError(ctx, status);
}
return zx::HandleCreate(ctx, out0, ZX_OBJ_TYPE_CHANNEL);
}
// Makes the root handles (representing elements of the namespace) available to JS callers.
JSClassDef flat_ns_class_ = {
"FlatNs",
.finalizer = nullptr,
};
JSClassID flat_ns_class_id_;
// Returns an object that represents the root namespace.
JSValue NsExportRoot(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
fdio_flat_namespace_t *root_ns = nullptr;
zx_status_t status = fdio_ns_export_root(&root_ns);
if (status != ZX_OK) {
return zx::ZxStatusToError(ctx, status);
}
JSValue flat_ns_obj = JS_NewObjectClass(ctx, flat_ns_class_id_);
JS_SetOpaque(flat_ns_obj, reinterpret_cast<void *>(root_ns));
return flat_ns_obj;
}
// Closes the elements in the root namespace associated with this object.
JSValue NsClose(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
fdio_flat_namespace_t *ns =
reinterpret_cast<fdio_flat_namespace_t *>(JS_GetOpaque(this_val, flat_ns_class_id_));
fdio_ns_free_flat_ns(ns);
return JS_NewInt32(ctx, 0);
}
// Gets the number of handles in the root namespace associated with this object.
JSValue NsGetCount(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
fdio_flat_namespace_t *ns =
reinterpret_cast<fdio_flat_namespace_t *>(JS_GetOpaque(this_val, flat_ns_class_id_));
return JS_NewInt32(ctx, ns->count);
}
// Gets a list of Handle objects that refer to the root namespace. They have
// a handle property and a property representing the type, which is an int
// defined by the PA_HND macro in processargs.h.
JSValue NsGetElements(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
fdio_flat_namespace_t *ns =
reinterpret_cast<fdio_flat_namespace_t *>(JS_GetOpaque(this_val, flat_ns_class_id_));
if (ns == nullptr) {
return JS_EXCEPTION;
}
JSValue dirents = JS_NewObject(ctx);
if (JS_IsException(dirents)) {
return dirents;
}
for (size_t i = 0; i < ns->count; i++) {
JSValue val = JS_NewObject(ctx);
if (JS_IsException(val)) {
return val;
}
if (zx_object_get_info(ns->handle[i], ZX_INFO_HANDLE_VALID, nullptr, 0, nullptr, nullptr) ==
ZX_ERR_BAD_HANDLE) {
continue;
}
if (JS_SetPropertyStr(ctx, val, "handle",
zx::HandleCreate(ctx, ns->handle[i], ZX_OBJ_TYPE_NONE)) < 0) {
return JS_EXCEPTION;
}
if (JS_SetPropertyStr(ctx, val, "type", JS_NewInt32(ctx, ns->type[i])) < 0) {
return JS_EXCEPTION;
}
if (JS_SetPropertyStr(ctx, dirents, ns->path[i], val) < 0) {
return JS_EXCEPTION;
}
}
return dirents;
}
const JSCFunctionListEntry flat_ns_proto_funcs_[] = {
JS_CFUNC_DEF("getCount", 0, NsGetCount),
JS_CFUNC_DEF("getElements", 0, NsGetElements),
JS_CFUNC_DEF("close", 0, NsClose),
};
const JSCFunctionListEntry funcs_[] = {
JS_CFUNC_DEF("serviceConnect", 1, ServiceConnect),
JS_CFUNC_DEF("nsExportRoot", 0, NsExportRoot),
};
int FdioRunOnInit(JSContext *ctx, JSModuleDef *m) {
JS_NewClassID(&flat_ns_class_id_);
JS_NewClass(JS_GetRuntime(ctx), flat_ns_class_id_, &flat_ns_class_);
JSValue proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, proto, flat_ns_proto_funcs_, std::size(flat_ns_proto_funcs_));
JS_SetClassProto(ctx, flat_ns_class_id_, proto);
return JS_SetModuleExportList(ctx, m, funcs_, std::size(funcs_));
}
} // namespace
// Returns a module that supports FDIO functionality.
JSModuleDef *FdioModuleInit(JSContext *ctx, const char *module_name) {
JSModuleDef *m = JS_NewCModule(ctx, module_name, FdioRunOnInit);
if (!m) {
return nullptr;
}
JS_AddModuleExportList(ctx, m, funcs_, std::size(funcs_));
return m;
}
} // namespace shell::fdio