2272 lines
47 KiB
Go
2272 lines
47 KiB
Go
// Copyright 2018 Google LLC
|
|
//
|
|
// 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"
|
|
"reflect"
|
|
|
|
"gvisor.googlesource.com/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)
|
|
}
|
|
|
|
// 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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rflush) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rflush) Type() 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()
|
|
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()
|
|
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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rclunk) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rclunk) Type() MsgType {
|
|
return MsgRclunk
|
|
}
|
|
|
|
// String implements fmt.Stringer.
|
|
func (r *Rclunk) String() string {
|
|
return fmt.Sprintf("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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rremove) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rremove) Type() 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)
|
|
}
|
|
|
|
// 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, Decode and Length 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
|
|
|
|
// File may be attached via the socket.
|
|
//
|
|
// This is an extension specific to this package.
|
|
File *fd.FD
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// FilePayload returns the file payload.
|
|
func (r *Rlopen) FilePayload() *fd.FD {
|
|
return r.File
|
|
}
|
|
|
|
// SetFilePayload sets the received file.
|
|
func (r *Rlopen) SetFilePayload(file *fd.FD) {
|
|
r.File = file
|
|
}
|
|
|
|
// 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(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)
|
|
}
|
|
|
|
// 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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rrenameat) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rrenameat) Type() 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)
|
|
}
|
|
|
|
// 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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Runlinkat) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Runlinkat) Type() MsgType {
|
|
return MsgRunlinkat
|
|
}
|
|
|
|
// String implements fmt.Stringer.
|
|
func (r *Runlinkat) String() string {
|
|
return fmt.Sprintf("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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rrename) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rrename) Type() 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)
|
|
}
|
|
|
|
// 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
|
|
|
|
// Permissions are the device permissions.
|
|
Permissions 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.Permissions = b.ReadPermissions()
|
|
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.WritePermissions(t.Permissions)
|
|
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, Permissions: 0o%o, Major: %d, Minor: %d, GID: %d}", t.Directory, t.Name, t.Permissions, 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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rsetattr) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rsetattr) Type() 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)
|
|
}
|
|
|
|
// 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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (r *Rxattrcreate) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rxattrcreate) Type() 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)
|
|
}
|
|
|
|
// 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}
|
|
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{}
|
|
for _, d := range r.Entries {
|
|
d.Encode(&entriesBuf)
|
|
if len(entriesBuf.data) >= int(r.Count) {
|
|
break
|
|
}
|
|
}
|
|
if len(entriesBuf.data) < int(r.Count) {
|
|
r.Count = uint32(len(entriesBuf.data))
|
|
r.payload = entriesBuf.data
|
|
} else {
|
|
r.payload = entriesBuf.data[:r.Count]
|
|
}
|
|
b.Write32(uint32(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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rfsync) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rfsync) Type() 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)
|
|
}
|
|
|
|
// 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(b *buffer) {
|
|
}
|
|
|
|
// Encode implements encoder.Encode.
|
|
func (*Rflushf) Encode(b *buffer) {
|
|
}
|
|
|
|
// Type implements message.Type.
|
|
func (*Rflushf) Type() MsgType {
|
|
return MsgRflushf
|
|
}
|
|
|
|
// String implements fmt.Stringer.
|
|
func (*Rflushf) String() string {
|
|
return fmt.Sprintf("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()
|
|
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()
|
|
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 {
|
|
// File is a host socket.
|
|
File *fd.FD
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// FilePayload returns the file payload.
|
|
func (r *Rlconnect) FilePayload() *fd.FD {
|
|
return r.File
|
|
}
|
|
|
|
// SetFilePayload sets the received file.
|
|
func (r *Rlconnect) SetFilePayload(file *fd.FD) {
|
|
r.File = file
|
|
}
|
|
|
|
// String implements fmt.Stringer.
|
|
func (r *Rlconnect) String() string {
|
|
return fmt.Sprintf("Rlconnect{File: %v}", r.File)
|
|
}
|
|
|
|
// messageRegistry indexes all messages by type.
|
|
var messageRegistry = make(map[MsgType]func() message)
|
|
|
|
// messageByType creates 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 messageByType(_ Tag, t MsgType) (message, error) {
|
|
fn, ok := messageRegistry[t]
|
|
if !ok {
|
|
return nil, &ErrInvalidMsgType{t}
|
|
}
|
|
return fn(), nil
|
|
}
|
|
|
|
// register registers the given message type.
|
|
//
|
|
// This uses reflection and records only the type. This may cause panic on
|
|
// failure and should only be used from init.
|
|
func register(m message) {
|
|
t := m.Type()
|
|
if fn, ok := messageRegistry[t]; ok {
|
|
panic(fmt.Sprintf("duplicate message type %d: first is %#v, second is %#v", t, fn(), m))
|
|
}
|
|
|
|
to := reflect.ValueOf(m).Elem().Type()
|
|
messageRegistry[t] = func() message {
|
|
return reflect.New(to).Interface().(message)
|
|
}
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
// largestFixedSize is computed within calculateLargestSize.
|
|
//
|
|
// This 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.
|
|
var largestFixedSize uint32
|
|
|
|
// calculateLargestFixedSize is called from within init.
|
|
func calculateLargestFixedSize() {
|
|
for _, fn := range messageRegistry {
|
|
if size := calculateSize(fn()); size > largestFixedSize {
|
|
largestFixedSize = size
|
|
}
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
register(&Rlerror{})
|
|
register(&Tstatfs{})
|
|
register(&Rstatfs{})
|
|
register(&Tlopen{})
|
|
register(&Rlopen{})
|
|
register(&Tlcreate{})
|
|
register(&Rlcreate{})
|
|
register(&Tsymlink{})
|
|
register(&Rsymlink{})
|
|
register(&Tmknod{})
|
|
register(&Rmknod{})
|
|
register(&Trename{})
|
|
register(&Rrename{})
|
|
register(&Treadlink{})
|
|
register(&Rreadlink{})
|
|
register(&Tgetattr{})
|
|
register(&Rgetattr{})
|
|
register(&Tsetattr{})
|
|
register(&Rsetattr{})
|
|
register(&Txattrwalk{})
|
|
register(&Rxattrwalk{})
|
|
register(&Txattrcreate{})
|
|
register(&Rxattrcreate{})
|
|
register(&Treaddir{})
|
|
register(&Rreaddir{})
|
|
register(&Tfsync{})
|
|
register(&Rfsync{})
|
|
register(&Tlink{})
|
|
register(&Rlink{})
|
|
register(&Tmkdir{})
|
|
register(&Rmkdir{})
|
|
register(&Trenameat{})
|
|
register(&Rrenameat{})
|
|
register(&Tunlinkat{})
|
|
register(&Runlinkat{})
|
|
register(&Tversion{})
|
|
register(&Rversion{})
|
|
register(&Tauth{})
|
|
register(&Rauth{})
|
|
register(&Tattach{})
|
|
register(&Rattach{})
|
|
register(&Tflush{})
|
|
register(&Rflush{})
|
|
register(&Twalk{})
|
|
register(&Rwalk{})
|
|
register(&Tread{})
|
|
register(&Rread{})
|
|
register(&Twrite{})
|
|
register(&Rwrite{})
|
|
register(&Tclunk{})
|
|
register(&Rclunk{})
|
|
register(&Tremove{})
|
|
register(&Rremove{})
|
|
register(&Tflushf{})
|
|
register(&Rflushf{})
|
|
register(&Twalkgetattr{})
|
|
register(&Rwalkgetattr{})
|
|
register(&Tucreate{})
|
|
register(&Rucreate{})
|
|
register(&Tumkdir{})
|
|
register(&Rumkdir{})
|
|
register(&Tumknod{})
|
|
register(&Rumknod{})
|
|
register(&Tusymlink{})
|
|
register(&Rusymlink{})
|
|
register(&Tlconnect{})
|
|
register(&Rlconnect{})
|
|
|
|
calculateLargestFixedSize()
|
|
}
|