blob: 107ccf7bad815d85545dc325fd06b619e3b1ab4d [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.ObjectInterfaceRequest) error {
c := ((fidl.InterfaceRequest)(req)).Channel
if err := n.Serve(c); err != nil {
c.Close()
return err
}
if flags&io.KOpenFlagDescribe != 0 {
pxy := io.ObjectEventProxy(fidl.Proxy{c})
info := &io.ObjectInfo{ObjectInfoTag: io.ObjectInfoService}
return pxy.OnOpen(zx.ErrOk, info)
}
return nil
}
func (n *Namespace) Close() (zx.Status, error) {
return 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.ObjectInfo, error) {
return io.ObjectInfo{ObjectInfoTag: io.ObjectInfoDirectory}, nil
}
func (n *Namespace) Sync() (zx.Status, error) {
return zx.ErrNotSupported, nil
}
func (n *Namespace) GetAttr() (zx.Status, io.NodeAttributes, error) {
return zx.ErrNotSupported, io.NodeAttributes{}, nil
}
func (n *Namespace) SetAttr(flags uint32, attributes io.NodeAttributes) (zx.Status, error) {
return zx.ErrNotSupported, nil
}
func (n *Namespace) Ioctl(opcode uint32,maxOut uint64,handles []zx.Handle,in []uint8) (zx.Status, []zx.Handle, []uint8, error) {
return 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.ObjectInterfaceRequest) error {
respond := func(status zx.Status) error {
if flags&io.KOpenFlagDescribe != 0 {
info := &io.ObjectInfo{ObjectInfoTag: io.ObjectInfoService}
c := fidl.InterfaceRequest(obj).Channel
pxy := io.ObjectEventProxy(fidl.Proxy{Channel: c})
return pxy.OnOpen(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) (zx.Status, error) {
return zx.ErrNotSupported, nil
}
// ReadDirents implements io.Directory for Namespace.
func (n *Namespace) ReadDirents(maxOut uint64) (zx.Status, []uint8, error) {
return zx.ErrNotSupported, nil, nil
}
// Rewind implements io.Directory for Namespace.
func (n *Namespace) Rewind() (zx.Status, error) {
return zx.ErrNotSupported, nil
}
// GetToken implements io.Directory for Namespace.
func (n *Namespace) GetToken() (zx.Status, zx.Handle, error) {
// The returned handle is non-nullable, so this will currently cause
// an internal failure.
return zx.ErrNotSupported, zx.HandleInvalid, nil
}
// Rename implements io.Directory for Namespace.
func (n *Namespace) Rename(src string, dstParentToken zx.Handle, dst string) (zx.Status, error) {
return zx.ErrNotSupported, nil
}
// Link implements io.Directory for Namespace.
func (n *Namespace) Link(src string, dstParentToken zx.Handle, dst string) (zx.Status, error) {
return 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)
}