getFuseHandle() {
+ return fuseHandle;
+ }
+
+ public fuse_h.fuse_operations getFuseOperations() {
+ return fuseOperations;
+ }
+
+ @Override
+ public void destroy(Pointer> pointer) {
+ this.fuseHandle = Pointer.ofNull();
+ LOG.debug("destroy()");
+ }
+
+ @Override
+ public void close() {
+ scope.close();
+ }
+}
diff --git a/bindings/src/main/java/de/skymatic/fusepanama/Errno.java b/bindings/src/main/java/de/skymatic/fusepanama/Errno.java
new file mode 100644
index 00000000..7cf582ac
--- /dev/null
+++ b/bindings/src/main/java/de/skymatic/fusepanama/Errno.java
@@ -0,0 +1,21 @@
+package de.skymatic.fusepanama;
+
+/**
+ * Error codes extracted from
+ * errno.h (linux)
+ * and errno.h (darwin)
+ */
+public interface Errno {
+
+ boolean IS_MAC = System.getProperty("os.name").toLowerCase().contains("mac");
+
+ /**
+ * No such file or directory
+ */
+ int ENOENT = 2;
+
+ /**
+ * Invalid system call number
+ */
+ int ENOSYS = IS_MAC ? 78 : 38;
+}
diff --git a/bindings/src/main/java/de/skymatic/fusepanama/Fuse.java b/bindings/src/main/java/de/skymatic/fusepanama/Fuse.java
new file mode 100644
index 00000000..6a4dbf2e
--- /dev/null
+++ b/bindings/src/main/java/de/skymatic/fusepanama/Fuse.java
@@ -0,0 +1,42 @@
+package de.skymatic.fusepanama;
+
+import java.foreign.Scope;
+import java.foreign.memory.Pointer;
+import java.util.concurrent.ThreadLocalRandom;
+
+import com.github.libfuse.fuse_lib;
+import com.github.libfuse.fuse_opt_h;
+import com.github.libfuse.fuse_opt_lib;
+
+public class Fuse {
+
+ /**
+ * Mounts the given file system at the given mount point.
+ *
+ * This method blocks until unmounted.
+ */
+ public static void mount(AbstractFuseFileSystem fs, String mountPoint, boolean debug) {
+ try (Scope scope = Scope.globalScope().fork()) {
+ var fuse_args = scope.allocateStruct(fuse_opt_h.fuse_args.class);
+ fuse_args.argc$set(0);
+ fuse_args.argv$set(Pointer.ofNull());
+ fuse_args.allocated$set(0);
+ fuse_opt_lib.fuse_opt_add_arg(fuse_args.ptr(), scope.allocateCString("fusefs-" + ThreadLocalRandom.current().nextInt()));
+ fuse_opt_lib.fuse_opt_add_arg(fuse_args.ptr(), scope.allocateCString("-f"));
+ if (debug) {
+ fuse_opt_lib.fuse_opt_add_arg(fuse_args.ptr(), scope.allocateCString("-d"));
+ }
+ fuse_opt_lib.fuse_opt_add_arg(fuse_args.ptr(), scope.allocateCString(mountPoint));
+
+ int result = fuse_lib.fuse_main_real(fuse_args.argc$get(), fuse_args.argv$get(), fs.fuseOperations.ptr(), FuseOperations.SIZEOF_FUSE_OPERATIONS, Pointer.ofNull());
+
+ fuse_opt_lib.fuse_opt_free_args(fuse_args.ptr());
+
+ if (result != 0) {
+ throw new RuntimeException("mount failed with return code " + result);
+ }
+ }
+ }
+
+
+}
diff --git a/bindings/src/main/java/de/skymatic/fusepanama/FuseOperations.java b/bindings/src/main/java/de/skymatic/fusepanama/FuseOperations.java
new file mode 100644
index 00000000..82635baa
--- /dev/null
+++ b/bindings/src/main/java/de/skymatic/fusepanama/FuseOperations.java
@@ -0,0 +1,523 @@
+package de.skymatic.fusepanama;
+
+import java.foreign.memory.Callback;
+import java.foreign.memory.LayoutType;
+import java.foreign.memory.Pointer;
+
+import com.github.libfuse.fuse_common_h;
+import com.github.libfuse.fuse_h;
+import usr.include.sys._types._timespec_h;
+import usr.include.sys.fcntl_h;
+import usr.include.sys.stat_h;
+import usr.include.sys.statvfs_h;
+import usr.include.utime_h;
+
+public interface FuseOperations {
+
+ long SIZEOF_FUSE_OPERATIONS = LayoutType.ofStruct(fuse_h.fuse_operations.class).bytesSize();
+
+ /**
+ * Get file attributes.
+ *
+ * Similar to stat(). The 'st_dev' and 'st_blksize' fields are
+ * ignored. The 'st_ino' field is ignored except if the 'use_ino'
+ * mount option is given.
+ */
+ int getattr(Pointer path, Pointer buf);
+
+ /**
+ * Read the target of a symbolic link
+ *
+ * The buffer should be filled with a null terminated string. The
+ * buffer size argument includes the space for the terminating
+ * null character. If the linkname is too long to fit in the
+ * buffer, it should be truncated. The return value should be 0
+ * for success.
+ */
+ int readlink(Pointer path, Pointer buf, long len);
+
+ /**
+ * @deprecated use {@link #readdir(Pointer, Pointer, Callback, long, Pointer) readdir()} instead
+ */
+ int getdir(Pointer path, Pointer fuse_dirhandlePointer, Callback fi2Callback);
+
+ /**
+ * Create a file node
+ *
+ * This is called for creation of all non-directory, non-symlink
+ * nodes. If the filesystem defines a create() method, then for
+ * regular files that will be called instead.
+ */
+ int mknod(Pointer path, short mode, int rdev);
+
+ /**
+ * Create a directory
+ *
+ * Note that the mode argument may not have the type specification
+ * bits set, i.e. S_ISDIR(mode) can be false. To obtain the
+ * correct directory type bits use mode|S_IFDIR
+ */
+ int mkdir(Pointer path, short mode);
+
+ /**
+ * Remove a file
+ */
+ int unlink(Pointer path);
+
+ /**
+ * Remove a directory
+ */
+ int rmdir(Pointer path);
+
+ /**
+ * Create a symbolic link
+ */
+ int symlink(Pointer linkname, Pointer target);
+
+ /**
+ * Rename a file
+ */
+ int rename(Pointer oldpath, Pointer newpath);
+
+ /**
+ * Create a hard link to a file
+ */
+ int link(Pointer linkname, Pointer target);
+
+ /**
+ * Change the permission bits of a file
+ */
+ int chmod(Pointer path, short mode);
+
+ /**
+ * Change the owner and group of a file
+ */
+ int chown(Pointer path, int uid, int gid);
+
+ /**
+ * Change the size of a file
+ */
+ int truncate(Pointer path, long size);
+
+ /**
+ * Change the access and/or modification times of a file
+ *
+ * @deprecated use {@link #utimens(Pointer, Pointer) utimens()} instead.
+ */
+ int utime(Pointer path, Pointer utimbufPointer);
+
+ /**
+ * File open operation
+ *
+ * No creation (O_CREAT, O_EXCL) and by default also no
+ * truncation (O_TRUNC) flags will be passed to open(). If an
+ * application specifies O_TRUNC, fuse first calls truncate()
+ * and then open(). Only if 'atomic_o_trunc' has been
+ * specified and kernel version is 2.6.24 or later, O_TRUNC is
+ * passed on to open.
+ *
+ * Unless the 'default_permissions' mount option is given,
+ * open should check if the operation is permitted for the
+ * given flags. Optionally open may also return an arbitrary
+ * filehandle in the fuse_file_info structure, which will be
+ * passed to all file operations.
+ *
+ * Changed in version 2.2
+ */
+ int open(Pointer path, Pointer fi);
+
+ /**
+ * Read data from an open file
+ *
+ * Read should return exactly the number of bytes requested except
+ * on EOF or error, otherwise the rest of the data will be
+ * substituted with zeroes. An exception to this is when the
+ * 'direct_io' mount option is specified, in which case the return
+ * value of the read system call will reflect the return value of
+ * this operation.
+ *
+ * Changed in version 2.2
+ */
+ int read(Pointer path, Pointer buf, long size, long offset, Pointer fi);
+
+ /**
+ * Write data to an open file
+ *
+ * Write should return exactly the number of bytes requested
+ * except on error. An exception to this is when the 'direct_io'
+ * mount option is specified (see read operation).
+ *
+ * Changed in version 2.2
+ */
+ int write(Pointer path, Pointer buf, long size, long offset, Pointer fi);
+
+ /**
+ * Get file system statistics
+ *
+ * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
+ *
+ * Replaced 'struct statfs' parameter with 'struct statvfs' in
+ * version 2.5
+ */
+ int statfs(Pointer path, Pointer buf);
+
+ /**
+ * Possibly flush cached data
+ *
+ * BIG NOTE: This is not equivalent to fsync(). It's not a
+ * request to sync dirty data.
+ *
+ * Flush is called on each close() of a file descriptor. So if a
+ * filesystem wants to return write errors in close() and the file
+ * has cached dirty data, this is a good place to write back data
+ * and return any errors. Since many applications ignore close()
+ * errors this is not always useful.
+ *
+ * NOTE: The flush() method may be called more than once for each
+ * open(). This happens if more than one file descriptor refers
+ * to an opened file due to dup(), dup2() or fork() calls. It is
+ * not possible to determine if a flush is final, so each flush
+ * should be treated equally. Multiple write-flush sequences are
+ * relatively rare, so this shouldn't be a problem.
+ *
+ * Filesystems shouldn't assume that flush will always be called
+ * after some writes, or that if will be called at all.
+ *
+ * Changed in version 2.2
+ */
+ int flush(Pointer path, Pointer fi);
+
+ /**
+ * Release an open file
+ *
+ * Release is called when there are no more references to an open
+ * file: all file descriptors are closed and all memory mappings
+ * are unmapped.
+ *
+ * For every open() call there will be exactly one release() call
+ * with the same flags and file descriptor. It is possible to
+ * have a file opened more than once, in which case only the last
+ * release will mean, that no more reads/writes will happen on the
+ * file. The return value of release is ignored.
+ *
+ * Changed in version 2.2
+ */
+ int release(Pointer path, Pointer fi);
+
+ /**
+ * Synchronize file contents
+ *
+ * If the datasync parameter is non-zero, then only the user data
+ * should be flushed, not the meta data.
+ *
+ * Changed in version 2.2
+ */
+ int fsync(Pointer path, int datasync, Pointer fi);
+
+ /**
+ * Set extended attributes
+ */
+ int setxattr(Pointer path, Pointer name, Pointer value, long size, int flags);
+
+ /**
+ * Get extended attributes
+ */
+ int getxattr(Pointer path, Pointer name, Pointer value, long size);
+
+ /**
+ * List extended attributes
+ */
+ int listxattr(Pointer path, Pointer list, long size);
+
+ /**
+ * Remove extended attributes
+ */
+ int removexattr(Pointer path, Pointer name);
+
+ /**
+ * Open directory
+ *
+ * Unless the 'default_permissions' mount option is given,
+ * this method should check if opendir is permitted for this
+ * directory. Optionally opendir may also return an arbitrary
+ * filehandle in the fuse_file_info structure, which will be
+ * passed to readdir, closedir and fsyncdir.
+ *
+ * Introduced in version 2.3
+ */
+ int opendir(Pointer path, Pointer fi);
+
+ /**
+ * Read directory
+ *
+ * This supersedes the old getdir() interface. New applications
+ * should use this.
+ *
+ * The filesystem may choose between two modes of operation:
+ *
+ * 1) The readdir implementation ignores the offset parameter, and
+ * passes zero to the filler function's offset. The filler
+ * function will not return '1' (unless an error happens), so the
+ * whole directory is read in a single readdir operation. This
+ * works just like the old getdir() method.
+ *
+ * 2) The readdir implementation keeps track of the offsets of the
+ * directory entries. It uses the offset parameter and always
+ * passes non-zero offset to the filler function. When the buffer
+ * is full (or an error happens) the filler function will return
+ * '1'.
+ *
+ * Introduced in version 2.3
+ */
+ int readdir(Pointer path, Pointer> buf, Callback filler, long offset, Pointer fi);
+
+ /**
+ * Release directory
+ *
+ * Introduced in version 2.3
+ */
+ int releasedir(Pointer path, Pointer fi);
+
+ /**
+ * Synchronize directory contents
+ *
+ * If the datasync parameter is non-zero, then only the user data
+ * should be flushed, not the meta data
+ *
+ * Introduced in version 2.3
+ */
+ int fsyncdir(Pointer path, int datasync, Pointer fi);
+
+ /**
+ * Initialize filesystem
+ *
+ * The return value will passed in the private_data field of
+ * fuse_context to all file operations and as a parameter to the
+ * destroy() method.
+ *
+ * Introduced in version 2.3
+ * Changed in version 2.6
+ */
+ Pointer init(Pointer conn);
+
+ /**
+ * Clean up filesystem
+ *
+ * Called on filesystem exit.
+ *
+ * Introduced in version 2.3
+ */
+ void destroy(Pointer> pointer);
+
+ /**
+ * Check file access permissions
+ *
+ * This will be called for the access() system call. If the
+ * 'default_permissions' mount option is given, this method is not
+ * called.
+ *
+ * This method is not called under Linux kernel versions 2.4.x
+ *
+ * Introduced in version 2.5
+ */
+ int access(Pointer path, int mask);
+
+ /**
+ * Create and open a file
+ *
+ * If the file does not exist, first create it with the specified
+ * mode, and then open it.
+ *
+ * If this method is not implemented or under Linux kernel
+ * versions earlier than 2.6.15, the mknod() and open() methods
+ * will be called instead.
+ *
+ * Introduced in version 2.5
+ */
+ int create(Pointer path, short mode, Pointer fi);
+
+ /**
+ * Change the size of an open file
+ *
+ * This method is called instead of the truncate() method if the
+ * truncation was invoked from an ftruncate() system call.
+ *
+ * If this method is not implemented or under Linux kernel
+ * versions earlier than 2.6.15, the truncate() method will be
+ * called instead.
+ *
+ * Introduced in version 2.5
+ */
+ int ftruncate(Pointer path, long size, Pointer fi);
+
+ /**
+ * Get attributes from an open file
+ *
+ * This method is called instead of the getattr() method if the
+ * file information is available.
+ *
+ * Currently this is only called after the create() method if that
+ * is implemented (see above). Later it may be called for
+ * invocations of fstat() too.
+ *
+ * Introduced in version 2.5
+ */
+ int fgetattr(Pointer path, Pointer buf, Pointer fi);
+
+ /**
+ * Perform POSIX file locking operation
+ *
+ * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
+ *
+ * For the meaning of fields in 'struct flock' see the man page
+ * for fcntl(2). The l_whence field will always be set to
+ * SEEK_SET.
+ *
+ * For checking lock ownership, the 'fuse_file_info->owner'
+ * argument must be used.
+ *
+ * For F_GETLK operation, the library will first check currently
+ * held locks, and if a conflicting lock is found it will return
+ * information without calling this method. This ensures, that
+ * for local locks the l_pid field is correctly filled in. The
+ * results may not be accurate in case of race conditions and in
+ * the presence of hard links, but it's unlikely that an
+ * application would rely on accurate GETLK results in these
+ * cases. If a conflicting lock is not found, this method will be
+ * called, and the filesystem may fill out l_pid by a meaningful
+ * value, or it may leave this field zero.
+ *
+ * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
+ * of the process performing the locking operation.
+ *
+ * Note: if this method is not implemented, the kernel will still
+ * allow file locking to work locally. Hence it is only
+ * interesting for network filesystems and similar.
+ *
+ * Introduced in version 2.6
+ */
+ int lock(Pointer path, Pointer fi, int cmd, Pointer lock);
+
+ /**
+ * Change the access and modification times of a file with
+ * nanosecond resolution
+ *
+ * This supersedes the old utime() interface. New applications
+ * should use this.
+ *
+ * See the utimensat(2) man page for details.
+ *
+ * Introduced in version 2.6
+ */
+ int utimens(Pointer path, Pointer<_timespec_h.timespec> tv);
+
+ /**
+ * Map block index within file to block index within device
+ *
+ * Note: This makes sense only for block device backed filesystems
+ * mounted with the 'blkdev' option
+ *
+ * Introduced in version 2.6
+ */
+ int bmap(Pointer path, long blocksize, Pointer idx);
+
+ /**
+ * Ioctl
+ *
+ * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
+ * 64bit environment. The size and direction of data is
+ * determined by _IOC_*() decoding of cmd. For _IOC_NONE,
+ * data will be NULL, for _IOC_WRITE data is out area, for
+ * _IOC_READ in area and if both are set in/out area. In all
+ * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
+ *
+ * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
+ * directory file handle.
+ *
+ * Introduced in version 2.8
+ */
+ int ioctl(Pointer path, int cmd, Pointer> arg, Pointer fi, int flags, Pointer> data);
+
+ /**
+ * Poll for IO readiness events
+ *
+ * Note: If ph is non-NULL, the client should notify
+ * when IO readiness events occur by calling
+ * fuse_notify_poll() with the specified ph.
+ *
+ * Regardless of the number of times poll with a non-NULL ph
+ * is received, single notification is enough to clear all.
+ * Notifying more times incurs overhead but doesn't harm
+ * correctness.
+ *
+ * The callee is responsible for destroying ph with
+ * fuse_pollhandle_destroy() when no longer in use.
+ *
+ * Introduced in version 2.8
+ */
+ int poll(Pointer path, Pointer fi, Pointer ph, Pointer reventsp);
+
+ /**
+ * Write contents of buffer to an open file
+ *
+ * Similar to the write() method, but data is supplied in a
+ * generic buffer. Use fuse_buf_copy() to transfer data to
+ * the destination.
+ *
+ * Introduced in version 2.9
+ */
+ int writeBuf(Pointer path, Pointer buf, long offset, Pointer fi);
+
+ /**
+ * Store data from an open file in a buffer
+ *
+ * Similar to the read() method, but data is stored and
+ * returned in a generic buffer.
+ *
+ * No actual copying of data has to take place, the source
+ * file descriptor may simply be stored in the buffer for
+ * later data transfer.
+ *
+ * The buffer must be allocated dynamically and stored at the
+ * location pointed to by bufp. If the buffer contains memory
+ * regions, they too must be allocated using malloc(). The
+ * allocated memory will be freed by the caller.
+ *
+ * Introduced in version 2.9
+ */
+ int readBuf(Pointer path, Pointer extends Pointer> bufp, long size, long offset, Pointer fi);
+
+ /**
+ * Perform BSD file locking operation
+ *
+ * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
+ *
+ * Nonblocking requests will be indicated by ORing LOCK_NB to
+ * the above operations
+ *
+ * For more information see the flock(2) manual page.
+ *
+ * Additionally fi->owner will be set to a value unique to
+ * this open file. This same value will be supplied to
+ * ->release() when the file is released.
+ *
+ * Note: if this method is not implemented, the kernel will still
+ * allow file locking to work locally. Hence it is only
+ * interesting for network filesystems and similar.
+ *
+ * Introduced in version 2.9
+ */
+ int flock(Pointer path, Pointer fi, int op);
+
+ /**
+ * Allocates space for an open file
+ *
+ * This function ensures that required space is allocated for specified
+ * file. If this function returns success then any subsequent write
+ * request to specified range is guaranteed not to fail because of lack
+ * of space on the file system media.
+ *
+ * Introduced in version 2.9.1
+ */
+ int fallocate(Pointer path, int mode, long offset, long length, Pointer fi);
+}
diff --git a/bindings/src/main/java/de/skymatic/fusepanama/NotImplemented.java b/bindings/src/main/java/de/skymatic/fusepanama/NotImplemented.java
new file mode 100644
index 00000000..71ef1906
--- /dev/null
+++ b/bindings/src/main/java/de/skymatic/fusepanama/NotImplemented.java
@@ -0,0 +1,13 @@
+package de.skymatic.fusepanama;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = ElementType.METHOD)
+public @interface NotImplemented {
+}
diff --git a/bindings/src/main/java/de/skymatic/fusepanama/StubFuseFileSystem.java b/bindings/src/main/java/de/skymatic/fusepanama/StubFuseFileSystem.java
new file mode 100644
index 00000000..1cfd37ca
--- /dev/null
+++ b/bindings/src/main/java/de/skymatic/fusepanama/StubFuseFileSystem.java
@@ -0,0 +1,273 @@
+package de.skymatic.fusepanama;
+
+import java.foreign.memory.Callback;
+import java.foreign.memory.Pointer;
+
+import com.github.libfuse.fuse_common_h;
+import com.github.libfuse.fuse_h;
+import usr.include.sys._types._timespec_h;
+import usr.include.sys.fcntl_h;
+import usr.include.sys.stat_h;
+import usr.include.sys.statvfs_h;
+import usr.include.utime_h;
+
+/**
+ * Implements all fuse operations with a default implementation, that returns -{@link Errno#ENOSYS},
+ * with the exception of {@link #open(Pointer, Pointer) open}, {@link #release(Pointer, Pointer) release},
+ * {@link #opendir(Pointer, Pointer) opendir}, {@link #releasedir(Pointer, Pointer) releasedir}
+ * and {@link #statfs(Pointer, Pointer) statfs}, which return 0.
+ */
+public class StubFuseFileSystem extends AbstractFuseFileSystem {
+
+ @Override
+ @NotImplemented
+ public int getattr(Pointer path, Pointer buf) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int readlink(Pointer path, Pointer buf, long len) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int getdir(Pointer path, Pointer fuse_dirhandlePointer, Callback fi2Callback) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int mknod(Pointer path, short mode, int rdev) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int mkdir(Pointer path, short mode) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int unlink(Pointer path) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int rmdir(Pointer path) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int symlink(Pointer linkname, Pointer target) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int rename(Pointer oldpath, Pointer newpath) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int link(Pointer linkname, Pointer target) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int chmod(Pointer path, short mode) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int chown(Pointer path, int uid, int gid) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int truncate(Pointer path, long size) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int utime(Pointer path, Pointer utimbufPointer) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int open(Pointer path, Pointer fi) {
+ return 0;
+ }
+
+ @Override
+ @NotImplemented
+ public int read(Pointer path, Pointer buf, long size, long offset, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int write(Pointer path, Pointer buf, long size, long offset, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int statfs(Pointer path, Pointer buf) {
+ return 0;
+ }
+
+ @Override
+ @NotImplemented
+ public int flush(Pointer path, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int release(Pointer path, Pointer fi) {
+ return 0;
+ }
+
+ @Override
+ @NotImplemented
+ public int fsync(Pointer path, int datasync, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int setxattr(Pointer path, Pointer name, Pointer value, long size, int flags) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int getxattr(Pointer path, Pointer name, Pointer value, long size) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int listxattr(Pointer path, Pointer list, long size) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int removexattr(Pointer path, Pointer name) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int opendir(Pointer path, Pointer fi) {
+ return 0;
+ }
+
+ @Override
+ @NotImplemented
+ public int readdir(Pointer path, Pointer> buf, Callback filler, long offset, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int releasedir(Pointer path, Pointer fi) {
+ return 0;
+ }
+
+ @Override
+ @NotImplemented
+ public int fsyncdir(Pointer path, int datasync, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int access(Pointer path, int mask) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int create(Pointer path, short mode, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int ftruncate(Pointer path, long size, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int fgetattr(Pointer path, Pointer buf, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int lock(Pointer path, Pointer fi, int cmd, Pointer lock) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int utimens(Pointer path, Pointer<_timespec_h.timespec> tv) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int bmap(Pointer path, long blocksize, Pointer idx) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int ioctl(Pointer path, int cmd, Pointer> arg, Pointer fi, int flags, Pointer> data) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int poll(Pointer path, Pointer fi, Pointer ph, Pointer reventsp) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int writeBuf(Pointer path, Pointer buf, long offset, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int readBuf(Pointer path, Pointer extends Pointer> bufp, long size, long offset, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int flock(Pointer path, Pointer fi, int op) {
+ return -Errno.ENOSYS;
+ }
+
+ @Override
+ @NotImplemented
+ public int fallocate(Pointer path, int mode, long offset, long length, Pointer fi) {
+ return -Errno.ENOSYS;
+ }
+}
diff --git a/bindings/src/main/java/de/skymatic/fusepanama/examples/HelloFileSystem.java b/bindings/src/main/java/de/skymatic/fusepanama/examples/HelloFileSystem.java
new file mode 100644
index 00000000..a3c6bc0f
--- /dev/null
+++ b/bindings/src/main/java/de/skymatic/fusepanama/examples/HelloFileSystem.java
@@ -0,0 +1,94 @@
+package de.skymatic.fusepanama.examples;
+
+import java.foreign.Scope;
+import java.foreign.memory.Callback;
+import java.foreign.memory.Pointer;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import com.github.libfuse.fuse_common_h;
+import com.github.libfuse.fuse_h;
+import de.skymatic.fusepanama.Errno;
+import de.skymatic.fusepanama.Fuse;
+import de.skymatic.fusepanama.StubFuseFileSystem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import usr.include.sys.stat_h;
+
+public class HelloFileSystem extends StubFuseFileSystem {
+
+ private static final int S_IFDIR = 0040000;
+ private static final int S_IFREG = 0100000;
+
+ private static final Logger LOG = LoggerFactory.getLogger(HelloFileSystem.class);
+
+ public static final String HELLO_PATH = "/hello";
+ public static final String HELLO_STR = "Hello World!";
+
+ public static void main(String[] args) throws IOException {
+ Path mountPoint = Files.createTempDirectory("mnt");
+ LOG.info("mounting at {}. Unmount to terminate this process.", mountPoint);
+ Fuse.mount(new HelloFileSystem(), mountPoint.toString(), false);
+ }
+
+ @Override
+ public int getattr(Pointer path, Pointer buf) {
+ String p = Pointer.toString(path);
+ LOG.debug("getattr() {}", p);
+ if ("/".equals(p)) {
+ buf.get().st_mode$set((short) (S_IFDIR | 0755));
+ buf.get().st_nlink$set((short) 2);
+ return 0;
+ } else if (HELLO_PATH.equals(p)) {
+ buf.get().st_mode$set((short) (S_IFREG | 0444));
+ buf.get().st_nlink$set((short) 1);
+ buf.get().st_size$set(HELLO_STR.getBytes().length);
+ return 0;
+ } else {
+ return -Errno.ENOENT;
+ }
+ }
+
+ @Override
+ public int readdir(Pointer path, Pointer> buf, Callback filler, long offset, Pointer fi) {
+ String p = Pointer.toString(path);
+ LOG.debug("readdir() {}", p);
+ try (Scope scope = fi.scope().fork()) {
+ filler.asFunction().fn(buf, scope.allocateCString("."), Pointer.ofNull(), 0);
+ filler.asFunction().fn(buf, scope.allocateCString(".."), Pointer.ofNull(), 0);
+ filler.asFunction().fn(buf, scope.allocateCString(HELLO_PATH.substring(1)), Pointer.ofNull(), 0);
+ return 0;
+ }
+ }
+
+ @Override
+ public int open(Pointer path, Pointer fi) {
+ String p = Pointer.toString(path);
+ LOG.debug("open() {}", p);
+ if (!HELLO_PATH.equals(p)) {
+ return -Errno.ENOENT;
+ }
+ return 0;
+ }
+
+ @Override
+ public int read(Pointer path, Pointer buf, long size, long offset, Pointer fi) {
+ String p = Pointer.toString(path);
+ LOG.debug("read() {}", p);
+ if (!HELLO_PATH.equals(p)) {
+ return -Errno.ENOENT;
+ }
+
+ ByteBuffer content = StandardCharsets.UTF_8.encode(HELLO_STR);
+ content.position((int) Math.min(content.capacity(), offset));
+ long numBytes = Math.min(size, content.remaining());
+
+ Pointer.copy(Pointer.fromByteBuffer(content), buf, numBytes);
+
+ return (int) numBytes;
+ }
+
+}
diff --git a/ffi/pom.xml b/ffi/pom.xml
new file mode 100644
index 00000000..c8f9f6e1
--- /dev/null
+++ b/ffi/pom.xml
@@ -0,0 +1,103 @@
+
+
+
+ fuse-panama
+ de.skymatic
+ 0.1.0-SNAPSHOT
+
+ 4.0.0
+ fuse-panama-ffi
+ pom
+
+
+
+ macos
+
+
+ mac
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+
+ exec
+
+ process-resources
+
+ ${java.home}/bin/jextract
+ ${project.basedir}
+
+ -L
+ /usr/local/lib
+ -l
+ osxfuse
+ -o
+ fuse.jar
+ -t
+ com.github.libfuse
+ -C-D_FILE_OFFSET_BITS=64
+ -C-DFUSE_USE_VERSION=29
+ ${project.basedir}/../libfuse/include/fuse.h
+
+
+
+
+
+
+
+
+
+
+ linux
+
+
+ unix
+ Linux
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+
+ exec
+
+ process-resources
+
+ ${java.home}/bin/jextract
+ ${project.basedir}
+
+ -L
+ /usr/local/lib
+ -l
+ fuse
+ -o
+ fuse.jar
+ -t
+ com.github.libfuse
+ -C-D_FILE_OFFSET_BITS=64
+ -C-DFUSE_USE_VERSION=29
+ ${project.basedir}/../libfuse/include/fuse.h
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libfuse b/libfuse
new file mode 160000
index 00000000..df499bf1
--- /dev/null
+++ b/libfuse
@@ -0,0 +1 @@
+Subproject commit df499bf1ce634f6e67d4d366c4475d32143f00f0
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..13450d94
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,51 @@
+
+
+ 4.0.0
+ de.skymatic
+ fuse-panama
+ pom
+ 0.1.0-SNAPSHOT
+
+
+
+ generate-libfuse
+
+
+ ffi/fuse.jar
+
+
+
+ ffi
+
+
+
+ default
+
+
+ ffi/fuse.jar
+
+
+
+ bindings
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 14
+ UTF-8
+ true
+
+
+
+
+
+
\ No newline at end of file