summaryrefslogtreecommitdiff
path: root/netfs/fuse/fuseAppBase.h
blob: 4fdfb3750579d2b62cff3ddc0738bb64eb982a22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#ifndef FUSEAPP_H
#define FUSEAPP_H

#include <c++11Helpers.h>
#include <cerrno>
#include <cstdio>
#include <exception>
#include <fuse.h>
#include <lockHelpers.h>
#include <shared_mutex>
#include <syslog.h>
#include <typeinfo>
#include <visibility.h>

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 _lock;

protected:
	static FuseAppBase * fuseApp;
};

template<typename FuseApp> class FuseAppBaseT : public FuseAppBase {
public:
#define GetIntHelper(func) \
	getInternalHelper<decltype(&FuseAppBase::func), decltype(&FuseApp::func), &FuseAppBase::func>(&FuseAppBase::func)
#define GetHelper(func) \
	getHelper<decltype(&FuseAppBase::func), decltype(&FuseApp::func), &FuseAppBase::func>(&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<typename BFunc, typename IFunc, BFunc bfunc, typename Rtn, typename... Args>
	constexpr static auto getInternalHelper(Rtn (FuseAppBase::*)(Args...)) -> Rtn (*)(Args...)
	{
		if constexpr (!std::is_same<BFunc, IFunc>::value) {
			return [](Args... a) {
				SharedLock(fuseApp->_lock);
				return (fuseApp->*bfunc)(a...);
			};
		}
		return nullptr;
	}
	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) -> 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<typename Func, Func f, typename... Args>
	static int
	internalHelper(Args... a)
	{
		return (fuseApp->*f)(a...);
	}
};

#endif