File: types.go

package info (click to toggle)
golang-github-hanwen-go-fuse 2.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,584 kB
  • sloc: cpp: 78; sh: 47; makefile: 16
file content (868 lines) | stat: -rw-r--r-- 16,732 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fuse

import (
	"io"
	"syscall"
	"time"
)

const (
	_DEFAULT_BACKGROUND_TASKS = 12
)

// Status is the errno number that a FUSE call returns to the kernel.
type Status int32

const (
	OK = Status(0)

	// EACCESS Permission denied
	EACCES = Status(syscall.EACCES)

	// EBUSY Device or resource busy
	EBUSY = Status(syscall.EBUSY)

	// EAGAIN Resource temporarily unavailable
	EAGAIN = Status(syscall.EAGAIN)

	// EINTR Call was interrupted
	EINTR = Status(syscall.EINTR)

	// EINVAL Invalid argument
	EINVAL = Status(syscall.EINVAL)

	// EIO I/O error
	EIO = Status(syscall.EIO)

	// ENOENT No such file or directory
	ENOENT = Status(syscall.ENOENT)

	// ENOSYS Function not implemented
	ENOSYS = Status(syscall.ENOSYS)

	// ENOTDIR Not a directory
	ENOTDIR = Status(syscall.ENOTDIR)

	// ENOTSUP Not supported
	ENOTSUP = Status(syscall.ENOTSUP)

	// EISDIR Is a directory
	EISDIR = Status(syscall.EISDIR)

	// EPERM Operation not permitted
	EPERM = Status(syscall.EPERM)

	// ERANGE Math result not representable
	ERANGE = Status(syscall.ERANGE)

	// EXDEV Cross-device link
	EXDEV = Status(syscall.EXDEV)

	// EBADF Bad file number
	EBADF = Status(syscall.EBADF)

	// ENODEV No such device
	ENODEV = Status(syscall.ENODEV)

	// EROFS Read-only file system
	EROFS = Status(syscall.EROFS)
)

type ForgetIn struct {
	InHeader

	Nlookup uint64
}

// batch forget is handled internally.
type _ForgetOne struct {
	NodeId  uint64
	Nlookup uint64
}

// batch forget is handled internally.
type _BatchForgetIn struct {
	InHeader
	Count uint32
	Dummy uint32
}

type MkdirIn struct {
	InHeader

	// The mode for the new directory. The calling process' umask
	// is already factored into the mode.
	Mode  uint32
	Umask uint32
}

type Rename1In struct {
	InHeader
	Newdir uint64
}

type RenameIn struct {
	InHeader
	Newdir  uint64
	Flags   uint32
	Padding uint32
}

type LinkIn struct {
	InHeader
	Oldnodeid uint64
}

type Owner struct {
	Uid uint32
	Gid uint32
}

const ( // SetAttrIn.Valid
	FATTR_MODE         = (1 << 0)
	FATTR_UID          = (1 << 1)
	FATTR_GID          = (1 << 2)
	FATTR_SIZE         = (1 << 3)
	FATTR_ATIME        = (1 << 4)
	FATTR_MTIME        = (1 << 5)
	FATTR_FH           = (1 << 6)
	FATTR_ATIME_NOW    = (1 << 7)
	FATTR_MTIME_NOW    = (1 << 8)
	FATTR_LOCKOWNER    = (1 << 9)
	FATTR_CTIME        = (1 << 10)
	FATTR_KILL_SUIDGID = (1 << 11)
)

type SetAttrInCommon struct {
	InHeader

	Valid     uint32
	Padding   uint32
	Fh        uint64
	Size      uint64
	LockOwner uint64
	Atime     uint64
	Mtime     uint64
	Ctime     uint64
	Atimensec uint32
	Mtimensec uint32
	Ctimensec uint32
	Mode      uint32
	Unused4   uint32
	Owner
	Unused5 uint32
}

// GetFh returns the file handle if available, or 0 if undefined.
func (s *SetAttrInCommon) GetFh() (uint64, bool) {
	if s.Valid&FATTR_FH != 0 {
		return s.Fh, true
	}
	return 0, false
}

func (s *SetAttrInCommon) GetMode() (uint32, bool) {
	if s.Valid&FATTR_MODE != 0 {
		return s.Mode & 07777, true
	}
	return 0, false
}

func (s *SetAttrInCommon) GetUID() (uint32, bool) {
	if s.Valid&FATTR_UID != 0 {
		return s.Uid, true
	}
	return ^uint32(0), false
}

