#pragma once #include #include #include #include #include #include #include #include #include #include class DLL_PUBLIC FuseAppBase { public: FuseAppBase(); SPECIAL_MEMBERS_DELETE(FuseAppBase); virtual ~FuseAppBase(); 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, 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 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 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); virtual int mkdir(const char *, mode_t); virtual int mknod(const char *, mode_t, dev_t); 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 *, 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 *, 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 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 *); // NOLINTNEXTLINE(hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 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 *, 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) noexcept; virtual void beforeOperation(); void log(int level, const char * message) const noexcept; void logf(int level, const char * fmt, ...) const noexcept __attribute__((__format__(__printf__, 3, 4))); virtual void vlogf(int level, const char * fmt, va_list) const noexcept __attribute__((__format__(__printf__, 3, 0))) = 0; mutable std::shared_mutex mutex; protected: static FuseAppBase * fuseApp; template constexpr static auto getInternalHelper() { if constexpr (Implemented) { return [](auto... a) { SharedLock(fuseApp->mutex); return (fuseApp->*bfunc)(a...); }; } else { return nullptr; } } template constexpr static auto getHelper() { if constexpr (Implemented) { return [](auto... a) { using Return = decltype((fuseApp->*bfunc)(a...)); for (int t = 0;; ++t) { try { fuseApp->beforeOperation(); SharedLock(fuseApp->mutex); return (fuseApp->*bfunc)(a...); } catch (const std::exception & ex) { if (t < 10) { if (Return rtn = fuseApp->onError(ex)) { return rtn; } } else { fuseApp->logf( LOG_ERR, "Retries expired with %s calling %s", ex.what(), typeid(bfunc).name()); return static_cast(-EIO); } } catch (...) { fuseApp->logf(LOG_ERR, "Unknown exception calling %s", typeid(bfunc).name()); return static_cast(-EIO); } } }; } else { return nullptr; } } }; template class FuseAppBaseT : public FuseAppBase { private: public: #define GetIntHelper(func) \ getInternalHelper, &FuseAppBase::func>() #define GetHelper(func) \ getHelper, &FuseAppBase::func>() constexpr const static fuse_operations operations { GetHelper(getattr), GetHelper(readlink), GetHelper(mknod), GetHelper(mkdir), GetHelper(unlink), GetHelper(rmdir), GetHelper(symlink), GetHelper(rename), GetHelper(link), GetHelper(chmod), GetHelper(chown), GetHelper(truncate), GetHelper(open), GetHelper(read), GetHelper(write), GetHelper(statfs), GetHelper(flush), GetHelper(release), GetHelper(fsync), GetHelper(setxattr), GetHelper(getxattr), GetHelper(listxattr), GetHelper(removexattr), GetHelper(opendir), GetHelper(readdir), GetHelper(releasedir), GetHelper(fsyncdir), GetIntHelper(init), nullptr, // fuseDestroy GetHelper(access), GetHelper(create), GetHelper(lock), GetHelper(utimens), GetHelper(bmap), GetHelper(ioctl), GetHelper(poll), GetHelper(write_buf), GetHelper(read_buf), GetHelper(flock), GetHelper(fallocate), GetHelper(copy_file_range), GetHelper(lseek), }; #undef GetHelper #undef GetIntHelper protected: template static int internalHelper(Args... a) { return (fuseApp->*f)(a...); } };