blob: 07873689241e238e0662f10a5887b4255817f283 [file] [log] [blame]
Miklos Szeredi12744942005-07-11 12:32:31 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
7*/
8
Miklos Szeredibd10a7b2005-07-15 09:59:59 +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 Szeredi12744942005-07-11 12:32:31 +000012
13#include <stdio.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <limits.h>
18#include <errno.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000019
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000020#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000021
Miklos Szeredi044da2e2005-12-06 17:59:55 +000022/* PATH_MAX is 4k on Linux, but I don't dare to define it to PATH_MAX,
23 because it may be much larger on other systems */
24#define MIN_SYMLINK 0x1000
25
26/* Generous 4k overhead for headers, includes room for xattr name
27 (XATTR_NAME_MAX = 255) */
28#define HEADER_OVERHEAD 0x1000
29
30/* 8k, the same as the old FUSE_MAX_IN constant */
31#define MIN_BUFFER_SIZE (MIN_SYMLINK + HEADER_OVERHEAD)
32
Miklos Szeredia1482422005-08-14 23:00:27 +000033struct fuse_ll {
34 unsigned int debug : 1;
35 unsigned int allow_root : 1;
36 struct fuse_lowlevel_ops op;
37 int got_init;
38 void *userdata;
39 int major;
40 int minor;
41 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000042};
43
Miklos Szeredi76c17522005-07-13 14:08:19 +000044struct fuse_req {
45 struct fuse_ll *f;
46 uint64_t unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000047 struct fuse_ctx ctx;
Miklos Szeredia1482422005-08-14 23:00:27 +000048 struct fuse_chan *ch;
Miklos Szeredi76c17522005-07-13 14:08:19 +000049};
50
Miklos Szeredi12744942005-07-11 12:32:31 +000051static const char *opname(enum fuse_opcode opcode)
52{
53 switch (opcode) {
54 case FUSE_LOOKUP: return "LOOKUP";
55 case FUSE_FORGET: return "FORGET";
56 case FUSE_GETATTR: return "GETATTR";
57 case FUSE_SETATTR: return "SETATTR";
58 case FUSE_READLINK: return "READLINK";
59 case FUSE_SYMLINK: return "SYMLINK";
60 case FUSE_MKNOD: return "MKNOD";
61 case FUSE_MKDIR: return "MKDIR";
62 case FUSE_UNLINK: return "UNLINK";
63 case FUSE_RMDIR: return "RMDIR";
64 case FUSE_RENAME: return "RENAME";
65 case FUSE_LINK: return "LINK";
66 case FUSE_OPEN: return "OPEN";
67 case FUSE_READ: return "READ";
68 case FUSE_WRITE: return "WRITE";
69 case FUSE_STATFS: return "STATFS";
70 case FUSE_FLUSH: return "FLUSH";
71 case FUSE_RELEASE: return "RELEASE";
72 case FUSE_FSYNC: return "FSYNC";
73 case FUSE_SETXATTR: return "SETXATTR";
74 case FUSE_GETXATTR: return "GETXATTR";
75 case FUSE_LISTXATTR: return "LISTXATTR";
76 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
77 case FUSE_INIT: return "INIT";
78 case FUSE_OPENDIR: return "OPENDIR";
79 case FUSE_READDIR: return "READDIR";
80 case FUSE_RELEASEDIR: return "RELEASEDIR";
81 case FUSE_FSYNCDIR: return "FSYNCDIR";
Miklos Szeredib0b13d12005-10-26 12:53:25 +000082 case FUSE_ACCESS: return "ACCESS";
Miklos Szeredid9079a72005-10-26 15:29:06 +000083 case FUSE_CREATE: return "CREATE";
Miklos Szeredi12744942005-07-11 12:32:31 +000084 default: return "???";
85 }
86}
87
Miklos Szeredi76c17522005-07-13 14:08:19 +000088static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000089{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000090 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000091 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000092 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000093 attr->uid = stbuf->st_uid;
94 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000095 attr->rdev = stbuf->st_rdev;
96 attr->size = stbuf->st_size;
97 attr->blocks = stbuf->st_blocks;
98 attr->atime = stbuf->st_atime;
99 attr->mtime = stbuf->st_mtime;
100 attr->ctime = stbuf->st_ctime;
101#ifdef HAVE_STRUCT_STAT_ST_ATIM
102 attr->atimensec = stbuf->st_atim.tv_nsec;
103 attr->mtimensec = stbuf->st_mtim.tv_nsec;
104 attr->ctimensec = stbuf->st_ctim.tv_nsec;
105#endif
106}
107
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000108static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000109{
110 stbuf->st_mode = attr->mode;
111 stbuf->st_uid = attr->uid;
112 stbuf->st_gid = attr->gid;
113 stbuf->st_size = attr->size;
114 stbuf->st_atime = attr->atime;
115 stbuf->st_mtime = attr->mtime;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000116#ifdef HAVE_STRUCT_STAT_ST_ATIM
117 stbuf->st_atim.tv_nsec = attr->atimensec;
118 stbuf->st_mtim.tv_nsec = attr->mtimensec;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000119#endif
120}
121
Miklos Szeredi12744942005-07-11 12:32:31 +0000122static size_t iov_length(const struct iovec *iov, size_t count)
123{
124 size_t seg;
125 size_t ret = 0;
126
127 for (seg = 0; seg < count; seg++)
128 ret += iov[seg].iov_len;
129 return ret;
130}
131
Miklos Szeredia1482422005-08-14 23:00:27 +0000132static void free_req(fuse_req_t req)
Miklos Szeredi12744942005-07-11 12:32:31 +0000133{
Miklos Szeredia1482422005-08-14 23:00:27 +0000134 free(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000135}
136
Miklos Szeredia1482422005-08-14 23:00:27 +0000137static int send_reply(fuse_req_t req, int error, const void *arg,
138 size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000139{
140 struct fuse_out_header out;
141 struct iovec iov[2];
142 size_t count;
Miklos Szeredia1482422005-08-14 23:00:27 +0000143 int res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000144
145 if (error <= -1000 || error > 0) {
146 fprintf(stderr, "fuse: bad error value: %i\n", error);
147 error = -ERANGE;
148 }
149
Miklos Szeredia1482422005-08-14 23:00:27 +0000150 out.unique = req->unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000151 out.error = error;
152 count = 1;
153 iov[0].iov_base = &out;
154 iov[0].iov_len = sizeof(struct fuse_out_header);
155 if (argsize && !error) {
156 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000157 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000158 iov[1].iov_len = argsize;
159 }
Miklos Szeredia1482422005-08-14 23:00:27 +0000160 out.len = iov_length(iov, count);
161
162 if (req->f->debug) {
163 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
164 out.unique, out.error, strerror(-out.error), out.len);
165 fflush(stdout);
166 }
167 res = fuse_chan_send(req->ch, iov, count);
168 free_req(req);
169
170 return res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000171}
172
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000173size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000174{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000175 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000176}
177
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000178char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000179 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000180{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000181 unsigned namelen = strlen(name);
182 unsigned entlen = FUSE_NAME_OFFSET + namelen;
183 unsigned entsize = fuse_dirent_size(namelen);
184 unsigned padlen = entsize - entlen;
185 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000186
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000187 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000188 dirent->off = off;
189 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000190 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000191 strncpy(dirent->name, name, namelen);
192 if (padlen)
193 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000194
Miklos Szeredi76c17522005-07-13 14:08:19 +0000195 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000196}
197
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000198static void convert_statfs(const struct statvfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000199 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000200{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000201 kstatfs->bsize = stbuf->f_bsize;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000202 kstatfs->frsize = stbuf->f_frsize;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000203 kstatfs->blocks = stbuf->f_blocks;
204 kstatfs->bfree = stbuf->f_bfree;
205 kstatfs->bavail = stbuf->f_bavail;
206 kstatfs->files = stbuf->f_files;
207 kstatfs->ffree = stbuf->f_ffree;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000208 kstatfs->namelen = stbuf->f_namemax;
Miklos Szeredi12744942005-07-11 12:32:31 +0000209}
210
Miklos Szeredia1482422005-08-14 23:00:27 +0000211static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000212{
Miklos Szeredia1482422005-08-14 23:00:27 +0000213 return send_reply(req, 0, arg, argsize);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000214}
215
216int fuse_reply_err(fuse_req_t req, int err)
217{
Miklos Szeredia1482422005-08-14 23:00:27 +0000218 return send_reply(req, -err, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000219}
220
Miklos Szeredi836ab712005-10-03 14:11:59 +0000221void fuse_reply_none(fuse_req_t req)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000222{
223 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000224}
225
226static unsigned long calc_timeout_sec(double t)
227{
228 if (t > (double) ULONG_MAX)
229 return ULONG_MAX;
230 else if (t < 0.0)
231 return 0;
232 else
233 return (unsigned long) t;
234}
235
236static unsigned int calc_timeout_nsec(double t)
237{
238 double f = t - (double) calc_timeout_sec(t);
239 if (f < 0.0)
240 return 0;
241 else if (f >= 0.999999999)
242 return 999999999;
243 else
244 return (unsigned int) (f * 1.0e9);
245}
246
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000247static void fill_entry(struct fuse_entry_out *arg,
248 const struct fuse_entry_param *e)
249{
250 arg->nodeid = e->ino;
251 arg->generation = e->generation;
252 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
253 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
254 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
255 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
256 convert_stat(&e->attr, &arg->attr);
257}
258
259static void fill_open(struct fuse_open_out *arg,
260 const struct fuse_file_info *f)
261{
262 arg->fh = f->fh;
263 if (f->direct_io)
264 arg->open_flags |= FOPEN_DIRECT_IO;
265 if (f->keep_cache)
266 arg->open_flags |= FOPEN_KEEP_CACHE;
267}
268
Miklos Szeredi76c17522005-07-13 14:08:19 +0000269int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
270{
271 struct fuse_entry_out arg;
272
Miklos Szeredi2b478112005-11-28 13:27:10 +0000273 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
274 negative entry */
275 if (!e->ino && req->f->minor < 4)
276 return fuse_reply_err(req, ENOENT);
277
Miklos Szeredi76c17522005-07-13 14:08:19 +0000278 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000279 fill_entry(&arg, e);
280 return send_reply_ok(req, &arg, sizeof(arg));
281}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000282
Miklos Szeredid9079a72005-10-26 15:29:06 +0000283int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
284 const struct fuse_file_info *f)
285{
286 struct {
287 struct fuse_entry_out e;
288 struct fuse_open_out o;
289 } arg;
290
291 memset(&arg, 0, sizeof(arg));
292 fill_entry(&arg.e, e);
293 fill_open(&arg.o, f);
294 return send_reply_ok(req, &arg, sizeof(arg));
295}
296
Miklos Szeredi76c17522005-07-13 14:08:19 +0000297int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
298 double attr_timeout)
299{
300 struct fuse_attr_out arg;
301
302 memset(&arg, 0, sizeof(arg));
303 arg.attr_valid = calc_timeout_sec(attr_timeout);
304 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
305 convert_stat(attr, &arg.attr);
306
Miklos Szeredia1482422005-08-14 23:00:27 +0000307 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000308}
309
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000310int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000311{
Miklos Szeredia1482422005-08-14 23:00:27 +0000312 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000313}
314
315int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
316{
317 struct fuse_open_out arg;
318
319 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000320 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000321 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000322}
323
324int fuse_reply_write(fuse_req_t req, size_t count)
325{
326 struct fuse_write_out arg;
327
328 memset(&arg, 0, sizeof(arg));
329 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000330
Miklos Szeredia1482422005-08-14 23:00:27 +0000331 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000332}
333
334int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
335{
Miklos Szeredia1482422005-08-14 23:00:27 +0000336 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000337}
338
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000339int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000340{
341 struct fuse_statfs_out arg;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000342 size_t size = req->f->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000343
344 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000345 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000346
Miklos Szeredi2b478112005-11-28 13:27:10 +0000347 return send_reply_ok(req, &arg, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000348}
349
350int fuse_reply_xattr(fuse_req_t req, size_t count)
351{
352 struct fuse_getxattr_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
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000360static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000361{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000362 if (req->f->op.lookup)
363 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000364 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000365 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000366}
367
Miklos Szeredi76c17522005-07-13 14:08:19 +0000368static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
369 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000370{
371 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000372 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000373}
374
375static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
376{
377 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000378 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000379 else
380 fuse_reply_err(req, ENOSYS);
381}
382
383static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000384 struct fuse_setattr_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000385{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000386 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000387 struct fuse_file_info *fi = NULL;
388 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000389 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000390 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000391 convert_attr(arg, &stbuf);
392 if (arg->valid & FATTR_FH) {
393 arg->valid &= ~FATTR_FH;
394 memset(&fi_store, 0, sizeof(fi_store));
395 fi = &fi_store;
396 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000397 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000398 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000399 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000400 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000401 fuse_reply_err(req, ENOSYS);
402}
403
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000404static void do_access(fuse_req_t req, fuse_ino_t nodeid,
405 struct fuse_access_in *arg)
406{
407 if (req->f->op.access)
408 req->f->op.access(req, nodeid, arg->mask);
409 else
410 fuse_reply_err(req, ENOSYS);
411}
412
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000413static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
414{
415 if (req->f->op.readlink)
416 req->f->op.readlink(req, nodeid);
417 else
418 fuse_reply_err(req, ENOSYS);
419}
420
421static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
422 struct fuse_mknod_in *arg)
423{
424 if (req->f->op.mknod)
425 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
426 else
427 fuse_reply_err(req, ENOSYS);
428}
429
430static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
431 struct fuse_mkdir_in *arg)
432{
433 if (req->f->op.mkdir)
434 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
435 else
436 fuse_reply_err(req, ENOSYS);
437}
438
439static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
440{
441 if (req->f->op.unlink)
442 req->f->op.unlink(req, nodeid, name);
443 else
444 fuse_reply_err(req, ENOSYS);
445}
446
447static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
448{
449 if (req->f->op.rmdir)
450 req->f->op.rmdir(req, nodeid, name);
451 else
452 fuse_reply_err(req, ENOSYS);
453}
454
455static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000456 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000457{
458 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000459 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000460 else
461 fuse_reply_err(req, ENOSYS);
462}
463
464static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
465 struct fuse_rename_in *arg)
466{
467 char *oldname = PARAM(arg);
468 char *newname = oldname + strlen(oldname) + 1;
469
470 if (req->f->op.rename)
471 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
472 else
473 fuse_reply_err(req, ENOSYS);
474}
475
476static void do_link(fuse_req_t req, fuse_ino_t nodeid,
477 struct fuse_link_in *arg)
478{
479 if (req->f->op.link)
480 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
481 else
482 fuse_reply_err(req, ENOSYS);
483}
484
Miklos Szeredid9079a72005-10-26 15:29:06 +0000485static void do_create(fuse_req_t req, fuse_ino_t nodeid,
486 struct fuse_open_in *arg)
487{
488 if (req->f->op.create) {
489 struct fuse_file_info fi;
490
491 memset(&fi, 0, sizeof(fi));
492 fi.flags = arg->flags;
493
494 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
495 } else
496 fuse_reply_err(req, ENOSYS);
497}
498
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000499static void do_open(fuse_req_t req, fuse_ino_t nodeid,
500 struct fuse_open_in *arg)
501{
502 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000503
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000504 memset(&fi, 0, sizeof(fi));
505 fi.flags = arg->flags;
506
507 if (req->f->op.open)
508 req->f->op.open(req, nodeid, &fi);
509 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000510 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000511}
512
513static void do_read(fuse_req_t req, fuse_ino_t nodeid,
514 struct fuse_read_in *arg)
515{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000516 if (req->f->op.read) {
517 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000518
Miklos Szeredi76c17522005-07-13 14:08:19 +0000519 memset(&fi, 0, sizeof(fi));
520 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000521 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000522 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000523 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000524 fuse_reply_err(req, ENOSYS);
525}
526
527static void do_write(fuse_req_t req, fuse_ino_t nodeid,
528 struct fuse_write_in *arg)
529{
530 struct fuse_file_info fi;
531
532 memset(&fi, 0, sizeof(fi));
533 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000534 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000535 fi.writepage = arg->write_flags & 1;
536
537 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000538 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
539 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000540 else
541 fuse_reply_err(req, ENOSYS);
542}
543
544static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
545 struct fuse_flush_in *arg)
546{
547 struct fuse_file_info fi;
548
549 memset(&fi, 0, sizeof(fi));
550 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000551 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000552
553 if (req->f->op.flush)
554 req->f->op.flush(req, nodeid, &fi);
555 else
556 fuse_reply_err(req, ENOSYS);
557}
558
559static void do_release(fuse_req_t req, fuse_ino_t nodeid,
560 struct fuse_release_in *arg)
561{
562 struct fuse_file_info fi;
563
564 memset(&fi, 0, sizeof(fi));
565 fi.flags = arg->flags;
566 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000567 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000568
569 if (req->f->op.release)
570 req->f->op.release(req, nodeid, &fi);
571 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000572 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000573}
574
575static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000576 struct fuse_fsync_in *inarg)
577{
Miklos Szeredi12744942005-07-11 12:32:31 +0000578 struct fuse_file_info fi;
579
580 memset(&fi, 0, sizeof(fi));
581 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000582 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000583
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000584 if (req->f->op.fsync)
585 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
586 else
587 fuse_reply_err(req, ENOSYS);
588}
589
590static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
591 struct fuse_open_in *arg)
592{
593 struct fuse_file_info fi;
594
595 memset(&fi, 0, sizeof(fi));
596 fi.flags = arg->flags;
597
598 if (req->f->op.opendir)
599 req->f->op.opendir(req, nodeid, &fi);
600 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000601 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000602}
603
604static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
605 struct fuse_read_in *arg)
606{
607 struct fuse_file_info fi;
608
609 memset(&fi, 0, sizeof(fi));
610 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000611 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000612
613 if (req->f->op.readdir)
614 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
615 else
616 fuse_reply_err(req, ENOSYS);
617}
618
619static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
620 struct fuse_release_in *arg)
621{
622 struct fuse_file_info fi;
623
624 memset(&fi, 0, sizeof(fi));
625 fi.flags = arg->flags;
626 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000627 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000628
629 if (req->f->op.releasedir)
630 req->f->op.releasedir(req, nodeid, &fi);
631 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000632 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000633}
634
635static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
636 struct fuse_fsync_in *inarg)
637{
638 struct fuse_file_info fi;
639
640 memset(&fi, 0, sizeof(fi));
641 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000642 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000643
644 if (req->f->op.fsyncdir)
645 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
646 else
647 fuse_reply_err(req, ENOSYS);
648}
649
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000650static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000651{
652 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000653 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000654 else
655 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000656}
657
Miklos Szeredi4331a272005-07-12 14:51:04 +0000658static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000659 struct fuse_setxattr_in *arg)
660{
Miklos Szeredi12744942005-07-11 12:32:31 +0000661 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000662 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000663
Miklos Szeredi4331a272005-07-12 14:51:04 +0000664 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000665 req->f->op.setxattr(req, nodeid, name, value, arg->size,
666 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000667 else
668 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000669}
670
Miklos Szeredi4331a272005-07-12 14:51:04 +0000671static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000672 struct fuse_getxattr_in *arg)
673{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000674 if (req->f->op.getxattr)
675 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000676 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000677 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000678}
679
Miklos Szeredi4331a272005-07-12 14:51:04 +0000680static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000681 struct fuse_getxattr_in *arg)
682{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000683 if (req->f->op.listxattr)
684 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000685 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000686 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000687}
688
Miklos Szeredi4331a272005-07-12 14:51:04 +0000689static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000690{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000691 if (req->f->op.removexattr)
692 req->f->op.removexattr(req, nodeid, name);
693 else
694 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000695}
696
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000697static void do_init(fuse_req_t req, struct fuse_init_in *arg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000698{
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000699 struct fuse_init_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000700 struct fuse_ll *f = req->f;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000701 size_t bufsize = fuse_chan_bufsize(req->ch);
Miklos Szeredi12744942005-07-11 12:32:31 +0000702
Miklos Szeredi76c17522005-07-13 14:08:19 +0000703 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000704 printf("INIT: %u.%u\n", arg->major, arg->minor);
705 fflush(stdout);
706 }
707 f->got_init = 1;
708 if (f->op.init)
Miklos Szeredia1482422005-08-14 23:00:27 +0000709 f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000710
Miklos Szeredi76c17522005-07-13 14:08:19 +0000711 f->major = FUSE_KERNEL_VERSION;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000712 f->minor = arg->minor;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000713
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000714 if (bufsize < MIN_BUFFER_SIZE) {
715 fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
716 bufsize = MIN_BUFFER_SIZE;
717 }
718
719 bufsize -= HEADER_OVERHEAD;
720
Miklos Szeredi12744942005-07-11 12:32:31 +0000721 memset(&outarg, 0, sizeof(outarg));
722 outarg.major = f->major;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000723 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi12744942005-07-11 12:32:31 +0000724
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000725 /* The calculated limits may be oversized, but because of the
726 limits in VFS names and symlinks are never larger than PATH_MAX - 1
727 and xattr values never larger than XATTR_SIZE_MAX */
728
729 /* Max two names per request */
730 outarg.symlink_max = outarg.name_max = bufsize / 2;
731 /* But if buffer is small, give more room to link name */
732 if (outarg.symlink_max < MIN_SYMLINK) {
733 outarg.symlink_max = MIN_SYMLINK;
734 /* Borrow from header overhead for the SYMLINK operation */
735 outarg.name_max = HEADER_OVERHEAD / 4;
736 }
737 outarg.xattr_size_max = outarg.max_write = bufsize;
738
Miklos Szeredi76c17522005-07-13 14:08:19 +0000739 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000740 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
741 fflush(stdout);
742 }
743
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000744 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000745}
746
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000747void *fuse_req_userdata(fuse_req_t req)
748{
749 return req->f->userdata;
750}
751
752const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
753{
754 return &req->ctx;
755}
756
Miklos Szeredia1482422005-08-14 23:00:27 +0000757static void fuse_ll_process(void *data, const char *buf, size_t len,
758 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000759{
Miklos Szeredia1482422005-08-14 23:00:27 +0000760 struct fuse_ll *f = (struct fuse_ll *) data;
761 struct fuse_in_header *in = (struct fuse_in_header *) buf;
762 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000763 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000764
Miklos Szeredi76c17522005-07-13 14:08:19 +0000765 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000766 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000767 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000768 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000769 fflush(stdout);
770 }
771
Miklos Szeredi76c17522005-07-13 14:08:19 +0000772 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
773 if (req == NULL) {
774 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000775 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000776 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000777
Miklos Szeredi76c17522005-07-13 14:08:19 +0000778 req->f = f;
779 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000780 req->ctx.uid = in->uid;
781 req->ctx.gid = in->gid;
782 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000783 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000784
Miklos Szeredia1482422005-08-14 23:00:27 +0000785 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +0000786 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +0000787 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
788 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
789 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
790 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
791 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
792 fuse_reply_err(req, EACCES);
793 } else switch (in->opcode) {
794 case FUSE_INIT:
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000795 do_init(req, (struct fuse_init_in *) inarg);
Miklos Szeredia1482422005-08-14 23:00:27 +0000796 break;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000797
Miklos Szeredi12744942005-07-11 12:32:31 +0000798 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000799 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000800 break;
801
Miklos Szeredi76c17522005-07-13 14:08:19 +0000802 case FUSE_FORGET:
803 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000804 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000805
Miklos Szeredi12744942005-07-11 12:32:31 +0000806 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000807 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000808 break;
809
810 case FUSE_SETATTR:
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000811 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000812 break;
813
Miklos Szeredi12744942005-07-11 12:32:31 +0000814 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000815 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000816 break;
817
818 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000819 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000820 break;
821
822 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000823 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000824 break;
825
826 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000827 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000828 break;
829
830 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000831 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000832 break;
833
834 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000835 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000836 ((char *) inarg) + strlen((char *) inarg) + 1);
837 break;
838
839 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000840 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000841 break;
842
843 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000844 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000845 break;
846
847 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000848 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000849 break;
850
851 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000852 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000853 break;
854
855 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 break;
858
859 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000860 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000861 break;
862
863 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000864 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000865 break;
866
867 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000868 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000869 break;
870
871 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000872 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000873 break;
874
875 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000876 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000877 break;
878
879 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000880 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000881 break;
882
883 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000884 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000885 break;
886
887 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000888 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000889 break;
890
891 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000892 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000893 break;
894
895 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000896 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000897 break;
898
899 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000900 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000901 break;
902
903 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000904 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000905 break;
906
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000907 case FUSE_ACCESS:
908 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
909 break;
910
Miklos Szeredid9079a72005-10-26 15:29:06 +0000911 case FUSE_CREATE:
912 do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
913 break;
914
Miklos Szeredi12744942005-07-11 12:32:31 +0000915 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000916 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000917 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000918}
919
Miklos Szeredia1482422005-08-14 23:00:27 +0000920int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000921{
922 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +0000923 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +0000924 return 1;
925 else
926 return 0;
927}
928
Miklos Szeredi76c17522005-07-13 14:08:19 +0000929static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +0000930{
931 if (opts) {
932 char *xopts = strdup(opts);
933 char *s = xopts;
934 char *opt;
935
936 if (xopts == NULL) {
937 fprintf(stderr, "fuse: memory allocation failed\n");
938 return -1;
939 }
940
941 while((opt = strsep(&s, ","))) {
942 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000943 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000944 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000945 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000946 else
947 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
948 }
949 free(xopts);
950 }
951 return 0;
952}
953
Miklos Szeredia1482422005-08-14 23:00:27 +0000954static void fuse_ll_destroy(void *data)
955{
956 struct fuse_ll *f = (struct fuse_ll *) data;
957
958 if (f->op.destroy)
959 f->op.destroy(f->userdata);
960
961 free(f);
962}
963
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000964struct fuse_session *fuse_lowlevel_new(const char *opts,
Miklos Szeredia1482422005-08-14 23:00:27 +0000965 const struct fuse_lowlevel_ops *op,
966 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000967{
968 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +0000969 struct fuse_session *se;
970 struct fuse_session_ops sop = {
971 .process = fuse_ll_process,
972 .destroy = fuse_ll_destroy,
973 };
Miklos Szeredi12744942005-07-11 12:32:31 +0000974
Miklos Szeredia1482422005-08-14 23:00:27 +0000975 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +0000976 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000977 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +0000978 }
979
980 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
981 if (f == NULL) {
982 fprintf(stderr, "fuse: failed to allocate fuse object\n");
983 goto out;
984 }
985
Miklos Szeredi76c17522005-07-13 14:08:19 +0000986 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +0000987 goto out_free;
988
Miklos Szeredi12744942005-07-11 12:32:31 +0000989 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000990 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000991 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +0000992
Miklos Szeredia1482422005-08-14 23:00:27 +0000993 se = fuse_session_new(&sop, f);
994 if (!se)
995 goto out_free;
996
997 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +0000998
999 out_free:
1000 free(f);
1001 out:
1002 return NULL;
1003}
Miklos Szeredic706ad92005-11-07 15:30:48 +00001004
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001005#ifndef __FreeBSD__
1006
1007#include "fuse_lowlevel_compat.h"
1008
1009static void fill_open_compat(struct fuse_open_out *arg,
1010 const struct fuse_file_info_compat *f)
1011{
1012 arg->fh = f->fh;
1013 if (f->direct_io)
1014 arg->open_flags |= FOPEN_DIRECT_IO;
1015 if (f->keep_cache)
1016 arg->open_flags |= FOPEN_KEEP_CACHE;
1017}
1018
Miklos Szeredi2b478112005-11-28 13:27:10 +00001019static void convert_statfs_compat(const struct statfs *compatbuf,
1020 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001021{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001022 buf->f_bsize = compatbuf->f_bsize;
1023 buf->f_blocks = compatbuf->f_blocks;
1024 buf->f_bfree = compatbuf->f_bfree;
1025 buf->f_bavail = compatbuf->f_bavail;
1026 buf->f_files = compatbuf->f_files;
1027 buf->f_ffree = compatbuf->f_ffree;
1028 buf->f_namemax = compatbuf->f_namelen;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001029}
1030
1031int fuse_reply_open_compat(fuse_req_t req,
1032 const struct fuse_file_info_compat *f)
1033{
1034 struct fuse_open_out arg;
1035
1036 memset(&arg, 0, sizeof(arg));
1037 fill_open_compat(&arg, f);
1038 return send_reply_ok(req, &arg, sizeof(arg));
1039}
1040
1041int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1042{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001043 struct statvfs newbuf;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001044
Miklos Szeredi2b478112005-11-28 13:27:10 +00001045 memset(&newbuf, 0, sizeof(newbuf));
1046 convert_statfs_compat(stbuf, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001047
Miklos Szeredi2b478112005-11-28 13:27:10 +00001048 return fuse_reply_statfs(req, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001049}
1050
1051
Miklos Szeredic706ad92005-11-07 15:30:48 +00001052__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
Miklos Szeredi3a770472005-11-11 21:32:42 +00001053__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001054
Miklos Szeredi2b478112005-11-28 13:27:10 +00001055#endif /* __FreeBSD__ */