blob: 04a34f3bb4b0e8d8fe3acdac5bc95c001c9c977c [file] [log] [blame]
Miklos Szeredi12744942005-07-11 12:32:31 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi12744942005-07-11 12:32:31 +00004
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
7*/
8
Miklos Szeredi9d3b7da2006-05-08 12:35:04 +00009#include "config.h"
Miklos Szeredia1482422005-08-14 23:00:27 +000010#include "fuse_lowlevel.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000011#include "fuse_kernel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000012#include "fuse_opt.h"
Miklos Szeredi065f2222006-01-20 15:15:21 +000013#include "fuse_i.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000014
15#include <stdio.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000016#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000017#include <stddef.h>
18#include <string.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000019#include <unistd.h>
20#include <limits.h>
21#include <errno.h>
Miklos Szeredib052a1a2006-06-28 14:51:20 +000022#include <pthread.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000023
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000024#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredib052a1a2006-06-28 14:51:20 +000025#define OFFSET_MAX 0x7fffffffffffffffLL
26
27struct fuse_ll;
28
29struct fuse_req {
30 struct fuse_ll *f;
31 uint64_t unique;
32 struct fuse_ctx ctx;
33 struct fuse_chan *ch;
34 int interrupted;
35 union {
36 struct {
37 uint64_t unique;
38 } i;
39 struct {
40 fuse_interrupt_func_t func;
41 void *data;
42 } ni;
43 } u;
44 struct fuse_req *next;
45 struct fuse_req *prev;
46};
Miklos Szeredi12744942005-07-11 12:32:31 +000047
Miklos Szeredia1482422005-08-14 23:00:27 +000048struct fuse_ll {
Miklos Szeredi659743b2005-12-09 17:41:42 +000049 int debug;
50 int allow_root;
Miklos Szeredia1482422005-08-14 23:00:27 +000051 struct fuse_lowlevel_ops op;
52 int got_init;
53 void *userdata;
Miklos Szeredia1482422005-08-14 23:00:27 +000054 uid_t owner;
Miklos Szeredi065f2222006-01-20 15:15:21 +000055 struct fuse_conn_info conn;
Miklos Szeredib052a1a2006-06-28 14:51:20 +000056 struct fuse_req list;
57 struct fuse_req interrupts;
58 pthread_mutex_t lock;
Miklos Szeredi12744942005-07-11 12:32:31 +000059};
60
Miklos Szeredib052a1a2006-06-28 14:51:20 +000061#ifndef USE_UCLIBC
62#define mutex_init(mut) pthread_mutex_init(mut, NULL)
63#else
64static void mutex_init(pthread_mutex_t *mut)
Miklos Szeredi12744942005-07-11 12:32:31 +000065{
Miklos Szeredib052a1a2006-06-28 14:51:20 +000066 pthread_mutexattr_t attr;
67 pthread_mutexattr_init(&attr);
68 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
69 pthread_mutex_init(mut, &attr);
70 pthread_mutexattr_destroy(&attr);
Miklos Szeredi12744942005-07-11 12:32:31 +000071}
Miklos Szeredib052a1a2006-06-28 14:51:20 +000072#endif
73
Miklos Szeredi12744942005-07-11 12:32:31 +000074
Miklos Szeredi76c17522005-07-13 14:08:19 +000075static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000076{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000077 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000078 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000079 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000080 attr->uid = stbuf->st_uid;
81 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000082 attr->rdev = stbuf->st_rdev;
83 attr->size = stbuf->st_size;
84 attr->blocks = stbuf->st_blocks;
85 attr->atime = stbuf->st_atime;
86 attr->mtime = stbuf->st_mtime;
87 attr->ctime = stbuf->st_ctime;
88#ifdef HAVE_STRUCT_STAT_ST_ATIM
89 attr->atimensec = stbuf->st_atim.tv_nsec;
90 attr->mtimensec = stbuf->st_mtim.tv_nsec;
91 attr->ctimensec = stbuf->st_ctim.tv_nsec;
92#endif
93}
94
Miklos Szeredi11509ce2005-10-26 16:04:04 +000095static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +000096{
97 stbuf->st_mode = attr->mode;
98 stbuf->st_uid = attr->uid;
99 stbuf->st_gid = attr->gid;
100 stbuf->st_size = attr->size;
101 stbuf->st_atime = attr->atime;
102 stbuf->st_mtime = attr->mtime;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000103#ifdef HAVE_STRUCT_STAT_ST_ATIM
104 stbuf->st_atim.tv_nsec = attr->atimensec;
105 stbuf->st_mtim.tv_nsec = attr->mtimensec;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000106#endif
107}
108
Miklos Szeredi12744942005-07-11 12:32:31 +0000109static size_t iov_length(const struct iovec *iov, size_t count)
110{
111 size_t seg;
112 size_t ret = 0;
113
114 for (seg = 0; seg < count; seg++)
115 ret += iov[seg].iov_len;
116 return ret;
117}
118
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000119static void list_init_req(struct fuse_req *req)
120{
121 req->next = req;
122 req->prev = req;
123}
124
125static void list_del_req(struct fuse_req *req)
126{
127 struct fuse_req *prev = req->prev;
128 struct fuse_req *next = req->next;
129 prev->next = next;
130 next->prev = prev;
131}
132
133static void list_add_req(struct fuse_req *req, struct fuse_req *next)
134{
135 struct fuse_req *prev = next->prev;
136 req->next = next;
137 req->prev = prev;
138 prev->next = req;
139 next->prev = req;
140}
141
Miklos Szeredia1482422005-08-14 23:00:27 +0000142static void free_req(fuse_req_t req)
Miklos Szeredi12744942005-07-11 12:32:31 +0000143{
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000144 pthread_mutex_lock(&req->f->lock);
145 list_del_req(req);
146 pthread_mutex_unlock(&req->f->lock);
Miklos Szeredia1482422005-08-14 23:00:27 +0000147 free(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000148}
149
Miklos Szeredia1482422005-08-14 23:00:27 +0000150static int send_reply(fuse_req_t req, int error, const void *arg,
151 size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000152{
153 struct fuse_out_header out;
154 struct iovec iov[2];
155 size_t count;
Miklos Szeredia1482422005-08-14 23:00:27 +0000156 int res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000157
158 if (error <= -1000 || error > 0) {
159 fprintf(stderr, "fuse: bad error value: %i\n", error);
160 error = -ERANGE;
161 }
162
Miklos Szeredia1482422005-08-14 23:00:27 +0000163 out.unique = req->unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000164 out.error = error;
165 count = 1;
166 iov[0].iov_base = &out;
167 iov[0].iov_len = sizeof(struct fuse_out_header);
168 if (argsize && !error) {
169 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000170 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000171 iov[1].iov_len = argsize;
172 }
Miklos Szeredia1482422005-08-14 23:00:27 +0000173 out.len = iov_length(iov, count);
174
175 if (req->f->debug) {
176 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
177 out.unique, out.error, strerror(-out.error), out.len);
178 fflush(stdout);
179 }
180 res = fuse_chan_send(req->ch, iov, count);
181 free_req(req);
182
183 return res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000184}
185
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000186size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000187{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000188 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000189}
190
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000191char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000192 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000193{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000194 unsigned namelen = strlen(name);
195 unsigned entlen = FUSE_NAME_OFFSET + namelen;
196 unsigned entsize = fuse_dirent_size(namelen);
197 unsigned padlen = entsize - entlen;
198 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000199
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000200 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000201 dirent->off = off;
202 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000203 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000204 strncpy(dirent->name, name, namelen);
205 if (padlen)
206 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000207
Miklos Szeredi76c17522005-07-13 14:08:19 +0000208 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000209}
210
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000211size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
212 const char *name, const struct stat *stbuf, off_t off)
213{
214 size_t entsize;
215
216 (void) req;
217 entsize = fuse_dirent_size(strlen(name));
218 if (entsize <= bufsize && buf)
219 fuse_add_dirent(buf, name, stbuf, off);
220 return entsize;
221}
222
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000223static void convert_statfs(const struct statvfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000224 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000225{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000226 kstatfs->bsize = stbuf->f_bsize;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000227 kstatfs->frsize = stbuf->f_frsize;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000228 kstatfs->blocks = stbuf->f_blocks;
229 kstatfs->bfree = stbuf->f_bfree;
230 kstatfs->bavail = stbuf->f_bavail;
231 kstatfs->files = stbuf->f_files;
232 kstatfs->ffree = stbuf->f_ffree;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000233 kstatfs->namelen = stbuf->f_namemax;
Miklos Szeredi12744942005-07-11 12:32:31 +0000234}
235
Miklos Szeredia1482422005-08-14 23:00:27 +0000236static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000237{
Miklos Szeredia1482422005-08-14 23:00:27 +0000238 return send_reply(req, 0, arg, argsize);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000239}
240
241int fuse_reply_err(fuse_req_t req, int err)
242{
Miklos Szeredia1482422005-08-14 23:00:27 +0000243 return send_reply(req, -err, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000244}
245
Miklos Szeredi836ab712005-10-03 14:11:59 +0000246void fuse_reply_none(fuse_req_t req)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000247{
Miklos Szeredi8d975f62006-03-17 15:56:05 +0000248 fuse_chan_send(req->ch, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000249 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000250}
251
252static unsigned long calc_timeout_sec(double t)
253{
254 if (t > (double) ULONG_MAX)
255 return ULONG_MAX;
256 else if (t < 0.0)
257 return 0;
258 else
259 return (unsigned long) t;
260}
261
262static unsigned int calc_timeout_nsec(double t)
263{
264 double f = t - (double) calc_timeout_sec(t);
265 if (f < 0.0)
266 return 0;
267 else if (f >= 0.999999999)
268 return 999999999;
269 else
270 return (unsigned int) (f * 1.0e9);
271}
272
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000273static void fill_entry(struct fuse_entry_out *arg,
274 const struct fuse_entry_param *e)
275{
276 arg->nodeid = e->ino;
277 arg->generation = e->generation;
278 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
279 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
280 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
281 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
282 convert_stat(&e->attr, &arg->attr);
283}
284
285static void fill_open(struct fuse_open_out *arg,
286 const struct fuse_file_info *f)
287{
288 arg->fh = f->fh;
289 if (f->direct_io)
290 arg->open_flags |= FOPEN_DIRECT_IO;
291 if (f->keep_cache)
292 arg->open_flags |= FOPEN_KEEP_CACHE;
293}
294
Miklos Szeredi76c17522005-07-13 14:08:19 +0000295int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
296{
297 struct fuse_entry_out arg;
298
Miklos Szeredi2b478112005-11-28 13:27:10 +0000299 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
300 negative entry */
Miklos Szeredi065f2222006-01-20 15:15:21 +0000301 if (!e->ino && req->f->conn.proto_minor < 4)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000302 return fuse_reply_err(req, ENOENT);
303
Miklos Szeredi76c17522005-07-13 14:08:19 +0000304 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000305 fill_entry(&arg, e);
306 return send_reply_ok(req, &arg, sizeof(arg));
307}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000308
Miklos Szeredid9079a72005-10-26 15:29:06 +0000309int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
310 const struct fuse_file_info *f)
311{
312 struct {
313 struct fuse_entry_out e;
314 struct fuse_open_out o;
315 } arg;
316
317 memset(&arg, 0, sizeof(arg));
318 fill_entry(&arg.e, e);
319 fill_open(&arg.o, f);
320 return send_reply_ok(req, &arg, sizeof(arg));
321}
322
Miklos Szeredi76c17522005-07-13 14:08:19 +0000323int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
324 double attr_timeout)
325{
326 struct fuse_attr_out arg;
327
328 memset(&arg, 0, sizeof(arg));
329 arg.attr_valid = calc_timeout_sec(attr_timeout);
330 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
331 convert_stat(attr, &arg.attr);
332
Miklos Szeredia1482422005-08-14 23:00:27 +0000333 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000334}
335
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000336int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000337{
Miklos Szeredia1482422005-08-14 23:00:27 +0000338 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000339}
340
341int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
342{
343 struct fuse_open_out arg;
344
345 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000346 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000347 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000348}
349
350int fuse_reply_write(fuse_req_t req, size_t count)
351{
352 struct fuse_write_out arg;
353
354 memset(&arg, 0, sizeof(arg));
355 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000356
Miklos Szeredia1482422005-08-14 23:00:27 +0000357 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000358}
359
360int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
361{
Miklos Szeredia1482422005-08-14 23:00:27 +0000362 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000363}
364
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000365int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000366{
367 struct fuse_statfs_out arg;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000368 size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000369
370 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000371 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000372
Miklos Szeredi2b478112005-11-28 13:27:10 +0000373 return send_reply_ok(req, &arg, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000374}
375
376int fuse_reply_xattr(fuse_req_t req, size_t count)
377{
378 struct fuse_getxattr_out arg;
379
380 memset(&arg, 0, sizeof(arg));
381 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000382
Miklos Szeredia1482422005-08-14 23:00:27 +0000383 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000384}
385
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000386int fuse_reply_lock(fuse_req_t req, struct flock *lock)
387{
388 struct fuse_lk_out arg;
389
390 memset(&arg, 0, sizeof(arg));
391 arg.lk.type = lock->l_type;
392 if (lock->l_type != F_UNLCK) {
393 arg.lk.start = lock->l_start;
394 if (lock->l_len == 0)
395 arg.lk.end = OFFSET_MAX;
396 else
397 arg.lk.end = lock->l_start + lock->l_len - 1;
398 }
399 arg.lk.pid = lock->l_pid;
400 return send_reply_ok(req, &arg, sizeof(arg));
401}
402
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000403static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000404{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000405 char *name = (char *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000406
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000407 if (req->f->op.lookup)
408 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000409 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000410 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000411}
412
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000413static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000414{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000415 struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000416
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000417 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000418 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000419}
420
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000421static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000422{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000423 (void) inarg;
424
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000425 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000426 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000427 else
428 fuse_reply_err(req, ENOSYS);
429}
430
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000431static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000432{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000433 struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000434
Miklos Szeredi76c17522005-07-13 14:08:19 +0000435 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000436 struct fuse_file_info *fi = NULL;
437 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000438 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000439 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000440 convert_attr(arg, &stbuf);
441 if (arg->valid & FATTR_FH) {
442 arg->valid &= ~FATTR_FH;
443 memset(&fi_store, 0, sizeof(fi_store));
444 fi = &fi_store;
445 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000446 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000447 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000448 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000449 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000450 fuse_reply_err(req, ENOSYS);
451}
452
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000453static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000454{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000455 struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000456
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000457 if (req->f->op.access)
458 req->f->op.access(req, nodeid, arg->mask);
459 else
460 fuse_reply_err(req, ENOSYS);
461}
462
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000463static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000464{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000465 (void) inarg;
466
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000467 if (req->f->op.readlink)
468 req->f->op.readlink(req, nodeid);
469 else
470 fuse_reply_err(req, ENOSYS);
471}
472
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000473static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000474{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000475 struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000476
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000477 if (req->f->op.mknod)
478 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
479 else
480 fuse_reply_err(req, ENOSYS);
481}
482
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000483static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000484{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000485 struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000486
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000487 if (req->f->op.mkdir)
488 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
489 else
490 fuse_reply_err(req, ENOSYS);
491}
492
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000493static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000494{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000495 char *name = (char *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000496
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000497 if (req->f->op.unlink)
498 req->f->op.unlink(req, nodeid, name);
499 else
500 fuse_reply_err(req, ENOSYS);
501}
502
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000503static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000504{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000505 char *name = (char *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000506
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000507 if (req->f->op.rmdir)
508 req->f->op.rmdir(req, nodeid, name);
509 else
510 fuse_reply_err(req, ENOSYS);
511}
512
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000513static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000514{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000515 char *name = (char *) inarg;
516 char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000517
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000518 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000519 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000520 else
521 fuse_reply_err(req, ENOSYS);
522}
523
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000524static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000525{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000526 struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000527 char *oldname = PARAM(arg);
528 char *newname = oldname + strlen(oldname) + 1;
529
530 if (req->f->op.rename)
531 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
532 else
533 fuse_reply_err(req, ENOSYS);
534}
535
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000536static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000537{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000538 struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000539
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000540 if (req->f->op.link)
541 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
542 else
543 fuse_reply_err(req, ENOSYS);
544}
545
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000546static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredid9079a72005-10-26 15:29:06 +0000547{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000548 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000549
Miklos Szeredid9079a72005-10-26 15:29:06 +0000550 if (req->f->op.create) {
551 struct fuse_file_info fi;
552
553 memset(&fi, 0, sizeof(fi));
554 fi.flags = arg->flags;
555
556 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
557 } else
558 fuse_reply_err(req, ENOSYS);
559}
560
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000561static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000562{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000563 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000564 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000565
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000566 memset(&fi, 0, sizeof(fi));
567 fi.flags = arg->flags;
568
569 if (req->f->op.open)
570 req->f->op.open(req, nodeid, &fi);
571 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000572 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000573}
574
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000575static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000576{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000577 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000578
Miklos Szeredi76c17522005-07-13 14:08:19 +0000579 if (req->f->op.read) {
580 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000581
Miklos Szeredi76c17522005-07-13 14:08:19 +0000582 memset(&fi, 0, sizeof(fi));
583 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000584 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000585 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000586 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000587 fuse_reply_err(req, ENOSYS);
588}
589
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000590static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000591{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000592 struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000593 struct fuse_file_info fi;
594
595 memset(&fi, 0, sizeof(fi));
596 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000597 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000598 fi.writepage = arg->write_flags & 1;
599
600 if (req->f->op.write)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000601 req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000602 else
603 fuse_reply_err(req, ENOSYS);
604}
605
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000606static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000607{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000608 struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000609 struct fuse_file_info fi;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000610 uint64_t lock_owner = 0;
611
612 if (req->f->conn.proto_minor >= 7)
613 lock_owner = arg->lock_owner;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000614
615 memset(&fi, 0, sizeof(fi));
616 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000617 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000618
619 if (req->f->op.flush)
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000620 req->f->op.flush(req, nodeid, &fi, lock_owner);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000621 else
622 fuse_reply_err(req, ENOSYS);
623}
624
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000625static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000626{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000627 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000628 struct fuse_file_info fi;
629
630 memset(&fi, 0, sizeof(fi));
631 fi.flags = arg->flags;
632 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000633 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000634
635 if (req->f->op.release)
636 req->f->op.release(req, nodeid, &fi);
637 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000638 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000639}
640
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000641static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000642{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000643 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000644 struct fuse_file_info fi;
645
646 memset(&fi, 0, sizeof(fi));
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000647 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000648 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000649
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000650 if (req->f->op.fsync)
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000651 req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000652 else
653 fuse_reply_err(req, ENOSYS);
654}
655
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000656static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000657{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000658 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000659 struct fuse_file_info fi;
660
661 memset(&fi, 0, sizeof(fi));
662 fi.flags = arg->flags;
663
664 if (req->f->op.opendir)
665 req->f->op.opendir(req, nodeid, &fi);
666 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000667 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000668}
669
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000670static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000671{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000672 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000673 struct fuse_file_info fi;
674
675 memset(&fi, 0, sizeof(fi));
676 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000677 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000678
679 if (req->f->op.readdir)
680 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
681 else
682 fuse_reply_err(req, ENOSYS);
683}
684
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000685static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000686{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000687 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000688 struct fuse_file_info fi;
689
690 memset(&fi, 0, sizeof(fi));
691 fi.flags = arg->flags;
692 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000693 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000694
695 if (req->f->op.releasedir)
696 req->f->op.releasedir(req, nodeid, &fi);
697 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000698 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000699}
700
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000701static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000702{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000703 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000704 struct fuse_file_info fi;
705
706 memset(&fi, 0, sizeof(fi));
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000707 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000708 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000709
710 if (req->f->op.fsyncdir)
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000711 req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000712 else
713 fuse_reply_err(req, ENOSYS);
714}
715
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000716static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000717{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000718 (void) nodeid;
719 (void) inarg;
720
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000721 if (req->f->op.statfs)
Miklos Szeredi3ded1a32006-08-18 18:43:50 +0000722 req->f->op.statfs(req, nodeid);
Miklos Szerediaa8258e2006-02-25 14:42:03 +0000723 else {
724 struct statvfs buf = {
725 .f_namemax = 255,
726 .f_bsize = 512,
727 };
728 fuse_reply_statfs(req, &buf);
729 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000730}
731
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000732static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000733{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000734 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000735 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000736 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000737
Miklos Szeredi4331a272005-07-12 14:51:04 +0000738 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000739 req->f->op.setxattr(req, nodeid, name, value, arg->size,
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000740 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000741 else
742 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000743}
744
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000745static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000746{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000747 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000748
Miklos Szeredi4331a272005-07-12 14:51:04 +0000749 if (req->f->op.getxattr)
750 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000751 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000752 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000753}
754
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000755static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000756{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000757 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000758
Miklos Szeredi4331a272005-07-12 14:51:04 +0000759 if (req->f->op.listxattr)
760 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000761 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000762 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000763}
764
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000765static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000766{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000767 char *name = (char *) inarg;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000768
Miklos Szeredi4331a272005-07-12 14:51:04 +0000769 if (req->f->op.removexattr)
770 req->f->op.removexattr(req, nodeid, name);
771 else
772 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000773}
774
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000775static void convert_fuse_file_lock(struct fuse_file_lock *fl,
776 struct flock *flock)
777{
778 memset(flock, 0, sizeof(struct flock));
779 flock->l_type = fl->type;
780 flock->l_whence = SEEK_SET;
781 flock->l_start = fl->start;
782 if (fl->end == OFFSET_MAX)
783 flock->l_len = 0;
784 else
785 flock->l_len = fl->end - fl->start + 1;
786 flock->l_pid = fl->pid;
787}
788
789static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
790{
791 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
792 struct fuse_file_info fi;
793 struct flock flock;
794
795 memset(&fi, 0, sizeof(fi));
796 fi.fh = arg->fh;
797
798 convert_fuse_file_lock(&arg->lk, &flock);
799 if (req->f->op.getlk)
800 req->f->op.getlk(req, nodeid, &fi, &flock, arg->owner);
801 else
802 fuse_reply_err(req, ENOSYS);
803}
804
805static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
806 const void *inarg, int sleep)
807{
808 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
809 struct fuse_file_info fi;
810 struct flock flock;
811
812 memset(&fi, 0, sizeof(fi));
813 fi.fh = arg->fh;
814
815 convert_fuse_file_lock(&arg->lk, &flock);
816 if (req->f->op.setlk)
817 req->f->op.setlk(req, nodeid, &fi, &flock, arg->owner, sleep);
818 else
819 fuse_reply_err(req, ENOSYS);
820}
821
822static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
823{
824 do_setlk_common(req, nodeid, inarg, 0);
825}
826
827static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
828{
829 do_setlk_common(req, nodeid, inarg, 1);
830}
831
832static int find_interrupted(struct fuse_ll *f, struct fuse_req *req)
833{
834 struct fuse_req *curr;
835
836 for (curr = f->list.next; curr != &f->list; curr = curr->next) {
837 if (curr->unique == req->u.i.unique) {
838 curr->interrupted = 1;
839 if (curr->u.ni.func)
840 curr->u.ni.func(curr, curr->u.ni.data);
841 return 1;
842 }
843 }
844 for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) {
845 if (curr->u.i.unique == req->u.i.unique)
846 return 1;
847 }
848 return 0;
849}
850
851static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
852{
853 struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
854 struct fuse_ll *f = req->f;
855
856 (void) nodeid;
857 if (f->debug) {
858 printf("INTERRUPT: %llu\n", (unsigned long long) arg->unique);
859 fflush(stdout);
860 }
861
862 req->u.i.unique = arg->unique;
863
864 pthread_mutex_lock(&f->lock);
865 if (find_interrupted(f, req))
866 free(req);
867 else
868 list_add_req(req, &f->interrupts);
869 pthread_mutex_unlock(&f->lock);
870}
871
872static void check_interrupt(struct fuse_ll *f, struct fuse_req *req)
873{
874 struct fuse_req *curr;
875
876 for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) {
877 if (curr->u.i.unique == req->unique) {
878 list_del_req(curr);
879 free(curr);
880 return;
881 }
882 }
883 curr = f->interrupts.next;
884 if (curr != &f->interrupts)
885 fuse_reply_err(curr, EAGAIN);
886}
887
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000888static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000889{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000890 struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000891 struct fuse_init_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000892 struct fuse_ll *f = req->f;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000893 size_t bufsize = fuse_chan_bufsize(req->ch);
Miklos Szeredi12744942005-07-11 12:32:31 +0000894
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000895 (void) nodeid;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000896 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000897 printf("INIT: %u.%u\n", arg->major, arg->minor);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000898 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
899 printf("flags=0x%08x\n", arg->flags);
900 printf("max_readahead=0x%08x\n", arg->max_readahead);
901 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000902 fflush(stdout);
903 }
Miklos Szeredi065f2222006-01-20 15:15:21 +0000904 f->conn.proto_major = arg->major;
905 f->conn.proto_minor = arg->minor;
Miklos Szeredi12744942005-07-11 12:32:31 +0000906
Miklos Szeredi065f2222006-01-20 15:15:21 +0000907 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
908 if (f->conn.async_read)
909 f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
910 if (arg->max_readahead < f->conn.max_readahead)
911 f->conn.max_readahead = arg->max_readahead;
912 } else {
913 f->conn.async_read = 0;
914 f->conn.max_readahead = 0;
915 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000916
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000917 if (bufsize < FUSE_MIN_READ_BUFFER) {
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000918 fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000919 bufsize = FUSE_MIN_READ_BUFFER;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000920 }
921
Miklos Szeredi065f2222006-01-20 15:15:21 +0000922 bufsize -= 4096;
923 if (bufsize < f->conn.max_write)
924 f->conn.max_write = bufsize;
925
926 f->got_init = 1;
927 if (f->op.init)
928 f->op.init(f->userdata, &f->conn);
929
Miklos Szeredi12744942005-07-11 12:32:31 +0000930 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi065f2222006-01-20 15:15:21 +0000931 outarg.major = FUSE_KERNEL_VERSION;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000932 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000933 if (f->conn.async_read)
934 outarg.flags |= FUSE_ASYNC_READ;
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000935 if (f->op.getlk && f->op.setlk)
936 outarg.flags |= FUSE_POSIX_LOCKS;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000937 outarg.max_readahead = f->conn.max_readahead;
938 outarg.max_write = f->conn.max_write;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000939
Miklos Szeredi76c17522005-07-13 14:08:19 +0000940 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000941 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000942 printf(" flags=0x%08x\n", outarg.flags);
943 printf(" max_readahead=0x%08x\n", outarg.max_readahead);
944 printf(" max_write=0x%08x\n", outarg.max_write);
Miklos Szeredi12744942005-07-11 12:32:31 +0000945 fflush(stdout);
946 }
947
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000948 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000949}
950
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000951void *fuse_req_userdata(fuse_req_t req)
952{
953 return req->f->userdata;
954}
955
956const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
957{
958 return &req->ctx;
959}
960
Miklos Szeredib052a1a2006-06-28 14:51:20 +0000961void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
962 void *data)
963{
964 struct fuse_ll *f = req->f;
965
966 pthread_mutex_lock(&f->lock);
967 req->u.ni.func = func;
968 req->u.ni.data = data;
969 if (req->interrupted && func)
970 func(req, data);
971 pthread_mutex_unlock(&f->lock);
972}
973
974static struct {
975 void (*func)(fuse_req_t, fuse_ino_t, const void *);
976 const char *name;
977} fuse_ll_ops[] = {
978 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
979 [FUSE_FORGET] = { do_forget, "FORGET" },
980 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
981 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
982 [FUSE_READLINK] = { do_readlink, "READLINK" },
983 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
984 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
985 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
986 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
987 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
988 [FUSE_RENAME] = { do_rename, "RENAME" },
989 [FUSE_LINK] = { do_link, "LINK" },
990 [FUSE_OPEN] = { do_open, "OPEN" },
991 [FUSE_READ] = { do_read, "READ" },
992 [FUSE_WRITE] = { do_write, "WRITE" },
993 [FUSE_STATFS] = { do_statfs, "STATFS" },
994 [FUSE_RELEASE] = { do_release, "RELEASE" },
995 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
996 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
997 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
998 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
999 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
1000 [FUSE_FLUSH] = { do_flush, "FLUSH" },
1001 [FUSE_INIT] = { do_init, "INIT" },
1002 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
1003 [FUSE_READDIR] = { do_readdir, "READDIR" },
1004 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
1005 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
1006 [FUSE_GETLK] = { do_getlk, "GETLK" },
1007 [FUSE_SETLK] = { do_setlk, "SETLK" },
1008 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
1009 [FUSE_ACCESS] = { do_access, "ACCESS" },
1010 [FUSE_CREATE] = { do_create, "CREATE" },
1011 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
Miklos Szeredi2c1381f2006-03-15 20:34:10 +00001012};
1013
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001014#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
1015
1016static const char *opname(enum fuse_opcode opcode)
1017{
1018 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
1019 return "???";
1020 else
1021 return fuse_ll_ops[opcode].name;
1022}
1023
Miklos Szeredia1482422005-08-14 23:00:27 +00001024static void fuse_ll_process(void *data, const char *buf, size_t len,
1025 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +00001026{
Miklos Szeredia1482422005-08-14 23:00:27 +00001027 struct fuse_ll *f = (struct fuse_ll *) data;
1028 struct fuse_in_header *in = (struct fuse_in_header *) buf;
1029 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +00001030 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +00001031
Miklos Szeredi76c17522005-07-13 14:08:19 +00001032 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +00001033 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001034 (unsigned long long) in->unique,
1035 opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +00001036 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +00001037 fflush(stdout);
1038 }
1039
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001040 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
Miklos Szeredi76c17522005-07-13 14:08:19 +00001041 if (req == NULL) {
1042 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00001043 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +00001044 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001045
Miklos Szeredi76c17522005-07-13 14:08:19 +00001046 req->f = f;
1047 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001048 req->ctx.uid = in->uid;
1049 req->ctx.gid = in->gid;
1050 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +00001051 req->ch = ch;
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001052 list_init_req(req);
Miklos Szeredi12744942005-07-11 12:32:31 +00001053
Miklos Szeredia1482422005-08-14 23:00:27 +00001054 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +00001055 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +00001056 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
1057 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
1058 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
1059 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
1060 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
1061 fuse_reply_err(req, EACCES);
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001062 } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
Miklos Szeredi76c17522005-07-13 14:08:19 +00001063 fuse_reply_err(req, ENOSYS);
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001064 else {
1065 if (in->opcode != FUSE_INTERRUPT) {
1066 pthread_mutex_lock(&f->lock);
1067 check_interrupt(f, req);
1068 list_add_req(req, &f->list);
1069 pthread_mutex_unlock(&f->lock);
1070 }
1071 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
1072 }
Miklos Szeredi12744942005-07-11 12:32:31 +00001073}
1074
Miklos Szerediad005972006-01-07 10:14:34 +00001075enum {
1076 KEY_HELP,
1077 KEY_VERSION,
1078};
1079
Miklos Szeredi659743b2005-12-09 17:41:42 +00001080static struct fuse_opt fuse_ll_opts[] = {
1081 { "debug", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi95da8602006-01-06 18:29:40 +00001082 { "-d", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi659743b2005-12-09 17:41:42 +00001083 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
Miklos Szeredi065f2222006-01-20 15:15:21 +00001084 { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
1085 { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
1086 { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
1087 { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
1088 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
Miklos Szerediad005972006-01-07 10:14:34 +00001089 FUSE_OPT_KEY("-h", KEY_HELP),
1090 FUSE_OPT_KEY("--help", KEY_HELP),
1091 FUSE_OPT_KEY("-V", KEY_VERSION),
1092 FUSE_OPT_KEY("--version", KEY_VERSION),
Miklos Szeredi659743b2005-12-09 17:41:42 +00001093 FUSE_OPT_END
1094};
1095
Miklos Szerediad005972006-01-07 10:14:34 +00001096static void fuse_ll_version(void)
1097{
1098 fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
1099 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1100}
1101
Miklos Szeredi065f2222006-01-20 15:15:21 +00001102static void fuse_ll_help(void)
1103{
1104 fprintf(stderr,
1105" -o max_write=N set maximum size of write requests\n"
1106" -o max_readahead=N set maximum readahead\n"
1107" -o async_read perform reads asynchronously (default)\n"
1108" -o sync_read perform reads synchronously\n");
1109}
1110
Miklos Szeredicaa09312005-12-14 23:25:00 +00001111static int fuse_ll_opt_proc(void *data, const char *arg, int key,
Miklos Szeredi73f41392005-12-16 11:12:16 +00001112 struct fuse_args *outargs)
Miklos Szeredi3b534a42005-12-09 20:09:42 +00001113{
Miklos Szerediad005972006-01-07 10:14:34 +00001114 (void) data; (void) outargs;
Miklos Szeredicb402b02006-01-09 14:44:23 +00001115
Miklos Szerediad005972006-01-07 10:14:34 +00001116 switch (key) {
1117 case KEY_HELP:
Miklos Szeredi065f2222006-01-20 15:15:21 +00001118 fuse_ll_help();
Miklos Szerediad005972006-01-07 10:14:34 +00001119 break;
Miklos Szeredicb402b02006-01-09 14:44:23 +00001120
Miklos Szerediad005972006-01-07 10:14:34 +00001121 case KEY_VERSION:
1122 fuse_ll_version();
1123 break;
1124
1125 default:
1126 fprintf(stderr, "fuse: unknown option `%s'\n", arg);
1127 }
Miklos Szeredicb402b02006-01-09 14:44:23 +00001128
Miklos Szeredi3b534a42005-12-09 20:09:42 +00001129 return -1;
1130}
1131
Miklos Szeredia1482422005-08-14 23:00:27 +00001132int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +00001133{
Miklos Szeredi659743b2005-12-09 17:41:42 +00001134 return fuse_opt_match(fuse_ll_opts, opt);
Miklos Szeredi12744942005-07-11 12:32:31 +00001135}
1136
Miklos Szeredia1482422005-08-14 23:00:27 +00001137static void fuse_ll_destroy(void *data)
1138{
1139 struct fuse_ll *f = (struct fuse_ll *) data;
1140
1141 if (f->op.destroy)
1142 f->op.destroy(f->userdata);
1143
1144 free(f);
1145}
1146
Miklos Szeredi1ee1a112006-02-15 14:28:22 +00001147/*
1148 * always call fuse_lowlevel_new_common() internally, to work around a
1149 * misfeature in the FreeBSD runtime linker, which links the old
1150 * version of a symbol to internal references.
1151 */
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001152struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
Miklos Szeredia1482422005-08-14 23:00:27 +00001153 const struct fuse_lowlevel_ops *op,
1154 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +00001155{
1156 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +00001157 struct fuse_session *se;
1158 struct fuse_session_ops sop = {
1159 .process = fuse_ll_process,
1160 .destroy = fuse_ll_destroy,
1161 };
Miklos Szeredi12744942005-07-11 12:32:31 +00001162
Miklos Szeredia1482422005-08-14 23:00:27 +00001163 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +00001164 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00001165 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +00001166 }
1167
1168 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1169 if (f == NULL) {
1170 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1171 goto out;
1172 }
1173
Miklos Szeredi065f2222006-01-20 15:15:21 +00001174 f->conn.async_read = 1;
1175 f->conn.max_write = UINT_MAX;
1176 f->conn.max_readahead = UINT_MAX;
Miklos Szeredib052a1a2006-06-28 14:51:20 +00001177 list_init_req(&f->list);
1178 list_init_req(&f->interrupts);
1179 mutex_init(&f->lock);
Miklos Szeredi065f2222006-01-20 15:15:21 +00001180
Miklos Szeredi95da8602006-01-06 18:29:40 +00001181 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
1182 goto out_free;
Miklos Szeredi12744942005-07-11 12:32:31 +00001183
Miklos Szeredi12744942005-07-11 12:32:31 +00001184 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +00001185 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001186 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +00001187
Miklos Szeredia1482422005-08-14 23:00:27 +00001188 se = fuse_session_new(&sop, f);
1189 if (!se)
1190 goto out_free;
1191
1192 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +00001193
1194 out_free:
1195 free(f);
1196 out:
1197 return NULL;
1198}
Miklos Szeredic706ad92005-11-07 15:30:48 +00001199
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001200
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001201struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
1202 const struct fuse_lowlevel_ops *op,
1203 size_t op_size, void *userdata)
1204{
1205 return fuse_lowlevel_new_common(args, op, op_size, userdata);
1206}
1207
1208
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001209#include "fuse_lowlevel_compat.h"
1210
Miklos Szeredi065f2222006-01-20 15:15:21 +00001211#ifndef __FreeBSD__
1212
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001213static void fill_open_compat(struct fuse_open_out *arg,
1214 const struct fuse_file_info_compat *f)
1215{
1216 arg->fh = f->fh;
1217 if (f->direct_io)
1218 arg->open_flags |= FOPEN_DIRECT_IO;
1219 if (f->keep_cache)
1220 arg->open_flags |= FOPEN_KEEP_CACHE;
1221}
1222
Miklos Szeredi2b478112005-11-28 13:27:10 +00001223static void convert_statfs_compat(const struct statfs *compatbuf,
1224 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001225{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001226 buf->f_bsize = compatbuf->f_bsize;
1227 buf->f_blocks = compatbuf->f_blocks;
1228 buf->f_bfree = compatbuf->f_bfree;
1229 buf->f_bavail = compatbuf->f_bavail;
1230 buf->f_files = compatbuf->f_files;
1231 buf->f_ffree = compatbuf->f_ffree;
1232 buf->f_namemax = compatbuf->f_namelen;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001233}
1234
1235int fuse_reply_open_compat(fuse_req_t req,
1236 const struct fuse_file_info_compat *f)
1237{
1238 struct fuse_open_out arg;
1239
1240 memset(&arg, 0, sizeof(arg));
1241 fill_open_compat(&arg, f);
1242 return send_reply_ok(req, &arg, sizeof(arg));
1243}
1244
1245int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1246{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001247 struct statvfs newbuf;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001248
Miklos Szeredi2b478112005-11-28 13:27:10 +00001249 memset(&newbuf, 0, sizeof(newbuf));
1250 convert_statfs_compat(stbuf, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001251
Miklos Szeredi2b478112005-11-28 13:27:10 +00001252 return fuse_reply_statfs(req, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001253}
1254
Miklos Szeredi95da8602006-01-06 18:29:40 +00001255struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
1256 const struct fuse_lowlevel_ops *op,
1257 size_t op_size, void *userdata)
1258{
1259 struct fuse_session *se;
1260 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
1261
1262 if (opts &&
1263 (fuse_opt_add_arg(&args, "") == -1 ||
1264 fuse_opt_add_arg(&args, "-o") == -1 ||
1265 fuse_opt_add_arg(&args, opts) == -1)) {
1266 fuse_opt_free_args(&args);
1267 return NULL;
1268 }
1269 se = fuse_lowlevel_new(&args, op, op_size, userdata);
1270 fuse_opt_free_args(&args);
1271
1272 return se;
1273}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001274
Miklos Szeredi065f2222006-01-20 15:15:21 +00001275struct fuse_ll_compat_conf {
1276 unsigned max_read;
1277 int set_max_read;
1278};
1279
1280static const struct fuse_opt fuse_ll_opts_compat[] = {
1281 { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },
1282 { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },
1283 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
1284 FUSE_OPT_END
1285};
1286
1287int fuse_sync_compat_args(struct fuse_args *args)
1288{
1289 struct fuse_ll_compat_conf conf;
1290
Miklos Szeredi67d26d42006-03-13 17:39:56 +00001291 memset(&conf, 0, sizeof(conf));
Miklos Szeredi065f2222006-01-20 15:15:21 +00001292 if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)
1293 return -1;
1294
1295 if (fuse_opt_insert_arg(args, 1, "-osync_read"))
1296 return -1;
1297
1298 if (conf.set_max_read) {
1299 char tmpbuf[64];
1300
1301 sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);
1302 if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)
1303 return -1;
1304 }
1305 return 0;
1306}
1307
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001308__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
1309__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
1310__asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
1311
1312#else /* __FreeBSD__ */
1313
1314int fuse_sync_compat_args(struct fuse_args *args)
1315{
1316 (void) args;
1317 return 0;
1318}
1319
1320#endif /* __FreeBSD__ */
1321
Miklos Szeredi065f2222006-01-20 15:15:21 +00001322struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
1323 const struct fuse_lowlevel_ops_compat25 *op,
1324 size_t op_size, void *userdata)
1325{
1326 if (fuse_sync_compat_args(args) == -1)
1327 return NULL;
1328
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001329 return fuse_lowlevel_new_common(args,
1330 (const struct fuse_lowlevel_ops *) op,
1331 op_size, userdata);
Miklos Szeredi065f2222006-01-20 15:15:21 +00001332}
1333
Miklos Szeredi065f2222006-01-20 15:15:21 +00001334__asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");