From 00e03b53403bbaec08d3b4ab9e424855752c2d65 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Thu, 21 Nov 2019 21:50:59 +0000
Subject: First cut migration to fuse3

---
 Jamroot.jam                       |   3 +-
 netfs/fuse/Jamfile.jam            |   2 +
 netfs/fuse/fuseApp.cpp            |   2 +-
 netfs/fuse/fuseApp.h              |  18 +++--
 netfs/fuse/fuseAppBase.cpp        |  34 +++++-----
 netfs/fuse/fuseAppBase.h          |  47 +++++--------
 netfs/fuse/fuseDirs.cpp           |   8 +--
 netfs/fuse/fuseFiles.cpp          |  46 +++++++------
 netfs/fuse/fuseMisc.cpp           |  26 ++------
 netfs/unittests/mockFuse.cpp      |   2 +-
 netfs/unittests/testCore.cpp      | 134 +++++++++++++++++++-------------------
 netfs/unittests/testEdgeCases.cpp |   6 +-
 netfs/unittests/testFuse.cpp      |  11 +---
 13 files changed, 153 insertions(+), 186 deletions(-)

diff --git a/Jamroot.jam b/Jamroot.jam
index 7c6a0bd..21faf95 100644
--- a/Jamroot.jam
+++ b/Jamroot.jam
@@ -10,7 +10,6 @@ variant coverage : debug ;
 project
   : requirements
 			<define>ICE_CPP11_MAPPING
-			<define>_FILE_OFFSET_BITS=64
 			<cxxstd>17
 			<visibility>hidden
       <linkflags>"-Wl,-z,defs,--warn-once,--gc-sections"
@@ -36,5 +35,5 @@ project
 build-project netfs ;
 
 pkg-config.import glibmm : : <name>glibmm-2.4 ;
-pkg-config.import fuse ;
+pkg-config.import fuse : : <name>fuse3 ;
 
diff --git a/netfs/fuse/Jamfile.jam b/netfs/fuse/Jamfile.jam
index 2f0f1af..b697a62 100644
--- a/netfs/fuse/Jamfile.jam
+++ b/netfs/fuse/Jamfile.jam
@@ -28,6 +28,7 @@ lib netfs-client :
 	netfs-client-configuration
 	[ glob *.cpp : fuseConfigImpl.cpp netfs.cpp ]
 	:
+	<define>FUSE_USE_VERSION=31
 	<implicit-dependency>../ice//netfs-api
 	<library>netfs-client-configuration
 	<implicit-dependency>netfs-client-configuration
@@ -41,6 +42,7 @@ lib netfs-client :
 	<library>..//slicer-xml
 	<use>../..//fuse
 	: :
+	<define>FUSE_USE_VERSION=31
 	<include>.
 	<library>../ice//netfs-api
 	<library>Glacier2
diff --git a/netfs/fuse/fuseApp.cpp b/netfs/fuse/fuseApp.cpp
index 1609280..1f628fa 100644
--- a/netfs/fuse/fuseApp.cpp
+++ b/netfs/fuse/fuseApp.cpp
@@ -66,7 +66,7 @@ NetFS::FuseApp::~FuseApp()
 }
 
 void *
