Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/fuse/src/filesystem.rs
5394 views
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 {
61
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.
86
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`.
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`.
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.
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<R: ZeroCopyReader> ZeroCopyReader for &mut R {
250
fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
251
(**self).read_to(f, count, off)
252
}
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
}
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`.
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`.
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.
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<W: ZeroCopyWriter> ZeroCopyWriter for &mut W {
343
fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
344
(**self).write_from(f, count, off)
345
}
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
}
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 {
368
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.
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.
421
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.
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.
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.
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`.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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`.
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.
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.
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
1138
fn getlk(&self) -> io::Result<()> {
1139
Err(io::Error::from_raw_os_error(libc::ENOSYS))
1140
}
1141
1142
/// TODO: support this
1143
fn setlk(&self) -> io::Result<()> {
1144
Err(io::Error::from_raw_os_error(libc::ENOSYS))
1145
}
1146
1147
/// TODO: support this
1148
fn setlkw(&self) -> io::Result<()> {
1149
Err(io::Error::from_raw_os_error(libc::ENOSYS))
1150
}
1151
1152
/// TODO: support this
1153
fn bmap(&self) -> io::Result<()> {
1154
Err(io::Error::from_raw_os_error(libc::ENOSYS))
1155
}
1156
1157
/// TODO: support this
1158
fn poll(&self) -> io::Result<()> {
1159
Err(io::Error::from_raw_os_error(libc::ENOSYS))
1160
}
1161
1162
/// TODO: support this
1163
fn notify_reply(&self) -> io::Result<()> {
1164
Err(io::Error::from_raw_os_error(libc::ENOSYS))
1165
}
1166
1167
/// TODO: support this
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.
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.
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.
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
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
1295