blob: d6952b5f0c8b51c506115dce7596570a01a1b314 [file] [log] [blame]
// Copyright 2017 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.
// Package svcfs implements the Fuchsia service namespace.
package svcfs
import (
"strings"
"syscall/zx"
"syscall/zx/fidl"
"syscall/zx/io"
)
type Provider func(name string, c zx.Channel)
type Namespace struct {
Provider Provider
service io.DirectoryService
}
func (n *Namespace) Clone(flags uint32, req io.NodeInterfaceRequest) error {
c := ((fidl.InterfaceRequest)(req)).Channel
if err := n.Serve(c); err != nil {
c.Close()
return err
}
if flags&io.OpenFlagDescribe != 0 {
pxy := io.NodeEventProxy(fidl.ChannelProxy{c})
info := &io.NodeInfo{NodeInfoTag: io.NodeInfoService}
return pxy.OnOpen(int32(zx.ErrOk), info)
}
return nil
}
func (n *Namespace) Close() (int32, error) {
return int32(zx.ErrNotSupported), nil
}
func (n *Namespace) ListInterfaces() ([]string, error) {
return nil, nil
}
func (n *Namespace) Bind(iface string) error {
return nil
}
func (n *Namespace) Describe() (io.NodeInfo, error) {
return io.NodeInfo{NodeInfoTag: io.NodeInfoDirectory}, nil
}
func (n *Namespace) Sync() (int32, error) {
return int32(zx.ErrNotSupported), nil
}
func (n *Namespace) GetAttr() (int32, io.NodeAttributes, error) {
return int32(zx.ErrNotSupported), io.NodeAttributes{}, nil
}
func (n *Namespace) SetAttr(flags uint32, attributes io.NodeAttributes) (int32, error) {
return int32(zx.ErrNotSupported), nil
}
func (n *Namespace) Ioctl(opcode uint32, maxOut uint64, handles []zx.Handle, in []uint8) (int32, []zx.Handle, []uint8, error) {
return int32(zx.ErrNotSupported), nil, nil, nil
}
// Open opens a service and emits an OnOpen event when ready.
func (n *Namespace) Open(flags, _ uint32, path string, obj io.NodeInterfaceRequest) error {
respond := func(status zx.Status) error {
if flags&io.OpenFlagDescribe != 0 {
info := &io.NodeInfo{NodeInfoTag: io.NodeInfoService}
c := fidl.InterfaceRequest(obj).Channel
pxy := io.NodeEventProxy(fidl.ChannelProxy{Channel: c})
return pxy.OnOpen(int32(status), info)
}
return nil
}
if strings.IndexByte(path, '/') != -1 {
// TODO(abarth): Implement path traversal.
ir := fidl.InterfaceRequest(obj)
ir.Close()
return respond(zx.ErrNotSupported)
}
if path == "." || path == ".." {
return respond(zx.ErrOk)
}
n.Provider(path, ((fidl.InterfaceRequest)(obj)).Channel)
return respond(zx.ErrOk)
}
// Unlink implements io.Directory for Namespace.
func (n *Namespace) Unlink(path string) (int32, error) {
return int32(zx.ErrNotSupported), nil
}
// ReadDirents implements io.Directory for Namespace.
func (n *Namespace) ReadDirents(maxOut uint64) (int32, []uint8, error) {
return int32(zx.ErrNotSupported), nil, nil
}
// Rewind implements io.Directory for Namespace.
func (n *Namespace) Rewind() (int32, error) {
return int32(zx.ErrNotSupported), nil
}
// GetToken implements io.Directory for Namespace.
func (n *Namespace) GetToken() (int32, zx.Handle, error) {
// The returned handle is non-nullable, so this will currently cause
// an internal failure.
return int32(zx.ErrNotSupported), zx.HandleInvalid, nil
}
// Rename implements io.Directory for Namespace.
func (n *Namespace) Rename(src string, dstParentToken zx.Handle, dst string) (int32, error) {
return int32(zx.ErrNotSupported), nil
}
// Link implements io.Directory for Namespace.
func (n *Namespace) Link(src string, dstParentToken zx.Handle, dst string) (int32, error) {
return int32(zx.ErrNotSupported), nil
}
func (n *Namespace) Watch(mask uint32, options uint32, watcher zx.Channel) (int32, error) {
watcher.Close()
return int32(zx.ErrNotSupported), nil
}
func (n *Namespace) Serve(c zx.Channel) error {
if _, err := n.service.Add(n, c, nil); err != nil {
return err
}
h := zx.Handle(c)
return h.SignalPeer(0, zx.SignalUser0)
}