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