func (s *SetAttrInCommon) GetGID() (uint32, bool) {
	if s.Valid&FATTR_GID != 0 {
		return s.Gid, true
	}
	return ^uint32(0), false
}

func (s *SetAttrInCommon) GetSize() (uint64, bool) {
	if s.Valid&FATTR_SIZE != 0 {
		return s.Size, true
	}
	return 0, false
}

func (s *SetAttrInCommon) GetMTime() (time.Time, bool) {
	var t time.Time
	if s.Valid&FATTR_MTIME != 0 {
		if s.Valid&FATTR_MTIME_NOW != 0 {
			t = time.Now()
		} else {
			t = time.Unix(int64(s.Mtime), int64(s.Mtimensec))
		}
		return t, true
	}

	return t, false
}

func (s *SetAttrInCommon) GetATime() (time.Time, bool) {
	var t time.Time
	if s.Valid&FATTR_ATIME != 0 {
		if s.Valid&FATTR_ATIME_NOW != 0 {
			t = time.Now()
		} else {
			t = time.Unix(int64(s.Atime), int64(s.Atimensec))
		}
		return t, true
	}

	return t, false
}

func (s *SetAttrInCommon) GetCTime() (time.Time, bool) {
	var t time.Time
	if s.Valid&FATTR_CTIME != 0 {
		t = time.Unix(int64(s.Ctime), int64(s.Ctimensec))
		return t, true
	}

	return t, false
}

const RELEASE_FLUSH = (1 << 0)

type ReleaseIn struct {
	InHeader
	Fh           uint64
	Flags        uint32
	ReleaseFlags uint32
	LockOwner    uint64
}

type OpenIn struct {
	InHeader
	Flags uint32
	Mode  uint32
}

const (
	// OpenOut.Flags
	FOPEN_DIRECT_IO              = (1 << 0)
	FOPEN_KEEP_CACHE             = (1 << 1)
	FOPEN_NONSEEKABLE            = (1 << 2)
	FOPEN_CACHE_DIR              = (1 << 3)
	FOPEN_STREAM                 = (1 << 4)
	FOPEN_NOFLUSH                = (1 << 5)
	FOPEN_PARALLEL_DIRECT_WRITES = (1 << 6)
	FOPEN_PASSTHROUGH            = (1 << 7)
)

type OpenOut struct {
	Fh        uint64
	OpenFlags uint32
	BackingID int32
}

// To be set in InitIn/InitOut.Flags.
//
// Keep in sync with either of
// * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/fuse.h
// * https://github.com/libfuse/libfuse/blob/master/include/fuse_kernel.h
// but NOT with
// * https://github.com/libfuse/libfuse/blob/master/include/fuse_common.h
// This file has CAP_HANDLE_KILLPRIV and CAP_POSIX_ACL reversed!
const (
	CAP_ASYNC_READ       = (1 << 0)
	CAP_POSIX_LOCKS      = (1 << 1)
	CAP_FILE_OPS         = (1 << 2)
	CAP_ATOMIC_O_TRUNC   = (1 << 3)
	CAP_EXPORT_SUPPORT   = (1 << 4)
	CAP_BIG_WRITES       = (1 << 5)
	CAP_DONT_MASK        = (1 << 6)
	CAP_SPLICE_WRITE     = (1 << 7)
	CAP_SPLICE_MOVE      = (1 << 8)
	CAP_SPLICE_READ      = (1 << 9)
	CAP_FLOCK_LOCKS      = (1 << 10)
	CAP_IOCTL_DIR        = (1 << 11)
	CAP_AUTO_INVAL_DATA  = (1 << 12) // mtime changes invalidate page cache.
	CAP_READDIRPLUS      = (1 << 13)
	CAP_READDIRPLUS_AUTO = (1 << 14)
	CAP_ASYNC_DIO        = (1 << 15)
	CAP_WRITEBACK_CACHE  = (1 << 16)
	CAP_NO_OPEN_SUPPORT  = (1 << 17)
	CAP_PARALLEL_DIROPS  = (1 << 18)
	CAP_HANDLE_KILLPRIV  = (1 << 19)
	CAP_POSIX_ACL        = (1 << 20)
	CAP_ABORT_ERROR      = (1 << 21)
	CAP_MAX_PAGES        = (1 << 22)
	CAP_CACHE_SYMLINKS   = (1 << 23)

	/* bits 24..31 differ across linux and mac */
	/* bits 32..63 get shifted down 32 bits into the Flags2 field */
	CAP_SECURITY_CTX         = (1 << 32)
	CAP_HAS_INODE_DAX        = (1 << 33)
	CAP_CREATE_SUPP_GROUP    = (1 << 34)
	CAP_HAS_EXPIRE_ONLY      = (1 << 35)
	CAP_DIRECT_IO_ALLOW_MMAP = (1 << 36)
	CAP_PASSTHROUGH          = (1 << 37)
	CAP_NO_EXPORT_SUPPORT    = (1 << 38)
	CAP_HAS_RESEND           = (1 << 39)
	CAP_ALLOW_IDMAP          = (1 << 40)
)

