1/*
2Copyright (c) 2017 VMware, Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package hgfs
18
19import (
20	"bytes"
21	"encoding/binary"
22	"fmt"
23	"log"
24	"os"
25	"strings"
26)
27
28// See: https://github.com/vmware/open-vm-tools/blob/master/open-vm-tools/lib/include/hgfsProto.h
29
30// Opcodes for server operations as defined in hgfsProto.h
31const (
32	OpOpen               = iota /* Open file */
33	OpRead                      /* Read from file */
34	OpWrite                     /* Write to file */
35	OpClose                     /* Close file */
36	OpSearchOpen                /* Start new search */
37	OpSearchRead                /* Get next search response */
38	OpSearchClose               /* End a search */
39	OpGetattr                   /* Get file attributes */
40	OpSetattr                   /* Set file attributes */
41	OpCreateDir                 /* Create new directory */
42	OpDeleteFile                /* Delete a file */
43	OpDeleteDir                 /* Delete a directory */
44	OpRename                    /* Rename a file or directory */
45	OpQueryVolumeInfo           /* Query volume information */
46	OpOpenV2                    /* Open file */
47	OpGetattrV2                 /* Get file attributes */
48	OpSetattrV2                 /* Set file attributes */
49	OpSearchReadV2              /* Get next search response */
50	OpCreateSymlink             /* Create a symlink */
51	OpServerLockChange          /* Change the oplock on a file */
52	OpCreateDirV2               /* Create a directory */
53	OpDeleteFileV2              /* Delete a file */
54	OpDeleteDirV2               /* Delete a directory */
55	OpRenameV2                  /* Rename a file or directory */
56	OpOpenV3                    /* Open file */
57	OpReadV3                    /* Read from file */
58	OpWriteV3                   /* Write to file */
59	OpCloseV3                   /* Close file */
60	OpSearchOpenV3              /* Start new search */
61	OpSearchReadV3              /* Read V3 directory entries */
62	OpSearchCloseV3             /* End a search */
63	OpGetattrV3                 /* Get file attributes */
64	OpSetattrV3                 /* Set file attributes */
65	OpCreateDirV3               /* Create new directory */
66	OpDeleteFileV3              /* Delete a file */
67	OpDeleteDirV3               /* Delete a directory */
68	OpRenameV3                  /* Rename a file or directory */
69	OpQueryVolumeInfoV3         /* Query volume information */
70	OpCreateSymlinkV3           /* Create a symlink */
71	OpServerLockChangeV3        /* Change the oplock on a file */
72	OpWriteWin32StreamV3        /* Write WIN32_STREAM_ID format data to file */
73	OpCreateSessionV4           /* Create a session and return host capabilities. */
74	OpDestroySessionV4          /* Destroy/close session. */
75	OpReadFastV4                /* Read */
76	OpWriteFastV4               /* Write */
77	OpSetWatchV4                /* Start monitoring directory changes. */
78	OpRemoveWatchV4             /* Stop monitoring directory changes. */
79	OpNotifyV4                  /* Notification for a directory change event. */
80	OpSearchReadV4              /* Read V4 directory entries. */
81	OpOpenV4                    /* Open file */
82	OpEnumerateStreamsV4        /* Enumerate alternative named streams for a file. */
83	OpGetattrV4                 /* Get file attributes */
84	OpSetattrV4                 /* Set file attributes */
85	OpDeleteV4                  /* Delete a file or a directory */
86	OpLinkmoveV4                /* Rename/move/create hard link. */
87	OpFsctlV4                   /* Sending FS control requests. */
88	OpAccessCheckV4             /* Access check. */
89	OpFsyncV4                   /* Flush all cached data to the disk. */
90	OpQueryVolumeInfoV4         /* Query volume information. */
91	OpOplockAcquireV4           /* Acquire OPLOCK. */
92	OpOplockBreakV4             /* Break or downgrade OPLOCK. */
93	OpLockByteRangeV4           /* Acquire byte range lock. */
94	OpUnlockByteRangeV4         /* Release byte range lock. */
95	OpQueryEasV4                /* Query extended attributes. */
96	OpSetEasV4                  /* Add or modify extended attributes. */
97	OpNewHeader          = 0xff /* Header op, must be unique, distinguishes packet headers. */
98)
99
100// Status codes
101const (
102	StatusSuccess = iota
103	StatusNoSuchFileOrDir
104	StatusInvalidHandle
105	StatusOperationNotPermitted
106	StatusFileExists
107	StatusNotDirectory
108	StatusDirNotEmpty
109	StatusProtocolError
110	StatusAccessDenied
111	StatusInvalidName
112	StatusGenericError
113	StatusSharingViolation
114	StatusNoSpace
115	StatusOperationNotSupported
116	StatusNameTooLong
117	StatusInvalidParameter
118	StatusNotSameDevice
119	StatusStaleSession
120	StatusTooManySessions
121	StatusTransportError
122)
123
124// Flags for attr mask
125const (
126	AttrValidType = 1 << iota
127	AttrValidSize
128	AttrValidCreateTime
129	AttrValidAccessTime
130	AttrValidWriteTime
131	AttrValidChangeTime
132	AttrValidSpecialPerms
133	AttrValidOwnerPerms
134	AttrValidGroupPerms
135	AttrValidOtherPerms
136	AttrValidFlags
137	AttrValidAllocationSize
138	AttrValidUserID
139	AttrValidGroupID
140	AttrValidFileID
141	AttrValidVolID
142	AttrValidNonStaticFileID
143	AttrValidEffectivePerms
144	AttrValidExtendAttrSize
145	AttrValidReparsePoint
146	AttrValidShortName
147)
148
149// HeaderVersion for HGFS protocol version 4
150const HeaderVersion = 0x1
151
152// LargePacketMax is maximum size of an hgfs packet
153const LargePacketMax = 0xf800 // HGFS_LARGE_PACKET_MAX
154
155// Packet flags
156const (
157	PacketFlagRequest = 1 << iota
158	PacketFlagReply
159	PacketFlagInfoExterror
160	PacketFlagValidFlags = 0x7
161)
162
163// Status is an error type that encapsulates an error status code and the cause
164type Status struct {
165	Err  error
166	Code uint32
167}
168
169func (s *Status) Error() string {
170	if s.Err != nil {
171		return s.Err.Error()
172	}
173
174	return fmt.Sprintf("hgfs.Status=%d", s.Code)
175}
176
177// errorStatus maps the given error type to a status code
178func errorStatus(err error) uint32 {
179	if x, ok := err.(*Status); ok {
180		return x.Code
181	}
182
183	switch {
184	case os.IsNotExist(err):
185		return StatusNoSuchFileOrDir
186	case os.IsExist(err):
187		return StatusFileExists
188	case os.IsPermission(err):
189		return StatusOperationNotPermitted
190	}
191
192	return StatusGenericError
193}
194
195// ProtocolError wraps the given error as a Status type
196func ProtocolError(err error) error {
197	return &Status{
198		Err:  err,
199		Code: StatusProtocolError,
200	}
201}
202
203// Request as defined in hgfsProto.h:HgfsRequest
204type Request struct {
205	Handle uint32
206	Op     int32
207}
208
209// Reply as defined in hgfsProto.h:HgfsReply
210type Reply struct {
211	Handle uint32
212	Status uint32
213}
214
215// Header as defined in hgfsProto.h:HgfsHeader
216type Header struct {
217	Version     uint8
218	Reserved1   [3]uint8
219	Dummy       int32
220	PacketSize  uint32
221	HeaderSize  uint32
222	RequestID   uint32
223	Op          int32
224	Status      uint32
225	Flags       uint32
226	Information uint32
227	SessionID   uint64
228	Reserved    uint64
229}
230
231var (
232	headerSize = uint32(binary.Size(new(Header)))
233
234	packetSize = func(r *Packet) uint32 {
235		return headerSize + uint32(len(r.Payload))
236	}
237)
238
239// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
240func (h *Header) UnmarshalBinary(data []byte) error {
241	buf := bytes.NewBuffer(data)
242
243	err := binary.Read(buf, binary.LittleEndian, h)
244	if err != nil {
245		return fmt.Errorf("reading hgfs header: %s", err)
246	}
247
248	if h.Dummy != OpNewHeader {
249		return fmt.Errorf("expected hgfs header with OpNewHeader (%#x), got: %#x", OpNewHeader, h.Dummy)
250	}
251
252	return nil
253}
254
255// Packet encapsulates an hgfs Header and Payload
256type Packet struct {
257	Header
258
259	Payload []byte
260}
261
262// Reply composes a new Packet with the given payload or error
263func (r *Packet) Reply(payload interface{}, err error) ([]byte, error) {
264	p := new(Packet)
265
266	status := uint32(StatusSuccess)
267
268	if err != nil {
269		status = errorStatus(err)
270	} else {
271		p.Payload, err = MarshalBinary(payload)
272		if err != nil {
273			return nil, err
274		}
275	}
276
277	p.Header = Header{
278		Version:     HeaderVersion,
279		Dummy:       OpNewHeader,
280		PacketSize:  headerSize + uint32(len(p.Payload)),
281		HeaderSize:  headerSize,
282		RequestID:   r.RequestID,
283		Op:          r.Op,
284		Status:      status,
285		Flags:       PacketFlagReply,
286		Information: 0,
287		SessionID:   r.SessionID,
288	}
289
290	if Trace {
291		rc := "OK"
292		if err != nil {
293			rc = err.Error()
294		}
295		fmt.Fprintf(os.Stderr, "[hgfs] response %#v [%s]\n", p.Header, rc)
296	} else if err != nil {
297		log.Printf("[hgfs] op=%d error: %s", r.Op, err)
298	}
299
300	return p.MarshalBinary()
301}
302
303// MarshalBinary implements the encoding.BinaryMarshaler interface
304func (r *Packet) MarshalBinary() ([]byte, error) {
305	r.Header.PacketSize = packetSize(r)
306
307	buf, _ := MarshalBinary(r.Header)
308
309	return append(buf, r.Payload...), nil
310}
311
312// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
313func (r *Packet) UnmarshalBinary(data []byte) error {
314	err := r.Header.UnmarshalBinary(data)
315	if err != nil {
316		return err
317	}
318
319	r.Payload = data[r.HeaderSize:r.PacketSize]
320
321	return nil
322}
323
324// Capability as defined in hgfsProto.h:HgfsCapability
325type Capability struct {
326	Op    int32
327	Flags uint32
328}
329
330// RequestCreateSessionV4 as defined in hgfsProto.h:HgfsRequestCreateSessionV4
331type RequestCreateSessionV4 struct {
332	NumCapabilities uint32
333	MaxPacketSize   uint32
334	Flags           uint32
335	Reserved        uint32
336	Capabilities    []Capability
337}
338
339// MarshalBinary implements the encoding.BinaryMarshaler interface
340func (r *RequestCreateSessionV4) MarshalBinary() ([]byte, error) {
341	buf := new(bytes.Buffer)
342
343	r.NumCapabilities = uint32(len(r.Capabilities))
344
345	fields := []*uint32{
346		&r.NumCapabilities,
347		&r.MaxPacketSize,
348		&r.Flags,
349		&r.Reserved,
350	}
351
352	for _, p := range fields {
353		err := binary.Write(buf, binary.LittleEndian, p)
354		if err != nil {
355			return nil, err
356		}
357	}
358
359	for i := uint32(0); i < r.NumCapabilities; i++ {
360		err := binary.Write(buf, binary.LittleEndian, &r.Capabilities[i])
361		if err != nil {
362			return nil, err
363		}
364	}
365
366	return buf.Bytes(), nil
367}
368
369// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
370func (r *RequestCreateSessionV4) UnmarshalBinary(data []byte) error {
371	buf := bytes.NewBuffer(data)
372
373	fields := []*uint32{
374		&r.NumCapabilities,
375		&r.MaxPacketSize,
376		&r.Flags,
377		&r.Reserved,
378	}
379
380	for _, p := range fields {
381		err := binary.Read(buf, binary.LittleEndian, p)
382		if err != nil {
383			return err
384		}
385	}
386
387	for i := uint32(0); i < r.NumCapabilities; i++ {
388		var cap Capability
389		err := binary.Read(buf, binary.LittleEndian, &cap)
390		if err != nil {
391			return err
392		}
393
394		r.Capabilities = append(r.Capabilities, cap)
395	}
396
397	return nil
398}
399
400// ReplyCreateSessionV4 as defined in hgfsProto.h:HgfsReplyCreateSessionV4
401type ReplyCreateSessionV4 struct {
402	SessionID       uint64
403	NumCapabilities uint32
404	MaxPacketSize   uint32
405	IdentityOffset  uint32
406	Flags           uint32
407	Reserved        uint32
408	Capabilities    []Capability
409}
410
411// MarshalBinary implements the encoding.BinaryMarshaler interface
412func (r *ReplyCreateSessionV4) MarshalBinary() ([]byte, error) {
413	buf := new(bytes.Buffer)
414
415	fields := []interface{}{
416		&r.SessionID,
417		&r.NumCapabilities,
418		&r.MaxPacketSize,
419		&r.IdentityOffset,
420		&r.Flags,
421		&r.Reserved,
422	}
423
424	for _, p := range fields {
425		err := binary.Write(buf, binary.LittleEndian, p)
426		if err != nil {
427			return nil, err
428		}
429	}
430
431	for i := uint32(0); i < r.NumCapabilities; i++ {
432		err := binary.Write(buf, binary.LittleEndian, &r.Capabilities[i])
433		if err != nil {
434			return nil, err
435		}
436	}
437
438	return buf.Bytes(), nil
439}
440
441// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
442func (r *ReplyCreateSessionV4) UnmarshalBinary(data []byte) error {
443	buf := bytes.NewBuffer(data)
444
445	fields := []interface{}{
446		&r.SessionID,
447		&r.NumCapabilities,
448		&r.MaxPacketSize,
449		&r.IdentityOffset,
450		&r.Flags,
451		&r.Reserved,
452	}
453
454	for _, p := range fields {
455		err := binary.Read(buf, binary.LittleEndian, p)
456		if err != nil {
457			return err
458		}
459	}
460
461	for i := uint32(0); i < r.NumCapabilities; i++ {
462		var cap Capability
463		err := binary.Read(buf, binary.LittleEndian, &cap)
464		if err != nil {
465			return err
466		}
467
468		r.Capabilities = append(r.Capabilities, cap)
469	}
470
471	return nil
472}
473
474// RequestDestroySessionV4 as defined in hgfsProto.h:HgfsRequestDestroySessionV4
475type RequestDestroySessionV4 struct {
476	Reserved uint64
477}
478
479// ReplyDestroySessionV4 as defined in hgfsProto.h:HgfsReplyDestroySessionV4
480type ReplyDestroySessionV4 struct {
481	Reserved uint64
482}
483
484// FileName as defined in hgfsProto.h:HgfsFileName
485type FileName struct {
486	Length uint32
487	Name   string
488}
489
490// MarshalBinary implements the encoding.BinaryMarshaler interface
491func (f *FileName) MarshalBinary() ([]byte, error) {
492	name := f.Name
493	f.Length = uint32(len(f.Name))
494	if f.Length == 0 {
495		// field is defined as 'char name[1];', this byte is required for min sizeof() validation
496		name = "\x00"
497	}
498	return MarshalBinary(&f.Length, name)
499}
500
501// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
502func (f *FileName) UnmarshalBinary(data []byte) error {
503	buf := bytes.NewBuffer(data)
504
505	_ = binary.Read(buf, binary.LittleEndian, &f.Length)
506
507	f.Name = string(buf.Next(int(f.Length)))
508
509	return nil
510}
511
512const serverPolicyRootShareName = "root"
513
514// FromString converts name to a FileName
515func (f *FileName) FromString(name string) {
516	name = strings.TrimPrefix(name, "/")
517
518	cp := strings.Split(name, "/")
519
520	cp = append([]string{serverPolicyRootShareName}, cp...)
521
522	f.Name = strings.Join(cp, "\x00")
523	f.Length = uint32(len(f.Name))
524}
525
526// Path converts FileName to a string
527func (f *FileName) Path() string {
528	cp := strings.Split(f.Name, "\x00")
529
530	if len(cp) == 0 || cp[0] != serverPolicyRootShareName {
531		return "" // TODO: not happening until if/when we handle Windows shares
532	}
533
534	cp[0] = ""
535
536	return strings.Join(cp, "/")
537}
538
539// FileNameV3 as defined in hgfsProto.h:HgfsFileNameV3
540type FileNameV3 struct {
541	Length   uint32
542	Flags    uint32
543	CaseType int32
544	ID       uint32
545	Name     string
546}
547
548// MarshalBinary implements the encoding.BinaryMarshaler interface
549func (f *FileNameV3) MarshalBinary() ([]byte, error) {
550	name := f.Name
551	f.Length = uint32(len(f.Name))
552	if f.Length == 0 {
553		// field is defined as 'char name[1];', this byte is required for min sizeof() validation
554		name = "\x00"
555	}
556	return MarshalBinary(&f.Length, &f.Flags, &f.CaseType, &f.ID, name)
557}
558
559// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
560func (f *FileNameV3) UnmarshalBinary(data []byte) error {
561	buf := bytes.NewBuffer(data)
562
563	fields := []interface{}{
564		&f.Length, &f.Flags, &f.CaseType, &f.ID,
565	}
566
567	for _, p := range fields {
568		if err := binary.Read(buf, binary.LittleEndian, p); err != nil {
569			return err
570		}
571	}
572
573	f.Name = string(buf.Next(int(f.Length)))
574
575	return nil
576}
577
578// FromString converts name to a FileNameV3
579func (f *FileNameV3) FromString(name string) {
580	p := new(FileName)
581	p.FromString(name)
582	f.Name = p.Name
583	f.Length = p.Length
584}
585
586// Path converts FileNameV3 to a string
587func (f *FileNameV3) Path() string {
588	return (&FileName{Name: f.Name, Length: f.Length}).Path()
589}
590
591// FileType
592const (
593	FileTypeRegular = iota
594	FileTypeDirectory
595	FileTypeSymlink
596)
597
598// AttrV2 as defined in hgfsProto.h:HgfsAttrV2
599type AttrV2 struct {
600	Mask           uint64
601	Type           int32
602	Size           uint64
603	CreationTime   uint64
604	AccessTime     uint64
605	WriteTime      uint64
606	AttrChangeTime uint64
607	SpecialPerms   uint8
608	OwnerPerms     uint8
609	GroupPerms     uint8
610	OtherPerms     uint8
611	AttrFlags      uint64
612	AllocationSize uint64
613	UserID         uint32
614	GroupID        uint32
615	HostFileID     uint64
616	VolumeID       uint32
617	EffectivePerms uint32
618	Reserved2      uint64
619}
620
621// RequestGetattrV2 as defined in hgfsProto.h:HgfsRequestGetattrV2
622type RequestGetattrV2 struct {
623	Request
624	AttrHint uint64
625	Handle   uint32
626	FileName FileName
627}
628
629// MarshalBinary implements the encoding.BinaryMarshaler interface
630func (r *RequestGetattrV2) MarshalBinary() ([]byte, error) {
631	return MarshalBinary(&r.Request, &r.AttrHint, &r.Handle, &r.FileName)
632}
633
634// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
635func (r *RequestGetattrV2) UnmarshalBinary(data []byte) error {
636	return UnmarshalBinary(data, &r.Request, &r.AttrHint, &r.Handle, &r.FileName)
637}
638
639// ReplyGetattrV2 as defined in hgfsProto.h:HgfsReplyGetattrV2
640type ReplyGetattrV2 struct {
641	Reply
642	Attr          AttrV2
643	SymlinkTarget FileName
644}
645
646// MarshalBinary implements the encoding.BinaryMarshaler interface
647func (r *ReplyGetattrV2) MarshalBinary() ([]byte, error) {
648	return MarshalBinary(&r.Reply, &r.Attr, &r.SymlinkTarget)
649}
650
651// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
652func (r *ReplyGetattrV2) UnmarshalBinary(data []byte) error {
653	return UnmarshalBinary(data, &r.Reply, &r.Attr, &r.SymlinkTarget)
654}
655
656// RequestSetattrV2 as defined in hgfsProto.h:HgfsRequestSetattrV2
657type RequestSetattrV2 struct {
658	Request
659	Hints    uint64
660	Attr     AttrV2
661	Handle   uint32
662	FileName FileName
663}
664
665// MarshalBinary implements the encoding.BinaryMarshaler interface
666func (r *RequestSetattrV2) MarshalBinary() ([]byte, error) {
667	return MarshalBinary(&r.Request, &r.Hints, &r.Attr, &r.Handle, &r.FileName)
668}
669
670// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
671func (r *RequestSetattrV2) UnmarshalBinary(data []byte) error {
672	return UnmarshalBinary(data, &r.Request, &r.Hints, &r.Attr, &r.Handle, &r.FileName)
673}
674
675// ReplySetattrV2 as defined in hgfsProto.h:HgfsReplySetattrV2
676type ReplySetattrV2 struct {
677	Header Reply
678}
679
680// OpenMode
681const (
682	OpenModeReadOnly = iota
683	OpenModeWriteOnly
684	OpenModeReadWrite
685	OpenModeAccmodes
686)
687
688// OpenFlags
689const (
690	Open = iota
691	OpenEmpty
692	OpenCreate
693	OpenCreateSafe
694	OpenCreateEmpty
695)
696
697// Permissions
698const (
699	PermRead  = 4
700	PermWrite = 2
701	PermExec  = 1
702)
703
704// RequestOpen as defined in hgfsProto.h:HgfsRequestOpen
705type RequestOpen struct {
706	Request
707	OpenMode    int32
708	OpenFlags   int32
709	Permissions uint8
710	FileName    FileName
711}
712
713// MarshalBinary implements the encoding.BinaryMarshaler interface
714func (r *RequestOpen) MarshalBinary() ([]byte, error) {
715	return MarshalBinary(&r.Request, &r.OpenMode, &r.OpenFlags, r.Permissions, &r.FileName)
716}
717
718// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
719func (r *RequestOpen) UnmarshalBinary(data []byte) error {
720	return UnmarshalBinary(data, &r.Request, &r.OpenMode, &r.OpenFlags, &r.Permissions, &r.FileName)
721}
722
723// ReplyOpen as defined in hgfsProto.h:HgfsReplyOpen
724type ReplyOpen struct {
725	Reply
726	Handle uint32
727}
728
729// RequestClose as defined in hgfsProto.h:HgfsRequestClose
730type RequestClose struct {
731	Request
732	Handle uint32
733}
734
735// ReplyClose as defined in hgfsProto.h:HgfsReplyClose
736type ReplyClose struct {
737	Reply
738}
739
740// Lock type
741const (
742	LockNone = iota
743	LockOpportunistic
744	LockExclusive
745	LockShared
746	LockBatch
747	LockLease
748)
749
750// RequestOpenV3 as defined in hgfsProto.h:HgfsRequestOpenV3
751type RequestOpenV3 struct {
752	Mask           uint64
753	OpenMode       int32
754	OpenFlags      int32
755	SpecialPerms   uint8
756	OwnerPerms     uint8
757	GroupPerms     uint8
758	OtherPerms     uint8
759	AttrFlags      uint64
760	AllocationSize uint64
761	DesiredAccess  uint32
762	ShareAccess    uint32
763	DesiredLock    int32
764	Reserved1      uint64
765	Reserved2      uint64
766	FileName       FileNameV3
767}
768
769// MarshalBinary implements the encoding.BinaryMarshaler interface
770func (r *RequestOpenV3) MarshalBinary() ([]byte, error) {
771	return MarshalBinary(&r.Mask, &r.OpenMode, &r.OpenFlags,
772		&r.SpecialPerms, &r.OwnerPerms, &r.GroupPerms, &r.OtherPerms,
773		&r.AttrFlags, &r.AllocationSize, &r.DesiredAccess, &r.ShareAccess,
774		&r.DesiredLock, &r.Reserved1, &r.Reserved2, &r.FileName)
775}
776
777// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
778func (r *RequestOpenV3) UnmarshalBinary(data []byte) error {
779	return UnmarshalBinary(data, &r.Mask, &r.OpenMode, &r.OpenFlags,
780		&r.SpecialPerms, &r.OwnerPerms, &r.GroupPerms, &r.OtherPerms,
781		&r.AttrFlags, &r.AllocationSize, &r.DesiredAccess, &r.ShareAccess,
782		&r.DesiredLock, &r.Reserved1, &r.Reserved2, &r.FileName)
783}
784
785// ReplyOpenV3 as defined in hgfsProto.h:HgfsReplyOpenV3
786type ReplyOpenV3 struct {
787	Handle       uint32
788	AcquiredLock int32
789	Flags        int32
790	Reserved     uint32
791}
792
793// RequestReadV3 as defined in hgfsProto.h:HgfsRequestReadV3
794type RequestReadV3 struct {
795	Handle       uint32
796	Offset       uint64
797	RequiredSize uint32
798	Reserved     uint64
799}
800
801// ReplyReadV3 as defined in hgfsProto.h:HgfsReplyReadV3
802type ReplyReadV3 struct {
803	ActualSize uint32
804	Reserved   uint64
805	Payload    []byte
806}
807
808// MarshalBinary implements the encoding.BinaryMarshaler interface
809func (r *ReplyReadV3) MarshalBinary() ([]byte, error) {
810	return MarshalBinary(&r.ActualSize, &r.Reserved, r.Payload)
811}
812
813// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
814func (r *ReplyReadV3) UnmarshalBinary(data []byte) error {
815	return UnmarshalBinary(data, &r.ActualSize, &r.Reserved, &r.Payload)
816}
817
818// Write flags
819const (
820	WriteAppend = 1
821)
822
823// RequestWriteV3 as defined in hgfsProto.h:HgfsRequestWriteV3
824type RequestWriteV3 struct {
825	Handle       uint32
826	WriteFlags   uint8
827	Offset       uint64
828	RequiredSize uint32
829	Reserved     uint64
830	Payload      []byte
831}
832
833// MarshalBinary implements the encoding.BinaryMarshaler interface
834func (r *RequestWriteV3) MarshalBinary() ([]byte, error) {
835	return MarshalBinary(&r.Handle, &r.WriteFlags, &r.Offset, &r.RequiredSize, &r.Reserved, r.Payload)
836}
837
838// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
839func (r *RequestWriteV3) UnmarshalBinary(data []byte) error {
840	return UnmarshalBinary(data, &r.Handle, &r.WriteFlags, &r.Offset, &r.RequiredSize, &r.Reserved, &r.Payload)
841}
842
843// ReplyWriteV3 as defined in hgfsProto.h:HgfsReplyWriteV3
844type ReplyWriteV3 struct {
845	ActualSize uint32
846	Reserved   uint64
847}
848