1 /*
2   FUSE: Filesystem in Userspace
3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4 
5   This program can be distributed under the terms of the GNU LGPLv2.
6   See the file COPYING.LIB.
7 */
8 
9 module c.fuse.fuse_common;
10 
11 public import c.fuse.fuse_opt;
12 
13 import core.sys.posix.config;
14 import core.sys.posix.sys.types;
15 
16 import std.bitmanip;
17 import std.stdint;
18 
19 enum FUSE_MAJOR_VERSION = 2;
20 enum FUSE_MINOR_VERSION = 9;
21 
22 auto FUSE_MAKE_VERSION(Maj, Min)(Maj maj, Min min) { return ((maj) * 10 + (min)); }
23 enum FUSE_VERSION = FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION);
24 
25 static assert(_FILE_OFFSET_BITS == 64);
26 
27 extern (C):
28 
29 /**
30  * Information about open files
31  *
32  * Changed in version 2.5
33  */
34 struct fuse_file_info
35 {
36     /** Open flags. Available in open() and release() */
37     int flags;
38 
39     /** Old file handle, don't use */
40     c_ulong fh_old;
41 
42     /** In case of a write operation indicates if this was caused by a
43       writepage */
44     int writepage;
45 
46     mixin(bitfields!(
47         /** Can be filled in by open, to use direct I/O on this file.
48           Introduced in version 2.4 */
49         uint, q{direct_io}, 1,
50 
51         /** Can be filled in by open, to indicate, that cached file data
52           need not be invalidated.  Introduced in version 2.4 */
53         uint, q{keep_cache}, 1,
54 
55         /** Indicates a flush operation.  Set in flush operation, also
56           maybe set in highlevel lock operation and lowlevel release
57           operation. Introduced in version 2.6 */
58         uint, q{flush}, 1,
59 
60         /** Can be filled in by open, to indicate that the file is not
61           seekable.  Introduced in version 2.8 */
62         uint, q{nonseekable}, 1,
63 
64         /* Indicates that flock locks for this file should be
65            released.  If set, lock_owner shall contain a valid value.
66            May only be set in ->release().  Introduced in version
67            2.9 */
68         uint, q{flock_release}, 1,
69 
70         /** Padding.  Do not use*/
71         uint, q{padding}, 27,
72     ));
73 
74     /** File handle.  May be filled in by filesystem in open().
75       Available in all other file operations */
76     uint64_t fh;
77 
78     /** Lock owner id.  Available in locking operations and flush */
79     uint64_t lock_owner;
80 }
81 version (D_LP64)
82     static assert(fuse_file_info.sizeof == 40);
83 else
84     static assert(fuse_file_info.sizeof == 32);
85 
86 /**
87  * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
88  *
89  * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
90  * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
91  * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
92  * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
93  * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
94  * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
95  * FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device
96  * FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice()
97  * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device
98  * FUSE_CAP_IOCTL_DIR: ioctl support on directories
99  */
100 enum FUSE_CAP_ASYNC_READ = (1 << 0);
101 enum FUSE_CAP_POSIX_LOCKS = (1 << 1);
102 enum FUSE_CAP_ATOMIC_O_TRUNC = (1 << 3);
103 enum FUSE_CAP_EXPORT_SUPPORT = (1 << 4);
104 enum FUSE_CAP_BIG_WRITES = (1 << 5);
105 enum FUSE_CAP_DONT_MASK = (1 << 6);
106 enum FUSE_CAP_SPLICE_WRITE = (1 << 7);
107 enum FUSE_CAP_SPLICE_MOVE = (1 << 8);
108 enum FUSE_CAP_SPLICE_READ = (1 << 9);
109 enum FUSE_CAP_FLOCK_LOCKS = (1 << 10);
110 enum FUSE_CAP_IOCTL_DIR = (1 << 11);
111 
112 /**
113  * Ioctl flags
114  *
115  * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
116  * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
117  * FUSE_IOCTL_RETRY: retry with new iovecs
118  * FUSE_IOCTL_DIR: is a directory
119  *
120  * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
121  */
122 enum FUSE_IOCTL_COMPAT = (1 << 0);
123 enum FUSE_IOCTL_UNRESTRICTED = (1 << 1);
124 enum FUSE_IOCTL_RETRY = (1 << 2);
125 enum FUSE_IOCTL_DIR = 	(1 << 4);
126 
127 enum FUSE_IOCTL_MAX_IOV = 256;
128 
129 /**
130  * Connection information, passed to the ->init() method
131  *
132  * Some of the elements are read-write, these can be changed to
133  * indicate the value requested by the filesystem.  The requested
134  * value must usually be smaller than the indicated value.
135  */
136 struct fuse_conn_info
137 {
138     /**
139      * Major version of the protocol (read-only)
140      */
141     uint proto_major;
142 
143     /**
144      * Minor version of the protocol (read-only)
145      */
146     uint proto_minor;
147 
148     /**
149      * Is asynchronous read supported (read-write)
150      */
151     uint async_read;
152 
153     /**
154      * Maximum size of the write buffer
155      */
156     uint max_write;
157 
158     /**
159      * Maximum readahead
160      */
161     uint max_readahead;
162 
163     /**
164      * Capability flags, that the kernel supports
165      */
166     uint capable;
167 
168     /**
169      * Capability flags, that the filesystem wants to enable
170      */
171     uint want;
172 
173     /**
174      * Maximum number of backgrounded requests
175      */
176     uint max_background;
177 
178     /**
179      * Kernel congestion threshold parameter
180      */
181     uint congestion_threshold;
182 
183     /**
184      * For future use.
185      */
186     uint[23] reserved;
187 }
188 static assert(fuse_conn_info.sizeof == 128);
189 
190 struct fuse_session;
191 struct fuse_chan;
192 struct fuse_pollhandle;
193 
194 /**
195  * Create a FUSE mountpoint
196  *
197  * Returns a control file descriptor suitable for passing to
198  * fuse_new()
199  *
200  * @param mountpoint the mount point path
201  * @param args argument vector
202  * @return the communication channel on success, NULL on failure
203  */
204 fuse_chan* fuse_mount(const char* mountpoint, fuse_args *args);
205 
206 /**
207  * Umount a FUSE mountpoint
208  *
209  * @param mountpoint the mount point path
210  * @param ch the communication channel
211  */
212 void fuse_unmount(const char* mountpoint, fuse_chan *ch);
213 
214 /**
215  * Parse common options
216  *
217  * The following options are parsed:
218  *
219  *   '-f'	     foreground
220  *   '-d' '-odebug'  foreground, but keep the debug option
221  *   '-s'	     single threaded
222  *   '-h' '--help'   help
223  *   '-ho'	     help without header
224  *   '-ofsname=..'   file system name, if not present, then set to the program
225  *		     name
226  *
227  * All parameters may be NULL
228  *
229  * @param args argument vector
230  * @param mountpoint the returned mountpoint, should be freed after use
231  * @param multithreaded set to 1 unless the '-s' option is present
232  * @param foreground set to 1 if one of the relevant options is present
233  * @return 0 on success, -1 on failure
234  */
235 int fuse_parse_cmdline(fuse_args* args, char** mountpoint,
236 		       int* multithreaded, int* foreground);
237 
238 /**
239  * Go into the background
240  *
241  * @param foreground if true, stay in the foreground
242  * @return 0 on success, -1 on failure
243  */
244 int fuse_daemonize(int foreground);
245 
246 /**
247  * Get the version of the library
248  *
249  * @return the version
250  */
251 int fuse_version();
252 
253 /**
254  * Destroy poll handle
255  *
256  * @param ph the poll handle
257  */
258 void fuse_pollhandle_destroy(fuse_pollhandle* ph);
259 
260 /* ----------------------------------------------------------- *
261  * Data buffer						       *
262  * ----------------------------------------------------------- */
263 
264 /**
265  * Buffer flags
266  */
267 enum fuse_buf_flags
268 {
269 	/**
270 	 * Buffer contains a file descriptor
271 	 *
272 	 * If this flag is set, the .fd field is valid, otherwise the
273 	 * .mem fields is valid.
274 	 */
275 	FUSE_BUF_IS_FD		= (1 << 1),
276 
277 	/**
278 	 * Seek on the file descriptor
279 	 *
280 	 * If this flag is set then the .pos field is valid and is
281 	 * used to seek to the given offset before performing
282 	 * operation on file descriptor.
283 	 */
284 	FUSE_BUF_FD_SEEK	= (1 << 2),
285 
286 	/**
287 	 * Retry operation on file descriptor
288 	 *
289 	 * If this flag is set then retry operation on file descriptor
290 	 * until .size bytes have been copied or an error or EOF is
291 	 * detected.
292 	 */
293 	FUSE_BUF_FD_RETRY	= (1 << 3),
294 }
295 enum FUSE_BUF_IS_FD    = fuse_buf_flags.FUSE_BUF_IS_FD;
296 enum FUSE_BUF_FD_SEEK  = fuse_buf_flags.FUSE_BUF_FD_SEEK;
297 enum FUSE_BUF_FD_RETRY = fuse_buf_flags.FUSE_BUF_FD_RETRY;
298 
299 /**
300  * Buffer copy flags
301  */
302 enum fuse_buf_copy_flags
303 {
304 	/**
305 	 * Don't use splice(2)
306 	 *
307 	 * Always fall back to using read and write instead of
308 	 * splice(2) to copy data from one file descriptor to another.
309 	 *
310 	 * If this flag is not set, then only fall back if splice is
311 	 * unavailable.
312 	 */
313 	FUSE_BUF_NO_SPLICE	= (1 << 1),
314 
315 	/**
316 	 * Force splice
317 	 *
318 	 * Always use splice(2) to copy data from one file descriptor
319 	 * to another.  If splice is not available, return -EINVAL.
320 	 */
321 	FUSE_BUF_FORCE_SPLICE	= (1 << 2),
322 
323 	/**
324 	 * Try to move data with splice.
325 	 *
326 	 * If splice is used, try to move pages from the source to the
327 	 * destination instead of copying.  See documentation of
328 	 * SPLICE_F_MOVE in splice(2) man page.
329 	 */
330 	FUSE_BUF_SPLICE_MOVE	= (1 << 3),
331 
332 	/**
333 	 * Don't block on the pipe when copying data with splice
334 	 *
335 	 * Makes the operations on the pipe non-blocking (if the pipe
336 	 * is full or empty).  See SPLICE_F_NONBLOCK in the splice(2)
337 	 * man page.
338 	 */
339 	FUSE_BUF_SPLICE_NONBLOCK= (1 << 4),
340 }
341 enum FUSE_BUF_NO_SPLICE       = fuse_buf_copy_flags.FUSE_BUF_NO_SPLICE;
342 enum FUSE_BUF_FORCE_SPLICE    = fuse_buf_copy_flags.FUSE_BUF_FORCE_SPLICE;
343 enum FUSE_BUF_SPLICE_MOVE     = fuse_buf_copy_flags.FUSE_BUF_SPLICE_MOVE;
344 enum FUSE_BUF_SPLICE_NONBLOCK = fuse_buf_copy_flags.FUSE_BUF_SPLICE_NONBLOCK;
345 
346 /**
347  * Single data buffer
348  *
349  * Generic data buffer for I/O, extended attributes, etc...  Data may
350  * be supplied as a memory pointer or as a file descriptor
351  */
352 struct fuse_buf
353 {
354 	/**
355 	 * Size of data in bytes
356 	 */
357 	size_t size;
358 
359 	/**
360 	 * Buffer flags
361 	 */
362 	fuse_buf_flags flags;
363 
364 	/**
365 	 * Memory pointer
366 	 *
367 	 * Used unless FUSE_BUF_IS_FD flag is set.
368 	 */
369 	void* mem;
370 
371 	/**
372 	 * File descriptor
373 	 *
374 	 * Used if FUSE_BUF_IS_FD flag is set.
375 	 */
376 	int fd;
377 
378 	/**
379 	 * File position
380 	 *
381 	 * Used if FUSE_BUF_FD_SEEK flag is set.
382 	 */
383 	off_t pos;
384 }
385 
386 /**
387  * Data buffer vector
388  *
389  * An array of data buffers, each containing a memory pointer or a
390  * file descriptor.
391  *
392  * Allocate dynamically to add more than one buffer.
393  */
394 struct fuse_bufvec
395 {
396 	/**
397 	 * Number of buffers in the array
398 	 */
399 	size_t count;
400 
401 	/**
402 	 * Index of current buffer within the array
403 	 */
404 	size_t idx;
405 
406 	/**
407 	 * Current offset within the current buffer
408 	 */
409 	size_t off;
410 
411 	/**
412 	 * Array of buffers
413 	 */
414 	fuse_buf[1] buf;
415 }
416 
417 /* Initialize bufvec with a single buffer of given size */
418 fuse_bufvec FUSE_BUFVEC_INIT()(size_t size__)
419 {
420     fuse_bufvec result = {
421 		/* .count= */ 1,
422 		/* .idx =  */ 0,
423 		/* .off =  */ 0,
424 		/* .buf =  */ [ /* [0] = */ {
425 			/* .size =  */ (size__),
426 			/* .flags = */ cast(fuse_buf_flags) 0,
427 			/* .mem =   */ null,
428 			/* .fd =    */ -1,
429 			/* .pos =   */ 0,
430 		} ]
431 	};
432     return result;
433 }
434 
435 /**
436  * Get total size of data in a fuse buffer vector
437  *
438  * @param bufv buffer vector
439  * @return size of data
440  */
441 size_t fuse_buf_size(const fuse_bufvec* bufv);
442 
443 /**
444  * Copy data from one buffer vector to another
445  *
446  * @param dst destination buffer vector
447  * @param src source buffer vector
448  * @param flags flags controlling the copy
449  * @return actual number of bytes copied or -errno on error
450  */
451 ssize_t fuse_buf_copy(fuse_bufvec* dst, fuse_bufvec* src,
452 		      fuse_buf_copy_flags flags);
453 
454 /* ----------------------------------------------------------- *
455  * Signal handling					       *
456  * ----------------------------------------------------------- */
457 
458 /**
459  * Exit session on HUP, TERM and INT signals and ignore PIPE signal
460  *
461  * Stores session in a global variable.	 May only be called once per
462  * process until fuse_remove_signal_handlers() is called.
463  *
464  * @param se the session to exit
465  * @return 0 on success, -1 on failure
466  */
467 int fuse_set_signal_handlers(fuse_session* se);
468 
469 /**
470  * Restore default signal handlers
471  *
472  * Resets global session.  After this fuse_set_signal_handlers() may
473  * be called again.
474  *
475  * @param se the same session as given in fuse_set_signal_handlers()
476  */
477 void fuse_remove_signal_handlers(fuse_session* se);
478 
479 /* ----------------------------------------------------------- *
480  * Compatibility stuff					       *
481  * ----------------------------------------------------------- */
482 
483 /// See FuseCompat in fuse.d.
484 mixin template FuseCommonCompat(uint FUSE_USE_VERSION = default_FUSE_USE_VERSION)
485 {
486     import c.fuse.fuse;
487     static if (FUSE_USE_VERSION < 26)
488     {
489         version (FreeBSD)
490         {
491             static if (FUSE_USE_VERSION < 25)
492                 static assert(false, "On FreeBSD API version 25 or greater must be used");
493         }
494         import c.fuse.fuse_common_compat;
495         alias fuse_unmount = fuse_unmount_compat22;
496         static if (FUSE_USE_VERSION == 25)
497         {
498             enum FUSE_MINOR_VERSION = 5;
499             alias fuse_mount = fuse_mount_compat25;
500         }
501         else static if (FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22)
502         {
503             enum FUSE_MINOR_VERSION = 4;
504             alias fuse_mount = fuse_mount_compat22;
505         }
506         else static if (FUSE_USE_VERSION == 21)
507         {
508             enum FUSE_MINOR_VERSION = 1;
509             alias fuse_mount = fuse_mount_compat22;
510         }
511         else static if (FUSE_USE_VERSION == 11)
512         {
513             pragma(msg, "Compatibility with API version 11 is deprecated");
514             enum FUSE_MAJOR_VERSION = 1;
515             enum FUSE_MINOR_VERSION = 1;
516 			alias fuse_mount = fuse_mount_compat1;
517 		}
518 		else
519 			static assert(false, "Compatibility with API version other than 21, 22, 24, 25 and 11 not supported");
520     }
521 }
522 
523 enum default_FUSE_USE_VERSION = 21;