type InitIn struct {
	InHeader

	Major        uint32
	Minor        uint32
	MaxReadAhead uint32
	Flags        uint32
	Flags2       uint32
	Unused       [11]uint32
}

func (i *InitIn) Flags64() uint64 {
	return uint64(i.Flags) | uint64(i.Flags2)<<32
}

type InitOut struct {
	Major               uint32
	Minor               uint32
	MaxReadAhead        uint32
	Flags               uint32
	MaxBackground       uint16
	CongestionThreshold uint16
	MaxWrite            uint32
	TimeGran            uint32
	MaxPages            uint16
	Padding             uint16
	Flags2              uint32
	MaxStackDepth       uint32
	Unused              [6]uint32
}

func (o *InitOut) Flags64() uint64 {
	return uint64(o.Flags) | uint64(o.Flags2)<<32
}

type _CuseInitIn struct {
	InHeader
	Major  uint32
	Minor  uint32
	Unused uint32
	Flags  uint32
}

type _CuseInitOut struct {
	Major    uint32
	Minor    uint32
	Unused   uint32
	Flags    uint32
	MaxRead  uint32
	MaxWrite uint32
	DevMajor uint32
	DevMinor uint32
	Spare    [10]uint32
}

type InterruptIn struct {
	InHeader
	Unique uint64
}

type _BmapIn struct {
	InHeader
	Block     uint64
	Blocksize uint32
	Padding   uint32
}

type _BmapOut struct {
	Block uint64
}

const (
	IOCTL_COMPAT       = (1 << 0)
	IOCTL_UNRESTRICTED = (1 << 1)
	IOCTL_RETRY        = (1 << 2)
	IOCTL_DIR          = (1 << 4)
)

type IoctlIn struct {
	InHeader
	Fh    uint64
	Flags uint32

	// The command, consisting of 16-bits metadata (direction + size) and 16-bits to encode the ioctl number
	Cmd uint32

	// The uint64 argument. If there is a payload, this is the
	// payload address in the caller, and should not be used.
	Arg uint64

	// Size for the payload, non-zero if Cmd is WRITE or READ/WRITE.
	InSize uint32

	// Size for the payload, non-zero if Cmd is READ or READ/WRITE.
	OutSize uint32
}

type IoctlOut struct {
	Result int32

	// The following fields are used for unrestricted ioctls,
	// which are only enabled on CUSE.
	Flags   uint32
	InIovs  uint32
	OutIovs uint32
}

type _PollIn struct {
	InHeader
	Fh      uint64
	Kh      uint64
	Flags   uint32
	Padding uint32
}

type _PollOut struct {
	Revents uint32
	Padding uint32
}

type _NotifyPollWakeupOut struct {
	Kh uint64
}

type WriteOut struct {
	Size    uint32
	Padding uint32
}

type GetXAttrOut struct {
	Size    uint32
	Padding uint32
}

type FileLock struct {
	Start uint64
	End   uint64
	Typ   uint32
	Pid   uint32
}

type LkIn struct {
	InHeader
	Fh      uint64
	Owner   uint64
	Lk      FileLock
	LkFlags uint32
	Padding uint32
}

type LkOut struct {
	Lk FileLock
}

// For AccessIn.Mask.
const (
	X_OK = 1
	W_OK = 2
	R_OK = 4
	F_OK = 0
)

type AccessIn struct {
	InHeader
	Mask    uint32
	Padding uint32
}

type FsyncIn struct {
	InHeader
	Fh         uint64
	FsyncFlags uint32
	Padding    uint32
}

type OutHeader struct {
	Length uint32
	Status int32
	Unique uint64
}

type NotifyInvalInodeOut struct {
	Ino    uint64
	Off    int64
	Length int64
}

type NotifyInvalEntryOut struct {
	Parent  uint64
	NameLen uint32
	Padding uint32
}

