drakey_fuse_sys/
abi.rs

1//! FUSE kernel interface
2//!
3//! Types and definitions used for communication between the kernel driver and the userspace
4//! part (this crate) of a FUSE filesystem. Since the kernel driver may be installed
5//! independently, the ABI interface is versioned and capabilities are exchanged during the
6//! initialization (mounting) of a filesystem.
7//!
8//! OSXFUSE (macOS): https://github.com/osxfuse/fuse/blob/master/include/fuse_kernel.h
9//! - supports ABI 7.8 in OSXFUSE 2.x
10//! - supports ABI 7.19 since OSXFUSE 3.0.0
11//!
12//! libfuse (Linux/BSD): https://github.com/libfuse/libfuse/blob/master/include/fuse_kernel.h
13//! - supports ABI 7.8 since FUSE 2.6.0
14//! - supports ABI 7.12 since FUSE 2.8.0
15//! - supports ABI 7.18 since FUSE 2.9.0
16//! - supports ABI 7.19 since FUSE 2.9.1
17//! - supports ABI 7.26 since FUSE 3.0.0
18//!
19//! Items without a version annotation are valid with ABI 7.8 and later
20
21// TODO: We currently target ABI 7.8, which is very conservative and missing many newer
22// features. We still need to figure out a way to support different ABI version without hazzle.
23pub const FUSE_KERNEL_VERSION: u32 = 7;
24pub const FUSE_KERNEL_MINOR_VERSION: u32 = 8;
25
26pub const FUSE_ROOT_ID: u64 = 1;
27
28#[repr(C)]
29#[derive(Debug)]
30pub struct fuse_attr {
31    pub ino: u64,
32    pub size: u64,
33    pub blocks: u64,
34    pub atime: i64,
35    pub mtime: i64,
36    pub ctime: i64,
37    #[cfg(target_os = "macos")]
38    pub crtime: i64,
39    pub atimensec: i32,
40    pub mtimensec: i32,
41    pub ctimensec: i32,
42    #[cfg(target_os = "macos")]
43    pub crtimensec: i32,
44    pub mode: u32,
45    pub nlink: u32,
46    pub uid: u32,
47    pub gid: u32,
48    pub rdev: u32,
49    #[cfg(target_os = "macos")]
50    pub flags: u32,                                     // see chflags(2)
51}
52
53#[repr(C)]
54#[derive(Debug)]
55pub struct fuse_kstatfs {
56    pub blocks: u64,                                    // Total blocks (in units of frsize)
57    pub bfree: u64,                                     // Free blocks
58    pub bavail: u64,                                    // Free blocks for unprivileged users
59    pub files: u64,                                     // Total inodes
60    pub ffree: u64,                                     // Free inodes
61    pub bsize: u32,                                     // Filesystem block size
62    pub namelen: u32,                                   // Maximum filename length
63    pub frsize: u32,                                    // Fundamental file system block size
64    pub padding: u32,
65    pub spare: [u32; 6],
66}
67
68#[repr(C)]
69#[derive(Debug)]
70pub struct fuse_file_lock {
71    pub start: u64,
72    pub end: u64,
73    pub typ: u32,
74    pub pid: u32,
75}
76
77pub mod consts {
78    // CUSE init request/reply flags
79    pub const CUSE_UNRESTRICTED_IOCTL: u32  = 1 << 0;
80
81    //Bitmasks for fuse_setattr_in.valid
82    pub const FATTR_MODE: u32               = 1 << 0;
83    pub const FATTR_UID: u32                = 1 << 1;
84    pub const FATTR_GID: u32                = 1 << 2;
85    pub const FATTR_SIZE: u32               = 1 << 3;
86    pub const FATTR_ATIME: u32              = 1 << 4;
87    pub const FATTR_MTIME: u32              = 1 << 5;
88    pub const FATTR_FH: u32                 = 1 << 6;
89    #[cfg(target_os = "macos")]
90    pub const FATTR_CRTIME: u32             = 1 << 28;
91    #[cfg(target_os = "macos")]
92    pub const FATTR_CHGTIME: u32            = 1 << 29;
93    #[cfg(target_os = "macos")]
94    pub const FATTR_BKUPTIME: u32           = 1 << 30;
95    #[cfg(target_os = "macos")]
96    pub const FATTR_FLAGS: u32              = 1 << 31;
97
98    // Flags returned by the open request
99    pub const FOPEN_DIRECT_IO: u32          = 1 << 0;   // bypass page cache for this open file
100    pub const FOPEN_KEEP_CACHE: u32         = 1 << 1;   // don't invalidate the data cache on open
101    #[cfg(target_os = "macos")]
102    pub const FOPEN_PURGE_ATTR: u32         = 1 << 30;
103    #[cfg(target_os = "macos")]
104    pub const FOPEN_PURGE_UBC: u32          = 1 << 31;
105
106    // Init request/reply flags
107    pub const FUSE_ASYNC_READ: u32          = 1 << 0;
108    pub const FUSE_POSIX_LOCKS: u32         = 1 << 1;
109    #[cfg(target_os = "macos")]
110    pub const FUSE_CASE_INSENSITIVE: u32    = 1 << 29;
111    #[cfg(target_os = "macos")]
112    pub const FUSE_VOL_RENAME: u32          = 1 << 30;
113    #[cfg(target_os = "macos")]
114    pub const FUSE_XTIMES: u32              = 1 << 31;
115
116    // Release flags
117    pub const FUSE_RELEASE_FLUSH: u32       = 1 << 0;
118
119    // The read buffer is required to be at least 8k, but may be much larger
120    pub const FUSE_MIN_READ_BUFFER: usize   = 8192;
121
122    // IOCTL flags
123   pub const FUSE_IOCTL_COMPAT: u32        = 1 << 0;   // since ABI 7.11: 32bit compat ioctl on 64bit machine
124   pub const FUSE_IOCTL_UNRESTRICTED: u32  = 1 << 1;   // since ABI 7.11: not restricted to well-formed ioctls, retry allowed
125   pub const FUSE_IOCTL_RETRY: u32         = 1 << 2;   // since ABI 7.11: retry with new iovecs
126   pub const FUSE_IOCTL_32BIT: u32         = 1 << 3;   // since ABI 7.16: 32bit ioctl
127   pub const FUSE_IOCTL_DIR: u32           = 1 << 4;   // since ABI 7.18: is a directory
128   pub const FUSE_IOCTL_MAX_IOV: u32       = 256;      // since ABI 7.11: maximum of in_iovecs + out_iovecs
129}
130
131#[repr(C)]
132#[derive(Debug)]
133#[allow(non_camel_case_types)]
134pub enum fuse_opcode {
135    CUSE_INIT = 4096,
136    FUSE_LOOKUP = 1,
137    FUSE_FORGET = 2,                                    // no reply
138    FUSE_GETATTR = 3,
139    FUSE_SETATTR = 4,
140    FUSE_READLINK = 5,
141    FUSE_SYMLINK = 6,
142    FUSE_MKNOD = 8,
143    FUSE_MKDIR = 9,
144    FUSE_UNLINK = 10,
145    FUSE_RMDIR = 11,
146    FUSE_RENAME = 12,
147    FUSE_LINK = 13,
148    FUSE_OPEN = 14,
149    FUSE_READ = 15,
150    FUSE_WRITE = 16,
151    FUSE_STATFS = 17,
152    FUSE_RELEASE = 18,
153    FUSE_FSYNC = 20,
154    FUSE_SETXATTR = 21,
155    FUSE_GETXATTR = 22,
156    FUSE_LISTXATTR = 23,
157    FUSE_REMOVEXATTR = 24,
158    FUSE_FLUSH = 25,
159    FUSE_INIT = 26,
160    FUSE_OPENDIR = 27,
161    FUSE_READDIR = 28,
162    FUSE_RELEASEDIR = 29,
163    FUSE_FSYNCDIR = 30,
164    FUSE_GETLK = 31,
165    FUSE_SETLK = 32,
166    FUSE_SETLKW = 33,
167    FUSE_ACCESS = 34,
168    FUSE_CREATE = 35,
169    FUSE_INTERRUPT = 36,
170    FUSE_BMAP = 37,
171    FUSE_DESTROY = 38,
172    #[cfg(target_os = "macos")]
173    FUSE_SETVOLNAME = 61,
174    #[cfg(target_os = "macos")]
175    FUSE_GETXTIMES = 62,
176    #[cfg(target_os = "macos")]
177    FUSE_EXCHANGE = 63,
178}
179
180// FIXME: Hopefully Rust will once have a more convenient way of converting primitive to enum
181impl fuse_opcode {
182    pub fn from_u32(n: u32) -> Option<Self> {
183        match n {
184            1 => Some(fuse_opcode::FUSE_LOOKUP),
185            2 => Some(fuse_opcode::FUSE_FORGET),
186            3 => Some(fuse_opcode::FUSE_GETATTR),
187            4 => Some(fuse_opcode::FUSE_SETATTR),
188            5 => Some(fuse_opcode::FUSE_READLINK),
189            6 => Some(fuse_opcode::FUSE_SYMLINK),
190            8 => Some(fuse_opcode::FUSE_MKNOD),
191            9 => Some(fuse_opcode::FUSE_MKDIR),
192            10 => Some(fuse_opcode::FUSE_UNLINK),
193            11 => Some(fuse_opcode::FUSE_RMDIR),
194            12 => Some(fuse_opcode::FUSE_RENAME),
195            13 => Some(fuse_opcode::FUSE_LINK),
196            14 => Some(fuse_opcode::FUSE_OPEN),
197            15 => Some(fuse_opcode::FUSE_READ),
198            16 => Some(fuse_opcode::FUSE_WRITE),
199            17 => Some(fuse_opcode::FUSE_STATFS),
200            18 => Some(fuse_opcode::FUSE_RELEASE),
201            20 => Some(fuse_opcode::FUSE_FSYNC),
202            21 => Some(fuse_opcode::FUSE_SETXATTR),
203            22 => Some(fuse_opcode::FUSE_GETXATTR),
204            23 => Some(fuse_opcode::FUSE_LISTXATTR),
205            24 => Some(fuse_opcode::FUSE_REMOVEXATTR),
206            25 => Some(fuse_opcode::FUSE_FLUSH),
207            26 => Some(fuse_opcode::FUSE_INIT),
208            27 => Some(fuse_opcode::FUSE_OPENDIR),
209            28 => Some(fuse_opcode::FUSE_READDIR),
210            29 => Some(fuse_opcode::FUSE_RELEASEDIR),
211            30 => Some(fuse_opcode::FUSE_FSYNCDIR),
212            31 => Some(fuse_opcode::FUSE_GETLK),
213            32 => Some(fuse_opcode::FUSE_SETLK),
214            33 => Some(fuse_opcode::FUSE_SETLKW),
215            34 => Some(fuse_opcode::FUSE_ACCESS),
216            35 => Some(fuse_opcode::FUSE_CREATE),
217            36 => Some(fuse_opcode::FUSE_INTERRUPT),
218            37 => Some(fuse_opcode::FUSE_BMAP),
219            38 => Some(fuse_opcode::FUSE_DESTROY),
220            #[cfg(target_os = "macos")]
221            61 => Some(fuse_opcode::FUSE_SETVOLNAME),
222            #[cfg(target_os = "macos")]
223            62 => Some(fuse_opcode::FUSE_GETXTIMES),
224            #[cfg(target_os = "macos")]
225            63 => Some(fuse_opcode::FUSE_EXCHANGE),
226            4096 => Some(fuse_opcode::CUSE_INIT),
227            _ => None,
228        }
229    }
230}
231
232#[repr(C)]
233#[derive(Debug)]
234pub struct fuse_entry_out {
235    pub nodeid: u64,
236    pub generation: u64,
237    pub entry_valid: i64,
238    pub attr_valid: i64,
239    pub entry_valid_nsec: i32,
240    pub attr_valid_nsec: i32,
241    pub attr: fuse_attr,
242}
243
244#[repr(C)]
245#[derive(Debug)]
246pub struct fuse_forget_in {
247    pub nlookup: u64,
248}
249
250#[repr(C)]
251#[derive(Debug)]
252pub struct fuse_attr_out {
253    pub attr_valid: i64,
254    pub attr_valid_nsec: i32,
255    pub dummy: u32,
256    pub attr: fuse_attr,
257}
258
259#[cfg(target_os = "macos")]
260#[repr(C)]
261#[derive(Debug)]
262pub struct fuse_getxtimes_out {
263    pub bkuptime: i64,
264    pub crtime: i64,
265    pub bkuptimensec: i32,
266    pub crtimensec: i32,
267}
268
269#[repr(C)]
270#[derive(Debug)]
271pub struct fuse_mknod_in {
272    pub mode: u32,
273    pub rdev: u32,
274}
275
276#[repr(C)]
277#[derive(Debug)]
278pub struct fuse_mkdir_in {
279    pub mode: u32,
280    pub padding: u32,
281}
282
283#[repr(C)]
284#[derive(Debug)]
285pub struct fuse_rename_in {
286    pub newdir: u64,
287}
288
289#[cfg(target_os = "macos")]
290#[repr(C)]
291#[derive(Debug)]
292pub struct fuse_exchange_in {
293    pub olddir: u64,
294    pub newdir: u64,
295    pub options: u64,
296}
297
298#[repr(C)]
299#[derive(Debug)]
300pub struct fuse_link_in {
301    pub oldnodeid: u64,
302}
303
304#[repr(C)]
305#[derive(Debug)]
306pub struct fuse_setattr_in {
307    pub valid: u32,
308    pub padding: u32,
309    pub fh: u64,
310    pub size: u64,
311    pub unused1: u64,
312    pub atime: i64,
313    pub mtime: i64,
314    pub unused2: u64,
315    pub atimensec: i32,
316    pub mtimensec: i32,
317    pub unused3: u32,
318    pub mode: u32,
319    pub unused4: u32,
320    pub uid: u32,
321    pub gid: u32,
322    pub unused5: u32,
323    #[cfg(target_os = "macos")]
324    pub bkuptime: i64,
325    #[cfg(target_os = "macos")]
326    pub chgtime: i64,
327    #[cfg(target_os = "macos")]
328    pub crtime: i64,
329    #[cfg(target_os = "macos")]
330    pub bkuptimensec: i32,
331    #[cfg(target_os = "macos")]
332    pub chgtimensec: i32,
333    #[cfg(target_os = "macos")]
334    pub crtimensec: i32,
335    #[cfg(target_os = "macos")]
336    pub flags: u32,                                     // see chflags(2)
337}
338
339#[repr(C)]
340#[derive(Debug)]
341pub struct fuse_open_in {
342    pub flags: u32,
343    pub mode: u32,
344}
345
346#[repr(C)]
347#[derive(Debug)]
348pub struct fuse_open_out {
349    pub fh: u64,
350    pub open_flags: u32,
351    pub padding: u32,
352}
353
354#[repr(C)]
355#[derive(Debug)]
356pub struct fuse_release_in {
357    pub fh: u64,
358    pub flags: u32,
359    pub release_flags: u32,
360    pub lock_owner: u64,
361}
362
363#[repr(C)]
364#[derive(Debug)]
365pub struct fuse_flush_in {
366    pub fh: u64,
367    pub unused: u32,
368    pub padding: u32,
369    pub lock_owner: u64,
370}
371
372#[repr(C)]
373#[derive(Debug)]
374pub struct fuse_read_in {
375    pub fh: u64,
376    pub offset: i64,
377    pub size: u32,
378    pub padding: u32,
379}
380
381#[repr(C)]
382#[derive(Debug)]
383pub struct fuse_write_in {
384    pub fh: u64,
385    pub offset: i64,
386    pub size: u32,
387    pub write_flags: u32,
388}
389
390#[repr(C)]
391#[derive(Debug)]
392pub struct fuse_write_out {
393    pub size: u32,
394    pub padding: u32,
395}
396
397#[repr(C)]
398#[derive(Debug)]
399pub struct fuse_statfs_out {
400    pub st: fuse_kstatfs,
401}
402
403#[repr(C)]
404#[derive(Debug)]
405pub struct fuse_fsync_in {
406    pub fh: u64,
407    pub fsync_flags: u32,
408    pub padding: u32,
409}
410
411#[repr(C)]
412#[derive(Debug)]
413pub struct fuse_setxattr_in {
414    pub size: u32,
415    pub flags: u32,
416    #[cfg(target_os = "macos")]
417    pub position: u32,
418    #[cfg(target_os = "macos")]
419    pub padding: u32,
420}
421
422#[repr(C)]
423#[derive(Debug)]
424pub struct fuse_getxattr_in {
425    pub size: u32,
426    pub padding: u32,
427    #[cfg(target_os = "macos")]
428    pub position: u32,
429    #[cfg(target_os = "macos")]
430    pub padding2: u32,
431}
432
433#[repr(C)]
434#[derive(Debug)]
435pub struct fuse_getxattr_out {
436    pub size: u32,
437    pub padding: u32,
438}
439
440#[repr(C)]
441#[derive(Debug)]
442pub struct fuse_lk_in {
443    pub fh: u64,
444    pub owner: u64,
445    pub lk: fuse_file_lock,
446}
447
448#[repr(C)]
449#[derive(Debug)]
450pub struct fuse_lk_out {
451    pub lk: fuse_file_lock,
452}
453
454#[repr(C)]
455#[derive(Debug)]
456pub struct fuse_access_in {
457    pub mask: u32,
458    pub padding: u32,
459}
460
461#[repr(C)]
462#[derive(Debug)]
463pub struct fuse_init_in {
464    pub major: u32,
465    pub minor: u32,
466    pub max_readahead: u32,
467    pub flags: u32,
468}
469
470#[repr(C)]
471#[derive(Debug)]
472pub struct fuse_init_out {
473    pub major: u32,
474    pub minor: u32,
475    pub max_readahead: u32,
476    pub flags: u32,
477    pub unused: u32,
478    pub max_write: u32,
479}
480
481#[repr(C)]
482#[derive(Debug)]
483pub struct fuse_interrupt_in {
484    pub unique: u64,
485}
486
487#[repr(C)]
488#[derive(Debug)]
489pub struct fuse_bmap_in {
490    pub block: u64,
491    pub blocksize: u32,
492    pub padding: u32,
493}
494
495#[repr(C)]
496#[derive(Debug)]
497pub struct fuse_bmap_out {
498    pub block: u64,
499}
500
501#[repr(C)]
502#[derive(Debug)]
503pub struct fuse_ioctl_in {                              // since ABI 7.11
504    pub fh: u64,
505    pub flags: u32,
506    pub cmd: u32,
507    pub arg: u64,
508    pub in_size: u32,
509    pub out_size: u32,
510}
511
512#[repr(C)]
513#[derive(Debug)]
514pub struct fuse_ioctl_iovec {                           // since ABI 7.16
515    pub base: u64,
516    pub len: u64,
517}
518
519#[repr(C)]
520#[derive(Debug)]
521pub struct fuse_ioctl_out {                             // since ABI 7.11
522    pub result: i32,
523    pub flags: u32,
524    pub in_iovs: u32,
525    pub out_iovs: u32,
526}
527
528#[repr(C)]
529#[derive(Debug)]
530pub struct fuse_poll_in {                               // since ABI 7.11
531    pub fh: u64,
532    pub kh: u64,
533    pub flags: u32,
534    pub padding: u32,
535}
536
537#[repr(C)]
538#[derive(Debug)]
539pub struct fuse_poll_out {                              // since ABI 7.11
540    pub revents: u32,
541    pub padding: u32,
542}
543
544#[repr(C)]
545#[derive(Debug)]
546pub struct cuse_init_in {                               // since ABI 7.12
547    pub major: u32,
548    pub minor: u32,
549    pub unused: u32,
550    pub flags: u32,
551}
552
553#[repr(C)]
554#[derive(Debug)]
555pub struct cuse_init_out {                              // since ABI 7.12
556    pub major: u32,
557    pub minor: u32,
558    pub unused: u32,
559    pub flags: u32,
560    pub max_read: u32,
561    pub max_write: u32,
562    pub dev_major: u32,                                 // chardev major
563    pub dev_minor: u32,                                 // chardev minor
564    pub spare: [u32; 10],
565}
566
567#[repr(C)]
568#[derive(Debug)]
569pub struct fuse_in_header {
570    pub len: u32,
571    pub opcode: u32,
572    pub unique: u64,
573    pub nodeid: u64,
574    pub uid: u32,
575    pub gid: u32,
576    pub pid: u32,
577    pub padding: u32,
578}
579
580#[repr(C)]
581#[derive(Debug)]
582pub struct fuse_out_header {
583    pub len: u32,
584    pub error: i32,
585    pub unique: u64,
586}
587
588#[repr(C)]
589#[derive(Debug)]
590pub struct fuse_dirent {
591    pub ino: u64,
592    pub off: i64,
593    pub namelen: u32,
594    pub typ: u32,
595    // followed by name of namelen bytes
596}