github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/p9/p9.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package p9 is a 9P2000.L implementation.
    16  package p9
    17  
    18  import (
    19  	"fmt"
    20  	"math"
    21  	"os"
    22  	"strings"
    23  	"syscall"
    24  
    25  	"golang.org/x/sys/unix"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/atomicbitops"
    28  )
    29  
    30  // OpenFlags is the mode passed to Open and Create operations.
    31  //
    32  // These correspond to bits sent over the wire.
    33  type OpenFlags uint32
    34  
    35  const (
    36  	// ReadOnly is a Tlopen and Tlcreate flag indicating read-only mode.
    37  	ReadOnly OpenFlags = 0
    38  
    39  	// WriteOnly is a Tlopen and Tlcreate flag indicating write-only mode.
    40  	WriteOnly OpenFlags = 1
    41  
    42  	// ReadWrite is a Tlopen flag indicates read-write mode.
    43  	ReadWrite OpenFlags = 2
    44  
    45  	// OpenFlagsModeMask is a mask of valid OpenFlags mode bits.
    46  	OpenFlagsModeMask OpenFlags = 3
    47  
    48  	// OpenTruncate is a Tlopen flag indicating that the opened file should be
    49  	// truncated.
    50  	OpenTruncate OpenFlags = 01000
    51  )
    52  
    53  // SocketType is the socket type passed in Connect and Bind operations.
    54  //
    55  // These correspond to bits sent over the wire.
    56  type SocketType uint32
    57  
    58  const (
    59  	// StreamSocket indicates SOCK_STREAM mode.
    60  	StreamSocket SocketType = 0
    61  
    62  	// DgramSocket indicates SOCK_DGRAM mode.
    63  	DgramSocket SocketType = 1
    64  
    65  	// SeqpacketSocket indicates SOCK_SEQPACKET mode.
    66  	SeqpacketSocket SocketType = 2
    67  
    68  	// AnonymousSocket is only valid for Connect calls, and indicates that
    69  	// the caller will accept any socket type.
    70  	AnonymousSocket SocketType = 3
    71  )
    72  
    73  // ToLinux maps the SocketType to a Linux socket type.
    74  func (st SocketType) ToLinux() (linux.SockType, bool) {
    75  	switch st {
    76  	case StreamSocket:
    77  		return linux.SOCK_STREAM, true
    78  	case DgramSocket:
    79  		return linux.SOCK_DGRAM, true
    80  	case SeqpacketSocket:
    81  		return linux.SOCK_SEQPACKET, true
    82  	default:
    83  		return 0, false
    84  	}
    85  }
    86  
    87  // SocketTypeFromLinux maps a Linux socket type to a SocketType.
    88  func SocketTypeFromLinux(st linux.SockType) (SocketType, bool) {
    89  	switch st {
    90  	case linux.SOCK_STREAM:
    91  		return StreamSocket, true
    92  	case linux.SOCK_DGRAM:
    93  		return DgramSocket, true
    94  	case linux.SOCK_SEQPACKET:
    95  		return SeqpacketSocket, true
    96  	default:
    97  		return 0, false
    98  	}
    99  }
   100  
   101  // OSFlags converts a p9.OpenFlags to an int compatible with open(2).
   102  func (o OpenFlags) OSFlags() int {
   103  	// "flags contains Linux open(2) flags bits" - 9P2000.L
   104  	return int(o)
   105  }
   106  
   107  // String implements fmt.Stringer.
   108  func (o OpenFlags) String() string {
   109  	var buf strings.Builder
   110  	switch mode := o & OpenFlagsModeMask; mode {
   111  	case ReadOnly:
   112  		buf.WriteString("ReadOnly")
   113  	case WriteOnly:
   114  		buf.WriteString("WriteOnly")
   115  	case ReadWrite:
   116  		buf.WriteString("ReadWrite")
   117  	default:
   118  		fmt.Fprintf(&buf, "%#o", mode)
   119  	}
   120  	otherFlags := o &^ OpenFlagsModeMask
   121  	if otherFlags&OpenTruncate != 0 {
   122  		buf.WriteString("|OpenTruncate")
   123  		otherFlags &^= OpenTruncate
   124  	}
   125  	if otherFlags != 0 {
   126  		fmt.Fprintf(&buf, "|%#o", otherFlags)
   127  	}
   128  	return buf.String()
   129  }
   130  
   131  // Tag is a message tag.
   132  type Tag uint16
   133  
   134  // FID is a file identifier.
   135  type FID uint64
   136  
   137  // FileMode are flags corresponding to file modes.
   138  //
   139  // These correspond to bits sent over the wire.
   140  // These also correspond to mode_t bits.
   141  type FileMode uint32
   142  
   143  const (
   144  	// FileModeMask is a mask of all the file mode bits of FileMode.
   145  	FileModeMask FileMode = 0170000
   146  
   147  	// ModeSocket is an (unused) mode bit for a socket.
   148  	ModeSocket FileMode = 0140000
   149  
   150  	// ModeSymlink is a mode bit for a symlink.
   151  	ModeSymlink FileMode = 0120000
   152  
   153  	// ModeRegular is a mode bit for regular files.
   154  	ModeRegular FileMode = 0100000
   155  
   156  	// ModeBlockDevice is a mode bit for block devices.
   157  	ModeBlockDevice FileMode = 060000
   158  
   159  	// ModeDirectory is a mode bit for directories.
   160  	ModeDirectory FileMode = 040000
   161  
   162  	// ModeCharacterDevice is a mode bit for a character device.
   163  	ModeCharacterDevice FileMode = 020000
   164  
   165  	// ModeNamedPipe is a mode bit for a named pipe.
   166  	ModeNamedPipe FileMode = 010000
   167  
   168  	// Read is a mode bit indicating read permission.
   169  	Read FileMode = 04
   170  
   171  	// Write is a mode bit indicating write permission.
   172  	Write FileMode = 02
   173  
   174  	// Exec is a mode bit indicating exec permission.
   175  	Exec FileMode = 01
   176  
   177  	// AllPermissions is a mask with rwx bits set for user, group and others.
   178  	AllPermissions FileMode = 0777
   179  
   180  	// Sticky is a mode bit indicating sticky directories.
   181  	Sticky FileMode = 01000
   182  
   183  	// SetGID is the set group ID bit.
   184  	SetGID FileMode = 02000
   185  
   186  	// SetUID is the set user ID bit.
   187  	SetUID FileMode = 04000
   188  
   189  	// permissionsMask is the mask to apply to FileModes for permissions. It
   190  	// includes rwx bits for user, group, and others, as well as the sticky
   191  	// bit, setuid bit, and setgid bit.
   192  	permissionsMask FileMode = 07777
   193  )
   194  
   195  // QIDType is the most significant byte of the FileMode word, to be used as the
   196  // Type field of p9.QID.
   197  func (m FileMode) QIDType() QIDType {
   198  	switch {
   199  	case m.IsDir():
   200  		return TypeDir
   201  	case m.IsSocket(), m.IsNamedPipe(), m.IsCharacterDevice():
   202  		// Best approximation.
   203  		return TypeAppendOnly
   204  	case m.IsSymlink():
   205  		return TypeSymlink
   206  	default:
   207  		return TypeRegular
   208  	}
   209  }
   210  
   211  // FileType returns the file mode without the permission bits.
   212  func (m FileMode) FileType() FileMode {
   213  	return m & FileModeMask
   214  }
   215  
   216  // Permissions returns just the permission bits of the mode.
   217  func (m FileMode) Permissions() FileMode {
   218  	return m & permissionsMask
   219  }
   220  
   221  // Writable returns the mode with write bits added.
   222  func (m FileMode) Writable() FileMode {
   223  	return m | 0222
   224  }
   225  
   226  // IsReadable returns true if m represents a file that can be read.
   227  func (m FileMode) IsReadable() bool {
   228  	return m&0444 != 0
   229  }
   230  
   231  // IsWritable returns true if m represents a file that can be written to.
   232  func (m FileMode) IsWritable() bool {
   233  	return m&0222 != 0
   234  }
   235  
   236  // IsExecutable returns true if m represents a file that can be executed.
   237  func (m FileMode) IsExecutable() bool {
   238  	return m&0111 != 0
   239  }
   240  
   241  // IsRegular returns true if m is a regular file.
   242  func (m FileMode) IsRegular() bool {
   243  	return m&FileModeMask == ModeRegular
   244  }
   245  
   246  // IsDir returns true if m represents a directory.
   247  func (m FileMode) IsDir() bool {
   248  	return m&FileModeMask == ModeDirectory
   249  }
   250  
   251  // IsNamedPipe returns true if m represents a named pipe.
   252  func (m FileMode) IsNamedPipe() bool {
   253  	return m&FileModeMask == ModeNamedPipe
   254  }
   255  
   256  // IsCharacterDevice returns true if m represents a character device.
   257  func (m FileMode) IsCharacterDevice() bool {
   258  	return m&FileModeMask == ModeCharacterDevice
   259  }
   260  
   261  // IsBlockDevice returns true if m represents a character device.
   262  func (m FileMode) IsBlockDevice() bool {
   263  	return m&FileModeMask == ModeBlockDevice
   264  }
   265  
   266  // IsSocket returns true if m represents a socket.
   267  func (m FileMode) IsSocket() bool {
   268  	return m&FileModeMask == ModeSocket
   269  }
   270  
   271  // IsSymlink returns true if m represents a symlink.
   272  func (m FileMode) IsSymlink() bool {
   273  	return m&FileModeMask == ModeSymlink
   274  }
   275  
   276  // ModeFromOS returns a FileMode from an os.FileMode.
   277  func ModeFromOS(mode os.FileMode) FileMode {
   278  	m := FileMode(mode.Perm())
   279  	switch {
   280  	case mode.IsDir():
   281  		m |= ModeDirectory
   282  	case mode&os.ModeSymlink != 0:
   283  		m |= ModeSymlink
   284  	case mode&os.ModeSocket != 0:
   285  		m |= ModeSocket
   286  	case mode&os.ModeNamedPipe != 0:
   287  		m |= ModeNamedPipe
   288  	case mode&os.ModeCharDevice != 0:
   289  		m |= ModeCharacterDevice
   290  	case mode&os.ModeDevice != 0:
   291  		m |= ModeBlockDevice
   292  	default:
   293  		m |= ModeRegular
   294  	}
   295  	return m
   296  }
   297  
   298  // OSMode converts a p9.FileMode to an os.FileMode.
   299  func (m FileMode) OSMode() os.FileMode {
   300  	var osMode os.FileMode
   301  	osMode |= os.FileMode(m.Permissions())
   302  	switch {
   303  	case m.IsDir():
   304  		osMode |= os.ModeDir
   305  	case m.IsSymlink():
   306  		osMode |= os.ModeSymlink
   307  	case m.IsSocket():
   308  		osMode |= os.ModeSocket
   309  	case m.IsNamedPipe():
   310  		osMode |= os.ModeNamedPipe
   311  	case m.IsCharacterDevice():
   312  		osMode |= os.ModeCharDevice | os.ModeDevice
   313  	case m.IsBlockDevice():
   314  		osMode |= os.ModeDevice
   315  	}
   316  	return osMode
   317  }
   318  
   319  // UID represents a user ID.
   320  type UID uint32
   321  
   322  // Ok returns true if uid is not NoUID.
   323  func (uid UID) Ok() bool {
   324  	return uid != NoUID
   325  }
   326  
   327  // GID represents a group ID.
   328  type GID uint32
   329  
   330  // Ok returns true if gid is not NoGID.
   331  func (gid GID) Ok() bool {
   332  	return gid != NoGID
   333  }
   334  
   335  const (
   336  	// NoTag is a sentinel used to indicate no valid tag.
   337  	NoTag Tag = math.MaxUint16
   338  
   339  	// NoFID is a sentinel used to indicate no valid FID.
   340  	NoFID FID = math.MaxUint32
   341  
   342  	// NoUID is a sentinel used to indicate no valid UID.
   343  	NoUID UID = math.MaxUint32
   344  
   345  	// NoGID is a sentinel used to indicate no valid GID.
   346  	NoGID GID = math.MaxUint32
   347  )
   348  
   349  // MsgType is a type identifier.
   350  type MsgType uint8
   351  
   352  // MsgType declarations.
   353  const (
   354  	MsgTlerror       MsgType = 6
   355  	MsgRlerror       MsgType = 7
   356  	MsgTstatfs       MsgType = 8
   357  	MsgRstatfs       MsgType = 9
   358  	MsgTlopen        MsgType = 12
   359  	MsgRlopen        MsgType = 13
   360  	MsgTlcreate      MsgType = 14
   361  	MsgRlcreate      MsgType = 15
   362  	MsgTsymlink      MsgType = 16
   363  	MsgRsymlink      MsgType = 17
   364  	MsgTmknod        MsgType = 18
   365  	MsgRmknod        MsgType = 19
   366  	MsgTrename       MsgType = 20
   367  	MsgRrename       MsgType = 21
   368  	MsgTreadlink     MsgType = 22
   369  	MsgRreadlink     MsgType = 23
   370  	MsgTgetattr      MsgType = 24
   371  	MsgRgetattr      MsgType = 25
   372  	MsgTsetattr      MsgType = 26
   373  	MsgRsetattr      MsgType = 27
   374  	MsgTlistxattr    MsgType = 28
   375  	MsgRlistxattr    MsgType = 29
   376  	MsgTxattrwalk    MsgType = 30
   377  	MsgRxattrwalk    MsgType = 31
   378  	MsgTxattrcreate  MsgType = 32
   379  	MsgRxattrcreate  MsgType = 33
   380  	MsgTgetxattr     MsgType = 34
   381  	MsgRgetxattr     MsgType = 35
   382  	MsgTsetxattr     MsgType = 36
   383  	MsgRsetxattr     MsgType = 37
   384  	MsgTremovexattr  MsgType = 38
   385  	MsgRremovexattr  MsgType = 39
   386  	MsgTreaddir      MsgType = 40
   387  	MsgRreaddir      MsgType = 41
   388  	MsgTfsync        MsgType = 50
   389  	MsgRfsync        MsgType = 51
   390  	MsgTlink         MsgType = 70
   391  	MsgRlink         MsgType = 71
   392  	MsgTmkdir        MsgType = 72
   393  	MsgRmkdir        MsgType = 73
   394  	MsgTrenameat     MsgType = 74
   395  	MsgRrenameat     MsgType = 75
   396  	MsgTunlinkat     MsgType = 76
   397  	MsgRunlinkat     MsgType = 77
   398  	MsgTversion      MsgType = 100
   399  	MsgRversion      MsgType = 101
   400  	MsgTauth         MsgType = 102
   401  	MsgRauth         MsgType = 103
   402  	MsgTattach       MsgType = 104
   403  	MsgRattach       MsgType = 105
   404  	MsgTflush        MsgType = 108
   405  	MsgRflush        MsgType = 109
   406  	MsgTwalk         MsgType = 110
   407  	MsgRwalk         MsgType = 111
   408  	MsgTread         MsgType = 116
   409  	MsgRread         MsgType = 117
   410  	MsgTwrite        MsgType = 118
   411  	MsgRwrite        MsgType = 119
   412  	MsgTclunk        MsgType = 120
   413  	MsgRclunk        MsgType = 121
   414  	MsgTremove       MsgType = 122
   415  	MsgRremove       MsgType = 123
   416  	MsgTflushf       MsgType = 124
   417  	MsgRflushf       MsgType = 125
   418  	MsgTwalkgetattr  MsgType = 126
   419  	MsgRwalkgetattr  MsgType = 127
   420  	MsgTucreate      MsgType = 128
   421  	MsgRucreate      MsgType = 129
   422  	MsgTumkdir       MsgType = 130
   423  	MsgRumkdir       MsgType = 131
   424  	MsgTumknod       MsgType = 132
   425  	MsgRumknod       MsgType = 133
   426  	MsgTusymlink     MsgType = 134
   427  	MsgRusymlink     MsgType = 135
   428  	MsgTlconnect     MsgType = 136
   429  	MsgRlconnect     MsgType = 137
   430  	MsgTallocate     MsgType = 138
   431  	MsgRallocate     MsgType = 139
   432  	MsgTsetattrclunk MsgType = 140
   433  	MsgRsetattrclunk MsgType = 141
   434  	MsgTmultigetattr MsgType = 142
   435  	MsgRmultigetattr MsgType = 143
   436  	MsgTbind         MsgType = 144
   437  	MsgRbind         MsgType = 145
   438  	MsgTchannel      MsgType = 250
   439  	MsgRchannel      MsgType = 251
   440  )
   441  
   442  // QIDType represents the file type for QIDs.
   443  //
   444  // QIDType corresponds to the high 8 bits of a Plan 9 file mode.
   445  type QIDType uint8
   446  
   447  const (
   448  	// TypeDir represents a directory type.
   449  	TypeDir QIDType = 0x80
   450  
   451  	// TypeAppendOnly represents an append only file.
   452  	TypeAppendOnly QIDType = 0x40
   453  
   454  	// TypeExclusive represents an exclusive-use file.
   455  	TypeExclusive QIDType = 0x20
   456  
   457  	// TypeMount represents a mounted channel.
   458  	TypeMount QIDType = 0x10
   459  
   460  	// TypeAuth represents an authentication file.
   461  	TypeAuth QIDType = 0x08
   462  
   463  	// TypeTemporary represents a temporary file.
   464  	TypeTemporary QIDType = 0x04
   465  
   466  	// TypeSymlink represents a symlink.
   467  	TypeSymlink QIDType = 0x02
   468  
   469  	// TypeLink represents a hard link.
   470  	TypeLink QIDType = 0x01
   471  
   472  	// TypeRegular represents a regular file.
   473  	TypeRegular QIDType = 0x00
   474  )
   475  
   476  // QID is a unique file identifier.
   477  //
   478  // This may be embedded in other requests and responses.
   479  type QID struct {
   480  	// Type is the highest order byte of the file mode.
   481  	Type QIDType
   482  
   483  	// Version is an arbitrary server version number.
   484  	Version uint32
   485  
   486  	// Path is a unique server identifier for this path (e.g. inode).
   487  	Path uint64
   488  }
   489  
   490  // String implements fmt.Stringer.
   491  func (q QID) String() string {
   492  	return fmt.Sprintf("QID{Type: %d, Version: %d, Path: %d}", q.Type, q.Version, q.Path)
   493  }
   494  
   495  // decode implements encoder.decode.
   496  func (q *QID) decode(b *buffer) {
   497  	q.Type = b.ReadQIDType()
   498  	q.Version = b.Read32()
   499  	q.Path = b.Read64()
   500  }
   501  
   502  // encode implements encoder.encode.
   503  func (q *QID) encode(b *buffer) {
   504  	b.WriteQIDType(q.Type)
   505  	b.Write32(q.Version)
   506  	b.Write64(q.Path)
   507  }
   508  
   509  // QIDGenerator is a simple generator for QIDs that atomically increments Path
   510  // values.
   511  type QIDGenerator struct {
   512  	// uids is an ever increasing value that can be atomically incremented
   513  	// to provide unique Path values for QIDs.
   514  	uids atomicbitops.Uint64
   515  }
   516  
   517  // Get returns a new 9P unique ID with a unique Path given a QID type.
   518  //
   519  // While the 9P spec allows Version to be incremented every time the file is
   520  // modified, we currently do not use the Version member for anything.  Hence,
   521  // it is set to 0.
   522  func (q *QIDGenerator) Get(t QIDType) QID {
   523  	return QID{
   524  		Type:    t,
   525  		Version: 0,
   526  		Path:    q.uids.Add(1),
   527  	}
   528  }
   529  
   530  // FSStat is used by statfs.
   531  type FSStat struct {
   532  	// Type is the filesystem type.
   533  	Type uint32
   534  
   535  	// BlockSize is the blocksize.
   536  	BlockSize uint32
   537  
   538  	// Blocks is the number of blocks.
   539  	Blocks uint64
   540  
   541  	// BlocksFree is the number of free blocks.
   542  	BlocksFree uint64
   543  
   544  	// BlocksAvailable is the number of blocks *available*.
   545  	BlocksAvailable uint64
   546  
   547  	// Files is the number of files available.
   548  	Files uint64
   549  
   550  	// FilesFree is the number of free file nodes.
   551  	FilesFree uint64
   552  
   553  	// FSID is the filesystem ID.
   554  	FSID uint64
   555  
   556  	// NameLength is the maximum name length.
   557  	NameLength uint32
   558  }
   559  
   560  // decode implements encoder.decode.
   561  func (f *FSStat) decode(b *buffer) {
   562  	f.Type = b.Read32()
   563  	f.BlockSize = b.Read32()
   564  	f.Blocks = b.Read64()
   565  	f.BlocksFree = b.Read64()
   566  	f.BlocksAvailable = b.Read64()
   567  	f.Files = b.Read64()
   568  	f.FilesFree = b.Read64()
   569  	f.FSID = b.Read64()
   570  	f.NameLength = b.Read32()
   571  }
   572  
   573  // encode implements encoder.encode.
   574  func (f *FSStat) encode(b *buffer) {
   575  	b.Write32(f.Type)
   576  	b.Write32(f.BlockSize)
   577  	b.Write64(f.Blocks)
   578  	b.Write64(f.BlocksFree)
   579  	b.Write64(f.BlocksAvailable)
   580  	b.Write64(f.Files)
   581  	b.Write64(f.FilesFree)
   582  	b.Write64(f.FSID)
   583  	b.Write32(f.NameLength)
   584  }
   585  
   586  // AttrMask is a mask of attributes for getattr.
   587  type AttrMask struct {
   588  	Mode        bool
   589  	NLink       bool
   590  	UID         bool
   591  	GID         bool
   592  	RDev        bool
   593  	ATime       bool
   594  	MTime       bool
   595  	CTime       bool
   596  	INo         bool
   597  	Size        bool
   598  	Blocks      bool
   599  	BTime       bool
   600  	Gen         bool
   601  	DataVersion bool
   602  }
   603  
   604  // Contains returns true if a contains all of the attributes masked as b.
   605  func (a AttrMask) Contains(b AttrMask) bool {
   606  	if b.Mode && !a.Mode {
   607  		return false
   608  	}
   609  	if b.NLink && !a.NLink {
   610  		return false
   611  	}
   612  	if b.UID && !a.UID {
   613  		return false
   614  	}
   615  	if b.GID && !a.GID {
   616  		return false
   617  	}
   618  	if b.RDev && !a.RDev {
   619  		return false
   620  	}
   621  	if b.ATime && !a.ATime {
   622  		return false
   623  	}
   624  	if b.MTime && !a.MTime {
   625  		return false
   626  	}
   627  	if b.CTime && !a.CTime {
   628  		return false
   629  	}
   630  	if b.INo && !a.INo {
   631  		return false
   632  	}
   633  	if b.Size && !a.Size {
   634  		return false
   635  	}
   636  	if b.Blocks && !a.Blocks {
   637  		return false
   638  	}
   639  	if b.BTime && !a.BTime {
   640  		return false
   641  	}
   642  	if b.Gen && !a.Gen {
   643  		return false
   644  	}
   645  	if b.DataVersion && !a.DataVersion {
   646  		return false
   647  	}
   648  	return true
   649  }
   650  
   651  // Empty returns true if no fields are masked.
   652  func (a AttrMask) Empty() bool {
   653  	return !a.Mode && !a.NLink && !a.UID && !a.GID && !a.RDev && !a.ATime && !a.MTime && !a.CTime && !a.INo && !a.Size && !a.Blocks && !a.BTime && !a.Gen && !a.DataVersion
   654  }
   655  
   656  // AttrMaskAll returns an AttrMask with all fields masked.
   657  func AttrMaskAll() AttrMask {
   658  	return AttrMask{
   659  		Mode:        true,
   660  		NLink:       true,
   661  		UID:         true,
   662  		GID:         true,
   663  		RDev:        true,
   664  		ATime:       true,
   665  		MTime:       true,
   666  		CTime:       true,
   667  		INo:         true,
   668  		Size:        true,
   669  		Blocks:      true,
   670  		BTime:       true,
   671  		Gen:         true,
   672  		DataVersion: true,
   673  	}
   674  }
   675  
   676  // String implements fmt.Stringer.
   677  func (a AttrMask) String() string {
   678  	var masks []string
   679  	if a.Mode {
   680  		masks = append(masks, "Mode")
   681  	}
   682  	if a.NLink {
   683  		masks = append(masks, "NLink")
   684  	}
   685  	if a.UID {
   686  		masks = append(masks, "UID")
   687  	}
   688  	if a.GID {
   689  		masks = append(masks, "GID")
   690  	}
   691  	if a.RDev {
   692  		masks = append(masks, "RDev")
   693  	}
   694  	if a.ATime {
   695  		masks = append(masks, "ATime")
   696  	}
   697  	if a.MTime {
   698  		masks = append(masks, "MTime")
   699  	}
   700  	if a.CTime {
   701  		masks = append(masks, "CTime")
   702  	}
   703  	if a.INo {
   704  		masks = append(masks, "INo")
   705  	}
   706  	if a.Size {
   707  		masks = append(masks, "Size")
   708  	}
   709  	if a.Blocks {
   710  		masks = append(masks, "Blocks")
   711  	}
   712  	if a.BTime {
   713  		masks = append(masks, "BTime")
   714  	}
   715  	if a.Gen {
   716  		masks = append(masks, "Gen")
   717  	}
   718  	if a.DataVersion {
   719  		masks = append(masks, "DataVersion")
   720  	}
   721  	return fmt.Sprintf("AttrMask{with: %s}", strings.Join(masks, " "))
   722  }
   723  
   724  // decode implements encoder.decode.
   725  func (a *AttrMask) decode(b *buffer) {
   726  	mask := b.Read64()
   727  	a.Mode = mask&0x00000001 != 0
   728  	a.NLink = mask&0x00000002 != 0
   729  	a.UID = mask&0x00000004 != 0
   730  	a.GID = mask&0x00000008 != 0
   731  	a.RDev = mask&0x00000010 != 0
   732  	a.ATime = mask&0x00000020 != 0
   733  	a.MTime = mask&0x00000040 != 0
   734  	a.CTime = mask&0x00000080 != 0
   735  	a.INo = mask&0x00000100 != 0
   736  	a.Size = mask&0x00000200 != 0
   737  	a.Blocks = mask&0x00000400 != 0
   738  	a.BTime = mask&0x00000800 != 0
   739  	a.Gen = mask&0x00001000 != 0
   740  	a.DataVersion = mask&0x00002000 != 0
   741  }
   742  
   743  // encode implements encoder.encode.
   744  func (a *AttrMask) encode(b *buffer) {
   745  	var mask uint64
   746  	if a.Mode {
   747  		mask |= 0x00000001
   748  	}
   749  	if a.NLink {
   750  		mask |= 0x00000002
   751  	}
   752  	if a.UID {
   753  		mask |= 0x00000004
   754  	}
   755  	if a.GID {
   756  		mask |= 0x00000008
   757  	}
   758  	if a.RDev {
   759  		mask |= 0x00000010
   760  	}
   761  	if a.ATime {
   762  		mask |= 0x00000020
   763  	}
   764  	if a.MTime {
   765  		mask |= 0x00000040
   766  	}
   767  	if a.CTime {
   768  		mask |= 0x00000080
   769  	}
   770  	if a.INo {
   771  		mask |= 0x00000100
   772  	}
   773  	if a.Size {
   774  		mask |= 0x00000200
   775  	}
   776  	if a.Blocks {
   777  		mask |= 0x00000400
   778  	}
   779  	if a.BTime {
   780  		mask |= 0x00000800
   781  	}
   782  	if a.Gen {
   783  		mask |= 0x00001000
   784  	}
   785  	if a.DataVersion {
   786  		mask |= 0x00002000
   787  	}
   788  	b.Write64(mask)
   789  }
   790  
   791  // Attr is a set of attributes for getattr.
   792  type Attr struct {
   793  	Mode             FileMode
   794  	UID              UID
   795  	GID              GID
   796  	NLink            uint64
   797  	RDev             uint64
   798  	Size             uint64
   799  	BlockSize        uint64
   800  	Blocks           uint64
   801  	ATimeSeconds     uint64
   802  	ATimeNanoSeconds uint64
   803  	MTimeSeconds     uint64
   804  	MTimeNanoSeconds uint64
   805  	CTimeSeconds     uint64
   806  	CTimeNanoSeconds uint64
   807  	BTimeSeconds     uint64
   808  	BTimeNanoSeconds uint64
   809  	Gen              uint64
   810  	DataVersion      uint64
   811  }
   812  
   813  // String implements fmt.Stringer.
   814  func (a Attr) String() string {
   815  	return fmt.Sprintf("Attr{Mode: 0o%o, UID: %d, GID: %d, NLink: %d, RDev: %d, Size: %d, BlockSize: %d, Blocks: %d, ATime: {Sec: %d, NanoSec: %d}, MTime: {Sec: %d, NanoSec: %d}, CTime: {Sec: %d, NanoSec: %d}, BTime: {Sec: %d, NanoSec: %d}, Gen: %d, DataVersion: %d}",
   816  		a.Mode, a.UID, a.GID, a.NLink, a.RDev, a.Size, a.BlockSize, a.Blocks, a.ATimeSeconds, a.ATimeNanoSeconds, a.MTimeSeconds, a.MTimeNanoSeconds, a.CTimeSeconds, a.CTimeNanoSeconds, a.BTimeSeconds, a.BTimeNanoSeconds, a.Gen, a.DataVersion)
   817  }
   818  
   819  // encode implements encoder.encode.
   820  func (a *Attr) encode(b *buffer) {
   821  	b.WriteFileMode(a.Mode)
   822  	b.WriteUID(a.UID)
   823  	b.WriteGID(a.GID)
   824  	b.Write64(a.NLink)
   825  	b.Write64(a.RDev)
   826  	b.Write64(a.Size)
   827  	b.Write64(a.BlockSize)
   828  	b.Write64(a.Blocks)
   829  	b.Write64(a.ATimeSeconds)
   830  	b.Write64(a.ATimeNanoSeconds)
   831  	b.Write64(a.MTimeSeconds)
   832  	b.Write64(a.MTimeNanoSeconds)
   833  	b.Write64(a.CTimeSeconds)
   834  	b.Write64(a.CTimeNanoSeconds)
   835  	b.Write64(a.BTimeSeconds)
   836  	b.Write64(a.BTimeNanoSeconds)
   837  	b.Write64(a.Gen)
   838  	b.Write64(a.DataVersion)
   839  }
   840  
   841  // decode implements encoder.decode.
   842  func (a *Attr) decode(b *buffer) {
   843  	a.Mode = b.ReadFileMode()
   844  	a.UID = b.ReadUID()
   845  	a.GID = b.ReadGID()
   846  	a.NLink = b.Read64()
   847  	a.RDev = b.Read64()
   848  	a.Size = b.Read64()
   849  	a.BlockSize = b.Read64()
   850  	a.Blocks = b.Read64()
   851  	a.ATimeSeconds = b.Read64()
   852  	a.ATimeNanoSeconds = b.Read64()
   853  	a.MTimeSeconds = b.Read64()
   854  	a.MTimeNanoSeconds = b.Read64()
   855  	a.CTimeSeconds = b.Read64()
   856  	a.CTimeNanoSeconds = b.Read64()
   857  	a.BTimeSeconds = b.Read64()
   858  	a.BTimeNanoSeconds = b.Read64()
   859  	a.Gen = b.Read64()
   860  	a.DataVersion = b.Read64()
   861  }
   862  
   863  // StatToAttr converts a Linux syscall stat structure to an Attr.
   864  func StatToAttr(s *syscall.Stat_t, req AttrMask) (Attr, AttrMask) {
   865  	attr := Attr{
   866  		UID: NoUID,
   867  		GID: NoGID,
   868  	}
   869  	if req.Mode {
   870  		// p9.FileMode corresponds to Linux mode_t.
   871  		attr.Mode = FileMode(s.Mode)
   872  	}
   873  	if req.NLink {
   874  		attr.NLink = uint64(s.Nlink)
   875  	}
   876  	if req.UID {
   877  		attr.UID = UID(s.Uid)
   878  	}
   879  	if req.GID {
   880  		attr.GID = GID(s.Gid)
   881  	}
   882  	if req.RDev {
   883  		attr.RDev = s.Dev
   884  	}
   885  	if req.ATime {
   886  		attr.ATimeSeconds = uint64(s.Atim.Sec)
   887  		attr.ATimeNanoSeconds = uint64(s.Atim.Nsec)
   888  	}
   889  	if req.MTime {
   890  		attr.MTimeSeconds = uint64(s.Mtim.Sec)
   891  		attr.MTimeNanoSeconds = uint64(s.Mtim.Nsec)
   892  	}
   893  	if req.CTime {
   894  		attr.CTimeSeconds = uint64(s.Ctim.Sec)
   895  		attr.CTimeNanoSeconds = uint64(s.Ctim.Nsec)
   896  	}
   897  	if req.Size {
   898  		attr.Size = uint64(s.Size)
   899  	}
   900  	if req.Blocks {
   901  		attr.BlockSize = uint64(s.Blksize)
   902  		attr.Blocks = uint64(s.Blocks)
   903  	}
   904  
   905  	// Use the req field because we already have it.
   906  	req.BTime = false
   907  	req.Gen = false
   908  	req.DataVersion = false
   909  
   910  	return attr, req
   911  }
   912  
   913  // SetAttrMask specifies a valid mask for setattr.
   914  type SetAttrMask struct {
   915  	Permissions        bool
   916  	UID                bool
   917  	GID                bool
   918  	Size               bool
   919  	ATime              bool
   920  	MTime              bool
   921  	CTime              bool
   922  	ATimeNotSystemTime bool
   923  	MTimeNotSystemTime bool
   924  }
   925  
   926  // IsSubsetOf returns whether s is a subset of m.
   927  func (s SetAttrMask) IsSubsetOf(m SetAttrMask) bool {
   928  	sb := s.bitmask()
   929  	sm := m.bitmask()
   930  	return sm|sb == sm
   931  }
   932  
   933  // String implements fmt.Stringer.
   934  func (s SetAttrMask) String() string {
   935  	var masks []string
   936  	if s.Permissions {
   937  		masks = append(masks, "Permissions")
   938  	}
   939  	if s.UID {
   940  		masks = append(masks, "UID")
   941  	}
   942  	if s.GID {
   943  		masks = append(masks, "GID")
   944  	}
   945  	if s.Size {
   946  		masks = append(masks, "Size")
   947  	}
   948  	if s.ATime {
   949  		masks = append(masks, "ATime")
   950  	}
   951  	if s.MTime {
   952  		masks = append(masks, "MTime")
   953  	}
   954  	if s.CTime {
   955  		masks = append(masks, "CTime")
   956  	}
   957  	if s.ATimeNotSystemTime {
   958  		masks = append(masks, "ATimeNotSystemTime")
   959  	}
   960  	if s.MTimeNotSystemTime {
   961  		masks = append(masks, "MTimeNotSystemTime")
   962  	}
   963  	return fmt.Sprintf("SetAttrMask{with: %s}", strings.Join(masks, " "))
   964  }
   965  
   966  // Empty returns true if no fields are masked.
   967  func (s SetAttrMask) Empty() bool {
   968  	return !s.Permissions && !s.UID && !s.GID && !s.Size && !s.ATime && !s.MTime && !s.CTime && !s.ATimeNotSystemTime && !s.MTimeNotSystemTime
   969  }
   970  
   971  // decode implements encoder.decode.
   972  func (s *SetAttrMask) decode(b *buffer) {
   973  	mask := b.Read32()
   974  	s.Permissions = mask&0x00000001 != 0
   975  	s.UID = mask&0x00000002 != 0
   976  	s.GID = mask&0x00000004 != 0
   977  	s.Size = mask&0x00000008 != 0
   978  	s.ATime = mask&0x00000010 != 0
   979  	s.MTime = mask&0x00000020 != 0
   980  	s.CTime = mask&0x00000040 != 0
   981  	s.ATimeNotSystemTime = mask&0x00000080 != 0
   982  	s.MTimeNotSystemTime = mask&0x00000100 != 0
   983  }
   984  
   985  func (s SetAttrMask) bitmask() uint32 {
   986  	var mask uint32
   987  	if s.Permissions {
   988  		mask |= 0x00000001
   989  	}
   990  	if s.UID {
   991  		mask |= 0x00000002
   992  	}
   993  	if s.GID {
   994  		mask |= 0x00000004
   995  	}
   996  	if s.Size {
   997  		mask |= 0x00000008
   998  	}
   999  	if s.ATime {
  1000  		mask |= 0x00000010
  1001  	}
  1002  	if s.MTime {
  1003  		mask |= 0x00000020
  1004  	}
  1005  	if s.CTime {
  1006  		mask |= 0x00000040
  1007  	}
  1008  	if s.ATimeNotSystemTime {
  1009  		mask |= 0x00000080
  1010  	}
  1011  	if s.MTimeNotSystemTime {
  1012  		mask |= 0x00000100
  1013  	}
  1014  	return mask
  1015  }
  1016  
  1017  // encode implements encoder.encode.
  1018  func (s *SetAttrMask) encode(b *buffer) {
  1019  	b.Write32(s.bitmask())
  1020  }
  1021  
  1022  // SetAttr specifies a set of attributes for a setattr.
  1023  type SetAttr struct {
  1024  	Permissions      FileMode
  1025  	UID              UID
  1026  	GID              GID
  1027  	Size             uint64
  1028  	ATimeSeconds     uint64
  1029  	ATimeNanoSeconds uint64
  1030  	MTimeSeconds     uint64
  1031  	MTimeNanoSeconds uint64
  1032  }
  1033  
  1034  // String implements fmt.Stringer.
  1035  func (s SetAttr) String() string {
  1036  	return fmt.Sprintf("SetAttr{Permissions: 0o%o, UID: %d, GID: %d, Size: %d, ATime: {Sec: %d, NanoSec: %d}, MTime: {Sec: %d, NanoSec: %d}}", s.Permissions, s.UID, s.GID, s.Size, s.ATimeSeconds, s.ATimeNanoSeconds, s.MTimeSeconds, s.MTimeNanoSeconds)
  1037  }
  1038  
  1039  // decode implements encoder.decode.
  1040  func (s *SetAttr) decode(b *buffer) {
  1041  	s.Permissions = b.ReadPermissions()
  1042  	s.UID = b.ReadUID()
  1043  	s.GID = b.ReadGID()
  1044  	s.Size = b.Read64()
  1045  	s.ATimeSeconds = b.Read64()
  1046  	s.ATimeNanoSeconds = b.Read64()
  1047  	s.MTimeSeconds = b.Read64()
  1048  	s.MTimeNanoSeconds = b.Read64()
  1049  }
  1050  
  1051  // encode implements encoder.encode.
  1052  func (s *SetAttr) encode(b *buffer) {
  1053  	b.WritePermissions(s.Permissions)
  1054  	b.WriteUID(s.UID)
  1055  	b.WriteGID(s.GID)
  1056  	b.Write64(s.Size)
  1057  	b.Write64(s.ATimeSeconds)
  1058  	b.Write64(s.ATimeNanoSeconds)
  1059  	b.Write64(s.MTimeSeconds)
  1060  	b.Write64(s.MTimeNanoSeconds)
  1061  }
  1062  
  1063  // Apply applies this to the given Attr.
  1064  func (a *Attr) Apply(mask SetAttrMask, attr SetAttr) {
  1065  	if mask.Permissions {
  1066  		a.Mode = a.Mode&^permissionsMask | (attr.Permissions & permissionsMask)
  1067  	}
  1068  	if mask.UID {
  1069  		a.UID = attr.UID
  1070  	}
  1071  	if mask.GID {
  1072  		a.GID = attr.GID
  1073  	}
  1074  	if mask.Size {
  1075  		a.Size = attr.Size
  1076  	}
  1077  	if mask.ATime {
  1078  		a.ATimeSeconds = attr.ATimeSeconds
  1079  		a.ATimeNanoSeconds = attr.ATimeNanoSeconds
  1080  	}
  1081  	if mask.MTime {
  1082  		a.MTimeSeconds = attr.MTimeSeconds
  1083  		a.MTimeNanoSeconds = attr.MTimeNanoSeconds
  1084  	}
  1085  }
  1086  
  1087  // DirentSizeStatic is the number of bytes required to encode a p9.Dirent
  1088  // with an empty name. In other words, it is the static part of its size.
  1089  const DirentSizeStatic = 24
  1090  
  1091  // Dirent is used for readdir.
  1092  type Dirent struct {
  1093  	// QID is the entry QID.
  1094  	QID QID
  1095  
  1096  	// Offset is the offset in the directory.
  1097  	//
  1098  	// This will be communicated back the original caller.
  1099  	Offset uint64
  1100  
  1101  	// Type is the 9P type.
  1102  	Type QIDType
  1103  
  1104  	// Name is the name of the entry (i.e. basename).
  1105  	Name string
  1106  }
  1107  
  1108  // String implements fmt.Stringer.
  1109  func (d Dirent) String() string {
  1110  	return fmt.Sprintf("Dirent{QID: %d, Offset: %d, Type: 0x%X, Name: %s}", d.QID, d.Offset, d.Type, d.Name)
  1111  }
  1112  
  1113  // decode implements encoder.decode.
  1114  func (d *Dirent) decode(b *buffer) {
  1115  	d.QID.decode(b)
  1116  	d.Offset = b.Read64()
  1117  	d.Type = b.ReadQIDType()
  1118  	d.Name = b.ReadString()
  1119  }
  1120  
  1121  // encode implements encoder.encode.
  1122  func (d *Dirent) encode(b *buffer) {
  1123  	d.QID.encode(b)
  1124  	b.Write64(d.Offset)
  1125  	b.WriteQIDType(d.Type)
  1126  	b.WriteString(d.Name)
  1127  }
  1128  
  1129  // AllocateMode are possible modes to p9.File.Allocate().
  1130  type AllocateMode struct {
  1131  	KeepSize      bool
  1132  	PunchHole     bool
  1133  	NoHideStale   bool
  1134  	CollapseRange bool
  1135  	ZeroRange     bool
  1136  	InsertRange   bool
  1137  	Unshare       bool
  1138  }
  1139  
  1140  // ToAllocateMode returns an AllocateMode from a fallocate(2) mode.
  1141  func ToAllocateMode(mode uint64) AllocateMode {
  1142  	return AllocateMode{
  1143  		KeepSize:      mode&unix.FALLOC_FL_KEEP_SIZE != 0,
  1144  		PunchHole:     mode&unix.FALLOC_FL_PUNCH_HOLE != 0,
  1145  		NoHideStale:   mode&unix.FALLOC_FL_NO_HIDE_STALE != 0,
  1146  		CollapseRange: mode&unix.FALLOC_FL_COLLAPSE_RANGE != 0,
  1147  		ZeroRange:     mode&unix.FALLOC_FL_ZERO_RANGE != 0,
  1148  		InsertRange:   mode&unix.FALLOC_FL_INSERT_RANGE != 0,
  1149  		Unshare:       mode&unix.FALLOC_FL_UNSHARE_RANGE != 0,
  1150  	}
  1151  }
  1152  
  1153  // ToLinux converts to a value compatible with fallocate(2)'s mode.
  1154  func (a *AllocateMode) ToLinux() uint32 {
  1155  	rv := uint32(0)
  1156  	if a.KeepSize {
  1157  		rv |= unix.FALLOC_FL_KEEP_SIZE
  1158  	}
  1159  	if a.PunchHole {
  1160  		rv |= unix.FALLOC_FL_PUNCH_HOLE
  1161  	}
  1162  	if a.NoHideStale {
  1163  		rv |= unix.FALLOC_FL_NO_HIDE_STALE
  1164  	}
  1165  	if a.CollapseRange {
  1166  		rv |= unix.FALLOC_FL_COLLAPSE_RANGE
  1167  	}
  1168  	if a.ZeroRange {
  1169  		rv |= unix.FALLOC_FL_ZERO_RANGE
  1170  	}
  1171  	if a.InsertRange {
  1172  		rv |= unix.FALLOC_FL_INSERT_RANGE
  1173  	}
  1174  	if a.Unshare {
  1175  		rv |= unix.FALLOC_FL_UNSHARE_RANGE
  1176  	}
  1177  	return rv
  1178  }
  1179  
  1180  // decode implements encoder.decode.
  1181  func (a *AllocateMode) decode(b *buffer) {
  1182  	mask := b.Read32()
  1183  	a.KeepSize = mask&0x01 != 0
  1184  	a.PunchHole = mask&0x02 != 0
  1185  	a.NoHideStale = mask&0x04 != 0
  1186  	a.CollapseRange = mask&0x08 != 0
  1187  	a.ZeroRange = mask&0x10 != 0
  1188  	a.InsertRange = mask&0x20 != 0
  1189  	a.Unshare = mask&0x40 != 0
  1190  }
  1191  
  1192  // encode implements encoder.encode.
  1193  func (a *AllocateMode) encode(b *buffer) {
  1194  	mask := uint32(0)
  1195  	if a.KeepSize {
  1196  		mask |= 0x01
  1197  	}
  1198  	if a.PunchHole {
  1199  		mask |= 0x02
  1200  	}
  1201  	if a.NoHideStale {
  1202  		mask |= 0x04
  1203  	}
  1204  	if a.CollapseRange {
  1205  		mask |= 0x08
  1206  	}
  1207  	if a.ZeroRange {
  1208  		mask |= 0x10
  1209  	}
  1210  	if a.InsertRange {
  1211  		mask |= 0x20
  1212  	}
  1213  	if a.Unshare {
  1214  		mask |= 0x40
  1215  	}
  1216  	b.Write32(mask)
  1217  }
  1218  
  1219  // FullStat is used in the result of a MultiGetAttr call.
  1220  type FullStat struct {
  1221  	QID   QID
  1222  	Valid AttrMask
  1223  	Attr  Attr
  1224  }
  1225  
  1226  // String implements fmt.Stringer.
  1227  func (f *FullStat) String() string {
  1228  	return fmt.Sprintf("FullStat{QID: %v, Valid: %v, Attr: %v}", f.QID, f.Valid, f.Attr)
  1229  }
  1230  
  1231  // decode implements encoder.decode.
  1232  func (f *FullStat) decode(b *buffer) {
  1233  	f.QID.decode(b)
  1234  	f.Valid.decode(b)
  1235  	f.Attr.decode(b)
  1236  }
  1237  
  1238  // encode implements encoder.encode.
  1239  func (f *FullStat) encode(b *buffer) {
  1240  	f.QID.encode(b)
  1241  	f.Valid.encode(b)
  1242  	f.Attr.encode(b)
  1243  }