Add dfuse

This commit is contained in:
Les De Ridder 2016-10-16 05:30:52 +02:00
parent 6e5c10d60e
commit 1b43c4965d
No known key found for this signature in database
GPG Key ID: 5EC132DFA85DB372
11 changed files with 960 additions and 1 deletions

1
dfuse

@ -1 +0,0 @@
Subproject commit 8daf1d4fffbcd1415b963ed5a43fae5e4bf06464

7
dfuse/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.o
*.so
*.dylib
*.a
simplefs
*.swp
*~

28
dfuse/LICENSE Normal file
View File

@ -0,0 +1,28 @@
Boost Software License - Version 1.0 - August 17th, 2003
For dfuse software
Copyright (c) 2014, Facebook, Inc.
All rights reserved.
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

82
dfuse/Makefile Normal file
View File

@ -0,0 +1,82 @@
#
# Copyright (c) 2014, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the Boost-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
#
VERSION=0.4.0-dev
INTERNAL_VERSION=0004
product=libdfuse-$(VERSION)
PREFIX=/usr/local
DMD=dmd
DMDFLAGS=
sources = source/c/fuse/fuse.d source/c/fuse/common.d source/dfuse/fuse.d
uname := $(shell uname -s)
# Define variables and buildmodes depending on ENABLE_DEBUG, ENABLE_64BIT and
# operating system.
buildmode=release
ifeq ($(ENABLE_DEBUG),1)
MODE=-debug -g
buildmode=debug
else
MODE=-release -O -inline
buildmode=release
endif
bitmode=64
ifeq ($(uname),Darwin)
ifeq ($(ENABLE_64BIT),1)
MODE+=-version=DARWIN_USE_64_BIT_INODE
LIBS=-L-losxfuse
bitmde=64
else
LIBS=-L-losxfuse_i32
bitmode=32
endif
endif
ifeq ($(uname),Linux)
LIBS=-L-lfuse
bitmode=64
endif
# Define build directories and main target for libs
builddir=build/$(buildmode)/$(bitmode)
ifeq ($(uname),Linux)
artifact=$(builddir)/$(product).so
endif
ifeq ($(uname),Darwin)
artifact=$(builddir)/$(product).dylib
endif
all:: dfuse
$(builddir):
mkdir -p $(builddir)
$(builddir)/$(product).so: $(sources)
$(DMD) -w $(MODE) -shared $(LIBS) -version=$(INTERNAL_VERSION) -of$@ $(sources)
$(builddir)/$(product).dylib: $(sources)
$(DMD) -w $(MODE) -shared $(LIBS) -version=$(INTERNAL_VERSION) -of$@ $(sources)
simplefs: example/simplefs.d $(sources)
$(DMD) -w -debug -g $(LIBS) -of$@ example/simplefs.d $(sources)
examples: simplefs
dfuse: $(artifact)
clean:
@(rm simplefs 2>/dev/null || exit 0)
@(rm -r $(artifact) || exit 0)
@(rm -rf build/ || exit 0)
.PHONY: dfuse all clean examples

23
dfuse/PATENTS Normal file
View File

@ -0,0 +1,23 @@
Additional Grant of Patent Rights
"Software" means the dfuse software distributed by Facebook, Inc.
Facebook hereby grants you a perpetual, worldwide, royalty-free,
non-exclusive, irrevocable (subject to the termination provision below)
license under any rights in any patent claims owned by Facebook, to make,
have made, use, sell, offer to sell, import, and otherwise transfer the
Software. For avoidance of doubt, no license is granted under Facebooks
rights in any patent claims that are infringed by (i) modifications to the
Software made by you or a third party, or (ii) the Software in combination
with any software or other technology provided by you or a third party.
The license granted hereunder will terminate, automatically and without
notice, for anyone that makes any claim (including by filing any lawsuit,
assertion or other action) alleging (a) direct, indirect, or contributory
infringement or inducement to infringe any patent: (i) by Facebook or any
of its subsidiaries or affiliates, whether or not such claim is related
to the Software, (ii) by any party if such claim arises in whole or in
part from any software, product or service of Facebook or any of its
subsidiaries or affiliates, whether or not such claim is related to the
Software, or (iii) by any party relating to the Software; or (b) that
any right in any patent claim of Facebook is invalid or unenforceable.