type NotifyInvalDeleteOut struct {
	Parent  uint64
	Child   uint64
	NameLen uint32
	Padding uint32
}

type NotifyStoreOut struct {
	Nodeid  uint64
	Offset  uint64
	Size    uint32
	Padding uint32
}

type NotifyRetrieveOut struct {
	NotifyUnique uint64
	Nodeid       uint64
	Offset       uint64
	Size         uint32
	Padding      uint32
}

type NotifyRetrieveIn struct {
	InHeader
	Dummy1 uint64
	Offset uint64
	Size   uint32
	Dummy2 uint32
	Dummy3 uint64
	Dummy4 uint64
}

const (
	//	NOTIFY_POLL         = -1 // notify kernel that a poll waiting for IO on a file handle should wake up
	NOTIFY_INVAL_INODE    = -2 // notify kernel that an inode should be invalidated
	NOTIFY_INVAL_ENTRY    = -3 // notify kernel that a directory entry should be invalidated
	NOTIFY_STORE_CACHE    = -4 // store data into kernel cache of an inode
	NOTIFY_RETRIEVE_CACHE = -5 // retrieve data from kernel cache of an inode
	NOTIFY_DELETE         = -6 // notify kernel that a directory entry has been deleted
	NOTIFY_RESEND         = -7

// NOTIFY_CODE_MAX     = -6
)

type FlushIn struct {
	InHeader
	Fh        uint64
	Unused    uint32
	Padding   uint32
	LockOwner uint64
}

type LseekIn struct {
	InHeader
	Fh      uint64
	Offset  uint64
	Whence  uint32
	Padding uint32
}

type LseekOut struct {
	Offset uint64
}

type CopyFileRangeIn struct {
	InHeader
	FhIn      uint64
	OffIn     uint64
	NodeIdOut uint64
	FhOut     uint64
	OffOut    uint64
	Len       uint64
	Flags     uint64
}

// EntryOut holds the result of a (directory,name) lookup.  It has two
// TTLs, one for the (directory, name) lookup itself, and one for the
// attributes (eg. size, mode). The entry TTL also applies if the
// lookup result is ENOENT ("negative entry lookup")
type EntryOut struct {
	NodeId         uint64
	Generation     uint64
	EntryValid     uint64
	AttrValid      uint64
	EntryValidNsec uint32
	AttrValidNsec  uint32
	Attr
}

// EntryTimeout returns the timeout in nanoseconds for a directory
// entry (existence or non-existence of a file within a directory).
func (o *EntryOut) EntryTimeout() time.Duration {
	return time.Duration(uint64(o.EntryValidNsec) + o.EntryValid*1e9)
}

// AttrTimeout returns the TTL in nanoseconds of the attribute data.
func (o *EntryOut) AttrTimeout() time.Duration {
	return time.Duration(uint64(o.AttrValidNsec) + o.AttrValid*1e9)
}

// SetEntryTimeout sets the entry TTL.
func (o *EntryOut) SetEntryTimeout(dt time.Duration) {
	ns := int64(dt)
	o.EntryValidNsec = uint32(ns % 1e9)
	o.EntryValid = uint64(ns / 1e9)
}

// SetAttrTimeout sets the attribute TTL.
func (o *EntryOut) SetAttrTimeout(dt time.Duration) {
	ns := int64(dt)
	o.AttrValidNsec = uint32(ns % 1e9)
	o.AttrValid = uint64(ns / 1e9)
}

// AttrOut is the type returned by the Getattr call.
type AttrOut struct {
	AttrValid     uint64
	AttrValidNsec uint32
	Dummy         uint32
	Attr
}

func (o *AttrOut) Timeout() time.Duration {
	return time.Duration(uint64(o.AttrValidNsec) + o.AttrValid*1e9)
}

func (o *AttrOut) SetTimeout(dt time.Duration) {
	ns := int64(dt)
	o.AttrValidNsec = uint32(ns % 1e9)
	o.AttrValid = uint64(ns / 1e9)
}

type CreateOut struct {
	EntryOut
	OpenOut
}

// Caller has data on the process making the FS call.
//
// The UID and GID are effective UID/GID, except for the ACCESS
// opcode, where UID and GID are the real UIDs
type Caller struct {
	Owner
	Pid uint32
}

type InHeader struct {
	Length uint32
	Opcode uint32
	Unique uint64
	NodeId uint64
	Caller
	Padding uint32
}

type StatfsOut struct {
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Bsize   uint32
	NameLen uint32
	Frsize  uint32
	Padding uint32
	Spare   [6]uint32
}

