diff options
Diffstat (limited to 'pkg/p9/messages.go')
-rw-r--r-- | pkg/p9/messages.go | 2662 |
1 files changed, 2662 insertions, 0 deletions
diff --git a/pkg/p9/messages.go b/pkg/p9/messages.go new file mode 100644 index 000000000..57b89ad7d --- /dev/null +++ b/pkg/p9/messages.go @@ -0,0 +1,2662 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package p9 + +import ( + "fmt" + "math" + + "gvisor.dev/gvisor/pkg/fd" +) + +// ErrInvalidMsgType is returned when an unsupported message type is found. +type ErrInvalidMsgType struct { + MsgType +} + +// Error returns a useful string. +func (e *ErrInvalidMsgType) Error() string { + return fmt.Sprintf("invalid message type: %d", e.MsgType) +} + +// message is a generic 9P message. +type message interface { + encoder + fmt.Stringer + + // Type returns the message type number. + Type() MsgType +} + +// payloader is a special message which may include an inline payload. +type payloader interface { + // FixedSize returns the size of the fixed portion of this message. + FixedSize() uint32 + + // Payload returns the payload for sending. + Payload() []byte + + // SetPayload returns the decoded message. + // + // This is going to be total message size - FixedSize. But this should + // be validated during decode, which will be called after SetPayload. + SetPayload([]byte) +} + +// filer is a message capable of passing a file. +type filer interface { + // FilePayload returns the file payload. + FilePayload() *fd.FD + + // SetFilePayload sets the file payload. + SetFilePayload(*fd.FD) +} + +// filePayload embeds a File object. +type filePayload struct { + File *fd.FD +} + +// FilePayload returns the file payload. +func (f *filePayload) FilePayload() *fd.FD { + return f.File +} + +// SetFilePayload sets the received file. +func (f *filePayload) SetFilePayload(file *fd.FD) { + f.File = file +} + +// Tversion is a version request. +type Tversion struct { + // MSize is the message size to use. + MSize uint32 + + // Version is the version string. + // + // For this implementation, this must be 9P2000.L. + Version string +} + +// decode implements encoder.decode. +func (t *Tversion) decode(b *buffer) { + t.MSize = b.Read32() + t.Version = b.ReadString() +} + +// encode implements encoder.encode. +func (t *Tversion) encode(b *buffer) { + b.Write32(t.MSize) + b.WriteString(t.Version) +} + +// Type implements message.Type. +func (*Tversion) Type() MsgType { + return MsgTversion +} + +// String implements fmt.Stringer. +func (t *Tversion) String() string { + return fmt.Sprintf("Tversion{MSize: %d, Version: %s}", t.MSize, t.Version) +} + +// Rversion is a version response. +type Rversion struct { + // MSize is the negotiated size. + MSize uint32 + + // Version is the negotiated version. + Version string +} + +// decode implements encoder.decode. +func (r *Rversion) decode(b *buffer) { + r.MSize = b.Read32() + r.Version = b.ReadString() +} + +// encode implements encoder.encode. +func (r *Rversion) encode(b *buffer) { + b.Write32(r.MSize) + b.WriteString(r.Version) +} + +// Type implements message.Type. +func (*Rversion) Type() MsgType { + return MsgRversion +} + +// String implements fmt.Stringer. +func (r *Rversion) String() string { + return fmt.Sprintf("Rversion{MSize: %d, Version: %s}", r.MSize, r.Version) +} + +// Tflush is a flush request. +type Tflush struct { + // OldTag is the tag to wait on. + OldTag Tag +} + +// decode implements encoder.decode. +func (t *Tflush) decode(b *buffer) { + t.OldTag = b.ReadTag() +} + +// encode implements encoder.encode. +func (t *Tflush) encode(b *buffer) { + b.WriteTag(t.OldTag) +} + +// Type implements message.Type. +func (*Tflush) Type() MsgType { + return MsgTflush +} + +// String implements fmt.Stringer. +func (t *Tflush) String() string { + return fmt.Sprintf("Tflush{OldTag: %d}", t.OldTag) +} + +// Rflush is a flush response. +type Rflush struct { +} + +// decode implements encoder.decode. +func (*Rflush) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rflush) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rflush) Type() MsgType { + return MsgRflush +} + +// String implements fmt.Stringer. +func (r *Rflush) String() string { + return "RFlush{}" +} + +// Twalk is a walk request. +type Twalk struct { + // FID is the FID to be walked. + FID FID + + // NewFID is the resulting FID. + NewFID FID + + // Names are the set of names to be walked. + Names []string +} + +// decode implements encoder.decode. +func (t *Twalk) decode(b *buffer) { + t.FID = b.ReadFID() + t.NewFID = b.ReadFID() + n := b.Read16() + t.Names = t.Names[:0] + for i := 0; i < int(n); i++ { + t.Names = append(t.Names, b.ReadString()) + } +} + +// encode implements encoder.encode. +func (t *Twalk) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteFID(t.NewFID) + b.Write16(uint16(len(t.Names))) + for _, name := range t.Names { + b.WriteString(name) + } +} + +// Type implements message.Type. +func (*Twalk) Type() MsgType { + return MsgTwalk +} + +// String implements fmt.Stringer. +func (t *Twalk) String() string { + return fmt.Sprintf("Twalk{FID: %d, NewFID: %d, Names: %v}", t.FID, t.NewFID, t.Names) +} + +// Rwalk is a walk response. +type Rwalk struct { + // QIDs are the set of QIDs returned. + QIDs []QID +} + +// decode implements encoder.decode. +func (r *Rwalk) decode(b *buffer) { + n := b.Read16() + r.QIDs = r.QIDs[:0] + for i := 0; i < int(n); i++ { + var q QID + q.decode(b) + r.QIDs = append(r.QIDs, q) + } +} + +// encode implements encoder.encode. +func (r *Rwalk) encode(b *buffer) { + b.Write16(uint16(len(r.QIDs))) + for _, q := range r.QIDs { + q.encode(b) + } +} + +// Type implements message.Type. +func (*Rwalk) Type() MsgType { + return MsgRwalk +} + +// String implements fmt.Stringer. +func (r *Rwalk) String() string { + return fmt.Sprintf("Rwalk{QIDs: %v}", r.QIDs) +} + +// Tclunk is a close request. +type Tclunk struct { + // FID is the FID to be closed. + FID FID +} + +// decode implements encoder.decode. +func (t *Tclunk) decode(b *buffer) { + t.FID = b.ReadFID() +} + +// encode implements encoder.encode. +func (t *Tclunk) encode(b *buffer) { + b.WriteFID(t.FID) +} + +// Type implements message.Type. +func (*Tclunk) Type() MsgType { + return MsgTclunk +} + +// String implements fmt.Stringer. +func (t *Tclunk) String() string { + return fmt.Sprintf("Tclunk{FID: %d}", t.FID) +} + +// Rclunk is a close response. +type Rclunk struct { +} + +// decode implements encoder.decode. +func (*Rclunk) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rclunk) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rclunk) Type() MsgType { + return MsgRclunk +} + +// String implements fmt.Stringer. +func (r *Rclunk) String() string { + return "Rclunk{}" +} + +// Tremove is a remove request. +// +// This will eventually be replaced by Tunlinkat. +type Tremove struct { + // FID is the FID to be removed. + FID FID +} + +// decode implements encoder.decode. +func (t *Tremove) decode(b *buffer) { + t.FID = b.ReadFID() +} + +// encode implements encoder.encode. +func (t *Tremove) encode(b *buffer) { + b.WriteFID(t.FID) +} + +// Type implements message.Type. +func (*Tremove) Type() MsgType { + return MsgTremove +} + +// String implements fmt.Stringer. +func (t *Tremove) String() string { + return fmt.Sprintf("Tremove{FID: %d}", t.FID) +} + +// Rremove is a remove response. +type Rremove struct { +} + +// decode implements encoder.decode. +func (*Rremove) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rremove) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rremove) Type() MsgType { + return MsgRremove +} + +// String implements fmt.Stringer. +func (r *Rremove) String() string { + return "Rremove{}" +} + +// Rlerror is an error response. +// +// Note that this replaces the error code used in 9p. +type Rlerror struct { + Error uint32 +} + +// decode implements encoder.decode. +func (r *Rlerror) decode(b *buffer) { + r.Error = b.Read32() +} + +// encode implements encoder.encode. +func (r *Rlerror) encode(b *buffer) { + b.Write32(r.Error) +} + +// Type implements message.Type. +func (*Rlerror) Type() MsgType { + return MsgRlerror +} + +// String implements fmt.Stringer. +func (r *Rlerror) String() string { + return fmt.Sprintf("Rlerror{Error: %d}", r.Error) +} + +// Tauth is an authentication request. +type Tauth struct { + // AuthenticationFID is the FID to attach the authentication result. + AuthenticationFID FID + + // UserName is the user to attach. + UserName string + + // AttachName is the attach name. + AttachName string + + // UserID is the numeric identifier for UserName. + UID UID +} + +// decode implements encoder.decode. +func (t *Tauth) decode(b *buffer) { + t.AuthenticationFID = b.ReadFID() + t.UserName = b.ReadString() + t.AttachName = b.ReadString() + t.UID = b.ReadUID() +} + +// encode implements encoder.encode. +func (t *Tauth) encode(b *buffer) { + b.WriteFID(t.AuthenticationFID) + b.WriteString(t.UserName) + b.WriteString(t.AttachName) + b.WriteUID(t.UID) +} + +// Type implements message.Type. +func (*Tauth) Type() MsgType { + return MsgTauth +} + +// String implements fmt.Stringer. +func (t *Tauth) String() string { + return fmt.Sprintf("Tauth{AuthFID: %d, UserName: %s, AttachName: %s, UID: %d", t.AuthenticationFID, t.UserName, t.AttachName, t.UID) +} + +// Rauth is an authentication response. +// +// encode and decode are inherited directly from QID. +type Rauth struct { + QID +} + +// Type implements message.Type. +func (*Rauth) Type() MsgType { + return MsgRauth +} + +// String implements fmt.Stringer. +func (r *Rauth) String() string { + return fmt.Sprintf("Rauth{QID: %s}", r.QID) +} + +// Tattach is an attach request. +type Tattach struct { + // FID is the FID to be attached. + FID FID + + // Auth is the embedded authentication request. + // + // See client.Attach for information regarding authentication. + Auth Tauth +} + +// decode implements encoder.decode. +func (t *Tattach) decode(b *buffer) { + t.FID = b.ReadFID() + t.Auth.decode(b) +} + +// encode implements encoder.encode. +func (t *Tattach) encode(b *buffer) { + b.WriteFID(t.FID) + t.Auth.encode(b) +} + +// Type implements message.Type. +func (*Tattach) Type() MsgType { + return MsgTattach +} + +// String implements fmt.Stringer. +func (t *Tattach) String() string { + return fmt.Sprintf("Tattach{FID: %d, AuthFID: %d, UserName: %s, AttachName: %s, UID: %d}", t.FID, t.Auth.AuthenticationFID, t.Auth.UserName, t.Auth.AttachName, t.Auth.UID) +} + +// Rattach is an attach response. +type Rattach struct { + QID +} + +// Type implements message.Type. +func (*Rattach) Type() MsgType { + return MsgRattach +} + +// String implements fmt.Stringer. +func (r *Rattach) String() string { + return fmt.Sprintf("Rattach{QID: %s}", r.QID) +} + +// Tlopen is an open request. +type Tlopen struct { + // FID is the FID to be opened. + FID FID + + // Flags are the open flags. + Flags OpenFlags +} + +// decode implements encoder.decode. +func (t *Tlopen) decode(b *buffer) { + t.FID = b.ReadFID() + t.Flags = b.ReadOpenFlags() +} + +// encode implements encoder.encode. +func (t *Tlopen) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteOpenFlags(t.Flags) +} + +// Type implements message.Type. +func (*Tlopen) Type() MsgType { + return MsgTlopen +} + +// String implements fmt.Stringer. +func (t *Tlopen) String() string { + return fmt.Sprintf("Tlopen{FID: %d, Flags: %v}", t.FID, t.Flags) +} + +// Rlopen is a open response. +type Rlopen struct { + // QID is the file's QID. + QID QID + + // IoUnit is the recommended I/O unit. + IoUnit uint32 + + filePayload +} + +// decode implements encoder.decode. +func (r *Rlopen) decode(b *buffer) { + r.QID.decode(b) + r.IoUnit = b.Read32() +} + +// encode implements encoder.encode. +func (r *Rlopen) encode(b *buffer) { + r.QID.encode(b) + b.Write32(r.IoUnit) +} + +// Type implements message.Type. +func (*Rlopen) Type() MsgType { + return MsgRlopen +} + +// String implements fmt.Stringer. +func (r *Rlopen) String() string { + return fmt.Sprintf("Rlopen{QID: %s, IoUnit: %d, File: %v}", r.QID, r.IoUnit, r.File) +} + +// Tlcreate is a create request. +type Tlcreate struct { + // FID is the parent FID. + // + // This becomes the new file. + FID FID + + // Name is the file name to create. + Name string + + // Mode is the open mode (O_RDWR, etc.). + // + // Note that flags like O_TRUNC are ignored, as is O_EXCL. All + // create operations are exclusive. + OpenFlags OpenFlags + + // Permissions is the set of permission bits. + Permissions FileMode + + // GID is the group ID to use for creating the file. + GID GID +} + +// decode implements encoder.decode. +func (t *Tlcreate) decode(b *buffer) { + t.FID = b.ReadFID() + t.Name = b.ReadString() + t.OpenFlags = b.ReadOpenFlags() + t.Permissions = b.ReadPermissions() + t.GID = b.ReadGID() +} + +// encode implements encoder.encode. +func (t *Tlcreate) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteString(t.Name) + b.WriteOpenFlags(t.OpenFlags) + b.WritePermissions(t.Permissions) + b.WriteGID(t.GID) +} + +// Type implements message.Type. +func (*Tlcreate) Type() MsgType { + return MsgTlcreate +} + +// String implements fmt.Stringer. +func (t *Tlcreate) String() string { + return fmt.Sprintf("Tlcreate{FID: %d, Name: %s, OpenFlags: %s, Permissions: 0o%o, GID: %d}", t.FID, t.Name, t.OpenFlags, t.Permissions, t.GID) +} + +// Rlcreate is a create response. +// +// The encode, decode, etc. methods are inherited from Rlopen. +type Rlcreate struct { + Rlopen +} + +// Type implements message.Type. +func (*Rlcreate) Type() MsgType { + return MsgRlcreate +} + +// String implements fmt.Stringer. +func (r *Rlcreate) String() string { + return fmt.Sprintf("Rlcreate{QID: %s, IoUnit: %d, File: %v}", r.QID, r.IoUnit, r.File) +} + +// Tsymlink is a symlink request. +type Tsymlink struct { + // Directory is the directory FID. + Directory FID + + // Name is the new in the directory. + Name string + + // Target is the symlink target. + Target string + + // GID is the owning group. + GID GID +} + +// decode implements encoder.decode. +func (t *Tsymlink) decode(b *buffer) { + t.Directory = b.ReadFID() + t.Name = b.ReadString() + t.Target = b.ReadString() + t.GID = b.ReadGID() +} + +// encode implements encoder.encode. +func (t *Tsymlink) encode(b *buffer) { + b.WriteFID(t.Directory) + b.WriteString(t.Name) + b.WriteString(t.Target) + b.WriteGID(t.GID) +} + +// Type implements message.Type. +func (*Tsymlink) Type() MsgType { + return MsgTsymlink +} + +// String implements fmt.Stringer. +func (t *Tsymlink) String() string { + return fmt.Sprintf("Tsymlink{DirectoryFID: %d, Name: %s, Target: %s, GID: %d}", t.Directory, t.Name, t.Target, t.GID) +} + +// Rsymlink is a symlink response. +type Rsymlink struct { + // QID is the new symlink's QID. + QID QID +} + +// decode implements encoder.decode. +func (r *Rsymlink) decode(b *buffer) { + r.QID.decode(b) +} + +// encode implements encoder.encode. +func (r *Rsymlink) encode(b *buffer) { + r.QID.encode(b) +} + +// Type implements message.Type. +func (*Rsymlink) Type() MsgType { + return MsgRsymlink +} + +// String implements fmt.Stringer. +func (r *Rsymlink) String() string { + return fmt.Sprintf("Rsymlink{QID: %s}", r.QID) +} + +// Tlink is a link request. +type Tlink struct { + // Directory is the directory to contain the link. + Directory FID + + // FID is the target. + Target FID + + // Name is the new source name. + Name string +} + +// decode implements encoder.decode. +func (t *Tlink) decode(b *buffer) { + t.Directory = b.ReadFID() + t.Target = b.ReadFID() + t.Name = b.ReadString() +} + +// encode implements encoder.encode. +func (t *Tlink) encode(b *buffer) { + b.WriteFID(t.Directory) + b.WriteFID(t.Target) + b.WriteString(t.Name) +} + +// Type implements message.Type. +func (*Tlink) Type() MsgType { + return MsgTlink +} + +// String implements fmt.Stringer. +func (t *Tlink) String() string { + return fmt.Sprintf("Tlink{DirectoryFID: %d, TargetFID: %d, Name: %s}", t.Directory, t.Target, t.Name) +} + +// Rlink is a link response. +type Rlink struct { +} + +// Type implements message.Type. +func (*Rlink) Type() MsgType { + return MsgRlink +} + +// decode implements encoder.decode. +func (*Rlink) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rlink) encode(*buffer) { +} + +// String implements fmt.Stringer. +func (r *Rlink) String() string { + return "Rlink{}" +} + +// Trenameat is a rename request. +type Trenameat struct { + // OldDirectory is the source directory. + OldDirectory FID + + // OldName is the source file name. + OldName string + + // NewDirectory is the target directory. + NewDirectory FID + + // NewName is the new file name. + NewName string +} + +// decode implements encoder.decode. +func (t *Trenameat) decode(b *buffer) { + t.OldDirectory = b.ReadFID() + t.OldName = b.ReadString() + t.NewDirectory = b.ReadFID() + t.NewName = b.ReadString() +} + +// encode implements encoder.encode. +func (t *Trenameat) encode(b *buffer) { + b.WriteFID(t.OldDirectory) + b.WriteString(t.OldName) + b.WriteFID(t.NewDirectory) + b.WriteString(t.NewName) +} + +// Type implements message.Type. +func (*Trenameat) Type() MsgType { + return MsgTrenameat +} + +// String implements fmt.Stringer. +func (t *Trenameat) String() string { + return fmt.Sprintf("TrenameAt{OldDirectoryFID: %d, OldName: %s, NewDirectoryFID: %d, NewName: %s}", t.OldDirectory, t.OldName, t.NewDirectory, t.NewName) +} + +// Rrenameat is a rename response. +type Rrenameat struct { +} + +// decode implements encoder.decode. +func (*Rrenameat) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rrenameat) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rrenameat) Type() MsgType { + return MsgRrenameat +} + +// String implements fmt.Stringer. +func (r *Rrenameat) String() string { + return "Rrenameat{}" +} + +// Tunlinkat is an unlink request. +type Tunlinkat struct { + // Directory is the originating directory. + Directory FID + + // Name is the name of the entry to unlink. + Name string + + // Flags are extra flags (e.g. O_DIRECTORY). These are not interpreted by p9. + Flags uint32 +} + +// decode implements encoder.decode. +func (t *Tunlinkat) decode(b *buffer) { + t.Directory = b.ReadFID() + t.Name = b.ReadString() + t.Flags = b.Read32() +} + +// encode implements encoder.encode. +func (t *Tunlinkat) encode(b *buffer) { + b.WriteFID(t.Directory) + b.WriteString(t.Name) + b.Write32(t.Flags) +} + +// Type implements message.Type. +func (*Tunlinkat) Type() MsgType { + return MsgTunlinkat +} + +// String implements fmt.Stringer. +func (t *Tunlinkat) String() string { + return fmt.Sprintf("Tunlinkat{DirectoryFID: %d, Name: %s, Flags: 0x%X}", t.Directory, t.Name, t.Flags) +} + +// Runlinkat is an unlink response. +type Runlinkat struct { +} + +// decode implements encoder.decode. +func (*Runlinkat) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Runlinkat) encode(*buffer) { +} + +// Type implements message.Type. +func (*Runlinkat) Type() MsgType { + return MsgRunlinkat +} + +// String implements fmt.Stringer. +func (r *Runlinkat) String() string { + return "Runlinkat{}" +} + +// Trename is a rename request. +// +// Note that this generally isn't used anymore, and ideally all rename calls +// should Trenameat below. +type Trename struct { + // FID is the FID to rename. + FID FID + + // Directory is the target directory. + Directory FID + + // Name is the new file name. + Name string +} + +// decode implements encoder.decode. +func (t *Trename) decode(b *buffer) { + t.FID = b.ReadFID() + t.Directory = b.ReadFID() + t.Name = b.ReadString() +} + +// encode implements encoder.encode. +func (t *Trename) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteFID(t.Directory) + b.WriteString(t.Name) +} + +// Type implements message.Type. +func (*Trename) Type() MsgType { + return MsgTrename +} + +// String implements fmt.Stringer. +func (t *Trename) String() string { + return fmt.Sprintf("Trename{FID: %d, DirectoryFID: %d, Name: %s}", t.FID, t.Directory, t.Name) +} + +// Rrename is a rename response. +type Rrename struct { +} + +// decode implements encoder.decode. +func (*Rrename) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rrename) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rrename) Type() MsgType { + return MsgRrename +} + +// String implements fmt.Stringer. +func (r *Rrename) String() string { + return "Rrename{}" +} + +// Treadlink is a readlink request. +type Treadlink struct { + // FID is the symlink. + FID FID +} + +// decode implements encoder.decode. +func (t *Treadlink) decode(b *buffer) { + t.FID = b.ReadFID() +} + +// encode implements encoder.encode. +func (t *Treadlink) encode(b *buffer) { + b.WriteFID(t.FID) +} + +// Type implements message.Type. +func (*Treadlink) Type() MsgType { + return MsgTreadlink +} + +// String implements fmt.Stringer. +func (t *Treadlink) String() string { + return fmt.Sprintf("Treadlink{FID: %d}", t.FID) +} + +// Rreadlink is a readlink response. +type Rreadlink struct { + // Target is the symlink target. + Target string +} + +// decode implements encoder.decode. +func (r *Rreadlink) decode(b *buffer) { + r.Target = b.ReadString() +} + +// encode implements encoder.encode. +func (r *Rreadlink) encode(b *buffer) { + b.WriteString(r.Target) +} + +// Type implements message.Type. +func (*Rreadlink) Type() MsgType { + return MsgRreadlink +} + +// String implements fmt.Stringer. +func (r *Rreadlink) String() string { + return fmt.Sprintf("Rreadlink{Target: %s}", r.Target) +} + +// Tread is a read request. +type Tread struct { + // FID is the FID to read. + FID FID + + // Offset indicates the file offset. + Offset uint64 + + // Count indicates the number of bytes to read. + Count uint32 +} + +// decode implements encoder.decode. +func (t *Tread) decode(b *buffer) { + t.FID = b.ReadFID() + t.Offset = b.Read64() + t.Count = b.Read32() +} + +// encode implements encoder.encode. +func (t *Tread) encode(b *buffer) { + b.WriteFID(t.FID) + b.Write64(t.Offset) + b.Write32(t.Count) +} + +// Type implements message.Type. +func (*Tread) Type() MsgType { + return MsgTread +} + +// String implements fmt.Stringer. +func (t *Tread) String() string { + return fmt.Sprintf("Tread{FID: %d, Offset: %d, Count: %d}", t.FID, t.Offset, t.Count) +} + +// Rread is the response for a Tread. +type Rread struct { + // Data is the resulting data. + Data []byte +} + +// decode implements encoder.decode. +// +// Data is automatically decoded via Payload. +func (r *Rread) decode(b *buffer) { + count := b.Read32() + if count != uint32(len(r.Data)) { + b.markOverrun() + } +} + +// encode implements encoder.encode. +// +// Data is automatically encoded via Payload. +func (r *Rread) encode(b *buffer) { + b.Write32(uint32(len(r.Data))) +} + +// Type implements message.Type. +func (*Rread) Type() MsgType { + return MsgRread +} + +// FixedSize implements payloader.FixedSize. +func (*Rread) FixedSize() uint32 { + return 4 +} + +// Payload implements payloader.Payload. +func (r *Rread) Payload() []byte { + return r.Data +} + +// SetPayload implements payloader.SetPayload. +func (r *Rread) SetPayload(p []byte) { + r.Data = p +} + +// String implements fmt.Stringer. +func (r *Rread) String() string { + return fmt.Sprintf("Rread{len(Data): %d}", len(r.Data)) +} + +// Twrite is a write request. +type Twrite struct { + // FID is the FID to read. + FID FID + + // Offset indicates the file offset. + Offset uint64 + + // Data is the data to be written. + Data []byte +} + +// decode implements encoder.decode. +func (t *Twrite) decode(b *buffer) { + t.FID = b.ReadFID() + t.Offset = b.Read64() + count := b.Read32() + if count != uint32(len(t.Data)) { + b.markOverrun() + } +} + +// encode implements encoder.encode. +// +// This uses the buffer payload to avoid a copy. +func (t *Twrite) encode(b *buffer) { + b.WriteFID(t.FID) + b.Write64(t.Offset) + b.Write32(uint32(len(t.Data))) +} + +// Type implements message.Type. +func (*Twrite) Type() MsgType { + return MsgTwrite +} + +// FixedSize implements payloader.FixedSize. +func (*Twrite) FixedSize() uint32 { + return 16 +} + +// Payload implements payloader.Payload. +func (t *Twrite) Payload() []byte { + return t.Data +} + +// SetPayload implements payloader.SetPayload. +func (t *Twrite) SetPayload(p []byte) { + t.Data = p +} + +// String implements fmt.Stringer. +func (t *Twrite) String() string { + return fmt.Sprintf("Twrite{FID: %v, Offset %d, len(Data): %d}", t.FID, t.Offset, len(t.Data)) +} + +// Rwrite is the response for a Twrite. +type Rwrite struct { + // Count indicates the number of bytes successfully written. + Count uint32 +} + +// decode implements encoder.decode. +func (r *Rwrite) decode(b *buffer) { + r.Count = b.Read32() +} + +// encode implements encoder.encode. +func (r *Rwrite) encode(b *buffer) { + b.Write32(r.Count) +} + +// Type implements message.Type. +func (*Rwrite) Type() MsgType { + return MsgRwrite +} + +// String implements fmt.Stringer. +func (r *Rwrite) String() string { + return fmt.Sprintf("Rwrite{Count: %d}", r.Count) +} + +// Tmknod is a mknod request. +type Tmknod struct { + // Directory is the parent directory. + Directory FID + + // Name is the device name. + Name string + + // Mode is the device mode and permissions. + Mode FileMode + + // Major is the device major number. + Major uint32 + + // Minor is the device minor number. + Minor uint32 + + // GID is the device GID. + GID GID +} + +// decode implements encoder.decode. +func (t *Tmknod) decode(b *buffer) { + t.Directory = b.ReadFID() + t.Name = b.ReadString() + t.Mode = b.ReadFileMode() + t.Major = b.Read32() + t.Minor = b.Read32() + t.GID = b.ReadGID() +} + +// encode implements encoder.encode. +func (t *Tmknod) encode(b *buffer) { + b.WriteFID(t.Directory) + b.WriteString(t.Name) + b.WriteFileMode(t.Mode) + b.Write32(t.Major) + b.Write32(t.Minor) + b.WriteGID(t.GID) +} + +// Type implements message.Type. +func (*Tmknod) Type() MsgType { + return MsgTmknod +} + +// String implements fmt.Stringer. +func (t *Tmknod) String() string { + return fmt.Sprintf("Tmknod{DirectoryFID: %d, Name: %s, Mode: 0o%o, Major: %d, Minor: %d, GID: %d}", t.Directory, t.Name, t.Mode, t.Major, t.Minor, t.GID) +} + +// Rmknod is a mknod response. +type Rmknod struct { + // QID is the resulting QID. + QID QID +} + +// decode implements encoder.decode. +func (r *Rmknod) decode(b *buffer) { + r.QID.decode(b) +} + +// encode implements encoder.encode. +func (r *Rmknod) encode(b *buffer) { + r.QID.encode(b) +} + +// Type implements message.Type. +func (*Rmknod) Type() MsgType { + return MsgRmknod +} + +// String implements fmt.Stringer. +func (r *Rmknod) String() string { + return fmt.Sprintf("Rmknod{QID: %s}", r.QID) +} + +// Tmkdir is a mkdir request. +type Tmkdir struct { + // Directory is the parent directory. + Directory FID + + // Name is the new directory name. + Name string + + // Permissions is the set of permission bits. + Permissions FileMode + + // GID is the owning group. + GID GID +} + +// decode implements encoder.decode. +func (t *Tmkdir) decode(b *buffer) { + t.Directory = b.ReadFID() + t.Name = b.ReadString() + t.Permissions = b.ReadPermissions() + t.GID = b.ReadGID() +} + +// encode implements encoder.encode. +func (t *Tmkdir) encode(b *buffer) { + b.WriteFID(t.Directory) + b.WriteString(t.Name) + b.WritePermissions(t.Permissions) + b.WriteGID(t.GID) +} + +// Type implements message.Type. +func (*Tmkdir) Type() MsgType { + return MsgTmkdir +} + +// String implements fmt.Stringer. +func (t *Tmkdir) String() string { + return fmt.Sprintf("Tmkdir{DirectoryFID: %d, Name: %s, Permissions: 0o%o, GID: %d}", t.Directory, t.Name, t.Permissions, t.GID) +} + +// Rmkdir is a mkdir response. +type Rmkdir struct { + // QID is the resulting QID. + QID QID +} + +// decode implements encoder.decode. +func (r *Rmkdir) decode(b *buffer) { + r.QID.decode(b) +} + +// encode implements encoder.encode. +func (r *Rmkdir) encode(b *buffer) { + r.QID.encode(b) +} + +// Type implements message.Type. +func (*Rmkdir) Type() MsgType { + return MsgRmkdir +} + +// String implements fmt.Stringer. +func (r *Rmkdir) String() string { + return fmt.Sprintf("Rmkdir{QID: %s}", r.QID) +} + +// Tgetattr is a getattr request. +type Tgetattr struct { + // FID is the FID to get attributes for. + FID FID + + // AttrMask is the set of attributes to get. + AttrMask AttrMask +} + +// decode implements encoder.decode. +func (t *Tgetattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.AttrMask.decode(b) +} + +// encode implements encoder.encode. +func (t *Tgetattr) encode(b *buffer) { + b.WriteFID(t.FID) + t.AttrMask.encode(b) +} + +// Type implements message.Type. +func (*Tgetattr) Type() MsgType { + return MsgTgetattr +} + +// String implements fmt.Stringer. +func (t *Tgetattr) String() string { + return fmt.Sprintf("Tgetattr{FID: %d, AttrMask: %s}", t.FID, t.AttrMask) +} + +// Rgetattr is a getattr response. +type Rgetattr struct { + // Valid indicates which fields are valid. + Valid AttrMask + + // QID is the QID for this file. + QID + + // Attr is the set of attributes. + Attr Attr +} + +// decode implements encoder.decode. +func (r *Rgetattr) decode(b *buffer) { + r.Valid.decode(b) + r.QID.decode(b) + r.Attr.decode(b) +} + +// encode implements encoder.encode. +func (r *Rgetattr) encode(b *buffer) { + r.Valid.encode(b) + r.QID.encode(b) + r.Attr.encode(b) +} + +// Type implements message.Type. +func (*Rgetattr) Type() MsgType { + return MsgRgetattr +} + +// String implements fmt.Stringer. +func (r *Rgetattr) String() string { + return fmt.Sprintf("Rgetattr{Valid: %v, QID: %s, Attr: %s}", r.Valid, r.QID, r.Attr) +} + +// Tsetattr is a setattr request. +type Tsetattr struct { + // FID is the FID to change. + FID FID + + // Valid is the set of bits which will be used. + Valid SetAttrMask + + // SetAttr is the set request. + SetAttr SetAttr +} + +// decode implements encoder.decode. +func (t *Tsetattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.Valid.decode(b) + t.SetAttr.decode(b) +} + +// encode implements encoder.encode. +func (t *Tsetattr) encode(b *buffer) { + b.WriteFID(t.FID) + t.Valid.encode(b) + t.SetAttr.encode(b) +} + +// Type implements message.Type. +func (*Tsetattr) Type() MsgType { + return MsgTsetattr +} + +// String implements fmt.Stringer. +func (t *Tsetattr) String() string { + return fmt.Sprintf("Tsetattr{FID: %d, Valid: %v, SetAttr: %s}", t.FID, t.Valid, t.SetAttr) +} + +// Rsetattr is a setattr response. +type Rsetattr struct { +} + +// decode implements encoder.decode. +func (*Rsetattr) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rsetattr) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rsetattr) Type() MsgType { + return MsgRsetattr +} + +// String implements fmt.Stringer. +func (r *Rsetattr) String() string { + return "Rsetattr{}" +} + +// Tallocate is an allocate request. This is an extension to 9P protocol, not +// present in the 9P2000.L standard. +type Tallocate struct { + FID FID + Mode AllocateMode + Offset uint64 + Length uint64 +} + +// decode implements encoder.decode. +func (t *Tallocate) decode(b *buffer) { + t.FID = b.ReadFID() + t.Mode.decode(b) + t.Offset = b.Read64() + t.Length = b.Read64() +} + +// encode implements encoder.encode. +func (t *Tallocate) encode(b *buffer) { + b.WriteFID(t.FID) + t.Mode.encode(b) + b.Write64(t.Offset) + b.Write64(t.Length) +} + +// Type implements message.Type. +func (*Tallocate) Type() MsgType { + return MsgTallocate +} + +// String implements fmt.Stringer. +func (t *Tallocate) String() string { + return fmt.Sprintf("Tallocate{FID: %d, Offset: %d, Length: %d}", t.FID, t.Offset, t.Length) +} + +// Rallocate is an allocate response. +type Rallocate struct { +} + +// decode implements encoder.decode. +func (*Rallocate) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rallocate) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rallocate) Type() MsgType { + return MsgRallocate +} + +// String implements fmt.Stringer. +func (r *Rallocate) String() string { + return "Rallocate{}" +} + +// Tlistxattr is a listxattr request. +type Tlistxattr struct { + // FID refers to the file on which to list xattrs. + FID FID + + // Size is the buffer size for the xattr list. + Size uint64 +} + +// decode implements encoder.decode. +func (t *Tlistxattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.Size = b.Read64() +} + +// encode implements encoder.encode. +func (t *Tlistxattr) encode(b *buffer) { + b.WriteFID(t.FID) + b.Write64(t.Size) +} + +// Type implements message.Type. +func (*Tlistxattr) Type() MsgType { + return MsgTlistxattr +} + +// String implements fmt.Stringer. +func (t *Tlistxattr) String() string { + return fmt.Sprintf("Tlistxattr{FID: %d, Size: %d}", t.FID, t.Size) +} + +// Rlistxattr is a listxattr response. +type Rlistxattr struct { + // Xattrs is a list of extended attribute names. + Xattrs []string +} + +// decode implements encoder.decode. +func (r *Rlistxattr) decode(b *buffer) { + n := b.Read16() + r.Xattrs = r.Xattrs[:0] + for i := 0; i < int(n); i++ { + r.Xattrs = append(r.Xattrs, b.ReadString()) + } +} + +// encode implements encoder.encode. +func (r *Rlistxattr) encode(b *buffer) { + b.Write16(uint16(len(r.Xattrs))) + for _, x := range r.Xattrs { + b.WriteString(x) + } +} + +// Type implements message.Type. +func (*Rlistxattr) Type() MsgType { + return MsgRlistxattr +} + +// String implements fmt.Stringer. +func (r *Rlistxattr) String() string { + return fmt.Sprintf("Rlistxattr{Xattrs: %v}", r.Xattrs) +} + +// Txattrwalk walks extended attributes. +type Txattrwalk struct { + // FID is the FID to check for attributes. + FID FID + + // NewFID is the new FID associated with the attributes. + NewFID FID + + // Name is the attribute name. + Name string +} + +// decode implements encoder.decode. +func (t *Txattrwalk) decode(b *buffer) { + t.FID = b.ReadFID() + t.NewFID = b.ReadFID() + t.Name = b.ReadString() +} + +// encode implements encoder.encode. +func (t *Txattrwalk) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteFID(t.NewFID) + b.WriteString(t.Name) +} + +// Type implements message.Type. +func (*Txattrwalk) Type() MsgType { + return MsgTxattrwalk +} + +// String implements fmt.Stringer. +func (t *Txattrwalk) String() string { + return fmt.Sprintf("Txattrwalk{FID: %d, NewFID: %d, Name: %s}", t.FID, t.NewFID, t.Name) +} + +// Rxattrwalk is a xattrwalk response. +type Rxattrwalk struct { + // Size is the size of the extended attribute. + Size uint64 +} + +// decode implements encoder.decode. +func (r *Rxattrwalk) decode(b *buffer) { + r.Size = b.Read64() +} + +// encode implements encoder.encode. +func (r *Rxattrwalk) encode(b *buffer) { + b.Write64(r.Size) +} + +// Type implements message.Type. +func (*Rxattrwalk) Type() MsgType { + return MsgRxattrwalk +} + +// String implements fmt.Stringer. +func (r *Rxattrwalk) String() string { + return fmt.Sprintf("Rxattrwalk{Size: %d}", r.Size) +} + +// Txattrcreate prepare to set extended attributes. +type Txattrcreate struct { + // FID is input/output parameter, it identifies the file on which + // extended attributes will be set but after successful Rxattrcreate + // it is used to write the extended attribute value. + FID FID + + // Name is the attribute name. + Name string + + // Size of the attribute value. When the FID is clunked it has to match + // the number of bytes written to the FID. + AttrSize uint64 + + // Linux setxattr(2) flags. + Flags uint32 +} + +// decode implements encoder.decode. +func (t *Txattrcreate) decode(b *buffer) { + t.FID = b.ReadFID() + t.Name = b.ReadString() + t.AttrSize = b.Read64() + t.Flags = b.Read32() +} + +// encode implements encoder.encode. +func (t *Txattrcreate) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteString(t.Name) + b.Write64(t.AttrSize) + b.Write32(t.Flags) +} + +// Type implements message.Type. +func (*Txattrcreate) Type() MsgType { + return MsgTxattrcreate +} + +// String implements fmt.Stringer. +func (t *Txattrcreate) String() string { + return fmt.Sprintf("Txattrcreate{FID: %d, Name: %s, AttrSize: %d, Flags: %d}", t.FID, t.Name, t.AttrSize, t.Flags) +} + +// Rxattrcreate is a xattrcreate response. +type Rxattrcreate struct { +} + +// decode implements encoder.decode. +func (r *Rxattrcreate) decode(*buffer) { +} + +// encode implements encoder.encode. +func (r *Rxattrcreate) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rxattrcreate) Type() MsgType { + return MsgRxattrcreate +} + +// String implements fmt.Stringer. +func (r *Rxattrcreate) String() string { + return "Rxattrcreate{}" +} + +// Tgetxattr is a getxattr request. +type Tgetxattr struct { + // FID refers to the file for which to get xattrs. + FID FID + + // Name is the xattr to get. + Name string + + // Size is the buffer size for the xattr to get. + Size uint64 +} + +// decode implements encoder.decode. +func (t *Tgetxattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.Name = b.ReadString() + t.Size = b.Read64() +} + +// encode implements encoder.encode. +func (t *Tgetxattr) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteString(t.Name) + b.Write64(t.Size) +} + +// Type implements message.Type. +func (*Tgetxattr) Type() MsgType { + return MsgTgetxattr +} + +// String implements fmt.Stringer. +func (t *Tgetxattr) String() string { + return fmt.Sprintf("Tgetxattr{FID: %d, Name: %s, Size: %d}", t.FID, t.Name, t.Size) +} + +// Rgetxattr is a getxattr response. +type Rgetxattr struct { + // Value is the extended attribute value. + Value string +} + +// decode implements encoder.decode. +func (r *Rgetxattr) decode(b *buffer) { + r.Value = b.ReadString() +} + +// encode implements encoder.encode. +func (r *Rgetxattr) encode(b *buffer) { + b.WriteString(r.Value) +} + +// Type implements message.Type. +func (*Rgetxattr) Type() MsgType { + return MsgRgetxattr +} + +// String implements fmt.Stringer. +func (r *Rgetxattr) String() string { + return fmt.Sprintf("Rgetxattr{Value: %s}", r.Value) +} + +// Tsetxattr sets extended attributes. +type Tsetxattr struct { + // FID refers to the file on which to set xattrs. + FID FID + + // Name is the attribute name. + Name string + + // Value is the attribute value. + Value string + + // Linux setxattr(2) flags. + Flags uint32 +} + +// decode implements encoder.decode. +func (t *Tsetxattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.Name = b.ReadString() + t.Value = b.ReadString() + t.Flags = b.Read32() +} + +// encode implements encoder.encode. +func (t *Tsetxattr) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteString(t.Name) + b.WriteString(t.Value) + b.Write32(t.Flags) +} + +// Type implements message.Type. +func (*Tsetxattr) Type() MsgType { + return MsgTsetxattr +} + +// String implements fmt.Stringer. +func (t *Tsetxattr) String() string { + return fmt.Sprintf("Tsetxattr{FID: %d, Name: %s, Value: %s, Flags: %d}", t.FID, t.Name, t.Value, t.Flags) +} + +// Rsetxattr is a setxattr response. +type Rsetxattr struct { +} + +// decode implements encoder.decode. +func (r *Rsetxattr) decode(*buffer) { +} + +// encode implements encoder.encode. +func (r *Rsetxattr) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rsetxattr) Type() MsgType { + return MsgRsetxattr +} + +// String implements fmt.Stringer. +func (r *Rsetxattr) String() string { + return "Rsetxattr{}" +} + +// Tremovexattr is a removexattr request. +type Tremovexattr struct { + // FID refers to the file on which to set xattrs. + FID FID + + // Name is the attribute name. + Name string +} + +// decode implements encoder.decode. +func (t *Tremovexattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.Name = b.ReadString() +} + +// encode implements encoder.encode. +func (t *Tremovexattr) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteString(t.Name) +} + +// Type implements message.Type. +func (*Tremovexattr) Type() MsgType { + return MsgTremovexattr +} + +// String implements fmt.Stringer. +func (t *Tremovexattr) String() string { + return fmt.Sprintf("Tremovexattr{FID: %d, Name: %s}", t.FID, t.Name) +} + +// Rremovexattr is a removexattr response. +type Rremovexattr struct { +} + +// decode implements encoder.decode. +func (r *Rremovexattr) decode(*buffer) { +} + +// encode implements encoder.encode. +func (r *Rremovexattr) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rremovexattr) Type() MsgType { + return MsgRremovexattr +} + +// String implements fmt.Stringer. +func (r *Rremovexattr) String() string { + return "Rremovexattr{}" +} + +// Treaddir is a readdir request. +type Treaddir struct { + // Directory is the directory FID to read. + Directory FID + + // Offset is the offset to read at. + Offset uint64 + + // Count is the number of bytes to read. + Count uint32 +} + +// decode implements encoder.decode. +func (t *Treaddir) decode(b *buffer) { + t.Directory = b.ReadFID() + t.Offset = b.Read64() + t.Count = b.Read32() +} + +// encode implements encoder.encode. +func (t *Treaddir) encode(b *buffer) { + b.WriteFID(t.Directory) + b.Write64(t.Offset) + b.Write32(t.Count) +} + +// Type implements message.Type. +func (*Treaddir) Type() MsgType { + return MsgTreaddir +} + +// String implements fmt.Stringer. +func (t *Treaddir) String() string { + return fmt.Sprintf("Treaddir{DirectoryFID: %d, Offset: %d, Count: %d}", t.Directory, t.Offset, t.Count) +} + +// Rreaddir is a readdir response. +type Rreaddir struct { + // Count is the byte limit. + // + // This should always be set from the Treaddir request. + Count uint32 + + // Entries are the resulting entries. + // + // This may be constructed in decode. + Entries []Dirent + + // payload is the encoded payload. + // + // This is constructed by encode. + payload []byte +} + +// decode implements encoder.decode. +func (r *Rreaddir) decode(b *buffer) { + r.Count = b.Read32() + entriesBuf := buffer{data: r.payload} + r.Entries = r.Entries[:0] + for { + var d Dirent + d.decode(&entriesBuf) + if entriesBuf.isOverrun() { + // Couldn't decode a complete entry. + break + } + r.Entries = append(r.Entries, d) + } +} + +// encode implements encoder.encode. +func (r *Rreaddir) encode(b *buffer) { + entriesBuf := buffer{} + payloadSize := 0 + for _, d := range r.Entries { + d.encode(&entriesBuf) + if len(entriesBuf.data) > int(r.Count) { + break + } + payloadSize = len(entriesBuf.data) + } + r.Count = uint32(payloadSize) + r.payload = entriesBuf.data[:payloadSize] + b.Write32(r.Count) +} + +// Type implements message.Type. +func (*Rreaddir) Type() MsgType { + return MsgRreaddir +} + +// FixedSize implements payloader.FixedSize. +func (*Rreaddir) FixedSize() uint32 { + return 4 +} + +// Payload implements payloader.Payload. +func (r *Rreaddir) Payload() []byte { + return r.payload +} + +// SetPayload implements payloader.SetPayload. +func (r *Rreaddir) SetPayload(p []byte) { + r.payload = p +} + +// String implements fmt.Stringer. +func (r *Rreaddir) String() string { + return fmt.Sprintf("Rreaddir{Count: %d, Entries: %s}", r.Count, r.Entries) +} + +// Tfsync is an fsync request. +type Tfsync struct { + // FID is the fid to sync. + FID FID +} + +// decode implements encoder.decode. +func (t *Tfsync) decode(b *buffer) { + t.FID = b.ReadFID() +} + +// encode implements encoder.encode. +func (t *Tfsync) encode(b *buffer) { + b.WriteFID(t.FID) +} + +// Type implements message.Type. +func (*Tfsync) Type() MsgType { + return MsgTfsync +} + +// String implements fmt.Stringer. +func (t *Tfsync) String() string { + return fmt.Sprintf("Tfsync{FID: %d}", t.FID) +} + +// Rfsync is an fsync response. +type Rfsync struct { +} + +// decode implements encoder.decode. +func (*Rfsync) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rfsync) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rfsync) Type() MsgType { + return MsgRfsync +} + +// String implements fmt.Stringer. +func (r *Rfsync) String() string { + return "Rfsync{}" +} + +// Tstatfs is a stat request. +type Tstatfs struct { + // FID is the root. + FID FID +} + +// decode implements encoder.decode. +func (t *Tstatfs) decode(b *buffer) { + t.FID = b.ReadFID() +} + +// encode implements encoder.encode. +func (t *Tstatfs) encode(b *buffer) { + b.WriteFID(t.FID) +} + +// Type implements message.Type. +func (*Tstatfs) Type() MsgType { + return MsgTstatfs +} + +// String implements fmt.Stringer. +func (t *Tstatfs) String() string { + return fmt.Sprintf("Tstatfs{FID: %d}", t.FID) +} + +// Rstatfs is the response for a Tstatfs. +type Rstatfs struct { + // FSStat is the stat result. + FSStat FSStat +} + +// decode implements encoder.decode. +func (r *Rstatfs) decode(b *buffer) { + r.FSStat.decode(b) +} + +// encode implements encoder.encode. +func (r *Rstatfs) encode(b *buffer) { + r.FSStat.encode(b) +} + +// Type implements message.Type. +func (*Rstatfs) Type() MsgType { + return MsgRstatfs +} + +// String implements fmt.Stringer. +func (r *Rstatfs) String() string { + return fmt.Sprintf("Rstatfs{FSStat: %v}", r.FSStat) +} + +// Tflushf is a flush file request, not to be confused with Tflush. +type Tflushf struct { + // FID is the FID to be flushed. + FID FID +} + +// decode implements encoder.decode. +func (t *Tflushf) decode(b *buffer) { + t.FID = b.ReadFID() +} + +// encode implements encoder.encode. +func (t *Tflushf) encode(b *buffer) { + b.WriteFID(t.FID) +} + +// Type implements message.Type. +func (*Tflushf) Type() MsgType { + return MsgTflushf +} + +// String implements fmt.Stringer. +func (t *Tflushf) String() string { + return fmt.Sprintf("Tflushf{FID: %d}", t.FID) +} + +// Rflushf is a flush file response. +type Rflushf struct { +} + +// decode implements encoder.decode. +func (*Rflushf) decode(*buffer) { +} + +// encode implements encoder.encode. +func (*Rflushf) encode(*buffer) { +} + +// Type implements message.Type. +func (*Rflushf) Type() MsgType { + return MsgRflushf +} + +// String implements fmt.Stringer. +func (*Rflushf) String() string { + return "Rflushf{}" +} + +// Twalkgetattr is a walk request. +type Twalkgetattr struct { + // FID is the FID to be walked. + FID FID + + // NewFID is the resulting FID. + NewFID FID + + // Names are the set of names to be walked. + Names []string +} + +// decode implements encoder.decode. +func (t *Twalkgetattr) decode(b *buffer) { + t.FID = b.ReadFID() + t.NewFID = b.ReadFID() + n := b.Read16() + t.Names = t.Names[:0] + for i := 0; i < int(n); i++ { + t.Names = append(t.Names, b.ReadString()) + } +} + +// encode implements encoder.encode. +func (t *Twalkgetattr) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteFID(t.NewFID) + b.Write16(uint16(len(t.Names))) + for _, name := range t.Names { + b.WriteString(name) + } +} + +// Type implements message.Type. +func (*Twalkgetattr) Type() MsgType { + return MsgTwalkgetattr +} + +// String implements fmt.Stringer. +func (t *Twalkgetattr) String() string { + return fmt.Sprintf("Twalkgetattr{FID: %d, NewFID: %d, Names: %v}", t.FID, t.NewFID, t.Names) +} + +// Rwalkgetattr is a walk response. +type Rwalkgetattr struct { + // Valid indicates which fields are valid in the Attr below. + Valid AttrMask + + // Attr is the set of attributes for the last QID (the file walked to). + Attr Attr + + // QIDs are the set of QIDs returned. + QIDs []QID +} + +// decode implements encoder.decode. +func (r *Rwalkgetattr) decode(b *buffer) { + r.Valid.decode(b) + r.Attr.decode(b) + n := b.Read16() + r.QIDs = r.QIDs[:0] + for i := 0; i < int(n); i++ { + var q QID + q.decode(b) + r.QIDs = append(r.QIDs, q) + } +} + +// encode implements encoder.encode. +func (r *Rwalkgetattr) encode(b *buffer) { + r.Valid.encode(b) + r.Attr.encode(b) + b.Write16(uint16(len(r.QIDs))) + for _, q := range r.QIDs { + q.encode(b) + } +} + +// Type implements message.Type. +func (*Rwalkgetattr) Type() MsgType { + return MsgRwalkgetattr +} + +// String implements fmt.Stringer. +func (r *Rwalkgetattr) String() string { + return fmt.Sprintf("Rwalkgetattr{Valid: %s, Attr: %s, QIDs: %v}", r.Valid, r.Attr, r.QIDs) +} + +// Tucreate is a Tlcreate message that includes a UID. +type Tucreate struct { + Tlcreate + + // UID is the UID to use as the effective UID in creation messages. + UID UID +} + +// decode implements encoder.decode. +func (t *Tucreate) decode(b *buffer) { + t.Tlcreate.decode(b) + t.UID = b.ReadUID() +} + +// encode implements encoder.encode. +func (t *Tucreate) encode(b *buffer) { + t.Tlcreate.encode(b) + b.WriteUID(t.UID) +} + +// Type implements message.Type. +func (t *Tucreate) Type() MsgType { + return MsgTucreate +} + +// String implements fmt.Stringer. +func (t *Tucreate) String() string { + return fmt.Sprintf("Tucreate{Tlcreate: %v, UID: %d}", &t.Tlcreate, t.UID) +} + +// Rucreate is a file creation response. +type Rucreate struct { + Rlcreate +} + +// Type implements message.Type. +func (*Rucreate) Type() MsgType { + return MsgRucreate +} + +// String implements fmt.Stringer. +func (r *Rucreate) String() string { + return fmt.Sprintf("Rucreate{%v}", &r.Rlcreate) +} + +// Tumkdir is a Tmkdir message that includes a UID. +type Tumkdir struct { + Tmkdir + + // UID is the UID to use as the effective UID in creation messages. + UID UID +} + +// decode implements encoder.decode. +func (t *Tumkdir) decode(b *buffer) { + t.Tmkdir.decode(b) + t.UID = b.ReadUID() +} + +// encode implements encoder.encode. +func (t *Tumkdir) encode(b *buffer) { + t.Tmkdir.encode(b) + b.WriteUID(t.UID) +} + +// Type implements message.Type. +func (t *Tumkdir) Type() MsgType { + return MsgTumkdir +} + +// String implements fmt.Stringer. +func (t *Tumkdir) String() string { + return fmt.Sprintf("Tumkdir{Tmkdir: %v, UID: %d}", &t.Tmkdir, t.UID) +} + +// Rumkdir is a umkdir response. +type Rumkdir struct { + Rmkdir +} + +// Type implements message.Type. +func (*Rumkdir) Type() MsgType { + return MsgRumkdir +} + +// String implements fmt.Stringer. +func (r *Rumkdir) String() string { + return fmt.Sprintf("Rumkdir{%v}", &r.Rmkdir) +} + +// Tumknod is a Tmknod message that includes a UID. +type Tumknod struct { + Tmknod + + // UID is the UID to use as the effective UID in creation messages. + UID UID +} + +// decode implements encoder.decode. +func (t *Tumknod) decode(b *buffer) { + t.Tmknod.decode(b) + t.UID = b.ReadUID() +} + +// encode implements encoder.encode. +func (t *Tumknod) encode(b *buffer) { + t.Tmknod.encode(b) + b.WriteUID(t.UID) +} + +// Type implements message.Type. +func (t *Tumknod) Type() MsgType { + return MsgTumknod +} + +// String implements fmt.Stringer. +func (t *Tumknod) String() string { + return fmt.Sprintf("Tumknod{Tmknod: %v, UID: %d}", &t.Tmknod, t.UID) +} + +// Rumknod is a umknod response. +type Rumknod struct { + Rmknod +} + +// Type implements message.Type. +func (*Rumknod) Type() MsgType { + return MsgRumknod +} + +// String implements fmt.Stringer. +func (r *Rumknod) String() string { + return fmt.Sprintf("Rumknod{%v}", &r.Rmknod) +} + +// Tusymlink is a Tsymlink message that includes a UID. +type Tusymlink struct { + Tsymlink + + // UID is the UID to use as the effective UID in creation messages. + UID UID +} + +// decode implements encoder.decode. +func (t *Tusymlink) decode(b *buffer) { + t.Tsymlink.decode(b) + t.UID = b.ReadUID() +} + +// encode implements encoder.encode. +func (t *Tusymlink) encode(b *buffer) { + t.Tsymlink.encode(b) + b.WriteUID(t.UID) +} + +// Type implements message.Type. +func (t *Tusymlink) Type() MsgType { + return MsgTusymlink +} + +// String implements fmt.Stringer. +func (t *Tusymlink) String() string { + return fmt.Sprintf("Tusymlink{Tsymlink: %v, UID: %d}", &t.Tsymlink, t.UID) +} + +// Rusymlink is a usymlink response. +type Rusymlink struct { + Rsymlink +} + +// Type implements message.Type. +func (*Rusymlink) Type() MsgType { + return MsgRusymlink +} + +// String implements fmt.Stringer. +func (r *Rusymlink) String() string { + return fmt.Sprintf("Rusymlink{%v}", &r.Rsymlink) +} + +// Tlconnect is a connect request. +type Tlconnect struct { + // FID is the FID to be connected. + FID FID + + // Flags are the connect flags. + Flags ConnectFlags +} + +// decode implements encoder.decode. +func (t *Tlconnect) decode(b *buffer) { + t.FID = b.ReadFID() + t.Flags = b.ReadConnectFlags() +} + +// encode implements encoder.encode. +func (t *Tlconnect) encode(b *buffer) { + b.WriteFID(t.FID) + b.WriteConnectFlags(t.Flags) +} + +// Type implements message.Type. +func (*Tlconnect) Type() MsgType { + return MsgTlconnect +} + +// String implements fmt.Stringer. +func (t *Tlconnect) String() string { + return fmt.Sprintf("Tlconnect{FID: %d, Flags: %v}", t.FID, t.Flags) +} + +// Rlconnect is a connect response. +type Rlconnect struct { + filePayload +} + +// decode implements encoder.decode. +func (r *Rlconnect) decode(*buffer) {} + +// encode implements encoder.encode. +func (r *Rlconnect) encode(*buffer) {} + +// Type implements message.Type. +func (*Rlconnect) Type() MsgType { + return MsgRlconnect +} + +// String implements fmt.Stringer. +func (r *Rlconnect) String() string { + return fmt.Sprintf("Rlconnect{File: %v}", r.File) +} + +// Tchannel creates a new channel. +type Tchannel struct { + // ID is the channel ID. + ID uint32 + + // Control is 0 if the Rchannel response should provide the flipcall + // component of the channel, and 1 if the Rchannel response should + // provide the fdchannel component of the channel. + Control uint32 +} + +// decode implements encoder.decode. +func (t *Tchannel) decode(b *buffer) { + t.ID = b.Read32() + t.Control = b.Read32() +} + +// encode implements encoder.encode. +func (t *Tchannel) encode(b *buffer) { + b.Write32(t.ID) + b.Write32(t.Control) +} + +// Type implements message.Type. +func (*Tchannel) Type() MsgType { + return MsgTchannel +} + +// String implements fmt.Stringer. +func (t *Tchannel) String() string { + return fmt.Sprintf("Tchannel{ID: %d, Control: %d}", t.ID, t.Control) +} + +// Rchannel is the channel response. +type Rchannel struct { + Offset uint64 + Length uint64 + filePayload +} + +// decode implements encoder.decode. +func (r *Rchannel) decode(b *buffer) { + r.Offset = b.Read64() + r.Length = b.Read64() +} + +// encode implements encoder.encode. +func (r *Rchannel) encode(b *buffer) { + b.Write64(r.Offset) + b.Write64(r.Length) +} + +// Type implements message.Type. +func (*Rchannel) Type() MsgType { + return MsgRchannel +} + +// String implements fmt.Stringer. +func (r *Rchannel) String() string { + return fmt.Sprintf("Rchannel{Offset: %d, Length: %d}", r.Offset, r.Length) +} + +const maxCacheSize = 3 + +// msgFactory is used to reduce allocations by caching messages for reuse. +type msgFactory struct { + create func() message + cache chan message +} + +// msgRegistry indexes all message factories by type. +var msgRegistry registry + +type registry struct { + factories [math.MaxUint8]msgFactory + + // largestFixedSize is computed so that given some message size M, you can + // compute the maximum payload size (e.g. for Twrite, Rread) with + // M-largestFixedSize. You could do this individual on a per-message basis, + // but it's easier to compute a single maximum safe payload. + largestFixedSize uint32 +} + +// get returns a new message by type. +// +// An error is returned in the case of an unknown message. +// +// This takes, and ignores, a message tag so that it may be used directly as a +// lookupTagAndType function for recv (by design). +func (r *registry) get(_ Tag, t MsgType) (message, error) { + entry := &r.factories[t] + if entry.create == nil { + return nil, &ErrInvalidMsgType{t} + } + + select { + case msg := <-entry.cache: + return msg, nil + default: + return entry.create(), nil + } +} + +func (r *registry) put(msg message) { + if p, ok := msg.(payloader); ok { + p.SetPayload(nil) + } + if f, ok := msg.(filer); ok { + f.SetFilePayload(nil) + } + + entry := &r.factories[msg.Type()] + select { + case entry.cache <- msg: + default: + } +} + +// register registers the given message type. +// +// This may cause panic on failure and should only be used from init. +func (r *registry) register(t MsgType, fn func() message) { + if int(t) >= len(r.factories) { + panic(fmt.Sprintf("message type %d is too large. It must be smaller than %d", t, len(r.factories))) + } + if r.factories[t].create != nil { + panic(fmt.Sprintf("duplicate message type %d: first is %T, second is %T", t, r.factories[t].create(), fn())) + } + r.factories[t] = msgFactory{ + create: fn, + cache: make(chan message, maxCacheSize), + } + + if size := calculateSize(fn()); size > r.largestFixedSize { + r.largestFixedSize = size + } +} + +func calculateSize(m message) uint32 { + if p, ok := m.(payloader); ok { + return p.FixedSize() + } + var dataBuf buffer + m.encode(&dataBuf) + return uint32(len(dataBuf.data)) +} + +func init() { + msgRegistry.register(MsgRlerror, func() message { return &Rlerror{} }) + msgRegistry.register(MsgTstatfs, func() message { return &Tstatfs{} }) + msgRegistry.register(MsgRstatfs, func() message { return &Rstatfs{} }) + msgRegistry.register(MsgTlopen, func() message { return &Tlopen{} }) + msgRegistry.register(MsgRlopen, func() message { return &Rlopen{} }) + msgRegistry.register(MsgTlcreate, func() message { return &Tlcreate{} }) + msgRegistry.register(MsgRlcreate, func() message { return &Rlcreate{} }) + msgRegistry.register(MsgTsymlink, func() message { return &Tsymlink{} }) + msgRegistry.register(MsgRsymlink, func() message { return &Rsymlink{} }) + msgRegistry.register(MsgTmknod, func() message { return &Tmknod{} }) + msgRegistry.register(MsgRmknod, func() message { return &Rmknod{} }) + msgRegistry.register(MsgTrename, func() message { return &Trename{} }) + msgRegistry.register(MsgRrename, func() message { return &Rrename{} }) + msgRegistry.register(MsgTreadlink, func() message { return &Treadlink{} }) + msgRegistry.register(MsgRreadlink, func() message { return &Rreadlink{} }) + msgRegistry.register(MsgTgetattr, func() message { return &Tgetattr{} }) + msgRegistry.register(MsgRgetattr, func() message { return &Rgetattr{} }) + msgRegistry.register(MsgTsetattr, func() message { return &Tsetattr{} }) + msgRegistry.register(MsgRsetattr, func() message { return &Rsetattr{} }) + msgRegistry.register(MsgTlistxattr, func() message { return &Tlistxattr{} }) + msgRegistry.register(MsgRlistxattr, func() message { return &Rlistxattr{} }) + msgRegistry.register(MsgTxattrwalk, func() message { return &Txattrwalk{} }) + msgRegistry.register(MsgRxattrwalk, func() message { return &Rxattrwalk{} }) + msgRegistry.register(MsgTxattrcreate, func() message { return &Txattrcreate{} }) + msgRegistry.register(MsgRxattrcreate, func() message { return &Rxattrcreate{} }) + msgRegistry.register(MsgTgetxattr, func() message { return &Tgetxattr{} }) + msgRegistry.register(MsgRgetxattr, func() message { return &Rgetxattr{} }) + msgRegistry.register(MsgTsetxattr, func() message { return &Tsetxattr{} }) + msgRegistry.register(MsgRsetxattr, func() message { return &Rsetxattr{} }) + msgRegistry.register(MsgTremovexattr, func() message { return &Tremovexattr{} }) + msgRegistry.register(MsgRremovexattr, func() message { return &Rremovexattr{} }) + msgRegistry.register(MsgTreaddir, func() message { return &Treaddir{} }) + msgRegistry.register(MsgRreaddir, func() message { return &Rreaddir{} }) + msgRegistry.register(MsgTfsync, func() message { return &Tfsync{} }) + msgRegistry.register(MsgRfsync, func() message { return &Rfsync{} }) + msgRegistry.register(MsgTlink, func() message { return &Tlink{} }) + msgRegistry.register(MsgRlink, func() message { return &Rlink{} }) + msgRegistry.register(MsgTmkdir, func() message { return &Tmkdir{} }) + msgRegistry.register(MsgRmkdir, func() message { return &Rmkdir{} }) + msgRegistry.register(MsgTrenameat, func() message { return &Trenameat{} }) + msgRegistry.register(MsgRrenameat, func() message { return &Rrenameat{} }) + msgRegistry.register(MsgTunlinkat, func() message { return &Tunlinkat{} }) + msgRegistry.register(MsgRunlinkat, func() message { return &Runlinkat{} }) + msgRegistry.register(MsgTversion, func() message { return &Tversion{} }) + msgRegistry.register(MsgRversion, func() message { return &Rversion{} }) + msgRegistry.register(MsgTauth, func() message { return &Tauth{} }) + msgRegistry.register(MsgRauth, func() message { return &Rauth{} }) + msgRegistry.register(MsgTattach, func() message { return &Tattach{} }) + msgRegistry.register(MsgRattach, func() message { return &Rattach{} }) + msgRegistry.register(MsgTflush, func() message { return &Tflush{} }) + msgRegistry.register(MsgRflush, func() message { return &Rflush{} }) + msgRegistry.register(MsgTwalk, func() message { return &Twalk{} }) + msgRegistry.register(MsgRwalk, func() message { return &Rwalk{} }) + msgRegistry.register(MsgTread, func() message { return &Tread{} }) + msgRegistry.register(MsgRread, func() message { return &Rread{} }) + msgRegistry.register(MsgTwrite, func() message { return &Twrite{} }) + msgRegistry.register(MsgRwrite, func() message { return &Rwrite{} }) + msgRegistry.register(MsgTclunk, func() message { return &Tclunk{} }) + msgRegistry.register(MsgRclunk, func() message { return &Rclunk{} }) + msgRegistry.register(MsgTremove, func() message { return &Tremove{} }) + msgRegistry.register(MsgRremove, func() message { return &Rremove{} }) + msgRegistry.register(MsgTflushf, func() message { return &Tflushf{} }) + msgRegistry.register(MsgRflushf, func() message { return &Rflushf{} }) + msgRegistry.register(MsgTwalkgetattr, func() message { return &Twalkgetattr{} }) + msgRegistry.register(MsgRwalkgetattr, func() message { return &Rwalkgetattr{} }) + msgRegistry.register(MsgTucreate, func() message { return &Tucreate{} }) + msgRegistry.register(MsgRucreate, func() message { return &Rucreate{} }) + msgRegistry.register(MsgTumkdir, func() message { return &Tumkdir{} }) + msgRegistry.register(MsgRumkdir, func() message { return &Rumkdir{} }) + msgRegistry.register(MsgTumknod, func() message { return &Tumknod{} }) + msgRegistry.register(MsgRumknod, func() message { return &Rumknod{} }) + msgRegistry.register(MsgTusymlink, func() message { return &Tusymlink{} }) + msgRegistry.register(MsgRusymlink, func() message { return &Rusymlink{} }) + msgRegistry.register(MsgTlconnect, func() message { return &Tlconnect{} }) + msgRegistry.register(MsgRlconnect, func() message { return &Rlconnect{} }) + msgRegistry.register(MsgTallocate, func() message { return &Tallocate{} }) + msgRegistry.register(MsgRallocate, func() message { return &Rallocate{} }) + msgRegistry.register(MsgTchannel, func() message { return &Tchannel{} }) + msgRegistry.register(MsgRchannel, func() message { return &Rchannel{} }) +} |