132
dfuse/README.md Normal file
View File

@ -0,0 +1,132 @@
# dfuse
*dfuse* is a [D language binding](http://dlang.org) for the high level
[fuse](http://fuse.sourceforge.net) library. It allows to write a fuse
filesystem for Linux or Mac OS (using [osxfuse](http://osxfuse.github.io)) in D.
Fuse is a library and kernel extension to write filesystems in userspace. These
filesystems are easy to implement and have access to userland components like
HTTP libraries, etc. For more information about fuse see: http://fuse.sourceforge.net.
## Examples
A simple filesystems implementing a directory listing can be found in the [examples/](https://github.com/facebook/dfuse/tree/master/example) directory.
You can build the examples using:
```Shell
$ make examples
$ mkdir /mnt/simplefs
$ ./simplefs /mnt/simplefs
```
## Implementing a filesystem
dfuse provides a high level interface for libfuse. To implement a filesystem, extend the *Operations* class in the *dfuse.fuse* module:
```D
import dfuse.fuse;
class MyFS : Operations
{
override void getattr(const(char)[] path, ref stat_t s)
{
/* implementation */
throw new FuseException(EOPNOTSUPP);
}
override string[] readdir(const(char)[] path)
{
return [/*...list of files...*/];
}
override ulong read(const(char)[] path, ubyte[] buf, ulong offset)
{
/* implementation */
throw new FuseException(EOPNOTSUPP);
}
}
```
A minimal filesystem implements `Operations.getattr()`, `Operations.readdir()`, `Operations.read()`. See [dfuse/fuse.d](https://github.com/facebook/dfuse/blob/master/dfuse/fuse.d) for implementation specific details.
To mount a filesystem use a Fuse object and call mount:
```D
import dfuse.fuse;
int main(string[] args)
{
/* foreground=true, threading=false */
auto fs = new Fuse("MyFS", true, false);
fs.mount(new MyFS(), "/mnt", ["allow_other"]);
}
```
Error conditions are handled by throwin a *FuseException* with the appropriate error number. See `man 3 errno` for more information about errno.
## Requirements
dfuse requires:
* Mac OS X or Linux
* fuse >= 2.8.0 or [osxfuse](http://osxfuse.github.io/) >= 2.6.0
* DMD/Druntime/Phobos >= 2.065
## Building dfuse
dfuse comes with a standard makefile that assumes that DMD (the D-compiler) is
in your $PATH.
### Linux
In order to compile dfuse on Linux:
```Shell
$ make dfuse
or
$ make dfuse ENABLE_DEBUG=1
to build a debug version
```
### MacOS
MacOS supports two inode sizes which are both supported by OSXfuse, however when
compiling dfuse you have to be aware which OSXfuse should be linked.
By default dfuse is trying to build with a 32bit inode size and link against
osxfuse_i32 which is part of OSXfuse for compatibility. Please note that your
library itself will still be 64bit on a 64bit system. The setting only affects
the size of the inode.
To build just run
```Shell
$ make dfuse
```
If you want to compile with 64bit inodes you need a at least DMD, Druntime,
Phobos in version 2.066:
```Shell
$ make dfuse ENABLE_64BIT=1
```
### Dub
dfuse comes with experimental support for [dub](http://code.dlang.org/), a package manager for D. See the dub documentation how to build and use dub.
## Installing dfuse
At the moment the dfuse makefile doesn't support an install target. It is
recommended to just include the library in a project at this point.
## How dfuse works
dfuse is a simple D wrapper. It exposes a lowelevel interface to the libfuse C
functions in c/fuse/fuse.d. The lowlevel interface preserves C types.
A highlevel interface is provided by fs/fuse.d. The D interface initializes fuse filsystems operations structure and installs it's own handlers. Every dfuse handler converts C
types to D types and is trapping FuseExceptions used for error handling. The
handlers keep track of the initialized Operations object and call the
appropriate method once types are converted and pass the result into the D
layer.
The user facing interface is the *Operations* class in fs/fuse.d. It provides
default implementations for all handlers and every method can be invidually
overwritten to provide an interface.
## Issues and Bugs
If you encounter issues or bugs with dfuse, please file an issue on [github](https://github.com/facebook/dfuse/issues). Please ensure that you maintain a constructive feedback atmosphere and if possible attach a reproduction step. If you have any questions, feel free to write to the D mailinglist or ask in IRC.
Pull requests are highly appreciated!
## Join the dfuse community
* Website: https://github.com/facebook/dfuse/wiki
* Mailing list: [The D Mailinglist](http://lists.puremagic.com/cgi-bin/mailman/listinfo/digitalmars-d)
* irc: irc.freenode.net #d
## License
dfuse is Boost-licensed. We also provide an additional patent grant.

20
dfuse/dub.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "dfuse",
"description": "A D binding for libfuse",
"authors": ["David Soria Parra"],
"copyright": "Copyright (c) 2014, Facebook, Inc.",
"homepage": "http://github.com/facebook/dfuse",
"license": "BSL-1.0",
"dependencies": {},
"configurations": [{
"name": "dfuse-osx",
"targetType": "library",
"platforms": ["osx"],
"libs": ["osxfuse_i32"]
}, {
"name": "dfuse-linux",
"targetType": "library",
"platforms": ["linux"],
"libs": ["fuse"]
}]
}

63
dfuse/example/simplefs.d Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the Boost-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
import dfuse.fuse;
import std.algorithm, std.conv, std.stdio;
/**
* A simple directory listing using dfuse
*/
class SimpleFS : Operations
{
override void getattr(const(char)[] path, ref stat_t s)
{
if (path == "/")
{
s.st_mode = S_IFDIR | octal!755;
s.st_size = 0;
return;
}
if (path.among("/a", "/b"))
{
s.st_mode = S_IFREG | octal!644;
s.st_size = 42;
return;
}
throw new FuseException(errno.ENOENT);
}
override string[] readdir(const(char)[] path)
{
if (path == "/")
{
return ["a", "b"];
}
throw new FuseException(errno.ENOENT);
}
}
int main(string[] args)
{
if (args.length != 2)
{
stderr.writeln("simplefs <MOUNTPOINT>");
return -1;
}
stdout.writeln("mounting simplefs");
auto fs = new Fuse("SimpleFS", true, false);
fs.mount(new SimpleFS(), args[1], []);
return 0;
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the Boost-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
module c.fuse.common;
import std.stdint;
extern (System) {
static assert(fuse_conn_info.sizeof == 128);
struct fuse_conn_info
{
/**
* Major version of the protocol (read-only)
*/
uint proto_major;
/**
* Minor version of the protocol (read-only)
*/
uint proto_minor;
/**
* Is asynchronous read supported (read-write)
*/
uint async_read;
/**
* Maximum size of the write buffer
*/
uint max_write;
/**
* Maximum readahead
*/
uint max_readahead;
/**
* Capability flags, that the kernel supports
*/
uint capable;
/**
* Capability flags, that the filesystem wants to enable
*/
uint want;
/**
* Maximum number of backgrounded requests
*/
uint max_background;
/**
* Kernel congestion threshold parameter
*/
uint congestion_threshold;
/**
* For future use.
*/
uint[23] reserved;
}
static assert(fuse_file_info.sizeof == 64);
struct fuse_file_info
{
/** Open flags. Available in open() and release() */
int flags;
/** Old file handle, don't use */
ulong fh_old;
/** In case of a write operation indicates if this was caused by a
writepage */
int writepage;
/** Can be filled in by open, to use direct I/O on this file.
Introduced in version 2.4 */
uint direct_io = 1;
/** Can be filled in by open, to indicate, that cached file data
need not be invalidated. Introduced in version 2.4 */
uint keep_cache = 1;
/** Indicates a flush operation. Set in flush operation, also
maybe set in highlevel lock operation and lowlevel release
operation. Introduced in version 2.6 */
uint flush = 1;
/** Can be filled in by open, to indicate that the file is not
seekable. Introduced in version 2.8 */
uint nonseekable = 1;
/* Indicates that flock locks for this file should be
released. If set, lock_owner shall contain a valid value.
May only be set in ->release(). Introduced in version
2.9 */
uint flock_release = 1;
/** Padding. Do not use*/
uint padding = 27;
/** File handle. May be filled in by filesystem in open().
Available in all other file operations */
uint64_t fh;
/** Lock owner id. Available in locking operations and flush */
uint64_t lock_owner;
}
}

104
dfuse/source/c/fuse/fuse.d Normal file
View File

@ -0,0 +1,104 @@
/*
* From: https://code.google.com/p/dutils/
*
* Licensed under the Apache License 2.0. See
* http://www.apache.org/licenses/LICENSE-2.0
*/
module c.fuse.fuse;
public import c.fuse.common;
import std.stdint;
import core.sys.posix.sys.statvfs;
import core.sys.posix.fcntl;
import core.sys.posix.time;
import core.sys.posix.utime;
extern (System)
{
struct fuse;
struct fuse_pollhandle;
struct fuse_conn_info; /* temporary anonymous struct */
struct fuse_dirhandle;
alias fuse_dirh_t = fuse_dirhandle*;
alias flock _flock;
alias fuse_fill_dir_t =
int function(void *buf, char *name, stat_t *stbuf, off_t off);
alias fuse_dirfil_t =
int function(fuse_dirh_t, const char *name, int type, ino_t ino);
struct fuse_operations
{
int function(const char*, stat_t*) getattr;
int function(const char*, char *, size_t) readlink;
int function(const char*, fuse_dirh_t, fuse_dirfil_t) getdir;
int function(const char*, mode_t, dev_t) mknod;
int function(const char*, mode_t) mkdir;
int function(const char*) unlink;
int function(const char*) rmdir;
int function(const char*, char*) symlink;
int function(const char*, char*) rename;
int function(const char*, char*) link;
int function(const char*, mode_t) chmod;
int function(const char*, uid_t, gid_t) chown;
int function(const char*, off_t) truncate;
int function(const char*, utimbuf *) utime;
int function(const char*, fuse_file_info *) open;
int function(const char*, char*, size_t, off_t, fuse_file_info*) read;
int function(const char*, char*, size_t, off_t, fuse_file_info*) write;
int function(const char*, statvfs_t*) statfs;
int function(const char*, fuse_file_info*) flush;
int function(const char*, fuse_file_info*) release;
int function(const char*, int, fuse_file_info*) fsync;
int function(const char*, char*, char*, size_t, int) setxattr;
int function(const char*, char*, char*, size_t) getxattr;
int function(const char*, char*, size_t) listxattr;
int function(const char*, char*) removexattr;
int function(const char*, fuse_file_info*) opendir;
int function(const char*, void*, fuse_fill_dir_t, off_t,
fuse_file_info*) readdir;
int function(const char*, fuse_file_info*) releasedir;
int function(const char*, int, fuse_file_info*) fsyncdir;
void* function(fuse_conn_info* conn) init;
void function(void*) destroy;
int function(const char*, int) access;
int function(const char*, mode_t, fuse_file_info*) create;
int function(const char*, off_t, fuse_file_info*) ftruncate;
int function(const char*, stat_t*, fuse_file_info*) fgetattr;
int function(const char*, fuse_file_info*, int cmd, _flock*) lock;
int function(const char*, const timespec) utimens;
int function(const char*, size_t, uint64_t*) bmap;
uint flag_nullpath_ok = 1;
uint flag_reserved = 31;
int function(const char*, int, void*, fuse_file_info*, uint, void*)
ioctl;
int function(const char*, fuse_file_info*, fuse_pollhandle*, uint*)
poll;
}
struct fuse_context
{
/** Pointer to the fuse object */
fuse* _fuse;
uid_t uid; // User ID of the calling process
gid_t gid; // Group ID of the calling process
pid_t pid; // Thread ID of the calling process
void* private_data; // Private filesystem data
mode_t umask; // Umask of the calling process (introduced in version 2.8)
}
fuse_context* fuse_get_context();
int fuse_main_real(int argc, char** argv, fuse_operations* op,
size_t op_size, void* user_data);
}
/* mappping of the fuse_main macro in fuse.h */
int fuse_main(int argc, char** argv, fuse_operations* op, void* user_data)
{
return fuse_main_real(argc, argv, op, fuse_operations.sizeof, user_data);
}

386
dfuse/source/dfuse/fuse.d Normal file
View File

@ -0,0 +1,386 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the Boost-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
module dfuse.fuse;
/* reexport stat_t */
public import core.sys.posix.fcntl;
import std.algorithm;
import std.array;
import std.conv;
import std.stdio;
import std.string;
import errno = core.stdc.errno;
import core.stdc.string;
import c.fuse.fuse;
import core.thread : thread_attachThis, thread_detachThis;
import core.sys.posix.pthread;
/**
* libfuse is handling the thread creation and we cannot hook into it. However
* we need to make the GC aware of the threads. So for any call to a handler
* we check if the current thread is attached and attach it if necessary.
*/
private int threadAttached = false;
private pthread_cleanup cleanup;
extern(C) void detach(void* ptr) nothrow
{
import std.exception;
collectException(thread_detachThis());
}
private void attach()
{
if (!threadAttached)
{
thread_attachThis();
cleanup.push(&detach, cast(void*) null);
threadAttached = true;
}
}
/**
* A template to wrap C function calls and support exceptions to indicate
* errors.
*
* The templates passes the Operations object to the lambda as the first
* arguemnt.
*/
private auto call(alias fn)()
{
attach();
auto t = cast(Operations*) fuse_get_context().private_data;
try
{
return fn(*t);
}
catch (FuseException fe)
{
/* errno is used to indicate an error to libfuse */
errno.errno = fe.errno;
return -fe.errno;
}
catch (Exception e)
{
(*t).exception(e);
return -errno.EIO;
}
}
/* C calling convention compatible function to hand into libfuse which wrap
* the call to our Operations object.
*
* Note that we convert our * char pointer to an array using the
* ptr[0..len] syntax.
*/
extern(System)
{
private int dfuse_access(const char* path, int mode)
{
return call!(
(Operations t)
{
if(t.access(path[0..path.strlen], mode))
{
return 0;
}
return -1;
})();
}
private int dfuse_getattr(const char* path, stat_t* st)
{
return call!(
(Operations t)
{
t.getattr(path[0..path.strlen], *st);
return 0;
})();
}
private int dfuse_readdir(const char* path, void* buf,
fuse_fill_dir_t filler, off_t offset, fuse_file_info* fi)
{
return call!(
(Operations t)
{
foreach(file; t.readdir(path[0..path.strlen]))
{
filler(buf, cast(char*) toStringz(file), null, 0);
}
return 0;
})();
}
private int dfuse_readlink(const char* path, char* buf, size_t size)
{
return call!(
(Operations t)
{
auto length = t.readlink(path[0..path.strlen],
(cast(ubyte*)buf)[0..size]);
/* Null-terminate the string and copy it over to the buffer. */
assert(length <= size);
buf[length] = '\0';
return 0;
})();
}
private int dfuse_read(const char* path, char* buf, size_t size,
off_t offset, fuse_file_info* fi)
{
/* Ensure at compile time that off_t and size_t fit into an ulong. */
static assert(ulong.max >= size_t.max);
static assert(ulong.max >= off_t.max);
return call!(
(Operations t)
{
auto bbuf = cast(ubyte*) buf;
return cast(int) t.read(path[0..path.strlen], bbuf[0..size],
to!ulong(offset));
})();
}
private int dfuse_write(const char* path, char* data, size_t size,
off_t offset, fuse_file_info* fi)
{
static assert(ulong.max >= size_t.max);
static assert(ulong.max >= off_t.max);
return call!(
(Operations t)
{
auto bdata = cast(ubyte*) data;
return t.write(path[0..path.strlen], bdata[0..size],
to!ulong(offset));
})();
}
private int dfuse_truncate(const char* path, off_t length)
{
static assert(ulong.max >= off_t.max);
return call!(
(Operations t)
{
t.truncate(path[0..path.strlen], to!ulong(length));
return 0;
})();
}
private void* dfuse_init(fuse_conn_info* conn)
{
attach();
auto t = cast(Operations*) fuse_get_context().private_data;
(*t).initialize();
return t;
}
private void dfuse_destroy(void* data)
{
/* this is an ugly hack at the moment. We need to somehow detach all
threads from the runtime because after fuse_main finishes the pthreads
are joined. We circumvent that problem by just exiting while our
threads still run. */
import std.c.process;
exit(0);
}
} /* extern(C) */
export class FuseException : Exception
{
public int errno;
this(int errno, string file = __FILE__, size_t line = __LINE__,
Throwable next = null)
{
super("Fuse Exception", file, line, next);
this.errno = errno;
}
}
/**
* An object oriented wrapper around fuse_operations.
*/
export class Operations
{
/**
* Runs on filesystem creation
*/
void initialize()
{
}
/**
* Called to get a stat(2) structure for a path.
*/
void getattr(const(char)[] path, ref stat_t stat)
{
throw new FuseException(errno.EOPNOTSUPP);
}
/**
* Read path into the provided buffer beginning at offset.
*
* Params:
* path = The path to the file to read.
* buf = The buffer to read the data into.
* offset = An offset to start reading at.
* Returns: The amount of bytes read.
*/
ulong read(const(char)[] path, ubyte[] buf, ulong offset)
{
throw new FuseException(errno.EOPNOTSUPP);
}
/**
* Write the given data to the file.
*
* Params:
* path = The path to the file to write.
* buf = A read-only buffer containing the data to write.
* offset = An offset to start writing at.
* Returns: The amount of bytes written.
*/
int write(const(char)[] path, in ubyte[] data, ulong offset)
{
throw new FuseException(errno.EOPNOTSUPP);
}
/**
* Truncate a file to the given length.
* Params:
* path = The path to the file to trunate.
* length = Truncate file to this given length.
*/
void truncate(const(char)[] path, ulong length)
{
throw new FuseException(errno.EOPNOTSUPP);
}
/**
* Returns a list of files and directory names in the given folder. Note
* that you have to return . and ..
*
* Params:
* path = The path to the directory.
* Returns: An array of filenames.
*/
string[] readdir(const(char)[] path)
{
throw new FuseException(errno.EOPNOTSUPP);
}
/**
* Reads the link identified by path into the given buffer.
*
* Params:
* path = The path to the directory.
*/
ulong readlink(const(char)[] path, ubyte[] buf)
{
throw new FuseException(errno.EOPNOTSUPP);
}
/**
* Determine if the user has access to the given path.
*
* Params:
* path = The path to check.
* mode = An flag indicating what to check for. See access(2) for
* supported modes.
* Returns: True on success otherwise false.
*/
bool access(const(char)[] path, int mode)
{
throw new FuseException(errno.EOPNOTSUPP);
}
void exception(Exception e)
{
}
}
/**
* A wrapper around fuse_main()
*/
export class Fuse
{
private:
bool foreground;
bool threaded;
string fsname;
public:
this(string fsname)
{
this(fsname, false, true);
}
this(string fsname, bool foreground, bool threaded)
{
this.fsname = fsname;
this.foreground = foreground;
this.threaded = threaded;
}
void mount(Operations ops, const string mountpoint, string[] mountopts)
{
string [] args = [this.fsname];
args ~= mountpoint;
if(mountopts.length > 0)
{
args ~= format("-o%s", mountopts.join(","));
}
if(this.foreground)
{
args ~= "-f";
}
if(!this.threaded)
{
args ~= "-s";
}
debug writefln("fuse arguments s=(%s)", args);
fuse_operations fops;
fops.init = &dfuse_init;
fops.access = &dfuse_access;
fops.getattr = &dfuse_getattr;
fops.readdir = &dfuse_readdir;
fops.read = &dfuse_read;
fops.write = &dfuse_write;
fops.truncate = &dfuse_truncate;
fops.readlink = &dfuse_readlink;
fops.destroy = &dfuse_destroy;
/* Create c-style arguments from a string[] array. */
auto cargs = array(map!(a => toStringz(a))(args));
int length = cast(int) cargs.length;
static if(length.max < cargs.length.max)
{
/* This is an unsafe cast that we need to do for C compat.
Enforce unlike assert will be checked in opt-builds as well. */
import std.exception : enforce;
enforce(length >= 0);
enforce(length == cargs.length);
}
fuse_main(length, cast(char**) cargs.ptr, &fops, &ops);
}
}