// _Dirent is what we send to the kernel, but we offer DirEntry and
// DirEntryList to the user.
type _Dirent struct {
	Ino     uint64
	Off     uint64
	NameLen uint32
	Typ     uint32
}

const (
	READ_LOCKOWNER = (1 << 1)
)

const (
	WRITE_CACHE        = (1 << 0)
	WRITE_LOCKOWNER    = (1 << 1)
	WRITE_KILL_SUIDGID = (1 << 2)
)

type FallocateIn struct {
	InHeader
	Fh      uint64
	Offset  uint64
	Length  uint64
	Mode    uint32
	Padding uint32
}

func (lk *FileLock) ToFlockT(flockT *syscall.Flock_t) {
	flockT.Start = int64(lk.Start)
	if lk.End == (1<<63)-1 {
		flockT.Len = 0
	} else {
		flockT.Len = int64(lk.End - lk.Start + 1)
	}
	flockT.Whence = int16(io.SeekStart)
	flockT.Type = int16(lk.Typ)
}

func (lk *FileLock) FromFlockT(flockT *syscall.Flock_t) {
	lk.Typ = uint32(flockT.Type)
	if flockT.Type != syscall.F_UNLCK {
		lk.Start = uint64(flockT.Start)
		if flockT.Len == 0 {
			lk.End = (1 << 63) - 1
		} else {
			lk.End = uint64(flockT.Start + flockT.Len - 1)
		}
	}
	lk.Pid = uint32(flockT.Pid)
}

const (
	// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
	FUSE_GETATTR_FH = (1 << 0)
)

type GetAttrIn struct {
	InHeader

	Flags_ uint32
	Dummy  uint32
	Fh_    uint64
}

// Flags accesses the flags. This is a method, because OSXFuse does not
// have GetAttrIn flags.
func (g *GetAttrIn) Flags() uint32 {
	return g.Flags_
}

// Fh accesses the file handle. This is a method, because OSXFuse does not
// have GetAttrIn flags.
func (g *GetAttrIn) Fh() uint64 {
	return g.Fh_
}

type MknodIn struct {
	InHeader

	// Mode to use, including the Umask value
	Mode    uint32
	Rdev    uint32
	Umask   uint32
	Padding uint32
}

type CreateIn struct {
	InHeader
	Flags uint32

	// Mode for the new file; already takes Umask into account.
	Mode uint32

	// Umask used for this create call.
	Umask   uint32
	Padding uint32
}

type ReadIn struct {
	InHeader
	Fh        uint64
	Offset    uint64
	Size      uint32
	ReadFlags uint32
	LockOwner uint64
	Flags     uint32
	Padding   uint32
}

type WriteIn struct {
	InHeader
	Fh         uint64
	Offset     uint64
	Size       uint32
	WriteFlags uint32
	LockOwner  uint64
	Flags      uint32
	Padding    uint32
}

// Data for registering a file as backing an inode.
type BackingMap struct {
	Fd      int32
	Flags   uint32
	padding uint64
}

type SxTime struct {
	Sec       uint64
	Nsec      uint32
	_reserved uint32
}

func (t *SxTime) Seconds() float64 {
	return ft(t.Sec, t.Nsec)
}

type Statx struct {
	Mask       uint32
	Blksize    uint32
	Attributes uint64
	Nlink      uint32

	Uid            uint32
	Gid            uint32
	Mode           uint16
	_spare0        uint16
	Ino            uint64
	Size           uint64
	Blocks         uint64
	AttributesMask uint64

	Atime SxTime
	Btime SxTime
	Ctime SxTime
	Mtime SxTime

	RdevMajor uint32
	RdevMinor uint32
	DevMajor  uint32
	DevMinor  uint32
	_spare2   [14]uint64
}

type StatxIn struct {
	InHeader

	GetattrFlags uint32
	_reserved    uint32
	Fh           uint64
	SxFlags      uint32
	SxMask       uint32
}

type StatxOut struct {
	AttrValid     uint64
	AttrValidNsec uint32
	Flags         uint32
	_spare        [2]uint64

	Statx
}

func (o *StatxOut) Timeout() time.Duration {
	return time.Duration(uint64(o.AttrValidNsec) + o.AttrValid*1e9)
}

func (o *StatxOut) SetTimeout(dt time.Duration) {
	ns := int64(dt)
	o.AttrValidNsec = uint32(ns % 1e9)
	o.AttrValid = uint64(ns / 1e9)
}