blob: d1845f9fc14e32e5762d984ec38b196df4363712 [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Go's distribution tools attempt to compile everything; this file
// depends on types that don't compile in not-Fuchsia.
//go:build fuchsia
package fdio
import (
"syscall/zx"
"syscall/zx/fidl"
"syscall/zx/internal/context"
"syscall/zx/io"
"syscall/zx/unknown"
)
func zxStatusToError(status int32, err error, text string) error {
if err != nil {
return err
}
if zx.Status(status) != zx.ErrOk {
return &zx.Error{Status: zx.Status(status), Text: text}
}
return nil
}
type multiError struct {
err1 error
err2 error
string1 string
string2 string
}
func newMultiError(err1 error, string1 string, err2 error, string2 string) error {
if err1 == nil && err2 == nil {
return nil
}
if err1 != nil && err2 == nil {
return err1
}
if err1 == nil && err2 != nil {
return err2
}
return &multiError{
err1: err1,
err2: err2,
string1: string1,
string2: string2,
}
}
func (err *multiError) Error() string {
var errStr string
if e := err.err1; e != nil {
errStr += err.string1 + "=" + e.Error()
}
if e := err.err2; e != nil {
errStr += err.string2 + "=" + e.Error()
}
return errStr
}
func nodeFromInfo(info *io.NodeInfoDeprecated, node *io.NodeWithCtxInterface) (result FDIO, err error) {
if info == nil {
if err = ((*fidl.ChannelProxy)(node)).Channel.Close(); err != nil {
return nil, err
}
return nil, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
switch info.Which() {
case io.NodeInfoDeprecatedService:
// TODO(mknyszek): Figure out the correct type to return here.
result = &Node{NodeWithCtxInterface: node}
case io.NodeInfoDeprecatedFile:
result = NewFileWithCtx((*io.FileWithCtxInterface)(node), info.File.Event)
case io.NodeInfoDeprecatedDirectory:
result = NewDirectoryWithCtx((*io.DirectoryWithCtxInterface)(node))
default:
if err = ((*fidl.ChannelProxy)(node)).Channel.Close(); err != nil {
return nil, err
}
return nil, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
return result, nil
}
var _ FDIO = (*Node)(nil)
// Node is a wrapper around an NodeWithCtxInterface which implements FDIO.
type Node struct {
*io.NodeWithCtxInterface
}
// IsValid returns true if the Node is valid.
func (n *Node) IsValid() bool {
if n.NodeWithCtxInterface == nil {
return false
}
return ((*fidl.ChannelProxy)(n.NodeWithCtxInterface)).IsValid()
}
// Handles returns a slice of untyped zx handles containing the underlying
// channel of the Node.
func (n *Node) Handles() []zx.Handle {
return []zx.Handle{
zx.Handle(((*fidl.ChannelProxy)(n.NodeWithCtxInterface)).Channel),
}
}
// Clone makes a clone of the node.
func (n *Node) Clone() (FDIO, error) {
req, newNode, err := io.NewNodeWithCtxInterfaceRequest()
if err != nil {
return nil, err
}
cloneFlag := io.OpenFlagsCloneSameRights | io.OpenFlagsDescribe
fdio, err := func() (FDIO, error) {
if err := n.NodeWithCtxInterface.Clone(context.Background(), cloneFlag, req); err != nil {
return nil, err
}
status, info, err := newNode.ExpectOnOpen(context.Background())
if err := zxStatusToError(status, err, "io.node.Clone"); err != nil {
return nil, err
}
return nodeFromInfo(info, newNode)
}()
if err != nil {
return nil, newMultiError(((*fidl.ChannelProxy)(newNode)).Close(), "closeErr", err, "innerErr")
}
return fdio, nil
}
// Close closes the node.
func (n *Node) Close() error {
fidlErr := func() error {
result, err := n.NodeWithCtxInterface.Close(context.Background())
if err != nil {
return err
}
switch result.Which() {
case unknown.CloseableCloseResultErr:
return &zx.Error{Status: zx.Status(result.Err), Text: "io.node.Close"}
case unknown.CloseableCloseResultResponse:
return nil
default:
panic("unknown variant")
}
}()
channelErr := ((*fidl.ChannelProxy)(n.NodeWithCtxInterface)).Close()
return newMultiError(fidlErr, "fidlErr", channelErr, "channelErr")
}
// Sync performs a sync operation on a Node.
func (n *Node) Sync() error {
result, err := n.NodeWithCtxInterface.Sync(context.Background())
if err != nil {
return err
}
switch result.Which() {
case io.Node2SyncResultErr:
return &zx.Error{Status: zx.Status(result.Err), Text: "io.node.Sync"}
case io.Node2SyncResultResponse:
return nil
default:
panic("unknown variant")
}
}
// GetAttr returns the attributes for the Node.
func (n *Node) GetAttr() (io.NodeAttributes, error) {
status, attrs, err := n.NodeWithCtxInterface.GetAttr(context.Background())
if err := zxStatusToError(status, err, "io.node.GetAttr"); err != nil {
return io.NodeAttributes{}, err
}
return attrs, nil
}
// SetAttr sets the attributes for Node as defined by flags.
func (n *Node) SetAttr(flags uint32, attr io.NodeAttributes) error {
{
flags := io.NodeAttributeFlags(flags)
status, err := n.NodeWithCtxInterface.SetAttr(context.Background(), flags, attr)
return zxStatusToError(status, err, "io.node.SetAttr")
}
}
// GetFlags returns the rights and flags used to access this Node.
func (n *Node) GetFlags() (io.OpenFlags, error) {
status, flags, err := n.NodeWithCtxInterface.GetFlags(context.Background())
if err := zxStatusToError(status, err, "io.node.GetFlags"); err != nil {
return 0, err
}
return flags, nil
}
// Read implements FDIO for Node.
func (n *Node) Read(data []byte) (int, error) {
return 0, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// ReadAt implements FDIO for Node.
func (n *Node) ReadAt(data []byte, off int64) (int, error) {
return 0, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Write implements FDIO for Node.
func (n *Node) Write(data []byte) (int, error) {
return 0, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// WriteAt implements FDIO for Node.
func (n *Node) WriteAt(data []byte, off int64) (int, error) {
return 0, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Seek implements FDIO for Node.
func (n *Node) Seek(offset int64, whence int) (int64, error) {
return 0, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Resize implements FDIO for Node.
func (n *Node) Resize(length uint64) error {
return &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Open implements FDIO for Node.
func (n *Node) Open(string, io.OpenFlags) (FDIO, error) {
return nil, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Link implements FDIO for Node.
func (n *Node) Link(oldpath, newpath string) error {
return &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Rename implements FDIO for Node.
func (n *Node) Rename(oldpath, newpath string) error {
return &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Unlink implements FDIO for Node.
func (n *Node) Unlink(path string) error {
return &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// ReadDirents implements FDIO for Node.
func (n *Node) ReadDirents(max uint64) ([]byte, error) {
return nil, &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}
// Rewind implements FDIO for Node.
func (n *Node) Rewind() error {
return &zx.Error{Status: zx.ErrNotSupported, Text: "io.node"}
}