fs

package
v1.18.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2021 License: MIT Imports: 15 Imported by: 11

Documentation

Overview

Package fs is an package that implements a hierarchical filesystem as a struct, FS. An FS contains a hierarchy of Dirs and Files. The package also contains other types and functions useful for building 9p filesystems.

Constructing simple filesystems is easy. For example, creating a filesystem with a single file with static contents "Hello, World!" can be done as follows:

staticFS := fs.NewFS("glenda", "glenda", 0555)
staticFS.Root.AddChild(fs.NewStaticFile(
	staticFS.NewStat("name.of.file", "owner.name", "group.name", 0444),
	[]byte("Hello, World!\n"),
))

The filesystem can be served with one of the functions from github.com/knusbaum/go9p:

go9p.PostSrv("example", staticFS.Server())

There are more examples in this package and in github.com/knusbaum/go9p/examples

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func FullPath

func FullPath(f FSNode) string

FullPath is a helper function that assembles the names of all the parent nodes of f into a full path string.

func NewFS

func NewFS(rootUser, rootGroup string, rootPerms uint32, opts ...Option) (*FS, *StaticDir)

NewFS constructs and returns an *FS. Options may be passed to do things like setting the various hook functions.

func PlainAuth

func PlainAuth(userpass map[string]string) func(io.ReadWriter) (string, error)

PlainAuth takes a map of username to password.

func Plan9Auth

func Plan9Auth(s io.ReadWriter) (string, error)

func RMFile

func RMFile(fs *FS, f FSNode) error

RMFile is a function intended to be used with the WithRemoveFile Option. RMFile simply enables the deletion of files and directories on the FS subject to usual permissions checks.

Example
package main

import (
	"github.com/knusbaum/go9p"
	"github.com/knusbaum/go9p/fs"
)

func main() {
	staticFS, root := fs.NewFS("glenda", "glenda", 0555,
		// This Option will cause the FS to call fs.RMFile when a user with
		// permission attempts to remove a file. fs.RMFile simply deletes
		// the file with no further checking.
		fs.WithRemoveFile(fs.RMFile),
	)
	root.AddChild(fs.NewStaticFile(
		// Note the permissions 0544. Someone authenticated as the user "glenda"
		// will have the permission to remove the file.
		staticFS.NewStat("hello", "owner.name", "group.name", 0544),
		[]byte("Hello, World!\n"),
	))

	go9p.Serve("localhost:9999", staticFS.Server())
}
Output:

Types

type BaseFile

type BaseFile struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

BaseFile provides a simple File implementation that other implementations can base themselves off of. On its own it's not too useful. Stat and WriteStat work as expected, as do Parent and SetParent. Open always succeeds. Read always returns a zero-byte slice, Write always fails, and Close always succeeds.

Note, BaseFile is most useful when you want to create a custom File type rather than creating a single special file. Most of the time, you may want to use WrappedFile for custom behavior.

Example

ExampleBaseFile demonstrates how to use a BaseFile to create a File type with custom behavior. In this case, we override the Read() function to return random bytes.

package main

import (
	"math/rand"

	"github.com/knusbaum/go9p"
	"github.com/knusbaum/go9p/fs"
)

type randomFile struct {
	fs.BaseFile
}

func (f *randomFile) Read(fid uint32, offset, count uint64) ([]byte, error) {
	bs := make([]byte, count)
	rand.Read(bs)
	return bs, nil
}

func main() {
	//	type randomFile struct {
	//		fs.BaseFile
	//	}
	//
	//	func (f *randomFile) Read(fid uint32, offset, count uint64) ([]byte, error) {
	//		bs := make([]byte, count)
	//		rand.Read(bs)
	//		return bs, nil
	//	}

	randomFS, root := fs.NewFS("glenda", "glenda", 0555)
	root.AddChild(&randomFile{
		*fs.NewBaseFile(randomFS.NewStat("random", "owner.name", "group.name", 0444)),
	})

	go9p.Serve("localhost:9999", randomFS.Server())
}
Output:

func NewBaseFile

func NewBaseFile(s *proto.Stat) *BaseFile

func (*BaseFile) Close

func (f *BaseFile) Close(fid uint64) error

Close always succeeds.

func (*BaseFile) Open

func (f *BaseFile) Open(fid uint64, omode proto.Mode) error

Open always succeeds.

