github.com/vmware/govmomi@v0.51.0/toolbox/vix/protocol.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package vix
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/base64"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"os"
    13  	"os/exec"
    14  	"syscall"
    15  )
    16  
    17  const (
    18  	CommandMagicWord = 0xd00d0001
    19  
    20  	CommandGetToolsState = 62
    21  
    22  	CommandStartProgram     = 185
    23  	CommandListProcessesEx  = 186
    24  	CommandReadEnvVariables = 187
    25  	CommandTerminateProcess = 193
    26  
    27  	CommandCreateDirectoryEx        = 178
    28  	CommandMoveGuestFileEx          = 179
    29  	CommandMoveGuestDirectory       = 180
    30  	CommandCreateTemporaryFileEx    = 181
    31  	CommandCreateTemporaryDirectory = 182
    32  	CommandSetGuestFileAttributes   = 183
    33  	CommandDeleteGuestFileEx        = 194
    34  	CommandDeleteGuestDirectoryEx   = 195
    35  
    36  	CommandListFiles                     = 177
    37  	HgfsSendPacketCommand                = 84
    38  	CommandInitiateFileTransferFromGuest = 188
    39  	CommandInitiateFileTransferToGuest   = 189
    40  
    41  	// VIX_USER_CREDENTIAL_NAME_PASSWORD
    42  	UserCredentialTypeNamePassword = 1
    43  
    44  	// VIX_E_* constants from vix.h
    45  	OK                 = 0
    46  	Fail               = 1
    47  	InvalidArg         = 3
    48  	FileNotFound       = 4
    49  	FileAlreadyExists  = 12
    50  	FileAccessError    = 13
    51  	AuthenticationFail = 35
    52  
    53  	UnrecognizedCommandInGuest = 3025
    54  	InvalidMessageHeader       = 10000
    55  	InvalidMessageBody         = 10001
    56  	NotAFile                   = 20001
    57  	NotADirectory              = 20002
    58  	NoSuchProcess              = 20003
    59  	DirectoryNotEmpty          = 20006
    60  
    61  	// VIX_COMMAND_* constants from Commands.h
    62  	CommandGuestReturnsBinary = 0x80
    63  
    64  	// VIX_FILE_ATTRIBUTES_ constants from vix.h
    65  	FileAttributesDirectory = 0x0001
    66  	FileAttributesSymlink   = 0x0002
    67  )
    68  
    69  // SetGuestFileAttributes flags as defined in vixOpenSource.h
    70  const (
    71  	FileAttributeSetAccessDate      = 0x0001
    72  	FileAttributeSetModifyDate      = 0x0002
    73  	FileAttributeSetReadonly        = 0x0004
    74  	FileAttributeSetHidden          = 0x0008
    75  	FileAttributeSetUnixOwnerid     = 0x0010
    76  	FileAttributeSetUnixGroupid     = 0x0020
    77  	FileAttributeSetUnixPermissions = 0x0040
    78  )
    79  
    80  type Error int
    81  
    82  func (err Error) Error() string {
    83  	return fmt.Sprintf("vix error=%d", err)
    84  }
    85  
    86  // ErrorCode does its best to map the given error to a VIX error code.
    87  // See also: Vix_TranslateErrno
    88  func ErrorCode(err error) int {
    89  	switch t := err.(type) {
    90  	case Error:
    91  		return int(t)
    92  	case *os.PathError:
    93  		if errno, ok := t.Err.(syscall.Errno); ok {
    94  			switch errno {
    95  			case syscall.ENOTEMPTY:
    96  				return DirectoryNotEmpty
    97  			}
    98  		}
    99  	case *exec.Error:
   100  		if t.Err == exec.ErrNotFound {
   101  			return FileNotFound
   102  		}
   103  	}
   104  
   105  	switch {
   106  	case os.IsNotExist(err):
   107  		return FileNotFound
   108  	case os.IsExist(err):
   109  		return FileAlreadyExists
   110  	case os.IsPermission(err):
   111  		return FileAccessError
   112  	default:
   113  		return Fail
   114  	}
   115  }
   116  
   117  type Header struct {
   118  	Magic          uint32
   119  	MessageVersion uint16
   120  
   121  	TotalMessageLength uint32
   122  	HeaderLength       uint32
   123  	BodyLength         uint32
   124  	CredentialLength   uint32
   125  
   126  	CommonFlags uint8
   127  }
   128  
   129  type CommandRequestHeader struct {
   130  	Header
   131  
   132  	OpCode       uint32
   133  	RequestFlags uint32
   134  
   135  	TimeOut uint32
   136  
   137  	Cookie         uint64
   138  	ClientHandleID uint32
   139  
   140  	UserCredentialType uint32
   141  }
   142  
   143  type StartProgramRequest struct {
   144  	CommandRequestHeader
   145  
   146  	Body struct {
   147  		StartMinimized    uint8
   148  		ProgramPathLength uint32
   149  		ArgumentsLength   uint32
   150  		WorkingDirLength  uint32
   151  		NumEnvVars        uint32
   152  		EnvVarLength      uint32
   153  	}
   154  
   155  	ProgramPath string
   156  	Arguments   string
   157  	WorkingDir  string
   158  	EnvVars     []string
   159  }
   160  
   161  // MarshalBinary implements the encoding.BinaryMarshaler interface
   162  func (r *StartProgramRequest) MarshalBinary() ([]byte, error) {
   163  	var env bytes.Buffer
   164  
   165  	if n := len(r.EnvVars); n != 0 {
   166  		for _, e := range r.EnvVars {
   167  			_, _ = env.Write([]byte(e))
   168  			_ = env.WriteByte(0)
   169  		}
   170  		r.Body.NumEnvVars = uint32(n)
   171  		r.Body.EnvVarLength = uint32(env.Len())
   172  	}
   173  
   174  	var fields []string
   175  
   176  	add := func(s string, l *uint32) {
   177  		if n := len(s); n != 0 {
   178  			*l = uint32(n) + 1
   179  			fields = append(fields, s)
   180  		}
   181  	}
   182  
   183  	add(r.ProgramPath, &r.Body.ProgramPathLength)
   184  	add(r.Arguments, &r.Body.ArgumentsLength)
   185  	add(r.WorkingDir, &r.Body.WorkingDirLength)
   186  
   187  	buf := new(bytes.Buffer)
   188  
   189  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   190  
   191  	for _, val := range fields {
   192  		_, _ = buf.Write([]byte(val))
   193  		_ = buf.WriteByte(0)
   194  	}
   195  
   196  	if r.Body.EnvVarLength != 0 {
   197  		_, _ = buf.Write(env.Bytes())
   198  	}
   199  
   200  	return buf.Bytes(), nil
   201  }
   202  
   203  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   204  func (r *StartProgramRequest) UnmarshalBinary(data []byte) error {
   205  	buf := bytes.NewBuffer(data)
   206  
   207  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   208  	if err != nil {
   209  		return err
   210  	}
   211  
   212  	fields := []struct {
   213  		len uint32
   214  		val *string
   215  	}{
   216  		{r.Body.ProgramPathLength, &r.ProgramPath},
   217  		{r.Body.ArgumentsLength, &r.Arguments},
   218  		{r.Body.WorkingDirLength, &r.WorkingDir},
   219  	}
   220  
   221  	for _, field := range fields {
   222  		if field.len == 0 {
   223  			continue
   224  		}
   225  
   226  		x := buf.Next(int(field.len))
   227  		*field.val = string(bytes.TrimRight(x, "\x00"))
   228  	}
   229  
   230  	for i := 0; i < int(r.Body.NumEnvVars); i++ {
   231  		env, rerr := buf.ReadString(0)
   232  		if rerr != nil {
   233  			return rerr
   234  		}
   235  
   236  		env = env[:len(env)-1] // discard NULL terminator
   237  		r.EnvVars = append(r.EnvVars, env)
   238  	}
   239  
   240  	return nil
   241  }
   242  
   243  type KillProcessRequest struct {
   244  	CommandRequestHeader
   245  
   246  	Body struct {
   247  		Pid     int64
   248  		Options uint32
   249  	}
   250  }
   251  
   252  // MarshalBinary implements the encoding.BinaryMarshaler interface
   253  func (r *KillProcessRequest) MarshalBinary() ([]byte, error) {
   254  	buf := new(bytes.Buffer)
   255  
   256  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   257  
   258  	return buf.Bytes(), nil
   259  }
   260  
   261  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   262  func (r *KillProcessRequest) UnmarshalBinary(data []byte) error {
   263  	buf := bytes.NewBuffer(data)
   264  
   265  	return binary.Read(buf, binary.LittleEndian, &r.Body)
   266  }
   267  
   268  type ListProcessesRequest struct {
   269  	CommandRequestHeader
   270  
   271  	Body struct {
   272  		Key     uint32
   273  		Offset  uint32
   274  		NumPids uint32
   275  	}
   276  
   277  	Pids []int64
   278  }
   279  
   280  // MarshalBinary implements the encoding.BinaryMarshaler interface
   281  func (r *ListProcessesRequest) MarshalBinary() ([]byte, error) {
   282  	r.Body.NumPids = uint32(len(r.Pids))
   283  
   284  	buf := new(bytes.Buffer)
   285  
   286  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   287  
   288  	for _, pid := range r.Pids {
   289  		_ = binary.Write(buf, binary.LittleEndian, &pid)
   290  	}
   291  
   292  	return buf.Bytes(), nil
   293  }
   294  
   295  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   296  func (r *ListProcessesRequest) UnmarshalBinary(data []byte) error {
   297  	buf := bytes.NewBuffer(data)
   298  
   299  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   300  	if err != nil {
   301  		return err
   302  	}
   303  
   304  	r.Pids = make([]int64, r.Body.NumPids)
   305  
   306  	for i := uint32(0); i < r.Body.NumPids; i++ {
   307  		err := binary.Read(buf, binary.LittleEndian, &r.Pids[i])
   308  		if err != nil {
   309  			return err
   310  		}
   311  	}
   312  
   313  	return nil
   314  }
   315  
   316  type ReadEnvironmentVariablesRequest struct {
   317  	CommandRequestHeader
   318  
   319  	Body struct {
   320  		NumNames    uint32
   321  		NamesLength uint32
   322  	}
   323  
   324  	Names []string
   325  }
   326  
   327  // MarshalBinary implements the encoding.BinaryMarshaler interface
   328  func (r *ReadEnvironmentVariablesRequest) MarshalBinary() ([]byte, error) {
   329  	var env bytes.Buffer
   330  
   331  	if n := len(r.Names); n != 0 {
   332  		for _, e := range r.Names {
   333  			_, _ = env.Write([]byte(e))
   334  			_ = env.WriteByte(0)
   335  		}
   336  		r.Body.NumNames = uint32(n)
   337  		r.Body.NamesLength = uint32(env.Len())
   338  	}
   339  
   340  	buf := new(bytes.Buffer)
   341  
   342  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   343  
   344  	if r.Body.NamesLength != 0 {
   345  		_, _ = buf.Write(env.Bytes())
   346  	}
   347  
   348  	return buf.Bytes(), nil
   349  }
   350  
   351  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   352  func (r *ReadEnvironmentVariablesRequest) UnmarshalBinary(data []byte) error {
   353  	buf := bytes.NewBuffer(data)
   354  
   355  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   356  	if err != nil {
   357  		return err
   358  	}
   359  
   360  	for i := 0; i < int(r.Body.NumNames); i++ {
   361  		env, rerr := buf.ReadString(0)
   362  		if rerr != nil {
   363  			return rerr
   364  		}
   365  
   366  		env = env[:len(env)-1] // discard NULL terminator
   367  		r.Names = append(r.Names, env)
   368  	}
   369  
   370  	return nil
   371  }
   372  
   373  type CreateTempFileRequest struct {
   374  	CommandRequestHeader
   375  
   376  	Body struct {
   377  		Options             int32
   378  		FilePrefixLength    uint32
   379  		FileSuffixLength    uint32
   380  		DirectoryPathLength uint32
   381  		PropertyListLength  uint32
   382  	}
   383  
   384  	FilePrefix    string
   385  	FileSuffix    string
   386  	DirectoryPath string
   387  }
   388  
   389  // MarshalBinary implements the encoding.BinaryMarshaler interface
   390  func (r *CreateTempFileRequest) MarshalBinary() ([]byte, error) {
   391  	var fields []string
   392  
   393  	add := func(s string, l *uint32) {
   394  		*l = uint32(len(s)) // NOTE: NULL byte is not included in the length fields on the wire
   395  		fields = append(fields, s)
   396  	}
   397  
   398  	add(r.FilePrefix, &r.Body.FilePrefixLength)
   399  	add(r.FileSuffix, &r.Body.FileSuffixLength)
   400  	add(r.DirectoryPath, &r.Body.DirectoryPathLength)
   401  
   402  	buf := new(bytes.Buffer)
   403  
   404  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   405  
   406  	for _, val := range fields {
   407  		_, _ = buf.Write([]byte(val))
   408  		_ = buf.WriteByte(0)
   409  	}
   410  
   411  	return buf.Bytes(), nil
   412  }
   413  
   414  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   415  func (r *CreateTempFileRequest) UnmarshalBinary(data []byte) error {
   416  	buf := bytes.NewBuffer(data)
   417  
   418  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   419  	if err != nil {
   420  		return err
   421  	}
   422  
   423  	fields := []struct {
   424  		len uint32
   425  		val *string
   426  	}{
   427  		{r.Body.FilePrefixLength, &r.FilePrefix},
   428  		{r.Body.FileSuffixLength, &r.FileSuffix},
   429  		{r.Body.DirectoryPathLength, &r.DirectoryPath},
   430  	}
   431  
   432  	for _, field := range fields {
   433  		field.len++ // NOTE: NULL byte is not included in the length fields on the wire
   434  
   435  		x := buf.Next(int(field.len))
   436  		*field.val = string(bytes.TrimRight(x, "\x00"))
   437  	}
   438  
   439  	return nil
   440  }
   441  
   442  type FileRequest struct {
   443  	CommandRequestHeader
   444  
   445  	Body struct {
   446  		FileOptions         int32
   447  		GuestPathNameLength uint32
   448  	}
   449  
   450  	GuestPathName string
   451  }
   452  
   453  // MarshalBinary implements the encoding.BinaryMarshaler interface
   454  func (r *FileRequest) MarshalBinary() ([]byte, error) {
   455  	buf := new(bytes.Buffer)
   456  
   457  	r.Body.GuestPathNameLength = uint32(len(r.GuestPathName))
   458  
   459  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   460  
   461  	_, _ = buf.WriteString(r.GuestPathName)
   462  	_ = buf.WriteByte(0)
   463  
   464  	return buf.Bytes(), nil
   465  }
   466  
   467  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   468  func (r *FileRequest) UnmarshalBinary(data []byte) error {
   469  	buf := bytes.NewBuffer(data)
   470  
   471  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   472  	if err != nil {
   473  		return err
   474  	}
   475  
   476  	name := buf.Next(int(r.Body.GuestPathNameLength))
   477  	r.GuestPathName = string(bytes.TrimRight(name, "\x00"))
   478  
   479  	return nil
   480  }
   481  
   482  type DirRequest struct {
   483  	CommandRequestHeader
   484  
   485  	Body struct {
   486  		FileOptions          int32
   487  		GuestPathNameLength  uint32
   488  		FilePropertiesLength uint32
   489  		Recursive            bool
   490  	}
   491  
   492  	GuestPathName string
   493  }
   494  
   495  // MarshalBinary implements the encoding.BinaryMarshaler interface
   496  func (r *DirRequest) MarshalBinary() ([]byte, error) {
   497  	buf := new(bytes.Buffer)
   498  
   499  	r.Body.GuestPathNameLength = uint32(len(r.GuestPathName))
   500  
   501  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   502  
   503  	_, _ = buf.WriteString(r.GuestPathName)
   504  	_ = buf.WriteByte(0)
   505  
   506  	return buf.Bytes(), nil
   507  }
   508  
   509  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   510  func (r *DirRequest) UnmarshalBinary(data []byte) error {
   511  	buf := bytes.NewBuffer(data)
   512  
   513  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   514  	if err != nil {
   515  		return err
   516  	}
   517  
   518  	name := buf.Next(int(r.Body.GuestPathNameLength))
   519  	r.GuestPathName = string(bytes.TrimRight(name, "\x00"))
   520  
   521  	return nil
   522  }
   523  
   524  type RenameFileRequest struct {
   525  	CommandRequestHeader
   526  
   527  	Body struct {
   528  		CopyFileOptions      int32
   529  		OldPathNameLength    uint32
   530  		NewPathNameLength    uint32
   531  		FilePropertiesLength uint32
   532  		Overwrite            bool
   533  	}
   534  
   535  	OldPathName string
   536  	NewPathName string
   537  }
   538  
   539  // MarshalBinary implements the encoding.BinaryMarshaler interface
   540  func (r *RenameFileRequest) MarshalBinary() ([]byte, error) {
   541  	var fields []string
   542  
   543  	add := func(s string, l *uint32) {
   544  		*l = uint32(len(s)) // NOTE: NULL byte is not included in the length fields on the wire
   545  		fields = append(fields, s)
   546  	}
   547  
   548  	add(r.OldPathName, &r.Body.OldPathNameLength)
   549  	add(r.NewPathName, &r.Body.NewPathNameLength)
   550  
   551  	buf := new(bytes.Buffer)
   552  
   553  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   554  
   555  	for _, val := range fields {
   556  		_, _ = buf.Write([]byte(val))
   557  		_ = buf.WriteByte(0)
   558  	}
   559  
   560  	return buf.Bytes(), nil
   561  }
   562  
   563  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   564  func (r *RenameFileRequest) UnmarshalBinary(data []byte) error {
   565  	buf := bytes.NewBuffer(data)
   566  
   567  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   568  	if err != nil {
   569  		return err
   570  	}
   571  
   572  	fields := []struct {
   573  		len uint32
   574  		val *string
   575  	}{
   576  		{r.Body.OldPathNameLength, &r.OldPathName},
   577  		{r.Body.NewPathNameLength, &r.NewPathName},
   578  	}
   579  
   580  	for _, field := range fields {
   581  		field.len++ // NOTE: NULL byte is not included in the length fields on the wire
   582  
   583  		x := buf.Next(int(field.len))
   584  		*field.val = string(bytes.TrimRight(x, "\x00"))
   585  	}
   586  
   587  	return nil
   588  }
   589  
   590  type ListFilesRequest struct {
   591  	CommandRequestHeader
   592  
   593  	Body struct {
   594  		FileOptions         int32
   595  		GuestPathNameLength uint32
   596  		PatternLength       uint32
   597  		Index               int32
   598  		MaxResults          int32
   599  		Offset              uint64
   600  	}
   601  
   602  	GuestPathName string
   603  	Pattern       string
   604  }
   605  
   606  // MarshalBinary implements the encoding.BinaryMarshaler interface
   607  func (r *ListFilesRequest) MarshalBinary() ([]byte, error) {
   608  	var fields []string
   609  
   610  	add := func(s string, l *uint32) {
   611  		if n := len(s); n != 0 {
   612  			*l = uint32(n) + 1
   613  			fields = append(fields, s)
   614  		}
   615  	}
   616  
   617  	add(r.GuestPathName, &r.Body.GuestPathNameLength)
   618  	add(r.Pattern, &r.Body.PatternLength)
   619  
   620  	buf := new(bytes.Buffer)
   621  
   622  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   623  
   624  	for _, val := range fields {
   625  		_, _ = buf.Write([]byte(val))
   626  		_ = buf.WriteByte(0)
   627  	}
   628  
   629  	return buf.Bytes(), nil
   630  }
   631  
   632  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   633  func (r *ListFilesRequest) UnmarshalBinary(data []byte) error {
   634  	buf := bytes.NewBuffer(data)
   635  
   636  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   637  	if err != nil {
   638  		return err
   639  	}
   640  
   641  	fields := []struct {
   642  		len uint32
   643  		val *string
   644  	}{
   645  		{r.Body.GuestPathNameLength, &r.GuestPathName},
   646  		{r.Body.PatternLength, &r.Pattern},
   647  	}
   648  
   649  	for _, field := range fields {
   650  		if field.len == 0 {
   651  			continue
   652  		}
   653  
   654  		x := buf.Next(int(field.len))
   655  		*field.val = string(bytes.TrimRight(x, "\x00"))
   656  	}
   657  
   658  	return nil
   659  }
   660  
   661  type SetGuestFileAttributesRequest struct {
   662  	CommandRequestHeader
   663  
   664  	Body struct {
   665  		FileOptions         int32
   666  		AccessTime          int64
   667  		ModificationTime    int64
   668  		OwnerID             int32
   669  		GroupID             int32
   670  		Permissions         int32
   671  		Hidden              bool
   672  		ReadOnly            bool
   673  		GuestPathNameLength uint32
   674  	}
   675  
   676  	GuestPathName string
   677  }
   678  
   679  // MarshalBinary implements the encoding.BinaryMarshaler interface
   680  func (r *SetGuestFileAttributesRequest) MarshalBinary() ([]byte, error) {
   681  	buf := new(bytes.Buffer)
   682  
   683  	r.Body.GuestPathNameLength = uint32(len(r.GuestPathName))
   684  
   685  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   686  
   687  	_, _ = buf.WriteString(r.GuestPathName)
   688  	_ = buf.WriteByte(0)
   689  
   690  	return buf.Bytes(), nil
   691  }
   692  
   693  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   694  func (r *SetGuestFileAttributesRequest) UnmarshalBinary(data []byte) error {
   695  	buf := bytes.NewBuffer(data)
   696  
   697  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   698  	if err != nil {
   699  		return err
   700  	}
   701  
   702  	name := buf.Next(int(r.Body.GuestPathNameLength))
   703  	r.GuestPathName = string(bytes.TrimRight(name, "\x00"))
   704  
   705  	return nil
   706  }
   707  
   708  func (r *SetGuestFileAttributesRequest) IsSet(opt int32) bool {
   709  	return r.Body.FileOptions&opt == opt
   710  }
   711  
   712  type CommandHgfsSendPacket struct {
   713  	CommandRequestHeader
   714  
   715  	Body struct {
   716  		PacketSize uint32
   717  		Timeout    int32
   718  	}
   719  
   720  	Packet []byte
   721  }
   722  
   723  // MarshalBinary implements the encoding.BinaryMarshaler interface
   724  func (r *CommandHgfsSendPacket) MarshalBinary() ([]byte, error) {
   725  	buf := new(bytes.Buffer)
   726  
   727  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   728  
   729  	_, _ = buf.Write(r.Packet)
   730  
   731  	return buf.Bytes(), nil
   732  }
   733  
   734  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   735  func (r *CommandHgfsSendPacket) UnmarshalBinary(data []byte) error {
   736  	buf := bytes.NewBuffer(data)
   737  
   738  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   739  	if err != nil {
   740  		return err
   741  	}
   742  
   743  	r.Packet = buf.Next(int(r.Body.PacketSize))
   744  
   745  	return nil
   746  }
   747  
   748  type InitiateFileTransferToGuestRequest struct {
   749  	CommandRequestHeader
   750  
   751  	Body struct {
   752  		Options             int32
   753  		GuestPathNameLength uint32
   754  		Overwrite           bool
   755  	}
   756  
   757  	GuestPathName string
   758  }
   759  
   760  // MarshalBinary implements the encoding.BinaryMarshaler interface
   761  func (r *InitiateFileTransferToGuestRequest) MarshalBinary() ([]byte, error) {
   762  	buf := new(bytes.Buffer)
   763  
   764  	r.Body.GuestPathNameLength = uint32(len(r.GuestPathName))
   765  
   766  	_ = binary.Write(buf, binary.LittleEndian, &r.Body)
   767  
   768  	_, _ = buf.WriteString(r.GuestPathName)
   769  	_ = buf.WriteByte(0)
   770  
   771  	return buf.Bytes(), nil
   772  }
   773  
   774  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   775  func (r *InitiateFileTransferToGuestRequest) UnmarshalBinary(data []byte) error {
   776  	buf := bytes.NewBuffer(data)
   777  
   778  	err := binary.Read(buf, binary.LittleEndian, &r.Body)
   779  	if err != nil {
   780  		return err
   781  	}
   782  
   783  	name := buf.Next(int(r.Body.GuestPathNameLength))
   784  	r.GuestPathName = string(bytes.TrimRight(name, "\x00"))
   785  
   786  	return nil
   787  }
   788  
   789  type UserCredentialNamePassword struct {
   790  	Body struct {
   791  		NameLength     uint32
   792  		PasswordLength uint32
   793  	}
   794  
   795  	Name     string
   796  	Password string
   797  }
   798  
   799  func (c *UserCredentialNamePassword) UnmarshalBinary(data []byte) error {
   800  	buf := bytes.NewBuffer(bytes.TrimRight(data, "\x00"))
   801  
   802  	err := binary.Read(buf, binary.LittleEndian, &c.Body)
   803  	if err != nil {
   804  		return err
   805  	}
   806  
   807  	str, err := base64.StdEncoding.DecodeString(buf.String())
   808  	if err != nil {
   809  		return err
   810  	}
   811  
   812  	c.Name = string(str[0:c.Body.NameLength])
   813  	c.Password = string(str[c.Body.NameLength+1 : len(str)-1])
   814  
   815  	return nil
   816  }
   817  
   818  func (c *UserCredentialNamePassword) MarshalBinary() ([]byte, error) {
   819  	buf := new(bytes.Buffer)
   820  
   821  	c.Body.NameLength = uint32(len(c.Name))
   822  	c.Body.PasswordLength = uint32(len(c.Password))
   823  
   824  	_ = binary.Write(buf, binary.LittleEndian, &c.Body)
   825  
   826  	src := append([]byte(c.Name+"\x00"), []byte(c.Password+"\x00")...)
   827  
   828  	enc := base64.StdEncoding
   829  	pwd := make([]byte, enc.EncodedLen(len(src)))
   830  	enc.Encode(pwd, src)
   831  	_, _ = buf.Write(pwd)
   832  	_ = buf.WriteByte(0)
   833  
   834  	return buf.Bytes(), nil
   835  }