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 //! Data structures and traits for the fuse filesystem. 6 7 #![deny(missing_docs)] 8 9 use std::convert::TryInto; 10 use std::ffi::CStr; 11 use std::fs::File; 12 use std::io; 13 use std::mem; 14 use std::mem::MaybeUninit; 15 use std::time::Duration; 16 17 use crate::server::Mapper; 18 use crate::sys; 19 pub use crate::sys::FsOptions; 20 pub use crate::sys::IoctlFlags; 21 pub use crate::sys::IoctlIovec; 22 pub use crate::sys::OpenOptions; 23 pub use crate::sys::RemoveMappingOne; 24 pub use crate::sys::SetattrValid; 25 pub use crate::sys::ROOT_ID; 26 27 const MAX_BUFFER_SIZE: u32 = 1 << 20; 28 29 /// Information about a path in the filesystem. 30 #[derive(Debug)] 31 pub struct Entry { 32 /// An `Inode` that uniquely identifies this path. During `lookup`, setting this to `0` means a 33 /// negative entry. Returning `ENOENT` also means a negative entry but setting this to `0` 34 /// allows the kernel to cache the negative result for `entry_timeout`. The value should be 35 /// produced by converting a `FileSystem::Inode` into a `u64`. 36 pub inode: u64, 37 38 /// The generation number for this `Entry`. Typically used for network file systems. An `inode` 39 /// / `generation` pair must be unique over the lifetime of the file system (rather than just 40 /// the lifetime of the mount). In other words, if a `FileSystem` implementation re-uses an 41 /// `Inode` after it has been deleted then it must assign a new, previously unused generation 42 /// number to the `Inode` at the same time. 43 pub generation: u64, 44 45 /// Inode attributes. Even if `attr_timeout` is zero, `attr` must be correct. For example, for 46 /// `open()`, FUSE uses `attr.st_size` from `lookup()` to determine how many bytes to request. 47 /// If this value is not correct, incorrect data will be returned. 48 pub attr: libc::stat64, 49 50 /// How long the values in `attr` should be considered valid. If the attributes of the `Entry` 51 /// are only modified by the FUSE client, then this should be set to a very large value. 52 pub attr_timeout: Duration, 53 54 /// How long the name associated with this `Entry` should be considered valid. If directory 55 /// entries are only changed or deleted by the FUSE client, then this should be set to a very 56 /// large value. 57 pub entry_timeout: Duration, 58 } 59 60 impl From<Entry> for sys::EntryOut { from(entry: Entry) -> sys::EntryOut61 fn from(entry: Entry) -> sys::EntryOut { 62 sys::EntryOut { 63 nodeid: entry.inode, 64 generation: entry.generation, 65 entry_valid: entry.entry_timeout.as_secs(), 66 attr_valid: entry.attr_timeout.as_secs(), 67 entry_valid_nsec: entry.entry_timeout.subsec_nanos(), 68 attr_valid_nsec: entry.attr_timeout.subsec_nanos(), 69 attr: entry.attr.into(), 70 } 71 } 72 } 73 74 impl Entry { 75 /// Creates a new negative cache entry. A negative d_entry has an inode number of 0, and is 76 /// valid for the duration of `negative_timeout`. 77 /// 78 /// # Arguments 79 /// 80 /// * `negative_timeout` - The duration for which this negative d_entry should be considered 81 /// valid. After the timeout expires, the d_entry will be invalidated. 82 /// 83 /// # Returns 84 /// 85 /// A new negative entry with provided entry timeout and 0 attr timeout. new_negative(negative_timeout: Duration) -> Entry86 pub fn new_negative(negative_timeout: Duration) -> Entry { 87 let attr = MaybeUninit::<libc::stat64>::zeroed(); 88 Entry { 89 inode: 0, // Using 0 for negative entry 90 entry_timeout: negative_timeout, 91 // Zero-fill other fields that won't be used. 92 attr_timeout: Duration::from_secs(0), 93 generation: 0, 94 // SAFETY: zero-initialized `stat64` is a valid value. 95 attr: unsafe { attr.assume_init() }, 96 } 97 } 98 } 99 100 /// Represents information about an entry in a directory. 101 pub struct DirEntry<'a> { 102 /// The inode number for this entry. This does NOT have to be the same as the `Inode` for this 103 /// directory entry. However, it must be the same as the `attr.st_ino` field of the `Entry` 104 /// that would be returned by a `lookup` request in the parent directory for `name`. 105 pub ino: libc::ino64_t, 106 107 /// Any non-zero value that the kernel can use to identify the current point in the directory 108 /// entry stream. It does not need to be the actual physical position. A value of `0` is 109 /// reserved to mean "from the beginning" and should never be used. The `offset` value of the 110 /// first entry in a stream should point to the beginning of the second entry and so on. 111 pub offset: u64, 112 113 /// The type of this directory entry. Valid values are any of the `libc::DT_*` constants. 114 pub type_: u32, 115 116 /// The name of this directory entry. There are no requirements for the contents of this field 117 /// and any sequence of bytes is considered valid. 118 pub name: &'a CStr, 119 } 120 121 /// A reply to a `getxattr` method call. 122 #[derive(Debug)] 123 pub enum GetxattrReply { 124 /// The value of the requested extended attribute. This can be arbitrary textual or binary data 125 /// and does not need to be nul-terminated. 126 Value(Vec<u8>), 127 128 /// The size of the buffer needed to hold the value of the requested extended attribute. Should 129 /// be returned when the `size` parameter is 0. Callers should note that it is still possible 130 /// for the size of the value to change in between `getxattr` calls and should not assume that 131 /// a subsequent call to `getxattr` with the returned count will always succeed. 132 Count(u32), 133 } 134 135 /// A reply to a `listxattr` method call. 136 pub enum ListxattrReply { 137 /// A buffer containing a nul-separated list of the names of all the extended attributes 138 /// associated with this `Inode`. This list of names may be unordered and includes a namespace 139 /// prefix. There may be several disjoint namespaces associated with a single `Inode`. 140 Names(Vec<u8>), 141 142 /// This size of the buffer needed to hold the full list of extended attribute names associated 143 /// with this `Inode`. Should be returned when the `size` parameter is 0. Callers should note 144 /// that it is still possible for the set of extended attributes to change between `listxattr` 145 /// calls and so should not assume that a subsequent call to `listxattr` with the returned 146 /// count will always succeed. 147 Count(u32), 148 } 149 150 /// A reply to an `ioctl` method call. 151 #[derive(Debug)] 152 pub enum IoctlReply { 153 /// Indicates that the ioctl should be retried. This is only a valid reply when the `flags` 154 /// field of the ioctl request contains `IoctlFlags::UNRESTRICTED`. The kernel will read in 155 /// data and prepare output buffers as specified in the `input` and `output` fields before 156 /// re-sending the ioctl message. 157 Retry { 158 /// Data that should be read by the kernel module and sent to the server when the ioctl is 159 /// retried. 160 input: Vec<IoctlIovec>, 161 162 /// Buffer space that should be prepared so that the server can send back the response to 163 /// the ioctl. 164 output: Vec<IoctlIovec>, 165 }, 166 167 /// Indicates that the ioctl was processed. 168 Done(io::Result<Vec<u8>>), 169 } 170 171 /// A trait for directly copying data from the fuse transport into a `File` without first storing it 172 /// in an intermediate buffer. 173 pub trait ZeroCopyReader { 174 /// Copies at most `count` bytes from `self` directly into `f` at offset `off` without storing 175 /// it in any intermediate buffers. If the return value is `Ok(n)` then it must be guaranteed 176 /// that `0 <= n <= count`. If `n` is `0`, then it can indicate one of 3 possibilities: 177 /// 178 /// 1. There is no more data left in `self`. 179 /// 2. There is no more space in `f`. 180 /// 3. `count` was `0`. 181 /// 182 /// # Errors 183 /// 184 /// If any error is returned then the implementation must guarantee that no bytes were copied 185 /// from `self`. If the underlying write to `f` returns `0` then the implementation must return 186 /// an error of the kind `io::ErrorKind::WriteZero`. read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>187 fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>; 188 189 /// Copies exactly `count` bytes of data from `self` into `f` at offset `off`. `off + count` 190 /// must be less than `u64::MAX`. 191 /// 192 /// # Errors 193 /// 194 /// If an error is returned then the number of bytes copied from `self` is unspecified but it 195 /// will never be more than `count`. read_exact_to(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()>196 fn read_exact_to(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()> { 197 let c = count 198 .try_into() 199 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; 200 if off.checked_add(c).is_none() { 201 return Err(io::Error::new( 202 io::ErrorKind::InvalidInput, 203 "`off` + `count` must be less than u64::MAX", 204 )); 205 } 206 207 while count > 0 { 208 match self.read_to(f, count, off) { 209 Ok(0) => { 210 return Err(io::Error::new( 211 io::ErrorKind::WriteZero, 212 "failed to fill whole buffer", 213 )) 214 } 215 Ok(n) => { 216 count -= n; 217 off += n as u64; 218 } 219 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} 220 Err(e) => return Err(e), 221 } 222 } 223 224 Ok(()) 225 } 226 227 /// Copies all remaining bytes from `self` into `f` at offset `off`. Equivalent to repeatedly 228 /// calling `read_to` until it returns either `Ok(0)` or a non-`ErrorKind::Interrupted` error. 229 /// 230 /// # Errors 231 /// 232 /// If an error is returned then the number of bytes copied from `self` is unspecified. copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize>233 fn copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize> { 234 let mut out = 0; 235 loop { 236 match self.read_to(f, usize::MAX, off) { 237 Ok(0) => return Ok(out), 238 Ok(n) => { 239 off = off.saturating_add(n as u64); 240 out += n; 241 } 242 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} 243 Err(e) => return Err(e), 244 } 245 } 246 } 247 } 248 249 impl<'a, R: ZeroCopyReader> ZeroCopyReader for &'a mut R { read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>250 fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> { 251 (**self).read_to(f, count, off) 252 } read_exact_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()>253 fn read_exact_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()> { 254 (**self).read_exact_to(f, count, off) 255 } copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize>256 fn copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize> { 257 (**self).copy_to_end(f, off) 258 } 259 } 260 261 /// A trait for directly copying data from a `File` into the fuse transport without first storing 262 /// it in an intermediate buffer. 263 pub trait ZeroCopyWriter { 264 /// Copies at most `count` bytes from `f` at offset `off` directly into `self` without storing 265 /// it in any intermediate buffers. If the return value is `Ok(n)` then it must be guaranteed 266 /// that `0 <= n <= count`. If `n` is `0`, then it can indicate one of 3 possibilities: 267 /// 268 /// 1. There is no more data left in `f`. 269 /// 2. There is no more space in `self`. 270 /// 3. `count` was `0`. 271 /// 272 /// # Errors 273 /// 274 /// If any error is returned then the implementation must guarantee that no bytes were copied 275 /// from `f`. If the underlying read from `f` returns `0` then the implementation must return an 276 /// error of the kind `io::ErrorKind::UnexpectedEof`. write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>277 fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>; 278 279 /// Copies exactly `count` bytes of data from `f` at offset `off` into `self`. `off + count` 280 /// must be less than `u64::MAX`. 281 /// 282 /// # Errors 283 /// 284 /// If an error is returned then the number of bytes copied from `self` is unspecified but it 285 /// well never be more than `count`. write_all_from(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()>286 fn write_all_from(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()> { 287 let c = count 288 .try_into() 289 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; 290 if off.checked_add(c).is_none() { 291 return Err(io::Error::new( 292 io::ErrorKind::InvalidInput, 293 "`off` + `count` must be less than u64::MAX", 294 )); 295 } 296 297 while count > 0 { 298 match self.write_from(f, count, off) { 299 Ok(0) => { 300 return Err(io::Error::new( 301 io::ErrorKind::UnexpectedEof, 302 "failed to write whole buffer", 303 )) 304 } 305 Ok(n) => { 306 // No need for checked math here because we verified that `off + count` will not 307 // overflow and `n` must be <= `count`. 308 count -= n; 309 off += n as u64; 310 } 311 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} 312 Err(e) => return Err(e), 313 } 314 } 315 316 Ok(()) 317 } 318 319 /// Copies all remaining bytes from `f` at offset `off` into `self`. Equivalent to repeatedly 320 /// calling `write_from` until it returns either `Ok(0)` or a non-`ErrorKind::Interrupted` 321 /// error. 322 /// 323 /// # Errors 324 /// 325 /// If an error is returned then the number of bytes copied from `f` is unspecified. copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize>326 fn copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize> { 327 let mut out = 0; 328 loop { 329 match self.write_from(f, usize::MAX, off) { 330 Ok(0) => return Ok(out), 331 Ok(n) => { 332 off = off.saturating_add(n as u64); 333 out += n; 334 } 335 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} 336 Err(e) => return Err(e), 337 } 338 } 339 } 340 } 341 342 impl<'a, W: ZeroCopyWriter> ZeroCopyWriter for &'a mut W { write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>343 fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> { 344 (**self).write_from(f, count, off) 345 } write_all_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()>346 fn write_all_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()> { 347 (**self).write_all_from(f, count, off) 348 } copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize>349 fn copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize> { 350 (**self).copy_to_end(f, off) 351 } 352 } 353 354 /// Additional context associated with requests. 355 #[derive(Clone, Copy, Debug)] 356 pub struct Context { 357 /// The user ID of the calling process. 358 pub uid: libc::uid_t, 359 360 /// The group ID of the calling process. 361 pub gid: libc::gid_t, 362 363 /// The thread group ID of the calling process. 364 pub pid: libc::pid_t, 365 } 366 367 impl From<sys::InHeader> for Context { from(source: sys::InHeader) -> Self368 fn from(source: sys::InHeader) -> Self { 369 Context { 370 uid: source.uid, 371 gid: source.gid, 372 pid: source.pid as i32, 373 } 374 } 375 } 376 377 /// A trait for iterating over the contents of a directory. This trait is needed because rust 378 /// doesn't support generic associated types, which means that it's not possible to implement a 379 /// regular iterator that yields a `DirEntry` due to its generic lifetime parameter. 380 pub trait DirectoryIterator { 381 /// Returns the next entry in the directory or `None` if there are no more. next(&mut self) -> Option<DirEntry>382 fn next(&mut self) -> Option<DirEntry>; 383 } 384 385 /// The main trait that connects a file system with a transport. 386 #[allow(unused_variables)] 387 pub trait FileSystem { 388 /// Represents a location in the filesystem tree and can be used to perform operations that act 389 /// on the metadata of a file/directory (e.g., `getattr` and `setattr`). Can also be used as the 390 /// starting point for looking up paths in the filesystem tree. An `Inode` may support operating 391 /// directly on the content of the path that to which it points. `FileSystem` implementations 392 /// that support this should set the `FsOptions::ZERO_MESSAGE_OPEN` option in the return value 393 /// of the `init` function. On linux based systems, an `Inode` is equivalent to opening a file 394 /// or directory with the `libc::O_PATH` flag. 395 /// 396 /// # Lookup Count 397 /// 398 /// The `FileSystem` implementation is required to keep a "lookup count" for every `Inode`. 399 /// Every time an `Entry` is returned by a `FileSystem` trait method, this lookup count should 400 /// increase by 1. The lookup count for an `Inode` decreases when the kernel sends a `forget` 401 /// request. `Inode`s with a non-zero lookup count may receive requests from the kernel even 402 /// after calls to `unlink`, `rmdir` or (when overwriting an existing file) `rename`. 403 /// `FileSystem` implementations must handle such requests properly and it is recommended to 404 /// defer removal of the `Inode` until the lookup count reaches zero. Calls to `unlink`, `rmdir` 405 /// or `rename` will be followed closely by `forget` unless the file or directory is open, in 406 /// which case the kernel issues `forget` only after the `release` or `releasedir` calls. 407 /// 408 /// Note that if a file system will be exported over NFS the `Inode`'s lifetime must extend even 409 /// beyond `forget`. See the `generation` field in `Entry`. 410 type Inode: From<u64> + Into<u64>; 411 412 /// Represents a file or directory that is open for reading/writing. 413 type Handle: From<u64> + Into<u64>; 414 415 /// An iterator over the entries of a directory. See the documentation for `readdir` for more 416 /// details. 417 type DirIter: DirectoryIterator; 418 419 /// Maximum size of the buffer that the filesystem can generate data to, including the header. 420 /// This corresponds to max_write in the initialization. max_buffer_size(&self) -> u32421 fn max_buffer_size(&self) -> u32 { 422 MAX_BUFFER_SIZE 423 } 424 425 /// Initialize the file system. 426 /// 427 /// This method is called when a connection to the FUSE kernel module is first established. The 428 /// `capable` parameter indicates the features that are supported by the kernel module. The 429 /// implementation should return the options that it supports. Any options set in the returned 430 /// `FsOptions` that are not also set in `capable` are silently dropped. init(&self, capable: FsOptions) -> io::Result<FsOptions>431 fn init(&self, capable: FsOptions) -> io::Result<FsOptions> { 432 Ok(FsOptions::empty()) 433 } 434 435 /// Clean up the file system. 436 /// 437 /// Called when the filesystem exits. All open `Handle`s should be closed and the lookup count 438 /// for all open `Inode`s implicitly goes to zero. At this point the connection to the FUSE 439 /// kernel module may already be gone so implementations should not rely on being able to 440 /// communicate with the kernel. destroy(&self)441 fn destroy(&self) {} 442 443 /// Look up a directory entry by name and get its attributes. 444 /// 445 /// If this call is successful then the lookup count of the `Inode` associated with the returned 446 /// `Entry` must be increased by 1. lookup(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry>447 fn lookup(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> { 448 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 449 } 450 451 /// Forget about an inode. 452 /// 453 /// Called when the kernel removes an inode from its internal caches. `count` indicates the 454 /// amount by which the lookup count for the inode should be decreased. If reducing the lookup 455 /// count by `count` causes it to go to zero, then the implementation may delete the `Inode`. forget(&self, ctx: Context, inode: Self::Inode, count: u64)456 fn forget(&self, ctx: Context, inode: Self::Inode, count: u64) {} 457 458 /// Forget about multiple inodes. 459 /// 460 /// `requests` is a vector of `(inode, count)` pairs. See the documentation for `forget` for 461 /// more information. batch_forget(&self, ctx: Context, requests: Vec<(Self::Inode, u64)>)462 fn batch_forget(&self, ctx: Context, requests: Vec<(Self::Inode, u64)>) { 463 for (inode, count) in requests { 464 self.forget(ctx, inode, count) 465 } 466 } 467 468 /// Get attributes for a file / directory. 469 /// 470 /// If `handle` is not `None`, then it contains the handle previously returned by the 471 /// implementation after a call to `open` or `opendir`. However, implementations should still 472 /// take care to verify the handle if they do not trust the client (e.g., virtio-fs). 473 /// 474 /// If writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`), then the kernel module 475 /// likely has a better idea of the length of the file than the file system (for 476 /// example, if there was a write that extended the size of the file but has not yet been 477 /// flushed). In this case, the `st_size` field of the returned struct is ignored. 478 /// 479 /// The returned `Duration` indicates how long the returned attributes should be considered 480 /// valid by the client. If the attributes are only changed via the FUSE kernel module (i.e., 481 /// the kernel module has exclusive access), then this should be a very large value. getattr( &self, ctx: Context, inode: Self::Inode, handle: Option<Self::Handle>, ) -> io::Result<(libc::stat64, Duration)>482 fn getattr( 483 &self, 484 ctx: Context, 485 inode: Self::Inode, 486 handle: Option<Self::Handle>, 487 ) -> io::Result<(libc::stat64, Duration)> { 488 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 489 } 490 491 /// Set attributes for a file / directory. 492 /// 493 /// If `handle` is not `None`, then it contains the handle previously returned by the 494 /// implementation after a call to `open` or `opendir`. However, implementations should still 495 /// take care to verify the handle if they do not trust the client (e.g., virtio-fs). 496 /// 497 /// The `valid` parameter indicates the fields of `attr` that may be considered valid and should 498 /// be set by the file system. The content of all other fields in `attr` is undefined. 499 /// 500 /// If the `FsOptions::HANDLE_KILLPRIV` was set during `init`, then the implementation is 501 /// expected to reset the setuid and setgid bits if the file size or owner is being changed. 502 /// 503 /// This method returns the new attributes after making the modifications requested by the 504 /// client. The returned `Duration` indicates how long the returned attributes should be 505 /// considered valid by the client. If the attributes are only changed via the FUSE kernel 506 /// module (i.e., the kernel module has exclusive access), then this should be a very large 507 /// value. setattr( &self, ctx: Context, inode: Self::Inode, attr: libc::stat64, handle: Option<Self::Handle>, valid: SetattrValid, ) -> io::Result<(libc::stat64, Duration)>508 fn setattr( 509 &self, 510 ctx: Context, 511 inode: Self::Inode, 512 attr: libc::stat64, 513 handle: Option<Self::Handle>, 514 valid: SetattrValid, 515 ) -> io::Result<(libc::stat64, Duration)> { 516 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 517 } 518 519 /// Read a symbolic link. readlink(&self, ctx: Context, inode: Self::Inode) -> io::Result<Vec<u8>>520 fn readlink(&self, ctx: Context, inode: Self::Inode) -> io::Result<Vec<u8>> { 521 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 522 } 523 524 /// Create a symbolic link. 525 /// 526 /// The file system must create a symbolic link named `name` in the directory represented by 527 /// `parent`, which contains the string `linkname`. Returns an `Entry` for the newly created 528 /// symlink. 529 /// 530 /// If this call is successful then the lookup count of the `Inode` associated with the returned 531 /// `Entry` must be increased by 1. symlink( &self, ctx: Context, linkname: &CStr, parent: Self::Inode, name: &CStr, security_ctx: Option<&CStr>, ) -> io::Result<Entry>532 fn symlink( 533 &self, 534 ctx: Context, 535 linkname: &CStr, 536 parent: Self::Inode, 537 name: &CStr, 538 security_ctx: Option<&CStr>, 539 ) -> io::Result<Entry> { 540 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 541 } 542 543 /// Create a file node. 544 /// 545 /// Create a regular file, character device, block device, fifo, or socket node named `name` in 546 /// the directory represented by `inode`. Valid values for `mode` and `rdev` are the same as 547 /// those accepted by the `mknod(2)` system call. Returns an `Entry` for the newly created node. 548 /// 549 /// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting 550 /// the permissions of the created node to `mode & !umask`. 551 /// 552 /// If this call is successful then the lookup count of the `Inode` associated with the returned 553 /// `Entry` must be increased by 1. mknod( &self, ctx: Context, inode: Self::Inode, name: &CStr, mode: u32, rdev: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>554 fn mknod( 555 &self, 556 ctx: Context, 557 inode: Self::Inode, 558 name: &CStr, 559 mode: u32, 560 rdev: u32, 561 umask: u32, 562 security_ctx: Option<&CStr>, 563 ) -> io::Result<Entry> { 564 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 565 } 566 567 /// Create a directory. 568 /// 569 /// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting 570 /// the permissions of the created directory to `mode & !umask`. Returns an `Entry` for the 571 /// newly created directory. 572 /// 573 /// If this call is successful then the lookup count of the `Inode` associated with the returned 574 /// `Entry` must be increased by 1. mkdir( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>575 fn mkdir( 576 &self, 577 ctx: Context, 578 parent: Self::Inode, 579 name: &CStr, 580 mode: u32, 581 umask: u32, 582 security_ctx: Option<&CStr>, 583 ) -> io::Result<Entry> { 584 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 585 } 586 587 /// Create an unnamed temporary file. chromeos_tmpfile( &self, ctx: Context, parent: Self::Inode, mode: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>588 fn chromeos_tmpfile( 589 &self, 590 ctx: Context, 591 parent: Self::Inode, 592 mode: u32, 593 umask: u32, 594 security_ctx: Option<&CStr>, 595 ) -> io::Result<Entry> { 596 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 597 } 598 599 /// Remove a file. 600 /// 601 /// If the file's inode lookup count is non-zero, then the file system is expected to delay 602 /// removal of the inode until the lookup count goes to zero. See the documentation of the 603 /// `forget` function for more information. unlink(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()>604 fn unlink(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()> { 605 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 606 } 607 608 /// Remove a directory. 609 /// 610 /// If the directory's inode lookup count is non-zero, then the file system is expected to delay 611 /// removal of the inode until the lookup count goes to zero. See the documentation of the 612 /// `forget` function for more information. rmdir(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()>613 fn rmdir(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()> { 614 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 615 } 616 617 /// Rename a file / directory. 618 /// 619 /// If the destination exists, it should be atomically replaced. If the destination's inode 620 /// lookup count is non-zero, then the file system is expected to delay removal of the inode 621 /// until the lookup count goes to zero. See the documentation of the `forget` function for more 622 /// information. 623 /// 624 /// `flags` may be `libc::RENAME_EXCHANGE` or `libc::RENAME_NOREPLACE`. If 625 /// `libc::RENAME_NOREPLACE` is specified, the implementation must not overwrite `newname` if it 626 /// exists and must return an error instead. If `libc::RENAME_EXCHANGE` is specified, the 627 /// implementation must atomically exchange the two files, i.e., both must exist and neither may 628 /// be deleted. rename( &self, ctx: Context, olddir: Self::Inode, oldname: &CStr, newdir: Self::Inode, newname: &CStr, flags: u32, ) -> io::Result<()>629 fn rename( 630 &self, 631 ctx: Context, 632 olddir: Self::Inode, 633 oldname: &CStr, 634 newdir: Self::Inode, 635 newname: &CStr, 636 flags: u32, 637 ) -> io::Result<()> { 638 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 639 } 640 641 /// Create a hard link. 642 /// 643 /// Create a hard link from `inode` to `newname` in the directory represented by `newparent`. 644 /// 645 /// If this call is successful then the lookup count of the `Inode` associated with the returned 646 /// `Entry` must be increased by 1. link( &self, ctx: Context, inode: Self::Inode, newparent: Self::Inode, newname: &CStr, ) -> io::Result<Entry>647 fn link( 648 &self, 649 ctx: Context, 650 inode: Self::Inode, 651 newparent: Self::Inode, 652 newname: &CStr, 653 ) -> io::Result<Entry> { 654 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 655 } 656 657 /// Open a file. 658 /// 659 /// Open the file associated with `inode` for reading / writing. All values accepted by the 660 /// `open(2)` system call are valid values for `flags` and must be handled by the file system. 661 /// However, there are some additional rules: 662 /// 663 /// * Creation flags (`libc::O_CREAT`, `libc::O_EXCL`, `libc::O_NOCTTY`) will be filtered out 664 /// and handled by the kernel. 665 /// 666 /// * The file system should check the access modes (`libc::O_RDONLY`, `libc::O_WRONLY`, 667 /// `libc::O_RDWR`) to determine if the operation is permitted. If the file system was mounted 668 /// with the `-o default_permissions` mount option, then this check will also be carried out 669 /// by the kernel before sending the open request. 670 /// 671 /// * When writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`) the kernel may send read 672 /// requests even for files opened with `libc::O_WRONLY`. The file system should be prepared 673 /// to handle this. 674 /// 675 /// * When writeback caching is enabled, the kernel will handle the `libc::O_APPEND` flag. 676 /// However, this will not work reliably unless the kernel has exclusive access to the file. 677 /// In this case the file system may either ignore the `libc::O_APPEND` flag or return an 678 /// error to indicate that reliable `libc::O_APPEND` handling is not available. 679 /// 680 /// * When writeback caching is disabled, the file system is expected to properly handle 681 /// `libc::O_APPEND` and ensure that each write is appended to the end of the file. 682 /// 683 /// The file system may choose to return a `Handle` to refer to the newly opened file. The 684 /// kernel will then use this `Handle` for all operations on the content of the file (`read`, 685 /// `write`, `flush`, `release`, `fsync`). If the file system does not return a 686 /// `Handle` then the kernel will use the `Inode` for the file to operate on its contents. In 687 /// this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPEN` feature if 688 /// it is supported by the kernel (see below). 689 /// 690 /// The returned `OpenOptions` allow the file system to change the way the opened file is 691 /// handled by the kernel. See the documentation of `OpenOptions` for more information. 692 /// 693 /// If the `FsOptions::ZERO_MESSAGE_OPEN` feature is enabled by both the file system 694 /// implementation and the kernel, then the file system may return an error of `ENOSYS`. This 695 /// will be interpreted by the kernel as success and future calls to `open` and `release` will 696 /// be handled by the kernel without being passed on to the file system. open( &self, ctx: Context, inode: Self::Inode, flags: u32, ) -> io::Result<(Option<Self::Handle>, OpenOptions)>697 fn open( 698 &self, 699 ctx: Context, 700 inode: Self::Inode, 701 flags: u32, 702 ) -> io::Result<(Option<Self::Handle>, OpenOptions)> { 703 // Matches the behavior of libfuse. 704 Ok((None, OpenOptions::empty())) 705 } 706 707 /// Create and open a file. 708 /// 709 /// If the file does not already exist, the file system should create it with the specified 710 /// `mode`. When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for 711 /// setting the permissions of the created file to `mode & !umask`. 712 /// 713 /// If the file system returns an `ENOSYS` error, then the kernel will treat this method as 714 /// unimplemented and all future calls to `create` will be handled by calling the `mknod` and 715 /// `open` methods instead. 716 /// 717 /// See the documentation for the `open` method for more information about opening the file. In 718 /// addition to the optional `Handle` and the `OpenOptions`, the file system must also return an 719 /// `Entry` for the file. This increases the lookup count for the `Inode` associated with the 720 /// file by 1. create( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)>721 fn create( 722 &self, 723 ctx: Context, 724 parent: Self::Inode, 725 name: &CStr, 726 mode: u32, 727 flags: u32, 728 umask: u32, 729 security_ctx: Option<&CStr>, 730 ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> { 731 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 732 } 733 734 /// Read data from a file. 735 /// 736 /// Returns `size` bytes of data starting from offset `off` from the file associated with 737 /// `inode` or `handle`. 738 /// 739 /// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle` 740 /// returned by the file system from the `open` method, if any. If the file system 741 /// implementation did not return a `Handle` from `open` then the contents of `handle` are 742 /// undefined. 743 /// 744 /// This method should return exactly the number of bytes requested by the kernel, except in the 745 /// case of error or EOF. Otherwise, the kernel will substitute the rest of the data with 746 /// zeroes. An exception to this rule is if the file was opened with the "direct I/O" option 747 /// (`libc::O_DIRECT`), in which case the kernel will forward the return code from this method 748 /// to the userspace application that made the system call. read<W: io::Write + ZeroCopyWriter>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, w: W, size: u32, offset: u64, lock_owner: Option<u64>, flags: u32, ) -> io::Result<usize>749 fn read<W: io::Write + ZeroCopyWriter>( 750 &self, 751 ctx: Context, 752 inode: Self::Inode, 753 handle: Self::Handle, 754 w: W, 755 size: u32, 756 offset: u64, 757 lock_owner: Option<u64>, 758 flags: u32, 759 ) -> io::Result<usize> { 760 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 761 } 762 763 /// Write data to a file. 764 /// 765 /// Writes `size` bytes of data starting from offset `off` to the file associated with `inode` 766 /// or `handle`. 767 /// 768 /// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle` 769 /// returned by the file system from the `open` method, if any. If the file system 770 /// implementation did not return a `Handle` from `open` then the contents of `handle` are 771 /// undefined. 772 /// 773 /// If the `FsOptions::HANDLE_KILLPRIV` feature is not enabled then then the file system is 774 /// expected to clear the setuid and setgid bits. 775 /// 776 /// If `delayed_write` is true then it indicates that this is a write for buffered data. 777 /// 778 /// This method should return exactly the number of bytes requested by the kernel, except in the 779 /// case of error. An exception to this rule is if the file was opened with the "direct I/O" 780 /// option (`libc::O_DIRECT`), in which case the kernel will forward the return code from this 781 /// method to the userspace application that made the system call. write<R: io::Read + ZeroCopyReader>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, r: R, size: u32, offset: u64, lock_owner: Option<u64>, delayed_write: bool, flags: u32, ) -> io::Result<usize>782 fn write<R: io::Read + ZeroCopyReader>( 783 &self, 784 ctx: Context, 785 inode: Self::Inode, 786 handle: Self::Handle, 787 r: R, 788 size: u32, 789 offset: u64, 790 lock_owner: Option<u64>, 791 delayed_write: bool, 792 flags: u32, 793 ) -> io::Result<usize> { 794 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 795 } 796 797 /// Flush the contents of a file. 798 /// 799 /// This method is called on every `close()` of a file descriptor. Since it is possible to 800 /// duplicate file descriptors there may be many `flush` calls for one call to `open`. 801 /// 802 /// File systems should not make any assumptions about when `flush` will be 803 /// called or even if it will be called at all. 804 /// 805 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the 806 /// file system did not return a `Handle` from `open` then the contents of `handle` are 807 /// undefined. 808 /// 809 /// Unlike `fsync`, the file system is not required to flush pending writes. One reason to flush 810 /// data is if the file system wants to return write errors during close. However, this is not 811 /// portable because POSIX does not require `close` to wait for delayed I/O to complete. 812 /// 813 /// If the `FsOptions::POSIX_LOCKS` feature is enabled, then the file system must remove all 814 /// locks belonging to `lock_owner`. 815 /// 816 /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all 817 /// subsequent calls to `flush` will be handled by the kernel without being forwarded to the 818 /// file system. flush( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, lock_owner: u64, ) -> io::Result<()>819 fn flush( 820 &self, 821 ctx: Context, 822 inode: Self::Inode, 823 handle: Self::Handle, 824 lock_owner: u64, 825 ) -> io::Result<()> { 826 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 827 } 828 829 /// Synchronize file contents. 830 /// 831 /// File systems must ensure that the file contents have been flushed to disk before returning 832 /// from this method. If `datasync` is true then only the file data (but not the metadata) needs 833 /// to be flushed. 834 /// 835 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the 836 /// file system did not return a `Handle` from `open` then the contents of 837 /// `handle` are undefined. 838 /// 839 /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all 840 /// subsequent calls to `fsync` will be handled by the kernel without being forwarded to the 841 /// file system. fsync( &self, ctx: Context, inode: Self::Inode, datasync: bool, handle: Self::Handle, ) -> io::Result<()>842 fn fsync( 843 &self, 844 ctx: Context, 845 inode: Self::Inode, 846 datasync: bool, 847 handle: Self::Handle, 848 ) -> io::Result<()> { 849 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 850 } 851 852 /// Allocate requested space for file data. 853 /// 854 /// If this function returns success, then the file sytem must guarantee that it is possible to 855 /// write up to `length` bytes of data starting at `offset` without failing due to a lack of 856 /// free space on the disk. 857 /// 858 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the 859 /// file system did not return a `Handle` from `open` then the contents of `handle` are 860 /// undefined. 861 /// 862 /// If this method returns an `ENOSYS` error then the kernel will treat that as a permanent 863 /// failure: all future calls to `fallocate` will fail with `EOPNOTSUPP` without being forwarded 864 /// to the file system. fallocate( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, mode: u32, offset: u64, length: u64, ) -> io::Result<()>865 fn fallocate( 866 &self, 867 ctx: Context, 868 inode: Self::Inode, 869 handle: Self::Handle, 870 mode: u32, 871 offset: u64, 872 length: u64, 873 ) -> io::Result<()> { 874 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 875 } 876 877 /// Release an open file. 878 /// 879 /// This method is called when there are no more references to an open file: all file 880 /// descriptors are closed and all memory mappings are unmapped. 881 /// 882 /// For every `open` call there will be exactly one `release` call (unless the file system is 883 /// force-unmounted). 884 /// 885 /// The file system may reply with an error, but error values are not returned to the `close()` 886 /// or `munmap()` which triggered the release. 887 /// 888 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the 889 /// file system did not return a `Handle` from `open` then the contents of 890 /// `handle` are undefined. 891 /// 892 /// If `flush` is `true` then the contents of the file should also be flushed to disk. release( &self, ctx: Context, inode: Self::Inode, flags: u32, handle: Self::Handle, flush: bool, flock_release: bool, lock_owner: Option<u64>, ) -> io::Result<()>893 fn release( 894 &self, 895 ctx: Context, 896 inode: Self::Inode, 897 flags: u32, 898 handle: Self::Handle, 899 flush: bool, 900 flock_release: bool, 901 lock_owner: Option<u64>, 902 ) -> io::Result<()> { 903 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 904 } 905 906 /// Get information about the file system. statfs(&self, ctx: Context, inode: Self::Inode) -> io::Result<libc::statvfs64>907 fn statfs(&self, ctx: Context, inode: Self::Inode) -> io::Result<libc::statvfs64> { 908 // SAFETY: zero-initializing a struct with only POD fields. 909 let mut st: libc::statvfs64 = unsafe { mem::zeroed() }; 910 911 // This matches the behavior of libfuse as it returns these values if the 912 // filesystem doesn't implement this method. 913 st.f_namemax = 255; 914 st.f_bsize = 512; 915 916 Ok(st) 917 } 918 919 /// Set an extended attribute. 920 /// 921 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent 922 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `setxattr` without 923 /// forwarding them to the file system. 924 /// 925 /// Valid values for flags are the same as those accepted by the `setxattr(2)` system call and 926 /// have the same behavior. setxattr( &self, ctx: Context, inode: Self::Inode, name: &CStr, value: &[u8], flags: u32, ) -> io::Result<()>927 fn setxattr( 928 &self, 929 ctx: Context, 930 inode: Self::Inode, 931 name: &CStr, 932 value: &[u8], 933 flags: u32, 934 ) -> io::Result<()> { 935 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 936 } 937 938 /// Get an extended attribute. 939 /// 940 /// If `size` is 0, then the file system should respond with `GetxattrReply::Count` and the 941 /// number of bytes needed to hold the value. If `size` is large enough to hold the value, then 942 /// the file system should reply with `GetxattrReply::Value` and the value of the extended 943 /// attribute. If `size` is not 0 but is also not large enough to hold the value, then the file 944 /// system should reply with an `ERANGE` error. 945 /// 946 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent 947 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `getxattr` without 948 /// forwarding them to the file system. getxattr( &self, ctx: Context, inode: Self::Inode, name: &CStr, size: u32, ) -> io::Result<GetxattrReply>949 fn getxattr( 950 &self, 951 ctx: Context, 952 inode: Self::Inode, 953 name: &CStr, 954 size: u32, 955 ) -> io::Result<GetxattrReply> { 956 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 957 } 958 959 /// List extended attribute names. 960 /// 961 /// If `size` is 0, then the file system should respond with `ListxattrReply::Count` and the 962 /// number of bytes needed to hold a `\0` byte separated list of the names of all the extended 963 /// attributes. If `size` is large enough to hold the `\0` byte separated list of the attribute 964 /// names, then the file system should reply with `ListxattrReply::Names` and the list. If 965 /// `size` is not 0 but is also not large enough to hold the list, then the file system should 966 /// reply with an `ERANGE` error. 967 /// 968 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent 969 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `listxattr` without 970 /// forwarding them to the file system. listxattr(&self, ctx: Context, inode: Self::Inode, size: u32) -> io::Result<ListxattrReply>971 fn listxattr(&self, ctx: Context, inode: Self::Inode, size: u32) -> io::Result<ListxattrReply> { 972 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 973 } 974 975 /// Remove an extended attribute. 976 /// 977 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent 978 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `removexattr` without 979 /// forwarding them to the file system. removexattr(&self, ctx: Context, inode: Self::Inode, name: &CStr) -> io::Result<()>980 fn removexattr(&self, ctx: Context, inode: Self::Inode, name: &CStr) -> io::Result<()> { 981 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 982 } 983 984 /// Open a directory for reading. 985 /// 986 /// The file system may choose to return a `Handle` to refer to the newly opened directory. The 987 /// kernel will then use this `Handle` for all operations on the content of the directory 988 /// (`readdir`, `readdirplus`, `fsyncdir`, `releasedir`). If the file system does not return a 989 /// `Handle` then the kernel will use the `Inode` for the directory to operate on its contents. 990 /// In this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPENDIR` 991 /// feature if it is supported by the kernel (see below). 992 /// 993 /// The returned `OpenOptions` allow the file system to change the way the opened directory is 994 /// handled by the kernel. See the documentation of `OpenOptions` for more information. 995 /// 996 /// If the `FsOptions::ZERO_MESSAGE_OPENDIR` feature is enabled by both the file system 997 /// implementation and the kernel, then the file system may return an error of `ENOSYS`. This 998 /// will be interpreted by the kernel as success and future calls to `opendir` and `releasedir` 999 /// will be handled by the kernel without being passed on to the file system. opendir( &self, ctx: Context, inode: Self::Inode, flags: u32, ) -> io::Result<(Option<Self::Handle>, OpenOptions)>1000 fn opendir( 1001 &self, 1002 ctx: Context, 1003 inode: Self::Inode, 1004 flags: u32, 1005 ) -> io::Result<(Option<Self::Handle>, OpenOptions)> { 1006 // Matches the behavior of libfuse. 1007 Ok((None, OpenOptions::empty())) 1008 } 1009 1010 /// Read a directory. 1011 /// 1012 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If 1013 /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are 1014 /// undefined. 1015 /// 1016 /// `size` indicates the maximum number of bytes that should be returned by this method. 1017 /// 1018 /// If `offset` is non-zero then it corresponds to one of the `offset` values from a `DirEntry` 1019 /// that was previously returned by a call to `readdir` for the same handle. In this case the 1020 /// file system should skip over the entries before the position defined by the `offset` value. 1021 /// If entries were added or removed while the `Handle` is open then the file system may still 1022 /// include removed entries or skip newly created entries. However, adding or removing entries 1023 /// should never cause the file system to skip over unrelated entries or include an entry more 1024 /// than once. This means that `offset` cannot be a simple index and must include sufficient 1025 /// information to uniquely determine the next entry in the list even when the set of entries is 1026 /// being changed. 1027 /// 1028 /// The file system may return entries for the current directory (".") and parent directory 1029 /// ("..") but is not required to do so. If the file system does not return these entries, then 1030 /// they are implicitly added by the kernel. 1031 /// 1032 /// The lookup count for `Inode`s associated with the returned directory entries is **NOT** 1033 /// affected by this method. readdir( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, size: u32, offset: u64, ) -> io::Result<Self::DirIter>1034 fn readdir( 1035 &self, 1036 ctx: Context, 1037 inode: Self::Inode, 1038 handle: Self::Handle, 1039 size: u32, 1040 offset: u64, 1041 ) -> io::Result<Self::DirIter> { 1042 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1043 } 1044 1045 /// Synchronize the contents of a directory. 1046 /// 1047 /// File systems must ensure that the directory contents have been flushed to disk before 1048 /// returning from this method. If `datasync` is true then only the directory data (but not the 1049 /// metadata) needs to be flushed. 1050 /// 1051 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If 1052 /// the file system did not return a `Handle` from `opendir` then the contents of 1053 /// `handle` are undefined. 1054 /// 1055 /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all 1056 /// subsequent calls to `fsyncdir` will be handled by the kernel without being forwarded to the 1057 /// file system. fsyncdir( &self, ctx: Context, inode: Self::Inode, datasync: bool, handle: Self::Handle, ) -> io::Result<()>1058 fn fsyncdir( 1059 &self, 1060 ctx: Context, 1061 inode: Self::Inode, 1062 datasync: bool, 1063 handle: Self::Handle, 1064 ) -> io::Result<()> { 1065 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1066 } 1067 1068 /// Release an open directory. 1069 /// 1070 /// For every `opendir` call there will be exactly one `releasedir` call (unless the file system 1071 /// is force-unmounted). 1072 /// 1073 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If 1074 /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are 1075 /// undefined. 1076 /// 1077 /// `flags` contains used the flags used to open the directory in `opendir`. releasedir( &self, ctx: Context, inode: Self::Inode, flags: u32, handle: Self::Handle, ) -> io::Result<()>1078 fn releasedir( 1079 &self, 1080 ctx: Context, 1081 inode: Self::Inode, 1082 flags: u32, 1083 handle: Self::Handle, 1084 ) -> io::Result<()> { 1085 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1086 } 1087 1088 /// Check file access permissions. 1089 /// 1090 /// This method is called when a userspace process in the client makes an `access()` or 1091 /// `chdir()` system call. If the file system was mounted with the `-o default_permissions` 1092 /// mount option, then the kernel will perform these checks itself and this method will not be 1093 /// called. 1094 /// 1095 /// If this method returns an `ENOSYS` error, then the kernel will treat it as a permanent 1096 /// success: all future calls to `access` will return success without being forwarded to the 1097 /// file system. access(&self, ctx: Context, inode: Self::Inode, mask: u32) -> io::Result<()>1098 fn access(&self, ctx: Context, inode: Self::Inode, mask: u32) -> io::Result<()> { 1099 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1100 } 1101 1102 /// Perform an ioctl on a file or directory. 1103 /// 1104 /// `handle` is the `Handle` returned by the file system from the `open` or `opendir` methods, 1105 /// if any. If the file system did not return a `Handle` from then the contents of `handle` are 1106 /// undefined. 1107 /// 1108 /// If `flags` contains `IoctlFlags::UNRESTRICTED` then the file system may retry the ioctl 1109 /// after informing the kernel about the input and output areas. If `flags` does not contain 1110 /// `IoctlFlags::UNRESTRICTED` then the kernel will prepare the input and output areas according 1111 /// to the encoding in the ioctl command. In that case the ioctl cannot be retried. 1112 /// 1113 /// `cmd` is the ioctl request made by the calling process, truncated to 32 bits. 1114 /// 1115 /// `arg` is the argument provided by the calling process. 1116 /// 1117 /// `in_size` is the length of the additional data that accompanies the request. The file system 1118 /// may fetch this data from `reader`. 1119 /// 1120 /// `out_size` is the length of the output area prepared by the kernel to hold the response to 1121 /// the ioctl. ioctl<R: io::Read>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, flags: IoctlFlags, cmd: u32, arg: u64, in_size: u32, out_size: u32, reader: R, ) -> io::Result<IoctlReply>1122 fn ioctl<R: io::Read>( 1123 &self, 1124 ctx: Context, 1125 inode: Self::Inode, 1126 handle: Self::Handle, 1127 flags: IoctlFlags, 1128 cmd: u32, 1129 arg: u64, 1130 in_size: u32, 1131 out_size: u32, 1132 reader: R, 1133 ) -> io::Result<IoctlReply> { 1134 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1135 } 1136 1137 /// TODO: support this getlk(&self) -> io::Result<()>1138 fn getlk(&self) -> io::Result<()> { 1139 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1140 } 1141 1142 /// TODO: support this setlk(&self) -> io::Result<()>1143 fn setlk(&self) -> io::Result<()> { 1144 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1145 } 1146 1147 /// TODO: support this setlkw(&self) -> io::Result<()>1148 fn setlkw(&self) -> io::Result<()> { 1149 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1150 } 1151 1152 /// TODO: support this bmap(&self) -> io::Result<()>1153 fn bmap(&self) -> io::Result<()> { 1154 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1155 } 1156 1157 /// TODO: support this poll(&self) -> io::Result<()>1158 fn poll(&self) -> io::Result<()> { 1159 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1160 } 1161 1162 /// TODO: support this notify_reply(&self) -> io::Result<()>1163 fn notify_reply(&self) -> io::Result<()> { 1164 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1165 } 1166 1167 /// TODO: support this lseek(&self) -> io::Result<()>1168 fn lseek(&self) -> io::Result<()> { 1169 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1170 } 1171 1172 /// Copy a range of data from one file to another 1173 /// 1174 /// Performs an optimized copy between two file descriptors without the additional cost of 1175 /// transferring data through the kernel module to user space (glibc) and then back into 1176 /// the file system again. 1177 /// 1178 /// In case this method is not implemented, glibc falls back to reading data from the source and 1179 /// writing to the destination. 1180 /// 1181 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent 1182 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `copy_file_range` 1183 /// without forwarding them to the file system. 1184 /// 1185 /// All values accepted by the `copy_file_range(2)` system call are valid values for `flags` and 1186 /// must be handled by the file system. copy_file_range( &self, ctx: Context, inode_src: Self::Inode, handle_src: Self::Handle, offset_src: u64, inode_dst: Self::Inode, handle_dst: Self::Handle, offset_dst: u64, length: u64, flags: u64, ) -> io::Result<usize>1187 fn copy_file_range( 1188 &self, 1189 ctx: Context, 1190 inode_src: Self::Inode, 1191 handle_src: Self::Handle, 1192 offset_src: u64, 1193 inode_dst: Self::Inode, 1194 handle_dst: Self::Handle, 1195 offset_dst: u64, 1196 length: u64, 1197 flags: u64, 1198 ) -> io::Result<usize> { 1199 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1200 } 1201 1202 /// Set up memory mappings. 1203 /// 1204 /// Used to set up file mappings in DAX window. 1205 /// 1206 /// # Arguments 1207 /// 1208 /// * `file_offset` - Offset into the file to start the mapping. 1209 /// * `mem_offset` - Offset in Memory Window. 1210 /// * `size` - Length of mapping required. 1211 /// * `flags` - Bit field of `FUSE_SETUPMAPPING_FLAGS_*`. 1212 /// * `mapper` - Mapper object which performs the mapping. set_up_mapping<M: Mapper>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, file_offset: u64, mem_offset: u64, size: usize, flags: u32, mapper: M, ) -> io::Result<()>1213 fn set_up_mapping<M: Mapper>( 1214 &self, 1215 ctx: Context, 1216 inode: Self::Inode, 1217 handle: Self::Handle, 1218 file_offset: u64, 1219 mem_offset: u64, 1220 size: usize, 1221 flags: u32, 1222 mapper: M, 1223 ) -> io::Result<()> { 1224 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1225 } 1226 1227 /// Remove memory mappings. 1228 /// 1229 /// Used to tear down file mappings in DAX window. This method must be supported when 1230 /// `set_up_mapping` is supported. remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()>1231 fn remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()> { 1232 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1233 } 1234 1235 /// Lookup and open/create the file 1236 /// 1237 /// In this call, program first do a lookup on the file. Then depending upon 1238 /// flags combination, either do create + open, open only or return error. 1239 /// In all successful cases, it will return the dentry. For return value's 1240 /// handle and open options atomic_open should apply same rules to handle 1241 /// flags and configuration in open/create system call. 1242 /// 1243 /// This function is called when the client supports FUSE_OPEN_ATOMIC. 1244 /// Implementing atomic_open is optional. When the it's not implemented, 1245 /// the client fall back to send lookup and open requests separately. 1246 /// 1247 /// # Specification 1248 /// 1249 /// If file was indeed newly created (as a result of O_CREAT), then set 1250 /// `FOPEN_FILE_CREATED` bit in `struct OpenOptions open`. This bit is used by 1251 /// crosvm to inform the fuse client to set `FILE_CREATED` bit in `struct 1252 /// fuse_file_info'. 1253 /// 1254 /// All flags applied to open/create should be handled samely in atomic open, 1255 /// only the following are exceptions: 1256 /// * The O_NOCTTY is filtered out by fuse client. 1257 /// * O_TRUNC is filtered out by VFS for O_CREAT, O_EXCL combination. 1258 /// 1259 /// # Implementation 1260 /// 1261 /// To implement this API, you need to handle the following cases: 1262 /// 1263 /// a) File does not exist 1264 /// - O_CREAT: 1265 /// - Create file with specified mode 1266 /// - Set `FOPEN_FILE_CREATED` bit in `struct OpenOptions open` 1267 /// - Open the file 1268 /// - Return d_entry and file handler 1269 /// - ~O_CREAT: 1270 /// - ENOENT 1271 /// 1272 /// b) File exist already (exception is O_EXCL) 1273 /// - O_CREAT: 1274 /// - Open the file 1275 /// - Return d_entry and file handler 1276 /// - O_EXCL: 1277 /// - EEXIST 1278 /// 1279 /// c) File is symbol link 1280 /// - Return dentry and file handler atomic_open( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)>1281 fn atomic_open( 1282 &self, 1283 ctx: Context, 1284 parent: Self::Inode, 1285 name: &CStr, 1286 mode: u32, 1287 flags: u32, 1288 umask: u32, 1289 security_ctx: Option<&CStr>, 1290 ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> { 1291 Err(io::Error::from_raw_os_error(libc::ENOSYS)) 1292 } 1293 } 1294