1// See the file LICENSE for copyright and licensing information.
2
3// Derived from FUSE's fuse_kernel.h, which carries this notice:
4/*
5   This file defines the kernel interface of FUSE
6   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
7
8
9   This -- and only this -- header file may also be distributed under
10   the terms of the BSD Licence as follows:
11
12   Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
13
14   Redistribution and use in source and binary forms, with or without
15   modification, are permitted provided that the following conditions
16   are met:
17   1. Redistributions of source code must retain the above copyright
18      notice, this list of conditions and the following disclaimer.
19   2. Redistributions in binary form must reproduce the above copyright
20      notice, this list of conditions and the following disclaimer in the
21      documentation and/or other materials provided with the distribution.
22
23   THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26   ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33   SUCH DAMAGE.
34*/
35
36package fuse
37
38import (
39	"fmt"
40	"syscall"
41	"unsafe"
42)
43
44// The FUSE version implemented by the package.
45const (
46	protoVersionMinMajor = 7
47	protoVersionMinMinor = 8
48	protoVersionMaxMajor = 7
49	protoVersionMaxMinor = 12
50)
51
52const (
53	rootID = 1
54)
55
56type kstatfs struct {
57	Blocks  uint64
58	Bfree   uint64
59	Bavail  uint64
60	Files   uint64
61	Ffree   uint64
62	Bsize   uint32
63	Namelen uint32
64	Frsize  uint32
65	_       uint32
66	Spare   [6]uint32
67}
68
69type fileLock struct {
70	Start uint64
71	End   uint64
72	Type  uint32
73	Pid   uint32
74}
75
76// GetattrFlags are bit flags that can be seen in GetattrRequest.
77type GetattrFlags uint32
78
79const (
80	// Indicates the handle is valid.
81	GetattrFh GetattrFlags = 1 << 0
82)
83
84var getattrFlagsNames = []flagName{
85	{uint32(GetattrFh), "GetattrFh"},
86}
87
88func (fl GetattrFlags) String() string {
89	return flagString(uint32(fl), getattrFlagsNames)
90}
91
92// The SetattrValid are bit flags describing which fields in the SetattrRequest
93// are included in the change.
94type SetattrValid uint32
95
96const (
97	SetattrMode   SetattrValid = 1 << 0
98	SetattrUid    SetattrValid = 1 << 1
99	SetattrGid    SetattrValid = 1 << 2
100	SetattrSize   SetattrValid = 1 << 3
101	SetattrAtime  SetattrValid = 1 << 4
102	SetattrMtime  SetattrValid = 1 << 5
103	SetattrHandle SetattrValid = 1 << 6
104
105	// Linux only(?)
106	SetattrAtimeNow  SetattrValid = 1 << 7
107	SetattrMtimeNow  SetattrValid = 1 << 8
108	SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html
109
110	// OS X only
111	SetattrCrtime   SetattrValid = 1 << 28
112	SetattrChgtime  SetattrValid = 1 << 29
113	SetattrBkuptime SetattrValid = 1 << 30
114	SetattrFlags    SetattrValid = 1 << 31
115)
116
117func (fl SetattrValid) Mode() bool      { return fl&SetattrMode != 0 }
118func (fl SetattrValid) Uid() bool       { return fl&SetattrUid != 0 }
119func (fl SetattrValid) Gid() bool       { return fl&SetattrGid != 0 }
120func (fl SetattrValid) Size() bool      { return fl&SetattrSize != 0 }
121func (fl SetattrValid) Atime() bool     { return fl&SetattrAtime != 0 }
122func (fl SetattrValid) Mtime() bool     { return fl&SetattrMtime != 0 }
123func (fl SetattrValid) Handle() bool    { return fl&SetattrHandle != 0 }
124func (fl SetattrValid) AtimeNow() bool  { return fl&SetattrAtimeNow != 0 }
125func (fl SetattrValid) MtimeNow() bool  { return fl&SetattrMtimeNow != 0 }
126func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 }
127func (fl SetattrValid) Crtime() bool    { return fl&SetattrCrtime != 0 }
128func (fl SetattrValid) Chgtime() bool   { return fl&SetattrChgtime != 0 }
129func (fl SetattrValid) Bkuptime() bool  { return fl&SetattrBkuptime != 0 }
130func (fl SetattrValid) Flags() bool     { return fl&SetattrFlags != 0 }
131
132func (fl SetattrValid) String() string {
133	return flagString(uint32(fl), setattrValidNames)
134}
135
136var setattrValidNames = []flagName{
137	{uint32(SetattrMode), "SetattrMode"},
138	{uint32(SetattrUid), "SetattrUid"},
139	{uint32(SetattrGid), "SetattrGid"},
140	{uint32(SetattrSize), "SetattrSize"},
141	{uint32(SetattrAtime), "SetattrAtime"},
142	{uint32(SetattrMtime), "SetattrMtime"},
143	{uint32(SetattrHandle), "SetattrHandle"},
144	{uint32(SetattrAtimeNow), "SetattrAtimeNow"},
145	{uint32(SetattrMtimeNow), "SetattrMtimeNow"},
146	{uint32(SetattrLockOwner), "SetattrLockOwner"},
147	{uint32(SetattrCrtime), "SetattrCrtime"},
148	{uint32(SetattrChgtime), "SetattrChgtime"},
149	{uint32(SetattrBkuptime), "SetattrBkuptime"},
150	{uint32(SetattrFlags), "SetattrFlags"},
151}
152
153// Flags that can be seen in OpenRequest.Flags.
154const (
155	// Access modes. These are not 1-bit flags, but alternatives where
156	// only one can be chosen. See the IsReadOnly etc convenience
157	// methods.
158	OpenReadOnly  OpenFlags = syscall.O_RDONLY
159	OpenWriteOnly OpenFlags = syscall.O_WRONLY
160	OpenReadWrite OpenFlags = syscall.O_RDWR
161
162	// File was opened in append-only mode, all writes will go to end
163	// of file. OS X does not provide this information.
164	OpenAppend    OpenFlags = syscall.O_APPEND
165	OpenCreate    OpenFlags = syscall.O_CREAT
166	OpenDirectory OpenFlags = syscall.O_DIRECTORY
167	OpenExclusive OpenFlags = syscall.O_EXCL
168	OpenNonblock  OpenFlags = syscall.O_NONBLOCK
169	OpenSync      OpenFlags = syscall.O_SYNC
170	OpenTruncate  OpenFlags = syscall.O_TRUNC
171)
172
173// OpenAccessModeMask is a bitmask that separates the access mode
174// from the other flags in OpenFlags.
175const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE
176
177// OpenFlags are the O_FOO flags passed to open/create/etc calls. For
178// example, os.O_WRONLY | os.O_APPEND.
179type OpenFlags uint32
180
181func (fl OpenFlags) String() string {
182	// O_RDONLY, O_RWONLY, O_RDWR are not flags
183	s := accModeName(fl & OpenAccessModeMask)
184	flags := uint32(fl &^ OpenAccessModeMask)
185	if flags != 0 {
186		s = s + "+" + flagString(flags, openFlagNames)
187	}
188	return s
189}
190
191// Return true if OpenReadOnly is set.
192func (fl OpenFlags) IsReadOnly() bool {
193	return fl&OpenAccessModeMask == OpenReadOnly
194}
195
196// Return true if OpenWriteOnly is set.
197func (fl OpenFlags) IsWriteOnly() bool {
198	return fl&OpenAccessModeMask == OpenWriteOnly
199}
200
201// Return true if OpenReadWrite is set.
202func (fl OpenFlags) IsReadWrite() bool {
203	return fl&OpenAccessModeMask == OpenReadWrite
204}
205
206func accModeName(flags OpenFlags) string {
207	switch flags {
208	case OpenReadOnly:
209		return "OpenReadOnly"
210	case OpenWriteOnly:
211		return "OpenWriteOnly"
212	case OpenReadWrite:
213		return "OpenReadWrite"
214	default:
215		return ""
216	}
217}
218
219var openFlagNames = []flagName{
220	{uint32(OpenAppend), "OpenAppend"},
221	{uint32(OpenCreate), "OpenCreate"},
222	{uint32(OpenDirectory), "OpenDirectory"},
223	{uint32(OpenExclusive), "OpenExclusive"},
224	{uint32(OpenNonblock), "OpenNonblock"},
225	{uint32(OpenSync), "OpenSync"},
226	{uint32(OpenTruncate), "OpenTruncate"},
227}
228
229// The OpenResponseFlags are returned in the OpenResponse.
230type OpenResponseFlags uint32
231
232const (
233	OpenDirectIO    OpenResponseFlags = 1 << 0 // bypass page cache for this open file
234	OpenKeepCache   OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
235	OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X or FreeBSD)
236
237	OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
238	OpenPurgeUBC  OpenResponseFlags = 1 << 31 // OS X
239)
240
241func (fl OpenResponseFlags) String() string {
242	return flagString(uint32(fl), openResponseFlagNames)
243}
244
245var openResponseFlagNames = []flagName{
246	{uint32(OpenDirectIO), "OpenDirectIO"},
247	{uint32(OpenKeepCache), "OpenKeepCache"},
248	{uint32(OpenNonSeekable), "OpenNonSeekable"},
249	{uint32(OpenPurgeAttr), "OpenPurgeAttr"},
250	{uint32(OpenPurgeUBC), "OpenPurgeUBC"},
251}
252
253// The InitFlags are used in the Init exchange.
254type InitFlags uint32
255
256const (
257	InitAsyncRead     InitFlags = 1 << 0
258	InitPosixLocks    InitFlags = 1 << 1
259	InitFileOps       InitFlags = 1 << 2
260	InitAtomicTrunc   InitFlags = 1 << 3
261	InitExportSupport InitFlags = 1 << 4
262	InitBigWrites     InitFlags = 1 << 5
263	// Do not mask file access modes with umask. Not supported on OS X.
264	InitDontMask        InitFlags = 1 << 6
265	InitSpliceWrite     InitFlags = 1 << 7
266	InitSpliceMove      InitFlags = 1 << 8
267	InitSpliceRead      InitFlags = 1 << 9
268	InitFlockLocks      InitFlags = 1 << 10
269	InitHasIoctlDir     InitFlags = 1 << 11
270	InitAutoInvalData   InitFlags = 1 << 12
271	InitDoReaddirplus   InitFlags = 1 << 13
272	InitReaddirplusAuto InitFlags = 1 << 14
273	InitAsyncDIO        InitFlags = 1 << 15
274	InitWritebackCache  InitFlags = 1 << 16
275	InitNoOpenSupport   InitFlags = 1 << 17
276
277	InitCaseSensitive InitFlags = 1 << 29 // OS X only
278	InitVolRename     InitFlags = 1 << 30 // OS X only
279	InitXtimes        InitFlags = 1 << 31 // OS X only
280)
281
282type flagName struct {
283	bit  uint32
284	name string
285}
286
287var initFlagNames = []flagName{
288	{uint32(InitAsyncRead), "InitAsyncRead"},
289	{uint32(InitPosixLocks), "InitPosixLocks"},
290	{uint32(InitFileOps), "InitFileOps"},
291	{uint32(InitAtomicTrunc), "InitAtomicTrunc"},
292	{uint32(InitExportSupport), "InitExportSupport"},
293	{uint32(InitBigWrites), "InitBigWrites"},
294	{uint32(InitDontMask), "InitDontMask"},
295	{uint32(InitSpliceWrite), "InitSpliceWrite"},
296	{uint32(InitSpliceMove), "InitSpliceMove"},
297	{uint32(InitSpliceRead), "InitSpliceRead"},
298	{uint32(InitFlockLocks), "InitFlockLocks"},
299	{uint32(InitHasIoctlDir), "InitHasIoctlDir"},
300	{uint32(InitAutoInvalData), "InitAutoInvalData"},
301	{uint32(InitDoReaddirplus), "InitDoReaddirplus"},
302	{uint32(InitReaddirplusAuto), "InitReaddirplusAuto"},
303	{uint32(InitAsyncDIO), "InitAsyncDIO"},
304	{uint32(InitWritebackCache), "InitWritebackCache"},
305	{uint32(InitNoOpenSupport), "InitNoOpenSupport"},
306
307	{uint32(InitCaseSensitive), "InitCaseSensitive"},
308	{uint32(InitVolRename), "InitVolRename"},
309	{uint32(InitXtimes), "InitXtimes"},
310}
311
312func (fl InitFlags) String() string {
313	return flagString(uint32(fl), initFlagNames)
314}
315
316func flagString(f uint32, names []flagName) string {
317	var s string
318
319	if f == 0 {
320		return "0"
321	}
322
323	for _, n := range names {
324		if f&n.bit != 0 {
325			s += "+" + n.name
326			f &^= n.bit
327		}
328	}
329	if f != 0 {
330		s += fmt.Sprintf("%+#x", f)
331	}
332	return s[1:]
333}
334
335// The ReleaseFlags are used in the Release exchange.
336type ReleaseFlags uint32
337
338const (
339	ReleaseFlush ReleaseFlags = 1 << 0
340)
341
342func (fl ReleaseFlags) String() string {
343	return flagString(uint32(fl), releaseFlagNames)
344}
345
346var releaseFlagNames = []flagName{
347	{uint32(ReleaseFlush), "ReleaseFlush"},
348}
349
350// Opcodes
351const (
352	opLookup      = 1
353	opForget      = 2 // no reply
354	opGetattr     = 3
355	opSetattr     = 4
356	opReadlink    = 5
357	opSymlink     = 6
358	opMknod       = 8
359	opMkdir       = 9
360	opUnlink      = 10
361	opRmdir       = 11
362	opRename      = 12
363	opLink        = 13
364	opOpen        = 14
365	opRead        = 15
366	opWrite       = 16
367	opStatfs      = 17
368	opRelease     = 18
369	opFsync       = 20
370	opSetxattr    = 21
371	opGetxattr    = 22
372	opListxattr   = 23
373	opRemovexattr = 24
374	opFlush       = 25
375	opInit        = 26
376	opOpendir     = 27
377	opReaddir     = 28
378	opReleasedir  = 29
379	opFsyncdir    = 30
380	opGetlk       = 31
381	opSetlk       = 32
382	opSetlkw      = 33
383	opAccess      = 34
384	opCreate      = 35
385	opInterrupt   = 36
386	opBmap        = 37
387	opDestroy     = 38
388	opIoctl       = 39 // Linux?
389	opPoll        = 40 // Linux?
390
391	// OS X
392	opSetvolname = 61
393	opGetxtimes  = 62
394	opExchange   = 63
395)
396
397type entryOut struct {
398	Nodeid         uint64 // Inode ID
399	Generation     uint64 // Inode generation
400	EntryValid     uint64 // Cache timeout for the name
401	AttrValid      uint64 // Cache timeout for the attributes
402	EntryValidNsec uint32
403	AttrValidNsec  uint32
404	Attr           attr
405}
406
407func entryOutSize(p Protocol) uintptr {
408	switch {
409	case p.LT(Protocol{7, 9}):
410		return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize)
411	default:
412		return unsafe.Sizeof(entryOut{})
413	}
414}
415
416type forgetIn struct {
417	Nlookup uint64
418}
419
420type getattrIn struct {
421	GetattrFlags uint32
422	_            uint32
423	Fh           uint64
424}
425
426type attrOut struct {
427	AttrValid     uint64 // Cache timeout for the attributes
428	AttrValidNsec uint32
429	_             uint32
430	Attr          attr
431}
432
433func attrOutSize(p Protocol) uintptr {
434	switch {
435	case p.LT(Protocol{7, 9}):
436		return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize)
437	default:
438		return unsafe.Sizeof(attrOut{})
439	}
440}
441
442// OS X
443type getxtimesOut struct {
444	Bkuptime     uint64
445	Crtime       uint64
446	BkuptimeNsec uint32
447	CrtimeNsec   uint32
448}
449
450type mknodIn struct {
451	Mode  uint32
452	Rdev  uint32
453	Umask uint32
454	_     uint32
455	// "filename\x00" follows.
456}
457
458func mknodInSize(p Protocol) uintptr {
459	switch {
460	case p.LT(Protocol{7, 12}):
461		return unsafe.Offsetof(mknodIn{}.Umask)
462	default:
463		return unsafe.Sizeof(mknodIn{})
464	}
465}
466
467type mkdirIn struct {
468	Mode  uint32
469	Umask uint32
470	// filename follows
471}
472
473func mkdirInSize(p Protocol) uintptr {
474	switch {
475	case p.LT(Protocol{7, 12}):
476		return unsafe.Offsetof(mkdirIn{}.Umask) + 4
477	default:
478		return unsafe.Sizeof(mkdirIn{})
479	}
480}
481
482type renameIn struct {
483	Newdir uint64
484	// "oldname\x00newname\x00" follows
485}
486
487// OS X
488type exchangeIn struct {
489	Olddir  uint64
490	Newdir  uint64
491	Options uint64
492	// "oldname\x00newname\x00" follows
493}
494
495type linkIn struct {
496	Oldnodeid uint64
497}
498
499type setattrInCommon struct {
500	Valid     uint32
501	_         uint32
502	Fh        uint64
503	Size      uint64
504	LockOwner uint64 // unused on OS X?
505	Atime     uint64
506	Mtime     uint64
507	Unused2   uint64
508	AtimeNsec uint32
509	MtimeNsec uint32
510	Unused3   uint32
511	Mode      uint32
512	Unused4   uint32
513	Uid       uint32
514	Gid       uint32
515	Unused5   uint32
516}
517
518type openIn struct {
519	Flags  uint32
520	Unused uint32
521}
522
523type openOut struct {
524	Fh        uint64
525	OpenFlags uint32
526	_         uint32
527}
528
529type createIn struct {
530	Flags uint32
531	Mode  uint32
532	Umask uint32
533	_     uint32
534}
535
536func createInSize(p Protocol) uintptr {
537	switch {
538	case p.LT(Protocol{7, 12}):
539		return unsafe.Offsetof(createIn{}.Umask)
540	default:
541		return unsafe.Sizeof(createIn{})
542	}
543}
544
545type releaseIn struct {
546	Fh           uint64
547	Flags        uint32
548	ReleaseFlags uint32
549	LockOwner    uint32
550}
551
552type flushIn struct {
553	Fh         uint64
554	FlushFlags uint32
555	_          uint32
556	LockOwner  uint64
557}
558
559type readIn struct {
560	Fh        uint64
561	Offset    uint64
562	Size      uint32
563	ReadFlags uint32
564	LockOwner uint64
565	Flags     uint32
566	_         uint32
567}
568
569func readInSize(p Protocol) uintptr {
570	switch {
571	case p.LT(Protocol{7, 9}):
572		return unsafe.Offsetof(readIn{}.ReadFlags) + 4
573	default:
574		return unsafe.Sizeof(readIn{})
575	}
576}
577
578// The ReadFlags are passed in ReadRequest.
579type ReadFlags uint32
580
581const (
582	// LockOwner field is valid.
583	ReadLockOwner ReadFlags = 1 << 1
584)
585
586var readFlagNames = []flagName{
587	{uint32(ReadLockOwner), "ReadLockOwner"},
588}
589
590func (fl ReadFlags) String() string {
591	return flagString(uint32(fl), readFlagNames)
592}
593
594type writeIn struct {
595	Fh         uint64
596	Offset     uint64
597	Size       uint32
598	WriteFlags uint32
599	LockOwner  uint64
600	Flags      uint32
601	_          uint32
602}
603
604func writeInSize(p Protocol) uintptr {
605	switch {
606	case p.LT(Protocol{7, 9}):
607		return unsafe.Offsetof(writeIn{}.LockOwner)
608	default:
609		return unsafe.Sizeof(writeIn{})
610	}
611}
612
613type writeOut struct {
614	Size uint32
615	_    uint32
616}
617
618// The WriteFlags are passed in WriteRequest.
619type WriteFlags uint32
620
621const (
622	WriteCache WriteFlags = 1 << 0
623	// LockOwner field is valid.
624	WriteLockOwner WriteFlags = 1 << 1
625)
626
627var writeFlagNames = []flagName{
628	{uint32(WriteCache), "WriteCache"},
629	{uint32(WriteLockOwner), "WriteLockOwner"},
630}
631
632func (fl WriteFlags) String() string {
633	return flagString(uint32(fl), writeFlagNames)
634}
635
636type statfsOut struct {
637	St kstatfs
638}
639
640type fsyncIn struct {
641	Fh         uint64
642	FsyncFlags uint32
643	_          uint32
644}
645
646type setxattrInCommon struct {
647	Size  uint32
648	Flags uint32
649}
650
651func (setxattrInCommon) position() uint32 {
652	return 0
653}
654
655type getxattrInCommon struct {
656	Size uint32
657	_    uint32
658}
659
660func (getxattrInCommon) position() uint32 {
661	return 0
662}
663
664type getxattrOut struct {
665	Size uint32
666	_    uint32
667}
668
669type lkIn struct {
670	Fh      uint64
671	Owner   uint64
672	Lk      fileLock
673	LkFlags uint32
674	_       uint32
675}
676
677func lkInSize(p Protocol) uintptr {
678	switch {
679	case p.LT(Protocol{7, 9}):
680		return unsafe.Offsetof(lkIn{}.LkFlags)
681	default:
682		return unsafe.Sizeof(lkIn{})
683	}
684}
685
686type lkOut struct {
687	Lk fileLock
688}
689
690type accessIn struct {
691	Mask uint32
692	_    uint32
693}
694
695type initIn struct {
696	Major        uint32
697	Minor        uint32
698	MaxReadahead uint32
699	Flags        uint32
700}
701
702const initInSize = int(unsafe.Sizeof(initIn{}))
703
704type initOut struct {
705	Major        uint32
706	Minor        uint32
707	MaxReadahead uint32
708	Flags        uint32
709	Unused       uint32
710	MaxWrite     uint32
711}
712
713type interruptIn struct {
714	Unique uint64
715}
716
717type bmapIn struct {
718	Block     uint64
719	BlockSize uint32
720	_         uint32
721}
722
723type bmapOut struct {
724	Block uint64
725}
726
727type inHeader struct {
728	Len    uint32
729	Opcode uint32
730	Unique uint64
731	Nodeid uint64
732	Uid    uint32
733	Gid    uint32
734	Pid    uint32
735	_      uint32
736}
737
738const inHeaderSize = int(unsafe.Sizeof(inHeader{}))
739
740type outHeader struct {
741	Len    uint32
742	Error  int32
743	Unique uint64
744}
745
746type dirent struct {
747	Ino     uint64
748	Off     uint64
749	Namelen uint32
750	Type    uint32
751	Name    [0]byte
752}
753
754const direntSize = 8 + 8 + 4 + 4
755
756const (
757	notifyCodePoll       int32 = 1
758	notifyCodeInvalInode int32 = 2
759	notifyCodeInvalEntry int32 = 3
760)
761
762type notifyInvalInodeOut struct {
763	Ino uint64
764	Off int64
765	Len int64
766}
767
768type notifyInvalEntryOut struct {
769	Parent  uint64
770	Namelen uint32
771	_       uint32
772}
773