func (*BaseFile) Parent

func (f *BaseFile) Parent() Dir

func (*BaseFile) Read

func (f *BaseFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

Read always returns an empty slice.

func (*BaseFile) SetParent

func (f *BaseFile) SetParent(p Dir)

func (*BaseFile) Stat

func (f *BaseFile) Stat() proto.Stat

func (*BaseFile) Write

func (f *BaseFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

Write always fails with an error.

func (*BaseFile) WriteStat

func (f *BaseFile) WriteStat(s *proto.Stat) error

type BaseNode

type BaseNode struct {
	FStat   proto.Stat
	FParent Dir
}

BaseNode provides a basic FSNode. It is intended to be embedded in other structures implementing either the File or Dir interfaces.

func NewBaseNode

func NewBaseNode(fs *FS, parent Dir, name, uid, gid string, mode uint32) BaseNode

func (*BaseNode) Parent

func (n *BaseNode) Parent() Dir

func (*BaseNode) SetParent

func (n *BaseNode) SetParent(d Dir)

func (*BaseNode) Stat

func (n *BaseNode) Stat() proto.Stat

func (*BaseNode) WriteStat

func (n *BaseNode) WriteStat(s *proto.Stat) error

type BiDiStream

type BiDiStream interface {
	Stream
	AddReadWriter() StreamReadWriter
	Read(p []byte) (n int, err error)
}

A BiDiStream is a bi-directional stream. It adds two methods to the Stream interface, AddReadWriter and Read. BiDiStream allows Read()s of data written by StreamReadWriters. Although there is no way to determine which StreamReadWriter wrote the bytes read by Read(), it is guaranteed that a Write()s done by StreamReadWriters are delivered as complete chunks. That is, all bytes from a single StreamReadWriter.Write() call will be read by Read() before bytes from another StreamReader.Write() will be read.

type BiDiStreamFile

type BiDiStreamFile struct {
	*BaseFile
	// contains filtered or unexported fields
}

BiDiStreamFile implements a two-way (full-duplex) stream. Writes to the stream will be read by clients who open the file. Writes by clients will be received by calls to Read() on the stream.

func (*BiDiStreamFile) Close

func (f *BiDiStreamFile) Close(fid uint64) error

func (*BiDiStreamFile) Open

func (f *BiDiStreamFile) Open(fid uint64, omode proto.Mode) error

func (*BiDiStreamFile) Read

func (f *BiDiStreamFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

func (*BiDiStreamFile) Stat

func (f *BiDiStreamFile) Stat() proto.Stat

func (*BiDiStreamFile) Write

func (f *BiDiStreamFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

type BlockingStream

type BlockingStream struct {
	// contains filtered or unexported fields
}

A BlockingStream will ensure all data is written to active StreamReaders, or block if the readers are unable to receive the data. A certain number of bytes of data is buffered (see NewBlockingStream). If an unresponsive reader is removed, Write will be able to continue.

func NewBlockingStream

func NewBlockingStream(buffer int) *BlockingStream

func (*BlockingStream) AddReadWriter

func (s *BlockingStream) AddReadWriter() StreamReadWriter

func (*BlockingStream) AddReader

func (s *BlockingStream) AddReader() StreamReader

func (*BlockingStream) Close

func (s *BlockingStream) Close() error

func (*BlockingStream) Read

func (s *BlockingStream) Read(p []byte) (n int, err error)

func (*BlockingStream) RemoveReader

func (s *BlockingStream) RemoveReader(r StreamReader)

func (*BlockingStream) Write

func (s *BlockingStream) Write(p []byte) (n int, err error)

type Dir

type Dir interface {
	FSNode
	Children() map[string]FSNode
}

Dir represents a directory within the Filesystem.

func CreateStaticDir

func CreateStaticDir(fs *FS, parent Dir, user, name string, perm uint32, mode uint8) (Dir, error)

CreateStaticDir is a function meant to be passed to WithCreateDir. It will add an empty StaticDir to the FS whenever a client attempts to create a directory.

type DroppingStream

type DroppingStream struct {
	// contains filtered or unexported fields
}

DroppingStream is a stream which will disconnect readers who aren't able to keep up with the writer. The writer will slow down when writing (pausing for 50ms) to allow slower clients to catch up, but those that cannot keep up will be closed.

func NewDroppingStream

func NewDroppingStream(buffer int) *DroppingStream

func (*DroppingStream) AddReadWriter

func (s *DroppingStream) AddReadWriter() StreamReadWriter

func (*DroppingStream) AddReader

func (s *DroppingStream) AddReader() StreamReader

func (*DroppingStream) Close

func (s *DroppingStream) Close() error

func (*DroppingStream) Read

func (s *DroppingStream) Read(p []byte) (n int, err error)

func (*DroppingStream) RemoveReader

func (s *DroppingStream) RemoveReader(r StreamReader)

func (*DroppingStream) Write

func (s *DroppingStream) Write(p []byte) (n int, err error)

type DynamicFile

type DynamicFile struct {
	BaseFile
	// contains filtered or unexported fields
}

DynamicFile is a File implementation that will serve dynamic content. Every time a client opens the DynamicFile, content is generated for the opening fid with the function genContent, which is passed to NewDynamicFile. Subsequent reads on the fid will return byte ranges from that content generated when the fid was opened. Closing the fid releases the content.

Example
package main

import (
	"time"

	"github.com/knusbaum/go9p"
	"github.com/knusbaum/go9p/fs"
)

func main() {
	dynamicFS, root := fs.NewFS("glenda", "glenda", 0555)
	root.AddChild(fs.NewDynamicFile(
		dynamicFS.NewStat("name.of.file", "owner.name", "group.name", 0444),
		func() []byte {
			return []byte(time.Now().String() + "\n")
		},
	))
	go9p.Serve("localhost:9999", dynamicFS.Server())
}
Output:

func NewDynamicFile

func NewDynamicFile(s *proto.Stat, genContent func() []byte) *DynamicFile

NewDynamicFile creates a new DynamicFile that will use getContent to generate the file's content for each fid that opens it.

func (*DynamicFile) Close

func (f *DynamicFile) Close(fid uint64) error

func (*DynamicFile) Open

func (f *DynamicFile) Open(fid uint64, omode proto.Mode) error

func (*DynamicFile) Read

func (f *DynamicFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

type FS

type FS struct {
	Root       Dir
	CreateFile func(fs *FS, parent Dir, user, name string, perm uint32, mode uint8) (File, error)
	CreateDir  func(fs *FS, parent Dir, user, name string, perm uint32, mode uint8) (Dir, error)
	WalkFail   func(fs *FS, parent Dir, name string) (FSNode, error)
	RemoveFile func(fs *FS, f FSNode) error

	sync.RWMutex
	// contains filtered or unexported fields
}

The FS structure represents a hierarchical filesystem tree. It must contain a Root Dir, but all of the function members are optional. If provided, CreateFile is called when a client attempts to create a file. Similarly, CreateDir is called when a client attempts to create a directory. WalkFail's usefulness is dubious, but is called when a client walks to a path that does not exist in the fs. It can be used to create files on the fly. CreateFile returns a File, CreateDir returns a Dir, and WalkFail should return either a File or a Dir. All three can return an error, in which case the Error() will be returned to the client in a proto.TError. nil, nil is also an appropriate return pair, in which case a proto.TError with a generic message will be returned to the client.

FS is a tree structure. Every internal node should be a Dir - only instances of Dir can have children. Instances of File can only be leaves of the tree.

func (*FS) NewQid

func (fs *FS) NewQid(statMode uint32) proto.Qid

NewQid generates a new, unique proto.Qid for use in a new file. Each file in the FS should have a unique proto.Qid. statMode should come from the file's Stat().Mode

func (*FS) NewStat

func (fs *FS) NewStat(name, uid, gid string, mode uint32) *proto.Stat

NewStat creates and returns a new proto.Stat object for use with a FSNode. name will be the name of the node, and it will be owned by user uid and group gid. mode is standard unix permissions bits, along with any special mode bits (e.g. proto.DMDIR for directories)

func (*FS) Server

func (fs *FS) Server() go9p.Srv

Server returns a go9p.Srv instance which will serve the 9p2000 protocol.

type FSNode

type FSNode interface {
	Stat() proto.Stat
	WriteStat(s *proto.Stat) error
	SetParent(d Dir)
	Parent() Dir
}

FSNode represents a node in a FS tree. It should track its Parent, which should be the Dir that the FSNode belongs to. SetParent should not be called directly. Instead, use the AddChild and DeleteChild functions on a Dir to add, remove, and move FSNodes around a filesystem.

type File

type File interface {
	FSNode
	Open(fid uint64, omode proto.Mode) error
	Read(fid uint64, offset uint64, count uint64) ([]byte, error)
	Write(fid uint64, offset uint64, data []byte) (uint32, error)
	Close(fid uint64) error
}

File represents a leaf node in the FS tree. It must implement Open, Read, Write, and Close methods. fid is a unique number representing an open file descriptor to the file. For each fid, Open will be called before Read, Write, or Close, and should open a file in the given omode, or return an error. If Open returns an error, fid is not valid. Following a successful Open, a given fid represents the same file descriptor until Close is called. Read requests count bytes at offset in the file, for file descriptor fid. Similarly, Write should write data into the file from file descriptor fid at offset. Both Read and Write may return error, which will be sent back to the client in a proto.TError message.

See StaticFile for a simple File implementation.

func CreateStaticFile

func CreateStaticFile(fs *FS, parent Dir, user, name string, perm uint32, mode uint8) (File, error)

CreateStaticFile is a function meant to be passed to WithCreateFile. It will add an empty StaticFile to the FS whenever a client attempts to create a file.

func NewStreamFile

func NewStreamFile(stat *proto.Stat, s Stream) File

NewStreamFile creates a file that serves a stream to clients. If the Stream s implements the BiDiStream protocol, a BiDiStreamFile is returned. Otherwise a StreamFile is returned. Each Open() creates a new Reader or ReadWriter on the stream, and subsequent reads and writes on that fid operate on that Reader or ReadWriter. A Close() on a fid will close the Reader/ReadWriter.

type ListenFile

type ListenFile struct {
	BaseFile
	// contains filtered or unexported fields
}

ListenFile implements a net.Listener as a 9p File. The file is a stream, so offsets for Read and Write are ignored.

func NewListenFile

func NewListenFile(s *proto.Stat) *ListenFile

func (*ListenFile) Close

func (f *ListenFile) Close(fid uint64) error

func (*ListenFile) Open

func (f *ListenFile) Open(fid uint64, omode proto.Mode) error

func (*ListenFile) Read

func (f *ListenFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

func (*ListenFile) Write

func (f *ListenFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

type ListenFileListener

type ListenFileListener ListenFile

func (*ListenFileListener) Accept

func (l *ListenFileListener) Accept() (net.Conn, error)

Accept waits for and returns the next connection to the listener.

func (*ListenFileListener) Addr

func (l *ListenFileListener) Addr() net.Addr

Addr returns the listener's network address.

func (*ListenFileListener) Close

func (l *ListenFileListener) Close() error

Close closes the listener. Any blocked Accept operations will be unblocked and return errors.

type ModDir

type ModDir interface {
	Dir
	AddChild(n FSNode) error
	DeleteChild(name string) error
}

ModDir is a directory that allows the adding and removal of child nodes.

type Option

type Option func(*FS)

Options are used to configure an FS with NewFS

func IgnorePermissions

func IgnorePermissions() Option

IgnorePermissions configures the server to not enforce user/group permissions bits. This is useful, for instance, when permissions need to be enforced at a higher level, or by an underlying file system that is being exported by the server.

func WithAuth

func WithAuth(authFunc func(s io.ReadWriter) (string, error)) Option

WithAuth configures the server to require authentication. Authentication is performed using the standard plan9 or plan9port tools. A factotum must be running in the same namespace as this server in order to authenticate users. Please see http://man.cat-v.org/9front/4/factotum for more information.

func WithCreateDir

func WithCreateDir(f func(fs *FS, parent Dir, user, name string, perm uint32, mode uint8) (Dir, error)) Option

WithCreateDir configures a function to be called when a client attempts to create a directory on the FS. The function f, if successful, should return a Dir, which it should add to the parent Dir. If a file should not be created, f can return an error which will be sent to the client. Basic permissions checking is done by the FS before calling f, but any other checking can be done by f.

func WithCreateFile

func WithCreateFile(f func(fs *FS, parent Dir, user, name string, perm uint32, mode uint8) (File, error)) Option

WithCreateFile configures a function to be called when a client attempts to create a file on the FS. The function f, if successful, should return a File, which it should add to the parent Dir. If a file should not be created, f can return an error which will be sent to the client. Basic permissions checking is done by the FS before calling f, but any other checking can be done by f.

func WithRemoveFile

func WithRemoveFile(f func(fs *FS, f FSNode) error) Option

WithRemoveFile configures a function to be called when a client attempts to remove a file or directory from the FS. The function f, if successful, should remove the FSNode from its parent Dir, and return nil. If f does not choose to remove the FSNode, it should return an error, which will be sent to the client.

func WithWalkFailHandler

func WithWalkFailHandler(f func(fs *FS, parent Dir, name string) (FSNode, error)) Option

WithWalkFailHandler configures a function to be called when a client attempts to walk a path on the FS that does not exist. The function f may decide to create a File or Directory on the fly, which should be returned. If f chooses not to create an FSNode to satisfy the walk, an error may be returned which will be sent to the client.

type PipeFile

type PipeFile struct {
	*BaseFile
	// contains filtered or unexported fields
}

PipeFile creates a new full-duplex stream for each call to Open() The stream will be passed as a BiDiStream to the handler function passed to NewPipeFile, which will be run in a new goroutine. When that function returns, the stream will be closed.

func NewPipeFile

func NewPipeFile(stat *proto.Stat, handler func(s BiDiStream)) *PipeFile

NewPipeFile creates a new PipeFile that will create a new bi-directional stream for every Open(), starting a goroutine calling handler on the stream. handler should loop to read the stream. When handler returns, the stream will be closed.

func (*PipeFile) Close

func (f *PipeFile) Close(fid uint64) error

func (*PipeFile) Open

func (f *PipeFile) Open(fid uint64, omode proto.Mode) error

func (*PipeFile) Read

func (f *PipeFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

func (*PipeFile) Write

func (f *PipeFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

type SavedStream

type SavedStream struct {
	sync.Mutex
	// contains filtered or unexported fields
}

A SavedStream is a file-backed stream. Readers receive the full contents of the stream starting at the beginning and receive any new Writes.

func NewSavedStream

func NewSavedStream(path string) (*SavedStream, error)

func (*SavedStream) AddReader

func (s *SavedStream) AddReader() StreamReader

func (*SavedStream) Close

func (s *SavedStream) Close() error

func (*SavedStream) RemoveReader

func (s *SavedStream) RemoveReader(r StreamReader)

func (*SavedStream) Write

func (s *SavedStream) Write(p []byte) (n int, err error)

type SkippingStream

type SkippingStream struct {
	// contains filtered or unexported fields
}

A SkippingStream Sends all Writes() to all StreamReaders, skipping those that are not able to keep up. Once a StreamReader starts reading again, it will get new Writes, having skipped some of the data. This may be good for things like event streams, audio, etc.

func NewSkippingStream

func NewSkippingStream(buffer int) *SkippingStream

func (*SkippingStream) AddReadWriter

func (s *SkippingStream) AddReadWriter() StreamReadWriter

func (*SkippingStream) AddReader

func (s *SkippingStream) AddReader() StreamReader

func (*SkippingStream) Close

func (s *SkippingStream) Close() error

func (*SkippingStream) Read

func (s *SkippingStream) Read(p []byte) (n int, err error)

func (*SkippingStream) RemoveReader

func (s *SkippingStream) RemoveReader(r StreamReader)

func (*SkippingStream) Write

func (s *SkippingStream) Write(p []byte) (n int, err error)

type StaticDir

type StaticDir struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

StaticDir is a Dir that simply keeps track of a set of child Files.

func NewStaticDir

func NewStaticDir(stat *proto.Stat) *StaticDir

func (*StaticDir) AddChild

func (d *StaticDir) AddChild(n FSNode) error

func (*StaticDir) Children

func (d *StaticDir) Children() map[string]FSNode

func (*StaticDir) DeleteChild

func (d *StaticDir) DeleteChild(name string) error

func (*StaticDir) Parent

func (d *StaticDir) Parent() Dir

func (*StaticDir) SetParent

func (d *StaticDir) SetParent(p Dir)

func (*StaticDir) Stat

func (d *StaticDir) Stat() proto.Stat

func (*StaticDir) WriteStat

func (d *StaticDir) WriteStat(s *proto.Stat) error

type StaticFile

type StaticFile struct {
	BaseFile
	Data []byte
}

StaticFile implements File. It is a very simple implementation that allows the reading and writing of a byte slice that every client sees. Writes modify the content and reads serve the content.

Example
package main

import (
	"github.com/knusbaum/go9p"
	"github.com/knusbaum/go9p/fs"
)

func main() {
	staticFS, root := fs.NewFS("glenda", "glenda", 0555)
	root.AddChild(fs.NewStaticFile(
		staticFS.NewStat("name.of.file", "owner.name", "group.name", 0444),
		[]byte("Hello, World!\n"),
	))

	go9p.Serve("localhost:9999", staticFS.Server())
}
Output:

func NewStaticFile

func NewStaticFile(s *proto.Stat, data []byte) *StaticFile

NewStaticFile returns a StaticFile that contains the byte slice data.

func (*StaticFile) Open

func (f *StaticFile) Open(fid uint64, omode proto.Mode) error

func (*StaticFile) Read

func (f *StaticFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

func (*StaticFile) Stat

func (f *StaticFile) Stat() proto.Stat

func (*StaticFile) Write

func (f *StaticFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

type Stream

type Stream interface {
	AddReader() StreamReader
	RemoveReader(r StreamReader)
	Write(p []byte) (n int, err error)
	Close() error
	// contains filtered or unexported methods
}

A Stream is a fan-out pipe of data. Stream implements io.Writer, and can have multiple readers associated with it, created with AddReader. How and whether data written with Write() is delivered to every reader is up to the implementation.

For instance, when calling stream.Write([]byte("abc")) on a stream with 3 readers, it is equally valid for a stream to send "abc" to one and nothing to the others, or send "a" to one, "b" to the second, and "c" to the third, or to send "abc" to all three. See individual Stream implementations for their specific behavior.

type StreamFile

type StreamFile struct {
	*BaseFile
	// contains filtered or unexported fields
}

StreamFile implements a one-way stream. Writes by clients return errors.

func (*StreamFile) Close

func (f *StreamFile) Close(fid uint64) error

func (*StreamFile) Open

func (f *StreamFile) Open(fid uint64, omode proto.Mode) error

func (*StreamFile) Read

func (f *StreamFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

func (*StreamFile) Stat

func (f *StreamFile) Stat() proto.Stat

func (*StreamFile) Write

func (f *StreamFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

type StreamReadWriter

type StreamReadWriter interface {
	StreamReader
	Write(p []byte) (n int, err error)
}

A StreamReadWriter is just like a StreamReader, but allows the Reader to send data back to the Stream.

type StreamReader

type StreamReader interface {
	Read(p []byte) (n int, err error)
	Close()
}

A StreamReader reads from a Stream. See Stream.AddReader.

type WrappedFile

type WrappedFile struct {
	File
	OpenF  func(fid uint64, omode proto.Mode) error
	ReadF  func(fid uint64, offset uint64, count uint64) ([]byte, error)
	WriteF func(fid uint64, offset uint64, data []byte) (uint32, error)
	CloseF func(fid uint64) error
}

WrappedFile takes an existing File and adds optional hooks for the Open, Read, Write, and Close functions. OpenF, ReadF, WriteF, and CloseF, if set, are called rather than the File's Open, Read, Write, and Close functions.

Example

ExampleWrappedFile demonstrates how to use a WrappedFile to create a File instance with custom behavior. In this case, we set ReadF to return random bytes.

package main

import (
	"math/rand"

	"github.com/knusbaum/go9p"
	"github.com/knusbaum/go9p/fs"
)

func main() {
	randomFS, root := fs.NewFS("glenda", "glenda", 0555)
	root.AddChild(fs.WrappedFile{
		File: fs.NewBaseFile(randomFS.NewStat("name.of.file", "owner.name", "group.name", 0444)),
		ReadF: func(fid uint64, offset uint64, count uint64) ([]byte, error) {
			bs := make([]byte, count)
			rand.Read(bs)
			return bs, nil
		},
	})

	go9p.Serve("localhost:9999", randomFS.Server())
}
Output:

func (*WrappedFile) Close

func (f *WrappedFile) Close(fid uint64) error

func (*WrappedFile) Open

func (f *WrappedFile) Open(fid uint64, omode proto.Mode) error

func (*WrappedFile) Read

func (f *WrappedFile) Read(fid uint64, offset uint64, count uint64) ([]byte, error)

func (*WrappedFile) Write

func (f *WrappedFile) Write(fid uint64, offset uint64, data []byte) (uint32, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL