| // 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. |
| |
| //go:build !build_with_native_toolchain |
| |
| package component |
| |
| import ( |
| "bytes" |
| "context" |
| "encoding/binary" |
| "fmt" |
| stdio "io" |
| "log" |
| "runtime" |
| "runtime/pprof" |
| "strings" |
| "syscall" |
| "syscall/zx" |
| "syscall/zx/fdio" |
| "syscall/zx/fidl" |
| "unsafe" |
| |
| "fidl/fuchsia/io" |
| "fidl/fuchsia/unknown" |
| ) |
| |
| func respond(ctx fidl.Context, flags io.OpenFlags, req io.NodeWithCtxInterfaceRequest, err error, node Node) error { |
| if err != nil { |
| defer func() { |
| _ = req.Close() |
| }() |
| } |
| if flags&io.OpenFlagsDescribe != 0 { |
| proxy := io.NodeEventProxy{Channel: req.Channel} |
| switch err := err.(type) { |
| case nil: |
| info, err := node.DescribeDeprecated(ctx) |
| if err != nil { |
| panic(err) |
| } |
| return proxy.OnOpen(int32(zx.ErrOk), &info) |
| case *zx.Error: |
| return proxy.OnOpen(int32(err.Status), nil) |
| default: |
| panic(err) |
| } |
| } |
| return nil |
| } |
| |
| func logError(err error) { |
| log.Print(err) |
| } |
| |
| type Node interface { |
| getIO() (io.NodeWithCtx, func() error, error) |
| addConnection(ctx fidl.Context, flags io.OpenFlags, mode io.ModeType, req io.NodeWithCtxInterfaceRequest) error |
| DescribeDeprecated(fidl.Context) (io.NodeInfoDeprecated, error) |
| } |
| |
| func noop() error { |
| return nil |
| } |
| |
| type Service struct { |
| // AddFn is called serially with an incoming request. It must not block, and |
| // is expected to handle incoming calls on the request. |
| AddFn func(context.Context, zx.Channel) error |
| } |
| |
| var _ Node = (*Service)(nil) |
| var _ io.NodeWithCtx = (*Service)(nil) |
| |
| func (s *Service) getIO() (io.NodeWithCtx, func() error, error) { |
| return s, noop, nil |
| } |
| |
| func (s *Service) addConnection(ctx fidl.Context, flags io.OpenFlags, mode io.ModeType, req io.NodeWithCtxInterfaceRequest) error { |
| // TODO(https://fxbug.dev/42108808): this does not implement the node protocol correctly, |
| // but matches the behaviour of SDK VFS. |
| if flags&io.OpenFlagsNodeReference != 0 { |
| stub := io.NodeWithCtxStub{Impl: s} |
| go Serve(context.Background(), &stub, req.Channel, ServeOptions{ |
| OnError: logError, |
| }) |
| return respond(ctx, flags, req, nil, s) |
| } |
| return respond(ctx, flags, req, s.AddFn(context.Background(), req.Channel), s) |
| } |
| |
| func (s *Service) Clone(ctx fidl.Context, flags io.OpenFlags, req io.NodeWithCtxInterfaceRequest) error { |
| return s.addConnection(ctx, flags, 0, req) |
| } |
| |
| func (s *Service) Reopen(ctx fidl.Context, rights io.RightsRequest, req io.NodeWithCtxInterfaceRequest) error { |
| // TODO(https://fxbug.dev/42157659): implement. |
| _ = req.Close() |
| return nil |
| } |
| |
| func (*Service) Close(fidl.Context) (unknown.CloseableCloseResult, error) { |
| return unknown.CloseableCloseResultWithResponse(unknown.CloseableCloseResponse{}), nil |
| } |
| |
| func (*Service) DescribeDeprecated(fidl.Context) (io.NodeInfoDeprecated, error) { |
| var nodeInfo io.NodeInfoDeprecated |
| nodeInfo.SetService(io.Service{}) |
| return nodeInfo, nil |
| } |
| |
| func (*Service) GetConnectionInfo(fidl.Context) (io.ConnectionInfo, error) { |
| var connectionInfo io.ConnectionInfo |
| // TODO(https://fxbug.dev/42157659): Populate the rights requested by the client at connection. |
| // This might require separating Service from the VFS implementation so that the latter can |
| // hold these rights. |
| connectionInfo.SetRights(io.OperationsConnect) |
| return connectionInfo, nil |
| } |
| |
| func (*Service) Sync(fidl.Context) (io.Node2SyncResult, error) { |
| return io.Node2SyncResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*Service) GetAttr(fidl.Context) (int32, io.NodeAttributes, error) { |
| return int32(zx.ErrOk), io.NodeAttributes{ |
| Mode: uint32(io.ModeTypeService), |
| Id: io.InoUnknown, |
| LinkCount: 1, |
| }, nil |
| } |
| |
| func (*Service) SetAttr(fidl.Context, io.NodeAttributeFlags, io.NodeAttributes) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*Service) GetAttributes(fidl.Context, io.NodeAttributesQuery) (io.Node2GetAttributesResult, error) { |
| // TODO(https://fxbug.dev/42157659): implement. |
| return io.Node2GetAttributesResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*Service) UpdateAttributes(fidl.Context, io.MutableNodeAttributes) (io.Node2UpdateAttributesResult, error) { |
| // TODO(https://fxbug.dev/42157659): implement. |
| return io.Node2UpdateAttributesResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*Service) ListExtendedAttributes(_ fidl.Context, request io.ExtendedAttributeIteratorWithCtxInterfaceRequest) error { |
| _ = request.Close() |
| return nil |
| } |
| |
| func (*Service) GetExtendedAttribute(fidl.Context, []uint8) (io.Node2GetExtendedAttributeResult, error) { |
| return io.Node2GetExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*Service) SetExtendedAttribute(fidl.Context, []uint8, io.ExtendedAttributeValue, io.SetExtendedAttributeMode) (io.Node2SetExtendedAttributeResult, error) { |
| return io.Node2SetExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*Service) RemoveExtendedAttribute(fidl.Context, []uint8) (io.Node2RemoveExtendedAttributeResult, error) { |
| return io.Node2RemoveExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*Service) GetFlags(fidl.Context) (int32, io.OpenFlags, error) { |
| return int32(zx.ErrNotSupported), 0, nil |
| } |
| |
| func (*Service) SetFlags(fidl.Context, io.OpenFlags) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*Service) QueryFilesystem(fidl.Context) (int32, *io.FilesystemInfo, error) { |
| return int32(zx.ErrNotSupported), nil, nil |
| } |
| |
| func (*Service) Query(fidl.Context) ([]uint8, error) { |
| return []byte(io.NodeProtocolName_), nil |
| } |
| |
| type Directory interface { |
| Get(string) (Node, bool) |
| ForEach(func(string, Node) error) error |
| } |
| |
| var _ Directory = mapDirectory(nil) |
| |
| type mapDirectory map[string]Node |
| |
| func (md mapDirectory) Get(name string) (Node, bool) { |
| node, ok := md[name] |
| return node, ok |
| } |
| |
| func (md mapDirectory) ForEach(fn func(string, Node) error) error { |
| for name, node := range md { |
| if err := fn(name, node); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| var _ Directory = (*pprofDirectory)(nil) |
| |
| type pprofDirectory struct{} |
| |
| func (*pprofDirectory) Get(name string) (Node, bool) { |
| if p := pprof.Lookup(name); p != nil { |
| return &FileWrapper{ |
| File: &pprofFile{ |
| p: p, |
| }, |
| }, true |
| } |
| return nil, false |
| } |
| |
| func (*pprofDirectory) ForEach(fn func(string, Node) error) error { |
| for _, p := range pprof.Profiles() { |
| if err := fn(p.Name(), &FileWrapper{ |
| File: &pprofFile{ |
| p: p, |
| }, |
| }); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| type DirectoryWrapper struct { |
| Directory Directory |
| } |
| |
| var _ Node = (*DirectoryWrapper)(nil) |
| |
| func (dir *DirectoryWrapper) GetDirectory() io.DirectoryWithCtx { |
| return &directoryState{DirectoryWrapper: dir} |
| } |
| |
| func (dir *DirectoryWrapper) getIO() (io.NodeWithCtx, func() error, error) { |
| return dir.GetDirectory(), noop, nil |
| } |
| |
| func (dir *DirectoryWrapper) addConnection(ctx fidl.Context, flags io.OpenFlags, mode io.ModeType, req io.NodeWithCtxInterfaceRequest) error { |
| ioDir := dir.GetDirectory() |
| stub := io.DirectoryWithCtxStub{Impl: ioDir} |
| go Serve(context.Background(), &stub, req.Channel, ServeOptions{ |
| OnError: logError, |
| }) |
| return respond(ctx, flags, req, nil, dir) |
| } |
| |
| var _ io.DirectoryWithCtx = (*directoryState)(nil) |
| |
| type directoryState struct { |
| *DirectoryWrapper |
| |
| reading bool |
| dirents bytes.Buffer |
| } |
| |
| func (dirState *directoryState) Clone(ctx fidl.Context, flags io.OpenFlags, req io.NodeWithCtxInterfaceRequest) error { |
| return dirState.addConnection(ctx, flags, 0, req) |
| } |
| |
| func (dirState *directoryState) Reopen(ctx fidl.Context, rights io.RightsRequest, req io.NodeWithCtxInterfaceRequest) error { |
| // TODO(https://fxbug.dev/42157659): implement. |
| _ = req.Close() |
| return nil |
| } |
| |
| func (*directoryState) Close(fidl.Context) (unknown.CloseableCloseResult, error) { |
| return unknown.CloseableCloseResultWithResponse(unknown.CloseableCloseResponse{}), nil |
| } |
| |
| func (*DirectoryWrapper) DescribeDeprecated(fidl.Context) (io.NodeInfoDeprecated, error) { |
| var nodeInfo io.NodeInfoDeprecated |
| nodeInfo.SetDirectory(io.DirectoryObject{}) |
| return nodeInfo, nil |
| } |
| |
| func (*directoryState) GetConnectionInfo(fidl.Context) (io.ConnectionInfo, error) { |
| var connectionInfo io.ConnectionInfo |
| // TODO(https://fxbug.dev/42157659): Populate the rights requested by the client at connection. |
| rights := io.RStarDir |
| connectionInfo.SetRights(rights) |
| return connectionInfo, nil |
| } |
| |
| func (*directoryState) Sync(fidl.Context) (io.Node2SyncResult, error) { |
| return io.Node2SyncResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) GetAttr(fidl.Context) (int32, io.NodeAttributes, error) { |
| return int32(zx.ErrOk), io.NodeAttributes{ |
| Mode: uint32(io.ModeTypeDirectory) | uint32(fdio.VtypeIRUSR), |
| Id: io.InoUnknown, |
| LinkCount: 1, |
| }, nil |
| } |
| |
| func (*directoryState) SetAttr(fidl.Context, io.NodeAttributeFlags, io.NodeAttributes) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*directoryState) GetAttributes(fidl.Context, io.NodeAttributesQuery) (io.Node2GetAttributesResult, error) { |
| // TODO(https://fxbug.dev/42157659): implement. |
| return io.Node2GetAttributesResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) UpdateAttributes(fidl.Context, io.MutableNodeAttributes) (io.Node2UpdateAttributesResult, error) { |
| // TODO(https://fxbug.dev/42157659): implement. |
| return io.Node2UpdateAttributesResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) ListExtendedAttributes(_ fidl.Context, request io.ExtendedAttributeIteratorWithCtxInterfaceRequest) error { |
| _ = request.Close() |
| return nil |
| } |
| |
| func (*directoryState) GetExtendedAttribute(fidl.Context, []uint8) (io.Node2GetExtendedAttributeResult, error) { |
| return io.Node2GetExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) SetExtendedAttribute(fidl.Context, []uint8, io.ExtendedAttributeValue, io.SetExtendedAttributeMode) (io.Node2SetExtendedAttributeResult, error) { |
| return io.Node2SetExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) RemoveExtendedAttribute(fidl.Context, []uint8) (io.Node2RemoveExtendedAttributeResult, error) { |
| return io.Node2RemoveExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| const dot = "." |
| |
| func (dirState *directoryState) Open(ctx fidl.Context, flags io.OpenFlags, mode io.ModeType, path string, req io.NodeWithCtxInterfaceRequest) error { |
| if path == dot { |
| return dirState.addConnection(ctx, flags, mode, req) |
| } |
| const slash = "/" |
| if strings.HasSuffix(path, slash) { |
| path = path[:len(path)-len(slash)] |
| } |
| |
| if i := strings.Index(path, slash); i != -1 { |
| if node, ok := dirState.Directory.Get(path[:i]); ok { |
| proxy, cleanup, err := node.getIO() |
| if err != nil { |
| return err |
| } |
| defer cleanup() |
| if dir, ok := proxy.(io.DirectoryWithCtx); ok { |
| return dir.Open(ctx, flags, mode, path[i+len(slash):], req) |
| } |
| return respond(ctx, flags, req, &zx.Error{Status: zx.ErrNotDir}, node) |
| } |
| } else if node, ok := dirState.Directory.Get(path); ok { |
| return node.addConnection(ctx, flags, mode, req) |
| } |
| |
| return respond(ctx, flags, req, &zx.Error{Status: zx.ErrNotFound}, dirState) |
| } |
| |
| func (dirState *directoryState) Open2(ctx fidl.Context, path string, protocols io.ConnectionProtocols, channel zx.Channel) error { |
| // TODO(https://fxbug.dev/42157659): implement. |
| _ = channel.Close() |
| return nil |
| } |
| |
| func (*directoryState) Unlink(fidl.Context, string, io.UnlinkOptions) (io.Directory2UnlinkResult, error) { |
| return io.Directory2UnlinkResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (dirState *directoryState) Enumerate(ctx fidl.Context, options io.DirectoryEnumerateOptions, req io.DirectoryIteratorWithCtxInterfaceRequest) error { |
| // TODO(https://fxbug.dev/42157659): implement. |
| _ = req.Close() |
| return nil |
| } |
| |
| func (*directoryState) CreateSymlink(fidl.Context, string, []uint8, io.SymlinkWithCtxInterfaceRequest) (io.Directory2CreateSymlinkResult, error) { |
| return io.Directory2CreateSymlinkResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (dirState *directoryState) ReadDirents(ctx fidl.Context, maxOut uint64) (int32, []uint8, error) { |
| if !dirState.reading { |
| writeFn := func(name string, node Node) error { |
| ioNode, cleanup, err := node.getIO() |
| if err != nil { |
| return err |
| } |
| defer cleanup() |
| status, attr, err := ioNode.GetAttr(ctx) |
| if err != nil { |
| return err |
| } |
| if status := zx.Status(status); status != zx.ErrOk { |
| return fmt.Errorf("io.Node.GetAttr returned non-ok zx.Status %s", status) |
| } |
| dirent := syscall.Dirent{ |
| Ino: attr.Id, |
| Size: uint8(len(name)), |
| Type: uint8(func() io.DirentType { |
| switch modeType := attr.Mode & io.ModeTypeMask; modeType { |
| case io.ModeTypeDirectory: |
| return io.DirentTypeDirectory |
| case io.ModeTypeFile: |
| return io.DirentTypeFile |
| case io.ModeTypeService: |
| return io.DirentTypeService |
| default: |
| panic(fmt.Sprintf("unknown mode type: %b", modeType)) |
| } |
| }()), |
| } |
| if err := binary.Write(&dirState.dirents, binary.LittleEndian, dirent); err != nil { |
| return err |
| } |
| dirState.dirents.Truncate(dirState.dirents.Len() - int(unsafe.Sizeof(syscall.Dirent{}.Name))) |
| if _, err := dirState.dirents.WriteString(name); err != nil { |
| return err |
| } |
| return nil |
| } |
| if err := writeFn(dot, dirState); err != nil { |
| return 0, nil, err |
| } |
| if err := dirState.Directory.ForEach(writeFn); err != nil { |
| return 0, nil, err |
| } |
| dirState.reading = true |
| } else if dirState.dirents.Len() == 0 { |
| status, err := dirState.Rewind(ctx) |
| if err != nil { |
| return 0, nil, err |
| } |
| if status := zx.Status(status); status != zx.ErrOk { |
| return 0, nil, fmt.Errorf("dirState.Rewind(_) = %s", status) |
| } |
| } |
| return int32(zx.ErrOk), dirState.dirents.Next(int(maxOut)), nil |
| } |
| |
| func (dirState *directoryState) Rewind(fidl.Context) (int32, error) { |
| dirState.reading = false |
| dirState.dirents.Reset() |
| return int32(zx.ErrOk), nil |
| } |
| |
| func (*directoryState) GetToken(fidl.Context) (int32, zx.Handle, error) { |
| return int32(zx.ErrNotSupported), zx.HandleInvalid, nil |
| } |
| |
| func (*directoryState) Rename(fidl.Context, string, zx.Event, string) (io.Directory2RenameResult, error) { |
| return io.Directory2RenameResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) Link(fidl.Context, string, zx.Handle, string) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*directoryState) Watch(_ fidl.Context, _ io.WatchMask, _ uint32, watcher io.DirectoryWatcherWithCtxInterfaceRequest) (int32, error) { |
| if err := watcher.Close(); err != nil { |
| logError(err) |
| } |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*directoryState) GetFlags(fidl.Context) (int32, io.OpenFlags, error) { |
| return int32(zx.ErrNotSupported), 0, nil |
| } |
| |
| func (*directoryState) SetFlags(fidl.Context, io.OpenFlags) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (dirState *directoryState) AdvisoryLock(fidl.Context, io.AdvisoryLockRequest) (io.AdvisoryLockingAdvisoryLockResult, error) { |
| return io.AdvisoryLockingAdvisoryLockResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*directoryState) QueryFilesystem(fidl.Context) (int32, *io.FilesystemInfo, error) { |
| return int32(zx.ErrNotSupported), nil, nil |
| } |
| |
| func (*directoryState) Query(fidl.Context) ([]uint8, error) { |
| return []byte(io.DirectoryProtocolName_), nil |
| } |
| |
| type File interface { |
| // If error is non-nil, GetReader returns a component.Reader for the file |
| // contents, and the length of the file contents. |
| GetReader() (Reader, uint64, error) |
| } |
| |
| var _ File = (*pprofFile)(nil) |
| |
| type pprofFile struct { |
| p *pprof.Profile |
| } |
| |
| func (p *pprofFile) GetReader() (Reader, uint64, error) { |
| var b bytes.Buffer |
| if err := p.p.WriteTo(&b, 0); err != nil { |
| return nil, 0, err |
| } |
| return NoVMO(NopCloser(bytes.NewReader(b.Bytes()))), uint64(b.Len()), nil |
| } |
| |
| var _ File = (*stackTraceFile)(nil) |
| |
| // stackTraceFile provides a File implementation to expose goroutine |
| // stacks. |
| type stackTraceFile struct{} |
| |
| func (f *stackTraceFile) GetReader() (Reader, uint64, error) { |
| buf := make([]byte, 4096) |
| for { |
| n := runtime.Stack(buf, true) |
| if n < len(buf) { |
| return NoVMO(NopCloser(bytes.NewReader(buf[:n]))), uint64(n), nil |
| } |
| buf = make([]byte, 2*len(buf)) |
| } |
| } |
| |
| var _ Node = (*FileWrapper)(nil) |
| |
| type FileWrapper struct { |
| File File |
| } |
| |
| func (file *FileWrapper) getFileState() (*fileState, error) { |
| reader, size, err := file.File.GetReader() |
| if err != nil { |
| return nil, err |
| } |
| return &fileState{ |
| FileWrapper: file, |
| reader: reader, |
| size: size, |
| }, nil |
| } |
| |
| func (file *FileWrapper) GetFile() (io.FileWithCtx, error) { |
| return file.getFileState() |
| } |
| |
| func (file *FileWrapper) getIO() (io.NodeWithCtx, func() error, error) { |
| state, err := file.getFileState() |
| if err != nil { |
| return nil, noop, err |
| } |
| return state, state.reader.Close, nil |
| } |
| |
| func (file *FileWrapper) addConnection(ctx fidl.Context, flags io.OpenFlags, mode io.ModeType, req io.NodeWithCtxInterfaceRequest) error { |
| ioFile, err := file.getFileState() |
| if err != nil { |
| return err |
| } |
| stub := io.FileWithCtxStub{Impl: ioFile} |
| go func() { |
| defer ioFile.reader.Close() |
| Serve(context.Background(), &stub, req.Channel, ServeOptions{ |
| OnError: logError, |
| }) |
| }() |
| return respond(ctx, flags, req, nil, ioFile) |
| } |
| |
| var _ io.FileWithCtx = (*fileState)(nil) |
| |
| type ReaderWithoutCloser interface { |
| stdio.Reader |
| stdio.ReaderAt |
| stdio.Seeker |
| } |
| |
| type ReaderWithoutGetVMO interface { |
| ReaderWithoutCloser |
| stdio.Closer |
| } |
| |
| type Reader interface { |
| ReaderWithoutGetVMO |
| // GetVMO returns a pointer to the Reader's handle to its backing VMO, if the |
| // Reader is backed by a VMO. |
| GetVMO() *zx.VMO |
| } |
| |
| type nopCloser struct { |
| ReaderWithoutCloser |
| } |
| |
| func (nopCloser) Close() error { return nil } |
| |
| // NopCloser implements Closer for Readers that don't need closing. We can't just use io.NopCloser() |
| // because it doesn't compose with stdio.ReaderAt. |
| func NopCloser(r ReaderWithoutCloser) ReaderWithoutGetVMO { |
| return nopCloser{ReaderWithoutCloser: r} |
| } |
| |
| type noVMO struct { |
| ReaderWithoutGetVMO |
| } |
| |
| func (*noVMO) GetVMO() *zx.VMO { |
| return nil |
| } |
| |
| // NoVMO implements GetVMO for Readers that don't have a backing VMO. |
| func NoVMO(r ReaderWithoutGetVMO) Reader { |
| return &noVMO{ReaderWithoutGetVMO: r} |
| } |
| |
| type fileState struct { |
| *FileWrapper |
| reader Reader |
| size uint64 |
| } |
| |
| func (fState *fileState) Clone(ctx fidl.Context, flags io.OpenFlags, req io.NodeWithCtxInterfaceRequest) error { |
| return fState.addConnection(ctx, flags, 0, req) |
| } |
| |
| func (fState *fileState) Reopen(ctx fidl.Context, rights io.RightsRequest, req io.NodeWithCtxInterfaceRequest) error { |
| // TODO(https://fxbug.dev/42157659): implement. |
| _ = req.Close() |
| return nil |
| } |
| |
| func (fState *fileState) Close(fidl.Context) (unknown.CloseableCloseResult, error) { |
| return unknown.CloseableCloseResultWithResponse(unknown.CloseableCloseResponse{}), fState.reader.Close() |
| } |
| |
| func (*FileWrapper) DescribeDeprecated(fidl.Context) (io.NodeInfoDeprecated, error) { |
| var nodeInfo io.NodeInfoDeprecated |
| nodeInfo.SetFile(io.FileObject{}) |
| return nodeInfo, nil |
| } |
| |
| func (fState *fileState) Describe(fidl.Context) (io.FileInfo, error) { |
| var fileInfo io.FileInfo |
| return fileInfo, nil |
| } |
| |
| func (*fileState) LinkInto(fidl.Context, zx.Event, string) (io.LinkableLinkIntoResult, error) { |
| return io.LinkableLinkIntoResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (fState *fileState) GetConnectionInfo(fidl.Context) (io.ConnectionInfo, error) { |
| var connectionInfo io.ConnectionInfo |
| // TODO(https://fxbug.dev/42157659): Populate the rights requested by the client at connection. |
| rights := io.RStarDir |
| connectionInfo.SetRights(rights) |
| return connectionInfo, nil |
| } |
| |
| func (*fileState) Sync(fidl.Context) (io.Node2SyncResult, error) { |
| return io.Node2SyncResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (fState *fileState) GetAttr(fidl.Context) (int32, io.NodeAttributes, error) { |
| return int32(zx.ErrOk), io.NodeAttributes{ |
| Mode: uint32(io.ModeTypeFile) | uint32(fdio.VtypeIRUSR), |
| Id: io.InoUnknown, |
| ContentSize: fState.size, |
| LinkCount: 1, |
| }, nil |
| } |
| |
| func (*fileState) SetAttr(fidl.Context, io.NodeAttributeFlags, io.NodeAttributes) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*fileState) GetAttributes(fidl.Context, io.NodeAttributesQuery) (io.Node2GetAttributesResult, error) { |
| // TODO(https://fxbug.dev/42157659): implement. |
| return io.Node2GetAttributesResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) UpdateAttributes(fidl.Context, io.MutableNodeAttributes) (io.Node2UpdateAttributesResult, error) { |
| // TODO(https://fxbug.dev/42157659): implement. |
| return io.Node2UpdateAttributesResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) ListExtendedAttributes(_ fidl.Context, request io.ExtendedAttributeIteratorWithCtxInterfaceRequest) error { |
| _ = request.Close() |
| return nil |
| } |
| |
| func (*fileState) GetExtendedAttribute(fidl.Context, []uint8) (io.Node2GetExtendedAttributeResult, error) { |
| return io.Node2GetExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) SetExtendedAttribute(fidl.Context, []uint8, io.ExtendedAttributeValue, io.SetExtendedAttributeMode) (io.Node2SetExtendedAttributeResult, error) { |
| return io.Node2SetExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) RemoveExtendedAttribute(fidl.Context, []uint8) (io.Node2RemoveExtendedAttributeResult, error) { |
| return io.Node2RemoveExtendedAttributeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) Allocate(fidl.Context, uint64, uint64, io.AllocateMode) (io.FileAllocateResult, error) { |
| return io.FileAllocateResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) EnableVerity(fidl.Context, io.VerificationOptions) (io.FileEnableVerityResult, error) { |
| return io.FileEnableVerityResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (fState *fileState) Read(_ fidl.Context, count uint64) (io.ReadableReadResult, error) { |
| if l := fState.size; l < count { |
| count = l |
| } |
| b := make([]byte, count) |
| n, err := fState.reader.Read(b) |
| if err != nil && err != stdio.EOF { |
| return io.ReadableReadResult{}, err |
| } |
| b = b[:n] |
| return io.ReadableReadResultWithResponse(io.ReadableReadResponse{ |
| Data: b, |
| }), nil |
| } |
| |
| func (fState *fileState) ReadAt(_ fidl.Context, count uint64, offset uint64) (io.FileReadAtResult, error) { |
| if l := fState.size - offset; l < count { |
| count = l |
| } |
| b := make([]byte, count) |
| n, err := fState.reader.ReadAt(b, int64(offset)) |
| if err != nil && err != stdio.EOF { |
| return io.FileReadAtResult{}, err |
| } |
| b = b[:n] |
| return io.FileReadAtResultWithResponse(io.FileReadAtResponse{ |
| Data: b, |
| }), nil |
| } |
| |
| func (*fileState) Write(fidl.Context, []uint8) (io.WritableWriteResult, error) { |
| return io.WritableWriteResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) WriteAt(fidl.Context, []uint8, uint64) (io.FileWriteAtResult, error) { |
| return io.FileWriteAtResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (fState *fileState) Seek(_ fidl.Context, origin io.SeekOrigin, offset int64) (io.FileSeekResult, error) { |
| n, err := fState.reader.Seek(offset, int(origin)) |
| return io.FileSeekResultWithResponse( |
| io.FileSeekResponse{ |
| OffsetFromStart: uint64(n), |
| }), err |
| } |
| |
| func (*fileState) Resize(fidl.Context, uint64) (io.FileResizeResult, error) { |
| return io.FileResizeResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |
| |
| func (*fileState) GetFlags(fidl.Context) (int32, io.OpenFlags, error) { |
| return int32(zx.ErrNotSupported), 0, nil |
| } |
| |
| func (*fileState) SetFlags(fidl.Context, io.OpenFlags) (int32, error) { |
| return int32(zx.ErrNotSupported), nil |
| } |
| |
| func (*fileState) QueryFilesystem(fidl.Context) (int32, *io.FilesystemInfo, error) { |
| return int32(zx.ErrNotSupported), nil, nil |
| } |
| |
| func (*fileState) Query(fidl.Context) ([]byte, error) { |
| return []byte(io.FileProtocolName_), nil |
| } |
| |
| func (fState *fileState) AdvisoryLock(fidl.Context, io.AdvisoryLockRequest) (io.AdvisoryLockingAdvisoryLockResult, error) { |
| return io.AdvisoryLockingAdvisoryLockResult{}, &zx.Error{Status: zx.ErrNotSupported, Text: fmt.Sprintf("%T", fState)} |
| } |
| |
| func (fState *fileState) GetBackingMemory(fidl.Context, io.VmoFlags) (io.FileGetBackingMemoryResult, error) { |
| if vmo := fState.reader.GetVMO(); vmo != nil { |
| // TODO(https://fxbug.dev/42157659): The rights on this VMO should be capped at the connection's. |
| h, err := vmo.Handle().Duplicate(zx.RightSameRights) |
| switch err := err.(type) { |
| case nil: |
| return io.FileGetBackingMemoryResultWithResponse(io.FileGetBackingMemoryResponse{ |
| Vmo: zx.VMO(h), |
| }), nil |
| case *zx.Error: |
| return io.FileGetBackingMemoryResultWithErr(int32(err.Status)), nil |
| default: |
| return io.FileGetBackingMemoryResult{}, err |
| } |
| } |
| return io.FileGetBackingMemoryResultWithErr(int32(zx.ErrNotSupported)), nil |
| } |