xref: /aosp_15_r20/external/crosvm/fuse/src/sys.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2019 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::mem;
6 
7 use bitflags::bitflags;
8 use enumn::N;
9 use zerocopy::AsBytes;
10 use zerocopy::FromBytes;
11 use zerocopy::FromZeroes;
12 
13 /// Version number of this interface.
14 pub const KERNEL_VERSION: u32 = 7;
15 
16 /// Oldest supported minor version of the fuse interface.
17 pub const OLDEST_SUPPORTED_KERNEL_MINOR_VERSION: u32 = 27;
18 
19 /// Minor version number of this interface.
20 pub const KERNEL_MINOR_VERSION: u32 = 31;
21 
22 /// The ID of the inode corresponding to the root directory of the file system.
23 pub const ROOT_ID: u64 = 1;
24 
25 // Bitmasks for `fuse_setattr_in.valid`.
26 const FATTR_MODE: u32 = 1;
27 const FATTR_UID: u32 = 2;
28 const FATTR_GID: u32 = 4;
29 const FATTR_SIZE: u32 = 8;
30 const FATTR_ATIME: u32 = 16;
31 const FATTR_MTIME: u32 = 32;
32 pub const FATTR_FH: u32 = 64;
33 const FATTR_ATIME_NOW: u32 = 128;
34 const FATTR_MTIME_NOW: u32 = 256;
35 pub const FATTR_LOCKOWNER: u32 = 512;
36 const FATTR_CTIME: u32 = 1024;
37 
38 bitflags! {
39     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
40     #[repr(transparent)]
41     pub struct SetattrValid: u32 {
42         const MODE = FATTR_MODE;
43         const UID = FATTR_UID;
44         const GID = FATTR_GID;
45         const SIZE = FATTR_SIZE;
46         const ATIME = FATTR_ATIME;
47         const MTIME = FATTR_MTIME;
48         const ATIME_NOW = FATTR_ATIME_NOW;
49         const MTIME_NOW = FATTR_MTIME_NOW;
50         const CTIME = FATTR_CTIME;
51     }
52 }
53 
54 // Flags returned by the OPEN request.
55 
56 /// Bypass page cache for this open file.
57 const FOPEN_DIRECT_IO: u32 = 1 << 0;
58 
59 /// Don't invalidate the data cache on open.
60 const FOPEN_KEEP_CACHE: u32 = 1 << 1;
61 
62 /// The file is not seekable.
63 const FOPEN_NONSEEKABLE: u32 = 1 << 2;
64 
65 /// Allow caching the directory entries.
66 const FOPEN_CACHE_DIR: u32 = 1 << 3;
67 
68 /// This file is stream-like (i.e., no file position).
69 const FOPEN_STREAM: u32 = 1 << 4;
70 
71 /// New file was created in atomic open
72 const FOPEN_FILE_CREATED: u32 = 1 << 7;
73 
74 bitflags! {
75     /// Options controlling the behavior of files opened by the server in response
76     /// to an open or create request.
77     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
78     #[repr(transparent)]
79     pub struct OpenOptions: u32 {
80         const DIRECT_IO = FOPEN_DIRECT_IO;
81         const KEEP_CACHE = FOPEN_KEEP_CACHE;
82         const NONSEEKABLE = FOPEN_NONSEEKABLE;
83         const CACHE_DIR = FOPEN_CACHE_DIR;
84         const STREAM = FOPEN_STREAM;
85         const FILE_CREATED = FOPEN_FILE_CREATED;
86     }
87 }
88 
89 // INIT request/reply flags.
90 
91 /// Asynchronous read requests.
92 const ASYNC_READ: u64 = 1;
93 
94 /// Remote locking for POSIX file locks.
95 const POSIX_LOCKS: u64 = 2;
96 
97 /// Kernel sends file handle for fstat, etc... (not yet supported).
98 const FILE_OPS: u64 = 4;
99 
100 /// Handles the O_TRUNC open flag in the filesystem.
101 const ATOMIC_O_TRUNC: u64 = 8;
102 
103 /// FileSystem handles lookups of "." and "..".
104 const EXPORT_SUPPORT: u64 = 16;
105 
106 /// FileSystem can handle write size larger than 4kB.
107 const BIG_WRITES: u64 = 32;
108 
109 /// Don't apply umask to file mode on create operations.
110 const DONT_MASK: u64 = 64;
111 
112 /// Kernel supports splice write on the device.
113 const SPLICE_WRITE: u64 = 128;
114 
115 /// Kernel supports splice move on the device.
116 const SPLICE_MOVE: u64 = 256;
117 
118 /// Kernel supports splice read on the device.
119 const SPLICE_READ: u64 = 512;
120 
121 /// Remote locking for BSD style file locks.
122 const FLOCK_LOCKS: u64 = 1024;
123 
124 /// Kernel supports ioctl on directories.
125 const HAS_IOCTL_DIR: u64 = 2048;
126 
127 /// Automatically invalidate cached pages.
128 const AUTO_INVAL_DATA: u64 = 4096;
129 
130 /// Do READDIRPLUS (READDIR+LOOKUP in one).
131 const DO_READDIRPLUS: u64 = 8192;
132 
133 /// Adaptive readdirplus.
134 const READDIRPLUS_AUTO: u64 = 16384;
135 
136 /// Asynchronous direct I/O submission.
137 const ASYNC_DIO: u64 = 32768;
138 
139 /// Use writeback cache for buffered writes.
140 const WRITEBACK_CACHE: u64 = 65536;
141 
142 /// Kernel supports zero-message opens.
143 const NO_OPEN_SUPPORT: u64 = 131072;
144 
145 /// Allow parallel lookups and readdir.
146 const PARALLEL_DIROPS: u64 = 262144;
147 
148 /// Fs handles killing suid/sgid/cap on write/chown/trunc.
149 const HANDLE_KILLPRIV: u64 = 524288;
150 
151 /// FileSystem supports posix acls.
152 const POSIX_ACL: u64 = 1048576;
153 
154 /// Reading the device after an abort returns `ECONNABORTED`.
155 const ABORT_ERROR: u64 = 2097152;
156 
157 /// The reply to the `init` message contains the max number of request pages.
158 const MAX_PAGES: u64 = 4194304;
159 
160 /// Cache `readlink` responses.
161 const CACHE_SYMLINKS: u64 = 8388608;
162 
163 /// Kernel supports zero-message opens for directories.
164 const NO_OPENDIR_SUPPORT: u64 = 16777216;
165 
166 /// Kernel supports explicit cache invalidation.
167 const EXPLICIT_INVAL_DATA: u64 = 33554432;
168 
169 /// The `map_alignment` field of the `InitOut` struct is valid.
170 const MAP_ALIGNMENT: u64 = 67108864;
171 
172 /// Extended fuse_init_in request to hold additional flags
173 const INIT_EXT: u64 = 1073741824;
174 
175 /// The client should send the security context along with open, mkdir, create, and symlink
176 /// requests.
177 const SECURITY_CONTEXT: u64 = 4294967296;
178 
179 bitflags! {
180     /// A bitfield passed in as a parameter to and returned from the `init` method of the
181     /// `FileSystem` trait.
182     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
183     #[repr(transparent)]
184     pub struct FsOptions: u64 {
185         /// Indicates that the filesystem supports asynchronous read requests.
186         ///
187         /// If this capability is not requested/available, the kernel will ensure that there is at
188         /// most one pending read request per file-handle at any time, and will attempt to order
189         /// read requests by increasing offset.
190         ///
191         /// This feature is enabled by default when supported by the kernel.
192         const ASYNC_READ = ASYNC_READ;
193 
194         /// Indicates that the filesystem supports "remote" locking.
195         ///
196         /// This feature is not enabled by default and should only be set if the filesystem
197         /// implements the `getlk` and `setlk` methods of the `FileSystem` trait.
198         const POSIX_LOCKS = POSIX_LOCKS;
199 
200         /// Kernel sends file handle for fstat, etc... (not yet supported).
201         const FILE_OPS = FILE_OPS;
202 
203         /// Indicates that the filesystem supports the `O_TRUNC` open flag. If disabled, and an
204         /// application specifies `O_TRUNC`, fuse first calls `setattr` to truncate the file and
205         /// then calls `open` with `O_TRUNC` filtered out.
206         ///
207         /// This feature is enabled by default when supported by the kernel.
208         const ATOMIC_O_TRUNC = ATOMIC_O_TRUNC;
209 
210         /// Indicates that the filesystem supports lookups of "." and "..".
211         ///
212         /// This feature is disabled by default.
213         const EXPORT_SUPPORT = EXPORT_SUPPORT;
214 
215         /// FileSystem can handle write size larger than 4kB.
216         const BIG_WRITES = BIG_WRITES;
217 
218         /// Indicates that the kernel should not apply the umask to the file mode on create
219         /// operations.
220         ///
221         /// This feature is disabled by default.
222         const DONT_MASK = DONT_MASK;
223 
224         /// Indicates that the server should try to use `splice(2)` when writing to the fuse device.
225         /// This may improve performance.
226         ///
227         /// This feature is not currently supported.
228         const SPLICE_WRITE = SPLICE_WRITE;
229 
230         /// Indicates that the server should try to move pages instead of copying when writing to /
231         /// reading from the fuse device. This may improve performance.
232         ///
233         /// This feature is not currently supported.
234         const SPLICE_MOVE = SPLICE_MOVE;
235 
236         /// Indicates that the server should try to use `splice(2)` when reading from the fuse
237         /// device. This may improve performance.
238         ///
239         /// This feature is not currently supported.
240         const SPLICE_READ = SPLICE_READ;
241 
242         /// If set, then calls to `flock` will be emulated using POSIX locks and must
243         /// then be handled by the filesystem's `setlock()` handler.
244         ///
245         /// If not set, `flock` calls will be handled by the FUSE kernel module internally (so any
246         /// access that does not go through the kernel cannot be taken into account).
247         ///
248         /// This feature is disabled by default.
249         const FLOCK_LOCKS = FLOCK_LOCKS;
250 
251         /// Indicates that the filesystem supports ioctl's on directories.
252         ///
253         /// This feature is enabled by default when supported by the kernel.
254         const HAS_IOCTL_DIR = HAS_IOCTL_DIR;
255 
256         /// Traditionally, while a file is open the FUSE kernel module only asks the filesystem for
257         /// an update of the file's attributes when a client attempts to read beyond EOF. This is
258         /// unsuitable for e.g. network filesystems, where the file contents may change without the
259         /// kernel knowing about it.
260         ///
261         /// If this flag is set, FUSE will check the validity of the attributes on every read. If
262         /// the attributes are no longer valid (i.e., if the *attribute* timeout has expired) then
263         /// FUSE will first send another `getattr` request. If the new mtime differs from the
264         /// previous value, any cached file *contents* will be invalidated as well.
265         ///
266         /// This flag should always be set when available. If all file changes go through the
267         /// kernel, *attribute* validity should be set to a very large number to avoid unnecessary
268         /// `getattr()` calls.
269         ///
270         /// This feature is enabled by default when supported by the kernel.
271         const AUTO_INVAL_DATA = AUTO_INVAL_DATA;
272 
273         /// Indicates that the filesystem supports readdirplus.
274         ///
275         /// The feature is not enabled by default and should only be set if the filesystem
276         /// implements the `readdirplus` method of the `FileSystem` trait.
277         const DO_READDIRPLUS = DO_READDIRPLUS;
278 
279         /// Indicates that the filesystem supports adaptive readdirplus.
280         ///
281         /// If `DO_READDIRPLUS` is not set, this flag has no effect.
282         ///
283         /// If `DO_READDIRPLUS` is set and this flag is not set, the kernel will always issue
284         /// `readdirplus()` requests to retrieve directory contents.
285         ///
286         /// If `DO_READDIRPLUS` is set and this flag is set, the kernel will issue both `readdir()`
287         /// and `readdirplus()` requests, depending on how much information is expected to be
288         /// required.
289         ///
290         /// This feature is not enabled by default and should only be set if the file system
291         /// implements both the `readdir` and `readdirplus` methods of the `FileSystem` trait.
292         const READDIRPLUS_AUTO = READDIRPLUS_AUTO;
293 
294         /// Indicates that the filesystem supports asynchronous direct I/O submission.
295         ///
296         /// If this capability is not requested/available, the kernel will ensure that there is at
297         /// most one pending read and one pending write request per direct I/O file-handle at any
298         /// time.
299         ///
300         /// This feature is enabled by default when supported by the kernel.
301         const ASYNC_DIO = ASYNC_DIO;
302 
303         /// Indicates that writeback caching should be enabled. This means that individual write
304         /// request may be buffered and merged in the kernel before they are sent to the file
305         /// system.
306         ///
307         /// This feature is disabled by default.
308         const WRITEBACK_CACHE = WRITEBACK_CACHE;
309 
310         /// Indicates support for zero-message opens. If this flag is set in the `capable` parameter
311         /// of the `init` trait method, then the file system may return `ENOSYS` from the open() handler
312         /// to indicate success. Further attempts to open files will be handled in the kernel. (If
313         /// this flag is not set, returning ENOSYS will be treated as an error and signaled to the
314         /// caller).
315         ///
316         /// Setting (or not setting) the field in the `FsOptions` returned from the `init` method
317         /// has no effect.
318         const ZERO_MESSAGE_OPEN = NO_OPEN_SUPPORT;
319 
320         /// Indicates support for parallel directory operations. If this flag is unset, the FUSE
321         /// kernel module will ensure that lookup() and readdir() requests are never issued
322         /// concurrently for the same directory.
323         ///
324         /// This feature is enabled by default when supported by the kernel.
325         const PARALLEL_DIROPS = PARALLEL_DIROPS;
326 
327         /// Indicates that the file system is responsible for unsetting setuid and setgid bits when a
328         /// file is written, truncated, or its owner is changed.
329         ///
330         /// This feature is enabled by default when supported by the kernel.
331         const HANDLE_KILLPRIV = HANDLE_KILLPRIV;
332 
333         /// Indicates support for POSIX ACLs.
334         ///
335         /// If this feature is enabled, the kernel will cache and have responsibility for enforcing
336         /// ACLs. ACL will be stored as xattrs and passed to userspace, which is responsible for
337         /// updating the ACLs in the filesystem, keeping the file mode in sync with the ACL, and
338         /// ensuring inheritance of default ACLs when new filesystem nodes are created. Note that
339         /// this requires that the file system is able to parse and interpret the xattr
340         /// representation of ACLs.
341         ///
342         /// Enabling this feature implicitly turns on the `default_permissions` mount option (even
343         /// if it was not passed to mount(2)).
344         ///
345         /// This feature is disabled by default.
346         const POSIX_ACL = POSIX_ACL;
347 
348         /// Indicates that the kernel may cache responses to `readlink` calls.
349         const CACHE_SYMLINKS = CACHE_SYMLINKS;
350 
351         /// Indicates support for zero-message opens for directories. If this flag is set in the
352         /// `capable` parameter of the `init` trait method, then the file system may return `ENOSYS`
353         /// from the opendir() handler to indicate success. Further attempts to open directories
354         /// will be handled in the kernel. (If this flag is not set, returning ENOSYS will be
355         /// treated as an error and signaled to the caller).
356         ///
357         /// Setting (or not setting) the field in the `FsOptions` returned from the `init` method
358         /// has no effect.
359         const ZERO_MESSAGE_OPENDIR = NO_OPENDIR_SUPPORT;
360 
361         /// Indicates support for invalidating cached pages only on explicit request.
362         ///
363         /// If this flag is set in the `capable` parameter of the `init` trait method, then the FUSE
364         /// kernel module supports invalidating cached pages only on explicit request by the
365         /// filesystem.
366         ///
367         /// By setting this flag in the return value of the `init` trait method, the filesystem is
368         /// responsible for invalidating cached pages through explicit requests to the kernel.
369         ///
370         /// Note that setting this flag does not prevent the cached pages from being flushed by OS
371         /// itself and/or through user actions.
372         ///
373         /// Note that if both EXPLICIT_INVAL_DATA and AUTO_INVAL_DATA are set in the `capable`
374         /// parameter of the `init` trait method then AUTO_INVAL_DATA takes precedence.
375         ///
376         /// This feature is disabled by default.
377         const EXPLICIT_INVAL_DATA = EXPLICIT_INVAL_DATA;
378 
379         /// Indicates that the `map_alignment` field of the `InitOut` struct is valid.
380         ///
381         /// The `MAP_ALIGNMENT` field is used by the FUSE kernel driver to ensure that its DAX
382         /// mapping requests are pagesize-aligned. This field automatically set by the server and
383         /// this feature is enabled by default.
384         const MAP_ALIGNMENT = MAP_ALIGNMENT;
385 
386         /// Indicates that the `max_pages` field of the `InitOut` struct is valid.
387         ///
388         /// This field is used by the kernel driver to determine the maximum number of pages that
389         /// may be used for any read or write requests.
390         const MAX_PAGES = MAX_PAGES;
391 
392         /// Indicates that `InitIn`/`InitOut` struct is extended to hold additional flags.
393         const INIT_EXT = INIT_EXT;
394 
395         /// Indicates support for sending the security context with creation requests.
396         const SECURITY_CONTEXT = SECURITY_CONTEXT;
397     }
398 }
399 
400 // Release flags.
401 pub const RELEASE_FLUSH: u32 = 1;
402 pub const RELEASE_FLOCK_UNLOCK: u32 = 2;
403 
404 // Getattr flags.
405 pub const GETATTR_FH: u32 = 1;
406 
407 // Lock flags.
408 pub const LK_FLOCK: u32 = 1;
409 
410 // Write flags.
411 
412 /// Delayed write from page cache, file handle is guessed.
413 pub const WRITE_CACHE: u32 = 1;
414 
415 /// `lock_owner` field is valid.
416 pub const WRITE_LOCKOWNER: u32 = 2;
417 
418 /// Kill the suid and sgid bits.
419 pub const WRITE_KILL_PRIV: u32 = 3;
420 
421 // Read flags.
422 pub const READ_LOCKOWNER: u32 = 2;
423 
424 // Ioctl flags.
425 
426 /// 32bit compat ioctl on 64bit machine
427 const IOCTL_COMPAT: u32 = 1;
428 
429 /// Not restricted to well-formed ioctls, retry allowed
430 const IOCTL_UNRESTRICTED: u32 = 2;
431 
432 /// Retry with new iovecs
433 const IOCTL_RETRY: u32 = 4;
434 
435 /// 32bit ioctl
436 const IOCTL_32BIT: u32 = 8;
437 
438 /// Is a directory
439 const IOCTL_DIR: u32 = 16;
440 
441 /// 32-bit compat ioctl on 64-bit machine with 64-bit time_t.
442 const IOCTL_COMPAT_X32: u32 = 32;
443 
444 /// Maximum of in_iovecs + out_iovecs
445 pub const IOCTL_MAX_IOV: usize = 256;
446 
447 bitflags! {
448     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
449     #[repr(transparent)]
450     pub struct IoctlFlags: u32 {
451         /// 32bit compat ioctl on 64bit machine
452         const COMPAT = IOCTL_COMPAT;
453 
454         /// Not restricted to well-formed ioctls, retry allowed
455         const UNRESTRICTED = IOCTL_UNRESTRICTED;
456 
457         /// Retry with new iovecs
458         const RETRY = IOCTL_RETRY;
459 
460         /// 32bit ioctl
461         const IOCTL_32BIT = IOCTL_32BIT;
462 
463         /// Is a directory
464         const DIR = IOCTL_DIR;
465 
466         /// 32-bit compat ioctl on 64-bit machine with 64-bit time_t.
467         const COMPAT_X32 = IOCTL_COMPAT_X32;
468     }
469 }
470 
471 /// Request poll notify.
472 pub const POLL_SCHEDULE_NOTIFY: u32 = 1;
473 
474 /// The read buffer is required to be at least 8k, but may be much larger.
475 pub const FUSE_MIN_READ_BUFFER: u32 = 8192;
476 
477 pub const FUSE_COMPAT_ENTRY_OUT_SIZE: u32 = 120;
478 pub const FUSE_COMPAT_ATTR_OUT_SIZE: u32 = 96;
479 pub const FUSE_COMPAT_MKNOD_IN_SIZE: u32 = 8;
480 pub const FUSE_COMPAT_WRITE_IN_SIZE: u32 = 24;
481 pub const FUSE_COMPAT_STATFS_SIZE: u32 = 48;
482 pub const FUSE_COMPAT_INIT_OUT_SIZE: u32 = 8;
483 pub const FUSE_COMPAT_22_INIT_OUT_SIZE: u32 = 24;
484 
485 const SETUPMAPPING_FLAG_WRITE: u64 = 1;
486 const SETUPMAPPING_FLAG_READ: u64 = 2;
487 
488 bitflags! {
489     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
490     #[repr(transparent)]
491     pub struct SetUpMappingFlags: u64 {
492         /// Create writable mapping.
493         const WRITE = SETUPMAPPING_FLAG_WRITE;
494         /// Create readable mapping.
495         const READ = SETUPMAPPING_FLAG_READ;
496     }
497 }
498 
499 // Request Extension Constants
500 /// Maximum security contexts in a request
501 pub const MAX_NR_SECCTX: u32 = 31;
502 
503 #[repr(C)]
504 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
505 pub struct Attr {
506     pub ino: u64,
507     pub size: u64,
508     pub blocks: u64,
509     pub atime: u64,
510     pub mtime: u64,
511     pub ctime: u64,
512     pub atimensec: u32,
513     pub mtimensec: u32,
514     pub ctimensec: u32,
515     pub mode: u32,
516     pub nlink: u32,
517     pub uid: u32,
518     pub gid: u32,
519     pub rdev: u32,
520     pub blksize: u32,
521     pub padding: u32,
522 }
523 
524 impl From<libc::stat64> for Attr {
from(st: libc::stat64) -> Attr525     fn from(st: libc::stat64) -> Attr {
526         Attr {
527             ino: st.st_ino,
528             size: st.st_size as u64,
529             blocks: st.st_blocks as u64,
530             atime: st.st_atime as u64,
531             mtime: st.st_mtime as u64,
532             ctime: st.st_ctime as u64,
533             atimensec: st.st_atime_nsec as u32,
534             mtimensec: st.st_mtime_nsec as u32,
535             ctimensec: st.st_ctime_nsec as u32,
536             mode: st.st_mode,
537             #[allow(clippy::unnecessary_cast)]
538             nlink: st.st_nlink as u32,
539             uid: st.st_uid,
540             gid: st.st_gid,
541             rdev: st.st_rdev as u32,
542             blksize: st.st_blksize as u32,
543             ..Default::default()
544         }
545     }
546 }
547 
548 #[repr(C)]
549 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
550 pub struct Kstatfs {
551     pub blocks: u64,
552     pub bfree: u64,
553     pub bavail: u64,
554     pub files: u64,
555     pub ffree: u64,
556     pub bsize: u32,
557     pub namelen: u32,
558     pub frsize: u32,
559     pub padding: u32,
560     pub spare: [u32; 6],
561 }
562 
563 impl From<libc::statvfs64> for Kstatfs {
564     #[allow(clippy::unnecessary_cast)]
from(st: libc::statvfs64) -> Self565     fn from(st: libc::statvfs64) -> Self {
566         Kstatfs {
567             blocks: st.f_blocks,
568             bfree: st.f_bfree,
569             bavail: st.f_bavail,
570             files: st.f_files,
571             ffree: st.f_ffree,
572             bsize: st.f_bsize as u32,
573             namelen: st.f_namemax as u32,
574             frsize: st.f_frsize as u32,
575             ..Default::default()
576         }
577     }
578 }
579 
580 #[repr(C)]
581 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
582 pub struct FileLock {
583     pub start: u64,
584     pub end: u64,
585     pub type_: u32,
586     pub pid: u32, /* tgid */
587 }
588 
589 #[repr(u32)]
590 #[derive(Debug, Copy, Clone, N, AsBytes)]
591 pub enum Opcode {
592     Lookup = 1,
593     Forget = 2, /* No Reply */
594     Getattr = 3,
595     Setattr = 4,
596     Readlink = 5,
597     Symlink = 6,
598     Mknod = 8,
599     Mkdir = 9,
600     Unlink = 10,
601     Rmdir = 11,
602     Rename = 12,
603     Link = 13,
604     Open = 14,
605     Read = 15,
606     Write = 16,
607     Statfs = 17,
608     Release = 18,
609     Fsync = 20,
610     Setxattr = 21,
611     Getxattr = 22,
612     Listxattr = 23,
613     Removexattr = 24,
614     Flush = 25,
615     Init = 26,
616     Opendir = 27,
617     Readdir = 28,
618     Releasedir = 29,
619     Fsyncdir = 30,
620     Getlk = 31,
621     Setlk = 32,
622     Setlkw = 33,
623     Access = 34,
624     Create = 35,
625     Interrupt = 36,
626     Bmap = 37,
627     Destroy = 38,
628     Ioctl = 39,
629     Poll = 40,
630     NotifyReply = 41,
631     BatchForget = 42,
632     Fallocate = 43,
633     Readdirplus = 44,
634     Rename2 = 45,
635     Lseek = 46,
636     CopyFileRange = 47,
637     SetUpMapping = 48,
638     RemoveMapping = 49,
639     // TODO(b/310102543): Update the opcode keep same with kernel patch after the atomic open
640     // kernel is merged to upstream.
641     OpenAtomic = u32::MAX - 1,
642     ChromeOsTmpfile = u32::MAX,
643 }
644 
645 #[repr(u32)]
646 #[derive(Debug, Copy, Clone, N)]
647 pub enum NotifyOpcode {
648     Poll = 1,
649     InvalInode = 2,
650     InvalEntry = 3,
651     Store = 4,
652     Retrieve = 5,
653     Delete = 6,
654     CodeMax = 7,
655 }
656 
657 #[repr(C)]
658 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
659 pub struct EntryOut {
660     pub nodeid: u64,      /* Inode ID */
661     pub generation: u64,  /* Inode generation: nodeid:gen must be unique for the fs's lifetime */
662     pub entry_valid: u64, /* Cache timeout for the name */
663     pub attr_valid: u64,  /* Cache timeout for the attributes */
664     pub entry_valid_nsec: u32,
665     pub attr_valid_nsec: u32,
666     pub attr: Attr,
667 }
668 
669 #[repr(C)]
670 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
671 pub struct ForgetIn {
672     pub nlookup: u64,
673 }
674 
675 #[repr(C)]
676 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
677 pub struct ForgetOne {
678     pub nodeid: u64,
679     pub nlookup: u64,
680 }
681 
682 #[repr(C)]
683 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
684 pub struct BatchForgetIn {
685     pub count: u32,
686     pub dummy: u32,
687 }
688 
689 #[repr(C)]
690 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
691 pub struct GetattrIn {
692     pub flags: u32,
693     pub dummy: u32,
694     pub fh: u64,
695 }
696 
697 #[repr(C)]
698 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
699 pub struct AttrOut {
700     pub attr_valid: u64, /* Cache timeout for the attributes */
701     pub attr_valid_nsec: u32,
702     pub dummy: u32,
703     pub attr: Attr,
704 }
705 
706 #[repr(C)]
707 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
708 pub struct MknodIn {
709     pub mode: u32,
710     pub rdev: u32,
711     pub umask: u32,
712     pub padding: u32,
713 }
714 
715 #[repr(C)]
716 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
717 pub struct MkdirIn {
718     pub mode: u32,
719     pub umask: u32,
720 }
721 
722 #[repr(C)]
723 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
724 pub struct ChromeOsTmpfileIn {
725     pub mode: u32,
726     pub umask: u32,
727 }
728 
729 #[repr(C)]
730 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
731 pub struct RenameIn {
732     pub newdir: u64,
733 }
734 
735 #[repr(C)]
736 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
737 pub struct Rename2In {
738     pub newdir: u64,
739     pub flags: u32,
740     pub padding: u32,
741 }
742 
743 #[repr(C)]
744 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
745 pub struct LinkIn {
746     pub oldnodeid: u64,
747 }
748 
749 #[repr(C)]
750 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
751 pub struct SetattrIn {
752     pub valid: u32,
753     pub padding: u32,
754     pub fh: u64,
755     pub size: u64,
756     pub lock_owner: u64,
757     pub atime: u64,
758     pub mtime: u64,
759     pub ctime: u64,
760     pub atimensec: u32,
761     pub mtimensec: u32,
762     pub ctimensec: u32,
763     pub mode: u32,
764     pub unused4: u32,
765     pub uid: u32,
766     pub gid: u32,
767     pub unused5: u32,
768 }
769 
770 impl From<SetattrIn> for libc::stat64 {
from(s: SetattrIn) -> libc::stat64771     fn from(s: SetattrIn) -> libc::stat64 {
772         // SAFETY: zero-initializing a struct with only POD fields.
773         let mut out: libc::stat64 = unsafe { mem::zeroed() };
774         out.st_mode = s.mode;
775         out.st_uid = s.uid;
776         out.st_gid = s.gid;
777         out.st_size = s.size as i64;
778         out.st_atime = s.atime as libc::time_t;
779         out.st_mtime = s.mtime as libc::time_t;
780         out.st_ctime = s.ctime as libc::time_t;
781         out.st_atime_nsec = s.atimensec as libc::c_long;
782         out.st_mtime_nsec = s.mtimensec as libc::c_long;
783         out.st_ctime_nsec = s.ctimensec as libc::c_long;
784 
785         out
786     }
787 }
788 
789 #[repr(C)]
790 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
791 pub struct OpenIn {
792     pub flags: u32,
793     pub unused: u32,
794 }
795 
796 #[repr(C)]
797 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
798 pub struct CreateIn {
799     pub flags: u32,
800     pub mode: u32,
801     pub umask: u32,
802     pub padding: u32,
803 }
804 
805 #[repr(C)]
806 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
807 pub struct OpenOut {
808     pub fh: u64,
809     pub open_flags: u32,
810     pub padding: u32,
811 }
812 
813 #[repr(C)]
814 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
815 pub struct ReleaseIn {
816     pub fh: u64,
817     pub flags: u32,
818     pub release_flags: u32,
819     pub lock_owner: u64,
820 }
821 
822 #[repr(C)]
823 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
824 pub struct FlushIn {
825     pub fh: u64,
826     pub unused: u32,
827     pub padding: u32,
828     pub lock_owner: u64,
829 }
830 
831 #[repr(C)]
832 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
833 pub struct ReadIn {
834     pub fh: u64,
835     pub offset: u64,
836     pub size: u32,
837     pub read_flags: u32,
838     pub lock_owner: u64,
839     pub flags: u32,
840     pub padding: u32,
841 }
842 
843 #[repr(C)]
844 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
845 pub struct WriteIn {
846     pub fh: u64,
847     pub offset: u64,
848     pub size: u32,
849     pub write_flags: u32,
850     pub lock_owner: u64,
851     pub flags: u32,
852     pub padding: u32,
853 }
854 
855 #[repr(C)]
856 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
857 pub struct WriteOut {
858     pub size: u32,
859     pub padding: u32,
860 }
861 
862 #[repr(C)]
863 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
864 pub struct StatfsOut {
865     pub st: Kstatfs,
866 }
867 
868 #[repr(C)]
869 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
870 pub struct FsyncIn {
871     pub fh: u64,
872     pub fsync_flags: u32,
873     pub padding: u32,
874 }
875 
876 #[repr(C)]
877 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
878 pub struct SetxattrIn {
879     pub size: u32,
880     pub flags: u32,
881 }
882 
883 #[repr(C)]
884 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
885 pub struct GetxattrIn {
886     pub size: u32,
887     pub padding: u32,
888 }
889 
890 #[repr(C)]
891 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
892 pub struct GetxattrOut {
893     pub size: u32,
894     pub padding: u32,
895 }
896 
897 #[repr(C)]
898 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
899 pub struct LkIn {
900     pub fh: u64,
901     pub owner: u64,
902     pub lk: FileLock,
903     pub lk_flags: u32,
904     pub padding: u32,
905 }
906 
907 #[repr(C)]
908 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
909 pub struct LkOut {
910     pub lk: FileLock,
911 }
912 
913 #[repr(C)]
914 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
915 pub struct AccessIn {
916     pub mask: u32,
917     pub padding: u32,
918 }
919 
920 #[repr(C)]
921 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
922 pub struct InitIn {
923     pub major: u32,
924     pub minor: u32,
925     pub max_readahead: u32,
926     pub flags: u32,
927 }
928 
929 #[repr(C)]
930 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
931 pub struct InitInExt {
932     pub flags2: u32,
933     pub unused: [u32; 11],
934 }
935 
936 #[repr(C)]
937 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
938 pub struct InitOut {
939     pub major: u32,
940     pub minor: u32,
941     pub max_readahead: u32,
942     pub flags: u32,
943     pub max_background: u16,
944     pub congestion_threshold: u16,
945     pub max_write: u32,
946     pub time_gran: u32,
947     pub max_pages: u16,
948     pub map_alignment: u16,
949     pub flags2: u32,
950     pub unused: [u32; 7],
951 }
952 
953 #[repr(C)]
954 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
955 pub struct InterruptIn {
956     pub unique: u64,
957 }
958 
959 #[repr(C)]
960 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
961 pub struct BmapIn {
962     pub block: u64,
963     pub blocksize: u32,
964     pub padding: u32,
965 }
966 
967 #[repr(C)]
968 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
969 pub struct BmapOut {
970     pub block: u64,
971 }
972 
973 #[repr(C)]
974 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
975 pub struct IoctlIn {
976     pub fh: u64,
977     pub flags: u32,
978     pub cmd: u32,
979     pub arg: u64,
980     pub in_size: u32,
981     pub out_size: u32,
982 }
983 
984 /// Describes a region of memory in the address space of the process that made the ioctl syscall.
985 /// Similar to `libc::iovec` but uses `u64`s for the address and the length.
986 #[repr(C)]
987 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
988 pub struct IoctlIovec {
989     /// The start address of the memory region. This must be in the address space of the process
990     /// that made the ioctl syscall.
991     pub base: u64,
992 
993     /// The length of the memory region.
994     pub len: u64,
995 }
996 
997 #[repr(C)]
998 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
999 pub struct IoctlOut {
1000     pub result: i32,
1001     pub flags: u32,
1002     pub in_iovs: u32,
1003     pub out_iovs: u32,
1004 }
1005 
1006 #[repr(C)]
1007 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1008 pub struct PollIn {
1009     pub fh: u64,
1010     pub kh: u64,
1011     pub flags: u32,
1012     pub events: u32,
1013 }
1014 
1015 #[repr(C)]
1016 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1017 pub struct PollOut {
1018     pub revents: u32,
1019     pub padding: u32,
1020 }
1021 
1022 #[repr(C)]
1023 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1024 pub struct NotifyPollWakeupOut {
1025     pub kh: u64,
1026 }
1027 
1028 #[repr(C)]
1029 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1030 pub struct FallocateIn {
1031     pub fh: u64,
1032     pub offset: u64,
1033     pub length: u64,
1034     pub mode: u32,
1035     pub padding: u32,
1036 }
1037 
1038 #[repr(C)]
1039 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1040 pub struct InHeader {
1041     pub len: u32,
1042     pub opcode: u32,
1043     pub unique: u64,
1044     pub nodeid: u64,
1045     pub uid: u32,
1046     pub gid: u32,
1047     pub pid: u32,
1048     pub padding: u32,
1049 }
1050 
1051 #[repr(C)]
1052 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1053 pub struct OutHeader {
1054     pub len: u32,
1055     pub error: i32,
1056     pub unique: u64,
1057 }
1058 
1059 #[repr(C)]
1060 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1061 pub struct Dirent {
1062     pub ino: u64,
1063     pub off: u64,
1064     pub namelen: u32,
1065     pub type_: u32,
1066     // char name[];
1067 }
1068 
1069 #[repr(C)]
1070 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1071 pub struct Direntplus {
1072     pub entry_out: EntryOut,
1073     pub dirent: Dirent,
1074 }
1075 
1076 #[repr(C)]
1077 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1078 pub struct NotifyInvalInodeOut {
1079     pub ino: u64,
1080     pub off: i64,
1081     pub len: i64,
1082 }
1083 
1084 #[repr(C)]
1085 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1086 pub struct NotifyInvalEntryOut {
1087     pub parent: u64,
1088     pub namelen: u32,
1089     pub padding: u32,
1090 }
1091 
1092 #[repr(C)]
1093 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1094 pub struct NotifyDeleteOut {
1095     pub parent: u64,
1096     pub child: u64,
1097     pub namelen: u32,
1098     pub padding: u32,
1099 }
1100 
1101 #[repr(C)]
1102 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1103 pub struct NotifyStoreOut {
1104     pub nodeid: u64,
1105     pub offset: u64,
1106     pub size: u32,
1107     pub padding: u32,
1108 }
1109 
1110 #[repr(C)]
1111 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1112 pub struct Notify_Retrieve_Out {
1113     pub notify_unique: u64,
1114     pub nodeid: u64,
1115     pub offset: u64,
1116     pub size: u32,
1117     pub padding: u32,
1118 }
1119 
1120 /* Matches the size of fuse_write_in */
1121 #[repr(C)]
1122 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1123 pub struct NotifyRetrieveIn {
1124     pub dummy1: u64,
1125     pub offset: u64,
1126     pub size: u32,
1127     pub dummy2: u32,
1128     pub dummy3: u64,
1129     pub dummy4: u64,
1130 }
1131 
1132 #[repr(C)]
1133 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1134 pub struct LseekIn {
1135     pub fh: u64,
1136     pub offset: u64,
1137     pub whence: u32,
1138     pub padding: u32,
1139 }
1140 
1141 #[repr(C)]
1142 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1143 pub struct LseekOut {
1144     pub offset: u64,
1145 }
1146 
1147 #[repr(C)]
1148 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1149 pub struct CopyFileRangeIn {
1150     pub fh_src: u64,
1151     pub off_src: u64,
1152     pub nodeid_dst: u64,
1153     pub fh_dst: u64,
1154     pub off_dst: u64,
1155     pub len: u64,
1156     pub flags: u64,
1157 }
1158 
1159 #[repr(C)]
1160 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1161 pub struct SetUpMappingIn {
1162     /* An already open handle */
1163     pub fh: u64,
1164     /* Offset into the file to start the mapping */
1165     pub foffset: u64,
1166     /* Length of mapping required */
1167     pub len: u64,
1168     /* Flags, FUSE_SETUPMAPPING_FLAG_* */
1169     pub flags: u64,
1170     /* Offset in Memory Window */
1171     pub moffset: u64,
1172 }
1173 
1174 #[repr(C)]
1175 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1176 pub struct RemoveMappingIn {
1177     /* number of fuse_removemapping_one follows */
1178     pub count: u32,
1179 }
1180 
1181 #[repr(C)]
1182 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1183 pub struct RemoveMappingOne {
1184     /* Offset into the dax window start the unmapping */
1185     pub moffset: u64,
1186     /* Length of mapping required */
1187     pub len: u64,
1188 }
1189 
1190 /// For each security context, send fuse_secctx with size of security context
1191 /// fuse_secctx will be followed by security context name and this in turn
1192 /// will be followed by actual context label.
1193 /// fuse_secctx, name, context
1194 #[repr(C)]
1195 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1196 pub struct Secctx {
1197     pub size: u32,
1198     pub padding: u32,
1199 }
1200 
1201 /// Contains the information about how many fuse_secctx structures are being
1202 /// sent and what's the total size of all security contexts (including
1203 /// size of fuse_secctx_header).
1204 #[repr(C)]
1205 #[derive(Debug, Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)]
1206 pub struct SecctxHeader {
1207     pub size: u32,
1208     pub nr_secctx: u32,
1209 }
1210