#ifndef FUSEAPP_H #define FUSEAPP_H #include #include #include #include #include #include #include #include #include #include class DLL_PUBLIC FuseAppBase { public: 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 *); 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) throw(); virtual void beforeOperation(); void log(int level, const char * message) const throw(); void logf(int level, const char * fmt, ...) const throw() __attribute__ ((__format__ (__printf__, 3, 4))); virtual void vlogf(int level, const char * fmt, va_list) const throw() __attribute__ ((__format__ (__printf__, 3, 0))) = 0; mutable std::shared_mutex _lock; protected: static FuseAppBase * fuseApp; }; template class FuseAppBaseT : public FuseAppBase { public: #define GetIntHelper(func) getInternalHelper(&FuseAppBase::func) #define GetHelper(func) getHelper(&FuseAppBase::func) FuseAppBaseT() : 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 const struct fuse_operations operations; private: template constexpr static auto getInternalHelper(Rtn(FuseAppBase::*)(Args...)) -> Rtn(*)(Args...) { if constexpr (!std::is_same::value) { return [](Args ... a) { return (fuseApp->*bfunc)(a...); }; } return nullptr; } template constexpr static auto getHelper(Rtn(FuseAppBase::*)(Args...)) -> Rtn(*)(Args...) { if constexpr (!std::is_same::value) { return [](Args ... a) -> Rtn { for (int t = 0; ; ++t) { try { fuseApp->beforeOperation(); SharedLock(fuseApp->_lock); return (fuseApp->*bfunc)(a...); } catch (const std::exception & ex) { if (t < 10) { if (int rtn = fuseApp->onError(ex)) { return rtn; } } else { fuseApp->logf(LOG_ERR, "Retries expired with %s calling %s", ex.what(), typeid(bfunc).name()); return -EIO; } } catch (...) { fuseApp->logf(LOG_ERR, "Unknown exception calling %s", typeid(bfunc).name()); return -EIO; } } }; } return nullptr; } protected: template static int internalHelper(Args ... a) { return (fuseApp->*f)(a...); } }; #endif