-NetFS::FuseApp::init(struct fuse_conn_info *)
+NetFS::FuseApp::init(struct fuse_conn_info *, struct fuse_config *)
 {
 	BOOST_ASSERT(!ic);
 	ic = Ice::initialize(iceArgs);
diff --git a/netfs/fuse/fuseApp.h b/netfs/fuse/fuseApp.h
index 59fde20..d2b645e 100644
--- a/netfs/fuse/fuseApp.h
+++ b/netfs/fuse/fuseApp.h
@@ -53,7 +53,7 @@ namespace NetFS {
 			~FuseApp();
 
 			// lifecycle
-			void * init (struct fuse_conn_info * info) override;
+			void * init (struct fuse_conn_info * info, struct fuse_config * cfg) override;
 			static int opt_parse(void * data, const char * arg, int, struct fuse_args *);
 
 		protected:
@@ -66,21 +66,20 @@ namespace NetFS {
 		public:
 			// misc
 			int access(const char * p, int a) override;
-			int getattr(const char * p, struct stat * s) override;
-			int fgetattr(const char *, struct stat *, struct fuse_file_info *) override;
-			int chmod(const char *, mode_t) override;
-			int chown(const char *, uid_t, gid_t) override;
+			int getattr(const char *, struct stat *, struct fuse_file_info *) override;
+			int chmod(const char *, mode_t, struct fuse_file_info *) override;
+			int chown(const char *, uid_t, gid_t, struct fuse_file_info *) override;
 			int link(const char *, const char *) override;
 			int readlink(const char *, char *, size_t) override;
-			int rename(const char *, const char *) override;
+			int rename(const char *, const char *, unsigned int) override;
 			int symlink(const char *, const char *) override;
 			int unlink(const char *) override;
-			int utimens(const char *, const struct timespec tv[2]) override;
+			int utimens(const char *, const struct timespec tv[2], struct fuse_file_info *) override;
 			int mknod(const char *, mode_t, dev_t) override;
 			// dirs
 			int opendir(const char * p, struct fuse_file_info * fi) override;
 			int releasedir(const char *, struct fuse_file_info * fi) override;
-			int readdir(const char *, void * buf, fuse_fill_dir_t filler, off_t, struct fuse_file_info * fi) override;
+			int readdir(const char *, void * buf, fuse_fill_dir_t filler, off_t, struct fuse_file_info * fi, enum fuse_readdir_flags) override;
 			int mkdir(const char *, mode_t) override;
 			int rmdir(const char *) override;
 			// files
@@ -90,8 +89,7 @@ namespace NetFS {
 			int release(const char *, struct fuse_file_info * fi) override;
 			int read(const char *, char * buf, size_t s, off_t o, struct fuse_file_info * fi) override;
 			int write(const char *, const char * buf, size_t s, off_t o, struct fuse_file_info * fi) override;
-			int truncate(const char *, off_t) override;
-			int ftruncate(const char *, off_t, struct fuse_file_info *) override;
+			int truncate(const char *, off_t, struct fuse_file_info *) override;
 			// fs
 			int statfs(const char *, struct statvfs *) override;
 			// stuff
diff --git a/netfs/fuse/fuseAppBase.cpp b/netfs/fuse/fuseAppBase.cpp
index 68bc170..4d06b44 100644
--- a/netfs/fuse/fuseAppBase.cpp
+++ b/netfs/fuse/fuseAppBase.cpp
@@ -27,7 +27,7 @@ FuseAppBase::~FuseAppBase()
 // to call them in a realistic manner. They exist only as the default
 // implementation of the function which is never passed to libfuse
 // unless it is overridden.
-void * FuseAppBase::init(fuse_conn_info*)
+void * FuseAppBase::init(fuse_conn_info*, fuse_config *)
 {
 	return nullptr;
 }
@@ -35,11 +35,11 @@ int FuseAppBase::access(const char *, int)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::chmod(const char *, mode_t)
+int FuseAppBase::chmod(const char *, mode_t, struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::chown(const char *, uid_t, gid_t)
+int FuseAppBase::chown(const char *, uid_t, gid_t, struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
@@ -47,7 +47,7 @@ int FuseAppBase::create(const char *, mode_t, struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::fgetattr(const char *, struct stat *, struct fuse_file_info *)
+int FuseAppBase::getattr(const char *, struct stat *, struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
@@ -63,11 +63,7 @@ int FuseAppBase::fsyncdir(const char *, int, struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::ftruncate(const char *, off_t, struct fuse_file_info *)
-{
-	return -ENOSYS;
-}
-int FuseAppBase::getattr(const char *, struct stat *)
+int FuseAppBase::truncate(const char *, off_t, struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
@@ -103,7 +99,7 @@ int FuseAppBase::read(const char *, char *, size_t, off_t, struct fuse_file_info
 {
 	return -ENOSYS;
 }
-int FuseAppBase::readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)
+int FuseAppBase::readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags)
 {
 	return -ENOSYS;
 }
@@ -123,7 +119,7 @@ int FuseAppBase::removexattr(const char *, const char *)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::rename(const char *, const char *)
+int FuseAppBase::rename(const char *, const char *, unsigned int)
 {
 	return -ENOSYS;
 }
@@ -143,10 +139,6 @@ int FuseAppBase::symlink(const char *, const char *)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::truncate(const char *, off_t)
-{
-	return -ENOSYS;
-}
 int FuseAppBase::unlink(const char *)
 {
 	return -ENOSYS;
@@ -160,7 +152,7 @@ int FuseAppBase::lock(const char *, struct fuse_file_info *, int, struct flock *
 	return -ENOSYS;
 }
 // NOLINTNEXTLINE(modernize-avoid-c-arrays, hicpp-avoid-c-arrays)
-int FuseAppBase::utimens(const char *, const struct timespec[2])
+int FuseAppBase::utimens(const char *, const struct timespec[2], struct fuse_file_info *)
 {
 	return -ENOSYS;
 }
@@ -168,7 +160,7 @@ int FuseAppBase::bmap(const char *, size_t, uint64_t *)
 {
 	return -ENOSYS;
 }
-int FuseAppBase::ioctl(const char *, int, void *, struct fuse_file_info *, unsigned int, void *)
+int FuseAppBase::ioctl(const char *, unsigned int, void *, struct fuse_file_info *, unsigned int, void *)
 {
 	return -ENOSYS;
 }
@@ -192,6 +184,14 @@ int FuseAppBase::fallocate(const char *, int, off_t, off_t, struct fuse_file_inf
 {
 	return -ENOSYS;
 }
+ssize_t FuseAppBase::copy_file_range(const char *, struct fuse_file_info *, off_t, const char *, struct fuse_file_info *, off_t, size_t, int)
+{
+	return -ENOSYS;
+}
+off_t FuseAppBase::lseek(const char *, off_t, int, struct fuse_file_info *)
+{
+	return -ENOSYS;
+}
 // LCOV_EXCL_STOP
 void FuseAppBase::log(int level, const char * message) const noexcept
 {
diff --git a/netfs/fuse/fuseAppBase.h b/netfs/fuse/fuseAppBase.h
index 44943b7..c73a476 100644
--- a/netfs/fuse/fuseAppBase.h
+++ b/netfs/fuse/fuseAppBase.h
@@ -1,7 +1,6 @@
 #ifndef FUSEAPP_H
 #define FUSEAPP_H
 
-#define FUSE_USE_VERSION 26
 #include <fuse.h>
 #include <typeinfo>
 #include <exception>
@@ -18,17 +17,16 @@ class DLL_PUBLIC FuseAppBase {
 		FuseAppBase();
 		virtual ~FuseAppBase();
 
-		virtual void * init (struct fuse_conn_info * info);
+		virtual void * init (struct fuse_conn_info * info, struct fuse_config * cfg);
 		virtual int access(const char *, int);
-		virtual int chmod(const char *, mode_t);
-		virtual int chown(const char *, uid_t, gid_t);
+		virtual int chmod(const char *, mode_t, struct fuse_file_info *);
+		virtual int chown(const char *, uid_t, gid_t, struct fuse_file_info *);
 		virtual int create(const char *, mode_t, struct fuse_file_info *);
-		virtual int fgetattr(const char *, struct stat *, struct fuse_file_info *);
+		virtual int getattr(const char *, struct stat *, struct fuse_file_info *);
 		virtual int flush(const char *, struct fuse_file_info *);
 		virtual int fsync(const char *, int, struct fuse_file_info *);
 		virtual int fsyncdir(const char *, int, struct fuse_file_info *);
-		virtual int ftruncate(const char *, off_t, struct fuse_file_info *);
-		virtual int getattr(const char *, struct stat *);
+		virtual int truncate(const char *, off_t, struct fuse_file_info *);
 		virtual int getxattr(const char *, const char *, char *, size_t);
 		virtual int link(const char *, const char *);
 		virtual int listxattr(const char *, char *, size_t);
@@ -37,28 +35,29 @@ class DLL_PUBLIC FuseAppBase {
 		virtual int open(const char *, struct fuse_file_info *);
 		virtual int opendir(const char *, struct fuse_file_info *);
 		virtual int read(const char *, char *, size_t, off_t, struct fuse_file_info *);
-		virtual int readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *);
+		virtual int readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags);
 		virtual int readlink(const char *, char *, size_t);
 		virtual int release(const char *, struct fuse_file_info *);
 		virtual int releasedir(const char *, struct fuse_file_info *);
 		virtual int removexattr(const char *, const char *);
-		virtual int rename(const char *, const char *);
+		virtual int rename(const char *, const char *, unsigned int);
 		virtual int rmdir(const char *);
 		virtual int setxattr(const char *, const char *, const char *, size_t, int);
 		virtual int statfs(const char *, struct statvfs *);
 		virtual int symlink(const char *, const char *);
-		virtual int truncate(const char *, off_t);
 		virtual int unlink(const char *);
 		virtual int write(const char *, const char *, size_t, off_t, struct fuse_file_info *);
 		virtual int lock(const char *, struct fuse_file_info *, int cmd, struct flock *);
-		virtual int utimens(const char *, const struct timespec tv[2]);
+		virtual int utimens(const char *, const struct timespec tv[2], struct fuse_file_info *);
 		virtual int bmap(const char *, size_t blocksize, uint64_t *idx);
-		virtual int ioctl(const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void * data);
+		virtual int ioctl(const char *, unsigned int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void * data);
 		virtual int poll(const char *, struct fuse_file_info *, struct fuse_pollhandle *, unsigned *);
 		virtual int write_buf(const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *);
 		virtual int read_buf(const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *);
 		virtual int flock(const char *, struct fuse_file_info *, int op);
 		virtual int fallocate(const char *, int, off_t, off_t, struct fuse_file_info *);
+		virtual ssize_t copy_file_range(const char *, struct fuse_file_info *, off_t, const char *, struct fuse_file_info *, off_t, size_t, int);
+		virtual off_t lseek(const char *, off_t off, int whence, struct fuse_file_info *);
 		virtual int onError(const std::exception & err) throw();
 		virtual void beforeOperation();
 		void log(int level, const char * message) const throw();
@@ -78,7 +77,6 @@ class FuseAppBaseT : public FuseAppBase {
 		FuseAppBaseT() : operations({
 				GetHelper(getattr),
 				GetHelper(readlink),
-				nullptr, // getdir deprecated
 				GetHelper(mknod),
 				GetHelper(mkdir),
 				GetHelper(unlink),
@@ -89,7 +87,6 @@ class FuseAppBaseT : public FuseAppBase {
 				GetHelper(chmod),
 				GetHelper(chown),
 				GetHelper(truncate),
-				nullptr, // utime deprecated
 				GetHelper(open),
 				GetHelper(read),
 				GetHelper(write),
@@ -109,29 +106,17 @@ class FuseAppBaseT : public FuseAppBase {
 				nullptr, //fuseDestroy
 				GetHelper(access),
 				GetHelper(create),
-				GetHelper(ftruncate),
-				GetHelper(fgetattr),
-#if (FUSE_MINOR_VERSION >= 6)
 				GetHelper(lock),
 				GetHelper(utimens),
 				GetHelper(bmap),
-#if (FUSE_MINOR_VERSION >= 8)
-				0, // flag_nullpath_ok
-#if (FUSE_MINOR_VERSION >= 9)
-				0, // flag_nopath
-				0, // flag_utime_omit_ok
-#endif
-				0, // flag_reserved
 				GetHelper(ioctl),
 				GetHelper(poll),
-#if (FUSE_MINOR_VERSION >= 9)
 				GetHelper(write_buf),
 				GetHelper(read_buf),
 				GetHelper(flock),
 				GetHelper(fallocate),
-#endif
-#endif
-#endif
+				GetHelper(copy_file_range),
+				GetHelper(lseek),
 			})
 		{
 		}
@@ -151,11 +136,11 @@ class FuseAppBaseT : public FuseAppBase {
 			}
 			return nullptr;
 		}
-		template <typename BFunc, typename IFunc, BFunc bfunc, typename ... Args>
-		constexpr static auto getHelper(int(FuseAppBase::*)(Args...)) -> int(*)(Args...)
+		template <typename BFunc, typename IFunc, BFunc bfunc, typename Rtn, typename ... Args>
+		constexpr static auto getHelper(Rtn(FuseAppBase::*)(Args...)) -> Rtn(*)(Args...)
 		{
 			if constexpr (!std::is_same<BFunc, IFunc>::value) {
-				return [](Args ... a) {
+				return [](Args ... a) -> Rtn {
 					for (int t = 0; ; ++t) {
 						try {
 							fuseApp->beforeOperation();
diff --git a/netfs/fuse/fuseDirs.cpp b/netfs/fuse/fuseDirs.cpp
index 5091d39..490a4bb 100644
--- a/netfs/fuse/fuseDirs.cpp
+++ b/netfs/fuse/fuseDirs.cpp
@@ -46,15 +46,15 @@ FuseApp::releasedir(const char *, struct fuse_file_info * fi)
 }
 
 int
-FuseApp::readdir(const char * p, void * buf, fuse_fill_dir_t filler, off_t, struct fuse_file_info * fi)
+FuseApp::readdir(const char * p, void * buf, fuse_fill_dir_t filler, off_t, struct fuse_file_info * fi, enum fuse_readdir_flags flags)
 {
 	try {
 		auto od = getProxy<OpenDirPtr>(fi->fh);
 		std::string path(p);
 		auto expiry = time(nullptr) + 2;
-		if (fcr->ListDir && od->remoteV2) {
+		if (flags == FUSE_READDIR_PLUS && fcr->ListDir && od->remoteV2) {
 			for (const auto & e : od->remoteV2->listdir()) {
-				filler(buf, e.first.c_str(), nullptr, 0);
+				filler(buf, e.first.c_str(), nullptr, 0, FUSE_FILL_DIR_PLUS);
 				std::string k(path + e.first);
 				statCache.remove(k);
 				statCache.add(k, converter.convert(e.second), expiry);
@@ -62,7 +62,7 @@ FuseApp::readdir(const char * p, void * buf, fuse_fill_dir_t filler, off_t, stru
 		}
 		else {
 			for (const auto & e : od->remote->readdir()) {
-				filler(buf, e.c_str(), nullptr, 0);
+				filler(buf, e.c_str(), nullptr, 0, (fuse_fill_dir_flags)0);
 			}
 		}
 		return 0;
diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp
index 4ea7f47..c166e46 100644
--- a/netfs/fuse/fuseFiles.cpp
+++ b/netfs/fuse/fuseFiles.cpp
@@ -205,10 +205,18 @@ FuseApp::write(const char *, const char * buf, size_t s, off_t o, struct fuse_fi
 }
 
 int
-FuseApp::truncate(const char * p, off_t o)
+FuseApp::truncate(const char * p, off_t o, fuse_file_info * fi)
 {
 	try {
-		volume->truncate(reqEnv(), p, o);
+		if (fi) {
+			auto of = getProxy<OpenFilePtr>(fi->fh);
+			of->wait();
+			auto remote = of->remote;
+			remote->ftruncate(reqEnv(), o);
+		}
+		else {
+			volume->truncate(reqEnv(), p, o);
+		}
 		return 0;
 	}
 	catch (SystemError & e) {
@@ -217,28 +225,24 @@ FuseApp::truncate(const char * p, off_t o)
 }
 
 int
-FuseApp::ftruncate(const char *, off_t o, fuse_file_info * fi)
+FuseApp::getattr(const char * p, struct stat * s, fuse_file_info * fi)
 {
 	try {
-		auto of = getProxy<OpenFilePtr>(fi->fh);
-		of->wait();
-		auto remote = of->remote;
-		remote->ftruncate(reqEnv(), o);
-		return 0;
-	}
-	catch (SystemError & e) {
-		return -e.syserrno;
-	}
-}
+		if (fi) {
+			auto of = getProxy<OpenFilePtr>(fi->fh);
+			of->wait();
+			auto remote = of->remote;
+			*s = converter.convert(remote->fgetattr(reqEnv()));
+		}
+		else {
+			if (auto cacehedStat = statCache.get(p)) {
+				*s = *cacehedStat;
+			}
+			else {
+				*s = converter.convert(volume->getattr(reqEnv(), p));
+			}
 
-int
-FuseApp::fgetattr(const char *, struct stat * s, fuse_file_info * fi)
-{
-	try {
-		auto of = getProxy<OpenFilePtr>(fi->fh);
-		of->wait();
-		auto remote = of->remote;
-		*s = converter.convert(remote->fgetattr(reqEnv()));
+		}
 		return 0;
 	}
 	catch (SystemError & e) {
diff --git a/netfs/fuse/fuseMisc.cpp b/netfs/fuse/fuseMisc.cpp
index f46b2fe..6703fa7 100644
--- a/netfs/fuse/fuseMisc.cpp
+++ b/netfs/fuse/fuseMisc.cpp
@@ -9,24 +9,7 @@ NetFS::FuseApp::access(const char * p, int a)
 }
 
 int
-NetFS::FuseApp::getattr(const char * p, struct stat * s)
-{
-	try {
-		if (auto cacehedStat = statCache.get(p)) {
-			*s = *cacehedStat;
-		}
-		else {
-			*s = converter.convert(volume->getattr(reqEnv(), p));
-		}
-		return 0;
-	}
-	catch (NetFS::SystemError & e) {
-		return -e.syserrno;
-	}
-}
-
-int
-NetFS::FuseApp::chmod(const char * p, mode_t m)
+NetFS::FuseApp::chmod(const char * p, mode_t m, fuse_file_info *)
 {
 	try {
 		volume->chmod(reqEnv(), p, m);
@@ -38,7 +21,7 @@ NetFS::FuseApp::chmod(const char * p, mode_t m)
 }
 
 int
-NetFS::FuseApp::chown(const char * p, uid_t u, gid_t g)
+NetFS::FuseApp::chown(const char * p, uid_t u, gid_t g, fuse_file_info *)
 {
 	try {
 		volume->chown(reqEnv(), p, u, g);
@@ -100,9 +83,10 @@ NetFS::FuseApp::readlink(const char * p, char * p2, size_t s)
 }
 
 int
-NetFS::FuseApp::rename(const char * p1, const char * p2)
+NetFS::FuseApp::rename(const char * p1, const char * p2, unsigned int)
 {
 	try {
+		// TODO flags
 		volume->rename(reqEnv(), p1, p2);
 		return 0;
 	}
@@ -113,7 +97,7 @@ NetFS::FuseApp::rename(const char * p1, const char * p2)
 
 int
 // NOLINTNEXTLINE(modernize-avoid-c-arrays,hicpp-avoid-c-arrays)
-NetFS::FuseApp::utimens(const char * path, const struct timespec times[2])
+NetFS::FuseApp::utimens(const char * path, const struct timespec times[2], fuse_file_info *)
 {
 	try {
 		volume->utimens(reqEnv(), path,
diff --git a/netfs/unittests/mockFuse.cpp b/netfs/unittests/mockFuse.cpp
index b00c4c2..1b88027 100644
--- a/netfs/unittests/mockFuse.cpp
+++ b/netfs/unittests/mockFuse.cpp
@@ -46,7 +46,7 @@ FuseMockHost::FuseMockHost(std::string ep, const Ice::StringSeq & a) :
 	fuse(&app->operations)
 {
 	if (app->operations.init) {
-		app->operations.init(nullptr);
+		app->operations.init(nullptr, nullptr);
 	}
 }
 
diff --git a/netfs/unittests/testCore.cpp b/netfs/unittests/testCore.cpp
index 9c83d8a..2cc4110 100644
--- a/netfs/unittests/testCore.cpp
+++ b/netfs/unittests/testCore.cpp
@@ -68,7 +68,7 @@ class Core {
 
 		static
 		int
-		nameListAdd(void *buf, const char *name, const struct stat *, off_t)
+		nameListAdd(void *buf, const char *name, const struct stat *, off_t, fuse_fill_dir_flags)
 		{
 			static_cast<NetFS::NameList *>(buf)->push_back(name);
 			return 0;
@@ -96,8 +96,8 @@ BOOST_AUTO_TEST_CASE(fuse_operations_correct)
 {
 	// open should be defined
 	BOOST_REQUIRE(fuse->open);
-	// getdir should not be defined (Not supported)
-	BOOST_REQUIRE(!fuse->getdir);
+	// bmap should not be defined (Not supported)
+	BOOST_REQUIRE(!fuse->bmap);
 	// fsync should not be defined (Not implemented)
 	BOOST_REQUIRE(!fuse->fsync);
 }
@@ -131,25 +131,25 @@ BOOST_AUTO_TEST_CASE( testNavigation )
 	BOOST_REQUIRE(std::filesystem::exists(binDir / testExport / "inside"));
 	BOOST_REQUIRE_EQUAL(lstat((binDir / testExport).c_str(), &rootattr), 0);
 	BOOST_REQUIRE_EQUAL(lstat((binDir / testExport / "inside").c_str(), &insideattr), 0);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, rootattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr(".", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr(".", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, rootattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, rootattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/.", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/.", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, rootattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside/..", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside/..", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, rootattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("//inside/./..", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("//inside/./..", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, rootattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, insideattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside/", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside/", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, insideattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/anything/../inside", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/anything/../inside", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, insideattr);
-	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside/../inside", &attr));
+	BOOST_REQUIRE_EQUAL(0, fuse->getattr("/inside/../inside", &attr, nullptr));
 	BOOST_REQUIRE_EQUAL(attr, insideattr);
 }
 
@@ -184,8 +184,8 @@ void
 enableWriteOnDir(const fuse_operations * fuse, const char * dir)
 {
 	struct stat st {};
-	BOOST_REQUIRE_EQUAL(fuse->chmod(dir, 0700), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr(dir, &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->chmod(dir, 0700, nullptr), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr(dir, &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0700 | S_IFDIR);
 }
 
@@ -193,8 +193,8 @@ void
 disableWriteOnDir(const fuse_operations * fuse, const char * dir)
 {
 	struct stat st {};
-	BOOST_REQUIRE_EQUAL(fuse->chmod(dir, 0500), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr(dir, &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->chmod(dir, 0500, nullptr), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr(dir, &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0500 | S_IFDIR);
 }
 
@@ -205,23 +205,23 @@ BOOST_AUTO_TEST_CASE( directories )
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/test", 0700), 0);
 	BOOST_REQUIRE(std::filesystem::is_directory(binDir / testExport / "test"));
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/test", 0700), -EEXIST);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), 0);
 
 	BOOST_REQUIRE_EQUAL(fuse->opendir("/test", &fi), 0);
 	NetFS::NameList nl;
-	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi, FUSE_READDIR_PLUS), 0);
 	BOOST_REQUIRE_EQUAL(nl.size(), 2);
 	std::sort(nl.begin(), nl.end());
 	BOOST_REQUIRE_EQUAL(nl[0], ".");
 	BOOST_REQUIRE_EQUAL(nl[1], "..");
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test/.", &st), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test/..", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test/.", &st, nullptr), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test/..", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(fuse->releasedir("/test", &fi), 0);
 	nl.clear();
 
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/test/sub", 0700), 0);
 	BOOST_REQUIRE_EQUAL(fuse->opendir("/test", &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi, FUSE_READDIR_PLUS), 0);
 	BOOST_REQUIRE_EQUAL(nl.size(), 3);
 	std::sort(nl.begin(), nl.end());
 	BOOST_REQUIRE_EQUAL(nl[0], ".");
@@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE( directories )
 	BOOST_REQUIRE_EQUAL(fuse->releasedir("/test", &fi), 0);
 	nl.clear();
 
-	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi), -EBADF);
+	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi, FUSE_READDIR_PLUS), -EBADF);
 	BOOST_REQUIRE_EQUAL(fuse->releasedir("/test", &fi), -EBADF);
 
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/test"), -ENOTEMPTY);
@@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE( directories )
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/test"), 0);
 	BOOST_REQUIRE(!std::filesystem::is_directory(binDir / testExport / "test"));
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/test"), -ENOENT);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), -ENOENT);
 	BOOST_REQUIRE_EQUAL(fuse->opendir("/test", &fi), -ENOENT);
 }
 
@@ -256,30 +256,30 @@ BOOST_AUTO_TEST_CASE( files )
 	BOOST_REQUIRE_EQUAL(fuse->open("/test", &fi), 0);
 	BOOST_REQUIRE_EQUAL(fuse->write("/test", "some test buffer", 16, 0, &fi), 16);
 	BOOST_REQUIRE_EQUAL(fuse->flush("/test", &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_size, 16);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st), -ENOENT);
-	BOOST_REQUIRE_EQUAL(fuse->rename("/test", "/test2"), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), -ENOENT);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st2), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st, nullptr), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->rename("/test", "/test2", RENAME_EXCHANGE), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st2, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st, st2);
-	BOOST_REQUIRE_EQUAL(fuse->fgetattr("/test2", &st2, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st2, &fi), 0);
 	BOOST_REQUIRE_EQUAL(st, st2);
 	BOOST_REQUIRE_EQUAL(st2.st_size, 16);
 	BOOST_REQUIRE_EQUAL(fuse->write("/test2", "BUFFER some", 11, 10, &fi), 11);
-	BOOST_REQUIRE_EQUAL(fuse->fgetattr("/test2", &st2, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st2, &fi), 0);
 	BOOST_REQUIRE_EQUAL(st2.st_size, 21);
 	std::array<char, 11> buf {};
 	BOOST_REQUIRE_EQUAL(fuse->read("/test2", buf.data(), 10, 5, &fi), 10);
 	BOOST_REQUIRE_EQUAL(buf, "test BUFFE");
-	BOOST_REQUIRE_EQUAL(fuse->ftruncate("/test2", 11, &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->fgetattr("/test2", &st2, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->truncate("/test2", 11, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st2, &fi), 0);
 	BOOST_REQUIRE_EQUAL(st2.st_size, 11);
 	buf = {};
 	BOOST_REQUIRE_EQUAL(fuse->read("/test2", buf.data(), 10, 5, &fi), 6);
 	BOOST_REQUIRE_EQUAL(buf, "test B");
-	BOOST_REQUIRE_EQUAL(fuse->truncate("/test2", 7), 0);
-	BOOST_REQUIRE_EQUAL(fuse->fgetattr("/test2", &st2, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->truncate("/test2", 7, nullptr), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st2, &fi), 0);
 	BOOST_REQUIRE_EQUAL(st2.st_size, 7);
 	buf = {};
 	BOOST_REQUIRE_EQUAL(fuse->read("/test2", buf.data(), 10, 5, &fi), 2);
@@ -288,8 +288,8 @@ BOOST_AUTO_TEST_CASE( files )
 
 	BOOST_REQUIRE_EQUAL(fuse->link("/test3", "/test2"), -ENOENT);
 	BOOST_REQUIRE_EQUAL(fuse->link("/test2", "/test3"), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test3", &st2), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test2", &st, nullptr), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test3", &st2, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st, st2);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/test2"), 0);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/test2"), -ENOENT);
@@ -308,13 +308,13 @@ BOOST_AUTO_TEST_CASE( bgwriteOverlapped, * boost::unit_test::timeout(2) )
 	for (int32_t n = 0; n < N; n += 1) {
 		BOOST_REQUIRE_EQUAL(fuse->write("/test", (const char *)(&n), s, n, &fi), s);
 	}
-	BOOST_REQUIRE_EQUAL(fuse->fgetattr("/test", &st, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, &fi), 0);
 	BOOST_REQUIRE_EQUAL(st.st_size, N + s - 1);
 	std::array<char, s> buf;
 	BOOST_REQUIRE_EQUAL(fuse->read("/test", buf.data(), s, (N - 1), &fi), s);
 	BOOST_REQUIRE_EQUAL(*(int*)buf.data(), N - 1);
 	BOOST_REQUIRE_EQUAL(fuse->release("/test", &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_size, N + s - 1);
 }
 
@@ -329,13 +329,13 @@ BOOST_AUTO_TEST_CASE( bgwriteDistinct, * boost::unit_test::timeout(2) )
 	for (int32_t n = 0; n < N; n += 1) {
 		BOOST_REQUIRE_EQUAL(fuse->write("/test", (const char *)(&n), s, n * s, &fi), s);
 	}
-	BOOST_REQUIRE_EQUAL(fuse->fgetattr("/test", &st, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, &fi), 0);
 	BOOST_REQUIRE_EQUAL(st.st_size, N * s);
 	std::array<char, s> buf;
 	BOOST_REQUIRE_EQUAL(fuse->read("/test", buf.data(), s, (N - 1) * s, &fi), s);
 	BOOST_REQUIRE_EQUAL(*(int*)buf.data(), N - 1);
 	BOOST_REQUIRE_EQUAL(fuse->release("/test", &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_size, N * s);
 }
 
@@ -362,15 +362,15 @@ BOOST_AUTO_TEST_CASE( access )
 	BOOST_REQUIRE_EQUAL(fuse->access("/missing", F_OK), -ENOENT);
 	// Basic assertions
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir", 0700), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0700 | S_IFDIR);
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", F_OK), 0);
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", R_OK), 0);
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", W_OK), 0);
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", X_OK), 0);
-	BOOST_REQUIRE_EQUAL(fuse->chmod("/missing", 0000), -ENOENT);
-	BOOST_REQUIRE_EQUAL(fuse->chmod("/dir", 0000), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->chmod("/missing", 0000, nullptr), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->chmod("/dir", 0000, nullptr), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0000 | S_IFDIR);
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", F_OK), 0);
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", R_OK), -EACCES);
@@ -378,7 +378,7 @@ BOOST_AUTO_TEST_CASE( access )
 	BOOST_REQUIRE_EQUAL(fuse->access("/dir", X_OK), -EACCES);
 	enableWriteOnDir(fuse, "/dir");
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/dir"), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st, nullptr), -ENOENT);
 }
 
 BOOST_AUTO_TEST_CASE( permissionsDirs )
@@ -386,15 +386,15 @@ BOOST_AUTO_TEST_CASE( permissionsDirs )
 	struct stat st {};
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir", 0700), 0);
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir/yes", 0000), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0000 | S_IFDIR);
 	disableWriteOnDir(fuse, "/dir");
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir/no", 0700), -EACCES);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/no", &st), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/no", &st, nullptr), -ENOENT);
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/dir/yes"), -EACCES);
 	enableWriteOnDir(fuse, "/dir");
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/dir/yes"), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st, nullptr), -ENOENT);
 }
 
 BOOST_AUTO_TEST_CASE( permissionsFiles )
@@ -405,15 +405,15 @@ BOOST_AUTO_TEST_CASE( permissionsFiles )
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir", 0700), 0);
 	BOOST_REQUIRE_NE(fuse->create("/dir/yes", 0000, &fi), -1);
 	BOOST_REQUIRE_EQUAL(fuse->release("/dir/yes", &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0000 | S_IFREG);
 	disableWriteOnDir(fuse, "/dir");
 	BOOST_REQUIRE_EQUAL(fuse->create("/dir/no", 0600, &fi), -EACCES);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/no", &st), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/no", &st, nullptr), -ENOENT);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/dir/yes"), -EACCES);
 	enableWriteOnDir(fuse, "/dir");
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/dir/yes"), 0);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st), -ENOENT);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir/yes", &st, nullptr), -ENOENT);
 }
 
 BOOST_AUTO_TEST_CASE( mknod )
@@ -421,7 +421,7 @@ BOOST_AUTO_TEST_CASE( mknod )
 	BOOST_REQUIRE_EQUAL(fuse->mknod("/nod", 0600 | S_IFIFO, 0), 0);
 	BOOST_REQUIRE_EQUAL(fuse->mknod("/nod", 0600 | S_IFIFO, 0), -EEXIST);
 	struct stat st {};
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/nod", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/nod", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_mode, 0600 | S_IFIFO);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/nod"), 0);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/nod"), -ENOENT);
@@ -436,14 +436,14 @@ BOOST_AUTO_TEST_CASE( renameToDir )
 	BOOST_REQUIRE_EQUAL(fuse->create("/file", 0600, &fi), 0);
 	BOOST_REQUIRE_EQUAL(fuse->release("/file", &fi), 0);
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir", 0700), 0);
-	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir"), -EISDIR);
+	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir", RENAME_EXCHANGE), -EISDIR);
 	disableWriteOnDir(fuse, "/dir");
-	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir/file"), -EACCES);
+	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir/file", RENAME_EXCHANGE), -EACCES);
 	enableWriteOnDir(fuse, "/dir");
 	disableWriteOnDir(fuse, "/");
-	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir/file"), -EACCES);
+	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir/file", RENAME_EXCHANGE), -EACCES);
 	enableWriteOnDir(fuse, "/");
-	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir/file"), 0);
+	BOOST_REQUIRE_EQUAL(fuse->rename("/file", "/dir/file", RENAME_EXCHANGE), 0);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/file"), -ENOENT);
 	BOOST_REQUIRE_EQUAL(fuse->unlink("/dir/file"), 0);
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/dir"), 0);
@@ -452,12 +452,12 @@ BOOST_AUTO_TEST_CASE( renameToDir )
 BOOST_AUTO_TEST_CASE( chown )
 {
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/dir", 0777), 0);
-	BOOST_REQUIRE_EQUAL(fuse->chown("/dir", getuid(), getgid()), 0);
+	BOOST_REQUIRE_EQUAL(fuse->chown("/dir", getuid(), getgid(), nullptr), 0);
 	struct stat st {};
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/dir", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_uid, getuid());
 	BOOST_REQUIRE_EQUAL(st.st_gid, getgid());
-	BOOST_REQUIRE_EQUAL(fuse->chown("/dir", -2, getgid()), -EPERM);
+	BOOST_REQUIRE_EQUAL(fuse->chown("/dir", -2, getgid(), nullptr), -EPERM);
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/dir"), 0);
 }
 
@@ -465,11 +465,11 @@ BOOST_AUTO_TEST_CASE( utimens )
 {
 	BOOST_REQUIRE_EQUAL(fuse->mknod("/file", 0600, 0), 0);
 	std::array<timespec, 2> times { { {1, 100}, { 2, 200 } } };
-	BOOST_REQUIRE_EQUAL(fuse->utimens("/file", times.data()), 0);
+	BOOST_REQUIRE_EQUAL(fuse->utimens("/file", times.data(), nullptr), 0);
 	times[1].tv_nsec = -200;
-	BOOST_REQUIRE_EQUAL(fuse->utimens("/file", times.data()), -EINVAL);
+	BOOST_REQUIRE_EQUAL(fuse->utimens("/file", times.data(), nullptr), -EINVAL);
 	struct stat st {};
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/file", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/file", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_atime, 1);
 	BOOST_REQUIRE_EQUAL(st.st_atim.tv_sec, 1);
 	BOOST_REQUIRE_EQUAL(st.st_mtime, 2);
@@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE( noListDir )
 
 	BOOST_REQUIRE_EQUAL(fuse->opendir("/test", &fi), 0);
 	NetFS::NameList nl;
-	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi, FUSE_READDIR_PLUS), 0);
 	BOOST_REQUIRE_EQUAL(nl.size(), 2);
 	std::sort(nl.begin(), nl.end());
 	BOOST_REQUIRE_EQUAL(nl[0], ".");
@@ -511,7 +511,7 @@ BOOST_AUTO_TEST_CASE( noListDir )
 
 	BOOST_REQUIRE_EQUAL(fuse->mkdir("/test/sub", 0700), 0);
 	BOOST_REQUIRE_EQUAL(fuse->opendir("/test", &fi), 0);
-	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi), 0);
+	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi, FUSE_READDIR_PLUS), 0);
 	BOOST_REQUIRE_EQUAL(nl.size(), 3);
 	std::sort(nl.begin(), nl.end());
 	BOOST_REQUIRE_EQUAL(nl[0], ".");
@@ -520,7 +520,7 @@ BOOST_AUTO_TEST_CASE( noListDir )
 	BOOST_REQUIRE_EQUAL(fuse->releasedir("/test", &fi), 0);
 	nl.clear();
 
-	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi), -EBADF);
+	BOOST_REQUIRE_EQUAL(fuse->readdir("/test", &nl, &nameListAdd, 0, &fi, FUSE_READDIR_PLUS), -EBADF);
 	BOOST_REQUIRE_EQUAL(fuse->releasedir("/test", &fi), -EBADF);
 
 	BOOST_REQUIRE_EQUAL(fuse->rmdir("/test"), -ENOTEMPTY);
@@ -538,7 +538,7 @@ BOOST_AUTO_TEST_CASE( testFGWrites )
 	fi.flags = O_RDWR;
 	BOOST_REQUIRE_EQUAL(fuse->create("/test", 0600, &fi), 0);
 	BOOST_REQUIRE_EQUAL(fuse->write("/test", "some test buffer", 16, 0, &fi), 16);
-	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st), 0);
+	BOOST_REQUIRE_EQUAL(fuse->getattr("/test", &st, nullptr), 0);
 	BOOST_REQUIRE_EQUAL(st.st_size, 16);
 	std::array<char, 11> buf {};
 	BOOST_REQUIRE_EQUAL(fuse->read("/test", buf.data(), 10, 5, &fi), 10);
diff --git a/netfs/unittests/testEdgeCases.cpp b/netfs/unittests/testEdgeCases.cpp
index 37a40b6..2c5aef6 100644
--- a/netfs/unittests/testEdgeCases.cpp
+++ b/netfs/unittests/testEdgeCases.cpp
@@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE ( createAndDaemonRestart )
 
 	BOOST_TEST_CHECKPOINT("Fetch file attributes");
 	struct stat st {};
-	BOOST_REQUIRE_EQUAL(0, fuse.fuse->fgetattr(fileName, &st, &fh));
+	BOOST_REQUIRE_EQUAL(0, fuse.fuse->getattr(fileName, &st, &fh));
 	BOOST_REQUIRE_EQUAL(st.st_size, 0);
 	BOOST_REQUIRE_EQUAL(st.st_uid, getuid());
 	BOOST_REQUIRE_EQUAL(st.st_gid, getgid());
@@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE ( createAndDaemonRestart )
 	}
 	BOOST_REQUIRE_EQUAL(sizeof(someData), fuse.fuse->write(fileName, someData.data(), someData.size(), 0, &fh));
 
-	BOOST_REQUIRE_EQUAL(0, fuse.fuse->fgetattr(fileName, &st, &fh));
+	BOOST_REQUIRE_EQUAL(0, fuse.fuse->getattr(fileName, &st, &fh));
 	BOOST_REQUIRE_EQUAL(st.st_size, sizeof(someData));
 	BOOST_REQUIRE_EQUAL(0, fuse.fuse->flush(fileName, &fh));
 
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE ( createAndDaemonRestart )
 	daemon.restart();
 
 	BOOST_TEST_CHECKPOINT("Fetch file attributes again");
-	BOOST_REQUIRE_EQUAL(0, fuse.fuse->fgetattr(fileName, &st, &fh));
+	BOOST_REQUIRE_EQUAL(0, fuse.fuse->getattr(fileName, &st, &fh));
 
 	BOOST_TEST_CHECKPOINT("Close file");
 	BOOST_REQUIRE_EQUAL(0, fuse.fuse->release(fileName, &fh));
diff --git a/netfs/unittests/testFuse.cpp b/netfs/unittests/testFuse.cpp
index 2abe1f2..5d97642 100644
--- a/netfs/unittests/testFuse.cpp
+++ b/netfs/unittests/testFuse.cpp
@@ -1,5 +1,4 @@
 #define BOOST_TEST_MODULE TestNetFSFuse
-#define FUSE_USE_VERSION 26
 #include <boost/test/unit_test.hpp>
 #include <definedDirs.h>
 #include <filesystem>
@@ -28,18 +27,15 @@ class FuseMountPoint : public MockDaemonHost, public NetFS::FuseApp {
 			::fuse_opt_add_arg(&fargs, "-onoauto_cache");
 			::fuse_opt_add_arg(&fargs, "-oattr_timeout=0");
 			::fuse_opt_add_arg(&fargs, "-oac_attr_timeout=0");
-			ch = ::fuse_mount(mntpnt.c_str(), &fargs);
-			BOOST_REQUIRE(ch);
-			fs = ::fuse_new(ch, &fargs, &operations, sizeof(fuse_operations), this);
+			fs = ::fuse_new(&fargs, &operations, sizeof(fuse_operations), this);
 			BOOST_REQUIRE(fs);
+			BOOST_REQUIRE_EQUAL(0,::fuse_mount(fs, mntpnt.c_str()));
 			th = std::make_unique<std::thread>(::fuse_loop, fs);
 		}
 
 		~FuseMountPoint() override
 		{
-			if (ch) {
-				::fuse_unmount(mntpnt.c_str(), ch);
-			}
+			::fuse_unmount(fs);
 			if (th) {
 				th->join();
 			}
@@ -71,7 +67,6 @@ class FuseMountPoint : public MockDaemonHost, public NetFS::FuseApp {
 			BOOST_TEST_MESSAGE(msg.get());
 		}
 
-		struct fuse_chan * ch;
 		struct fuse * fs;
 		std::unique_ptr<std::thread> th;
 };
-- 
cgit v1.2.3