// 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" ) // 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. typ() 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) // PayloadCleanup is called after a payloader message is sent and // buffers can be reapt. PayloadCleanup() } // 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) } // typ implements message.typ. func (*tversion) typ() 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) } // typ implements message.typ. func (*rversion) typ() 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) } // typ implements message.typ. func (*tflush) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rflush) encode(b *buffer) { } // typ implements message.typ. func (*rflush) typ() msgType { return msgRflush } // String implements fmt.Stringer. func (r *rflush) String() string { return fmt.Sprintf("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) } } // typ implements message.typ. func (*twalk) typ() 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) } } // typ implements message.typ. func (*rwalk) typ() 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) } // typ implements message.typ. func (*tclunk) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rclunk) encode(b *buffer) { } // typ implements message.typ. func (*rclunk) typ() msgType { return msgRclunk } // String implements fmt.Stringer. func (r *rclunk) String() string { return fmt.Sprintf("Rclunk{}") } // tremove is a remove request. 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) } // typ implements message.typ. func (*tremove) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rremove) encode(b *buffer) { } // typ implements message.typ. func (*rremove) typ() msgType { return msgRremove } // String implements fmt.Stringer. func (r *rremove) String() string { return fmt.Sprintf("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) } // typ implements message.typ. func (*rlerror) typ() 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) } // typ implements message.typ. func (*tauth) typ() 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, decode and Length are inherited directly from QID. type rauth struct { QID } // typ implements message.typ. func (*rauth) typ() 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) } // typ implements message.typ. func (*tattach) typ() 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 } // typ implements message.typ. func (*rattach) typ() 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) } // typ implements message.typ. func (*tlopen) typ() 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 } // 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) } // typ implements message.typ. func (*rlopen) typ() msgType { return msgRlopen } // String implements fmt.Stringer. func (r *rlopen) String() string { return fmt.Sprintf("Rlopen{QID: %s, IoUnit: %d}", r.QID, r.IoUnit) } // 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) } // typ implements message.typ. func (*tlcreate) typ() 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 } // typ implements message.typ. func (*rlcreate) typ() msgType { return msgRlcreate } // String implements fmt.Stringer. func (r *rlcreate) String() string { return fmt.Sprintf("Rlcreate{QID: %s, IoUnit: %d}", r.QID, r.IoUnit) } // 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) } // typ implements message.typ. func (*tsymlink) typ() 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) } // typ implements message.typ. func (*rsymlink) typ() 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) } // typ implements message.typ. func (*tlink) typ() 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 { } // typ implements message.typ. func (*rlink) typ() msgType { return msgRlink } // decode implements encoder.decode. func (*rlink) decode(b *buffer) { } // encode implements encoder.encode. func (*rlink) encode(b *buffer) { } // String implements fmt.Stringer. func (r *rlink) String() string { return fmt.Sprintf("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) } // typ implements message.typ. func (*trenameat) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rrenameat) encode(b *buffer) { } // typ implements message.typ. func (*rrenameat) typ() msgType { return msgRrenameat } // String implements fmt.Stringer. func (r *rrenameat) String() string { return fmt.Sprintf("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) } // typ implements message.typ. func (*tunlinkat) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*runlinkat) encode(b *buffer) { } // typ implements message.typ. func (*runlinkat) typ() msgType { return msgRunlinkat } // String implements fmt.Stringer. func (r *runlinkat) String() string { return fmt.Sprintf("Runlinkat{}") } // trename is a rename request. 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) } // typ implements message.typ. func (*trename) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rrename) encode(b *buffer) { } // typ implements message.typ. func (*rrename) typ() msgType { return msgRrename } // String implements fmt.Stringer. func (r *rrename) String() string { return fmt.Sprintf("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) } // typ implements message.typ. func (*treadlink) typ() 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) } // typ implements message.typ. func (*rreadlink) typ() 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) } // typ implements message.typ. func (*tread) typ() 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) } // rreadServerPayloader is the response for a Tread by p9 servers. // // rreadServerPayloader exists so the fuzzer can fuzz rread -- however, // PayloadCleanup causes it to panic, and putting connState in the fuzzer seems // excessive. type rreadServerPayloader struct { rread fullBuffer []byte cs *connState } // 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))) } // typ implements message.typ. func (*rread) typ() 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 } func (*rread) PayloadCleanup() {} // FixedSize implements payloader.FixedSize. func (*rreadServerPayloader) FixedSize() uint32 { return 4 } // Payload implements payloader.Payload. func (r *rreadServerPayloader) Payload() []byte { return r.Data } // SetPayload implements payloader.SetPayload. func (r *rreadServerPayloader) SetPayload(p []byte) { r.Data = p } // PayloadCleanup implements payloader.PayloadCleanup. func (r *rreadServerPayloader) PayloadCleanup() { // Fill it with zeros to not risk leaking previous files' data. copy(r.Data, r.cs.pristineZeros) r.cs.readBufPool.Put(&r.fullBuffer) } // 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))) } // typ implements message.typ. func (*twrite) typ() 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 } func (t *twrite) PayloadCleanup() {} // 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) } // typ implements message.typ. func (*rwrite) typ() 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) } // typ implements message.typ. func (*tmknod) typ() 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) } // typ implements message.typ. func (*rmknod) typ() 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) } // typ implements message.typ. func (*tmkdir) typ() 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) } // typ implements message.typ. func (*rmkdir) typ() 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) } // typ implements message.typ. func (*tgetattr) typ() 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) } // typ implements message.typ. func (*rgetattr) typ() 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) } // typ implements message.typ. func (*tsetattr) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rsetattr) encode(b *buffer) { } // typ implements message.typ. func (*rsetattr) typ() msgType { return msgRsetattr } // String implements fmt.Stringer. func (r *rsetattr) String() string { return fmt.Sprintf("Rsetattr{}") } // 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) } // typ implements message.typ. func (*txattrwalk) typ() 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) } // typ implements message.typ. func (*rxattrwalk) typ() 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) } // typ implements message.typ. func (*txattrcreate) typ() 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(b *buffer) { } // encode implements encoder.encode. func (r *rxattrcreate) encode(b *buffer) { } // typ implements message.typ. func (*rxattrcreate) typ() msgType { return msgRxattrcreate } // String implements fmt.Stringer. func (r *rxattrcreate) String() string { return fmt.Sprintf("Rxattrcreate{}") } // 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) } // typ implements message.typ. func (*treaddir) typ() 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) } // typ implements message.typ. func (*rreaddir) typ() 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 } func (r *rreaddir) PayloadCleanup() {} // 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) } // typ implements message.typ. func (*tfsync) typ() 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(b *buffer) { } // encode implements encoder.encode. func (*rfsync) encode(b *buffer) { } // typ implements message.typ. func (*rfsync) typ() msgType { return msgRfsync } // String implements fmt.Stringer. func (r *rfsync) String() string { return fmt.Sprintf("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) } // typ implements message.typ. func (*tstatfs) typ() 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) } // typ implements message.typ. func (*rstatfs) typ() msgType { return msgRstatfs } // String implements fmt.Stringer. func (r *rstatfs) String() string { return fmt.Sprintf("Rstatfs{FSStat: %v}", r.FSStat) } // 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) } } // typ implements message.typ. func (*twalkgetattr) typ() 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) } } // typ implements message.typ. func (*rwalkgetattr) typ() 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) } // typ implements message.typ. func (t *tucreate) typ() 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 } // typ implements message.typ. func (*rucreate) typ() 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) } // typ implements message.typ. func (t *tumkdir) typ() 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 } // typ implements message.typ. func (*rumkdir) typ() 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) } // typ implements message.typ. func (t *tumknod) typ() 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 } // typ implements message.typ. func (*rumknod) typ() 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) } // typ implements message.typ. func (t *tusymlink) typ() 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 } // typ implements message.typ. func (*rusymlink) typ() msgType { return msgRusymlink } // String implements fmt.Stringer. func (r *rusymlink) String() string { return fmt.Sprintf("Rusymlink{%v}", &r.rsymlink) } // LockType is lock type for Tlock type LockType uint8 // These constants define Lock operations: Read, Write, and Un(lock) // They map to Linux values of F_RDLCK, F_WRLCK, F_UNLCK. // If that seems a little Linux-centric, recall that the "L" // in 9P2000.L means "Linux" :-) const ( ReadLock LockType = iota WriteLock Unlock ) func (l LockType) String() string { switch l { case ReadLock: return "ReadLock" case WriteLock: return "WriteLock" case Unlock: return "Unlock" } return "unknown lock type" } // LockFlags are flags for the lock. Currently, and possibly forever, only one // is really used: LockFlagsBlock type LockFlags uint32 const ( // LockFlagsBlock indicates a blocking request. LockFlagsBlock LockFlags = 1 // LockFlagsReclaim is "Reserved for future use." // It's been some time since 9P2000.L came about, // I suspect "future" in this case is "never"? LockFlagsReclaim LockFlags = 2 ) // LockStatus contains lock status result. type LockStatus uint8 // These are the four current return values for Rlock. const ( LockStatusOK LockStatus = iota LockStatusBlocked LockStatusError LockStatusGrace ) func (s LockStatus) String() string { switch s { case LockStatusOK: return "LockStatusOK" case LockStatusBlocked: return "LockStatusBlocked" case LockStatusError: return "LockStatusError" case LockStatusGrace: return "LockStatusGrace" } return "unknown lock status" } // tlock is a Tlock message type tlock struct { // fid is the fid to lock. fid fid Type LockType // Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ Flags LockFlags // flags, not whence, docs are wrong. Start uint64 // Starting offset for lock Length uint64 // Number of bytes to lock PID int32 // PID of process blocking our lock (F_GETLK only) // "client_id is an additional mechanism for uniquely // identifying the lock requester and is set to the nodename // by the Linux v9fs client." // https://github.com/chaos/diod/blob/master/protocol.md#lock---acquire-or-release-a-posix-record-lock Client string // Client id -- but technically can be anything. } // decode implements encoder.decode. func (t *tlock) decode(b *buffer) { t.fid = b.ReadFID() t.Type = LockType(b.Read8()) t.Flags = LockFlags(b.Read32()) t.Start = b.Read64() t.Length = b.Read64() t.PID = int32(b.Read32()) t.Client = b.ReadString() } // encode implements encoder.encode. func (t *tlock) encode(b *buffer) { b.WriteFID(t.fid) b.Write8(uint8(t.Type)) b.Write32(uint32(t.Flags)) b.Write64(t.Start) b.Write64(t.Length) b.Write32(uint32(t.PID)) b.WriteString(t.Client) } // typ implements message.typ. func (*tlock) typ() msgType { return msgTlock } // String implements fmt.Stringer. func (t *tlock) String() string { return fmt.Sprintf("Tlock{Type: %s, Flags: %#x, Start: %d, Length: %d, PID: %d, Client: %s}", t.Type.String(), t.Flags, t.Start, t.Length, t.PID, t.Client) } // rlock is a lock response. type rlock struct { Status LockStatus } // decode implements encoder.decode. func (r *rlock) decode(b *buffer) { r.Status = LockStatus(b.Read8()) } // encode implements encoder.encode. func (r *rlock) encode(b *buffer) { b.Write8(uint8(r.Status)) } // typ implements message.typ. func (*rlock) typ() msgType { return msgRlock } // String implements fmt.Stringer. func (r *rlock) String() string { return fmt.Sprintf("Rlock{Status: %s}", r.Status) } // Let's wait until we need this? POSIX locks over a network make 0 sense. // getlock - test for the existence of a POSIX record lock // size[4] Tgetlock tag[2] fid[4] type[1] start[8] length[8] proc_id[4] client_id[s] // size[4] Rgetlock tag[2] type[1] start[8] length[8] proc_id[4] client_id[s] // getlock tests for the existence of a POSIX record lock and has semantics similar to Linux fcntl(F_GETLK). // As with lock, type has one of the values defined above, and start, // length, and proc_id correspond to the analogous fields in struct // flock passed to Linux fcntl(F_GETLK), and client_Id is an // additional mechanism for uniquely identifying the lock requester // and is set to the nodename by the Linux v9fs client. tusymlink is // a Tsymlink message that includes a UID. /// END LOCK const maxCacheSize = 3 // msgFactory is used to reduce allocations by caching messages for reuse. type msgFactory struct { create func() message cache chan message } // msgDotLRegistry indexes all 9P2000.L(.Google.N) message factories by type. var msgDotLRegistry registry type registry struct { factories [math.MaxUint8 + 1]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) } entry := &r.factories[msg.typ()] 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() { msgDotLRegistry.register(msgRlerror, func() message { return &rlerror{} }) msgDotLRegistry.register(msgTstatfs, func() message { return &tstatfs{} }) msgDotLRegistry.register(msgRstatfs, func() message { return &rstatfs{} }) msgDotLRegistry.register(msgTlopen, func() message { return &tlopen{} }) msgDotLRegistry.register(msgRlopen, func() message { return &rlopen{} }) msgDotLRegistry.register(msgTlcreate, func() message { return &tlcreate{} }) msgDotLRegistry.register(msgRlcreate, func() message { return &rlcreate{} }) msgDotLRegistry.register(msgTsymlink, func() message { return &tsymlink{} }) msgDotLRegistry.register(msgRsymlink, func() message { return &rsymlink{} }) msgDotLRegistry.register(msgTmknod, func() message { return &tmknod{} }) msgDotLRegistry.register(msgRmknod, func() message { return &rmknod{} }) msgDotLRegistry.register(msgTrename, func() message { return &trename{} }) msgDotLRegistry.register(msgRrename, func() message { return &rrename{} }) msgDotLRegistry.register(msgTreadlink, func() message { return &treadlink{} }) msgDotLRegistry.register(msgRreadlink, func() message { return &rreadlink{} }) msgDotLRegistry.register(msgTgetattr, func() message { return &tgetattr{} }) msgDotLRegistry.register(msgRgetattr, func() message { return &rgetattr{} }) msgDotLRegistry.register(msgTsetattr, func() message { return &tsetattr{} }) msgDotLRegistry.register(msgRsetattr, func() message { return &rsetattr{} }) msgDotLRegistry.register(msgTxattrwalk, func() message { return &txattrwalk{} }) msgDotLRegistry.register(msgRxattrwalk, func() message { return &rxattrwalk{} }) msgDotLRegistry.register(msgTxattrcreate, func() message { return &txattrcreate{} }) msgDotLRegistry.register(msgRxattrcreate, func() message { return &rxattrcreate{} }) msgDotLRegistry.register(msgTreaddir, func() message { return &treaddir{} }) msgDotLRegistry.register(msgRreaddir, func() message { return &rreaddir{} }) msgDotLRegistry.register(msgTfsync, func() message { return &tfsync{} }) msgDotLRegistry.register(msgRfsync, func() message { return &rfsync{} }) msgDotLRegistry.register(msgTlink, func() message { return &tlink{} }) msgDotLRegistry.register(msgRlink, func() message { return &rlink{} }) msgDotLRegistry.register(msgTlock, func() message { return &tlock{} }) msgDotLRegistry.register(msgRlock, func() message { return &rlock{} }) msgDotLRegistry.register(msgTmkdir, func() message { return &tmkdir{} }) msgDotLRegistry.register(msgRmkdir, func() message { return &rmkdir{} }) msgDotLRegistry.register(msgTrenameat, func() message { return &trenameat{} }) msgDotLRegistry.register(msgRrenameat, func() message { return &rrenameat{} }) msgDotLRegistry.register(msgTunlinkat, func() message { return &tunlinkat{} }) msgDotLRegistry.register(msgRunlinkat, func() message { return &runlinkat{} }) msgDotLRegistry.register(msgTversion, func() message { return &tversion{} }) msgDotLRegistry.register(msgRversion, func() message { return &rversion{} }) msgDotLRegistry.register(msgTauth, func() message { return &tauth{} }) msgDotLRegistry.register(msgRauth, func() message { return &rauth{} }) msgDotLRegistry.register(msgTattach, func() message { return &tattach{} }) msgDotLRegistry.register(msgRattach, func() message { return &rattach{} }) msgDotLRegistry.register(msgTflush, func() message { return &tflush{} }) msgDotLRegistry.register(msgRflush, func() message { return &rflush{} }) msgDotLRegistry.register(msgTwalk, func() message { return &twalk{} }) msgDotLRegistry.register(msgRwalk, func() message { return &rwalk{} }) msgDotLRegistry.register(msgTread, func() message { return &tread{} }) msgDotLRegistry.register(msgRread, func() message { return &rread{} }) msgDotLRegistry.register(msgTwrite, func() message { return &twrite{} }) msgDotLRegistry.register(msgRwrite, func() message { return &rwrite{} }) msgDotLRegistry.register(msgTclunk, func() message { return &tclunk{} }) msgDotLRegistry.register(msgRclunk, func() message { return &rclunk{} }) msgDotLRegistry.register(msgTremove, func() message { return &tremove{} }) msgDotLRegistry.register(msgRremove, func() message { return &rremove{} }) msgDotLRegistry.register(msgTwalkgetattr, func() message { return &twalkgetattr{} }) msgDotLRegistry.register(msgRwalkgetattr, func() message { return &rwalkgetattr{} }) msgDotLRegistry.register(msgTucreate, func() message { return &tucreate{} }) msgDotLRegistry.register(msgRucreate, func() message { return &rucreate{} }) msgDotLRegistry.register(msgTumkdir, func() message { return &tumkdir{} }) msgDotLRegistry.register(msgRumkdir, func() message { return &rumkdir{} }) msgDotLRegistry.register(msgTumknod, func() message { return &tumknod{} }) msgDotLRegistry.register(msgRumknod, func() message { return &rumknod{} }) msgDotLRegistry.register(msgTusymlink, func() message { return &tusymlink{} }) msgDotLRegistry.register(msgRusymlink, func() message { return &rusymlink{} }) }