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