| // 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"} |
| } |