blob: 370e320df7c06157e6e9208ff83c539f121744bc [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 Szeredi659743b2005-12-09 17:41:42 +000012#include "fuse_opt.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000013
14#include <stdio.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000015#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000016#include <stddef.h>
17#include <string.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000018#include <unistd.h>
19#include <limits.h>
20#include <errno.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000021
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000022#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000023
Miklos Szeredi044da2e2005-12-06 17:59:55 +000024/* PATH_MAX is 4k on Linux, but I don't dare to define it to PATH_MAX,
25 because it may be much larger on other systems */
26#define MIN_SYMLINK 0x1000
27
28/* Generous 4k overhead for headers, includes room for xattr name
29 (XATTR_NAME_MAX = 255) */
30#define HEADER_OVERHEAD 0x1000
31
32/* 8k, the same as the old FUSE_MAX_IN constant */
33#define MIN_BUFFER_SIZE (MIN_SYMLINK + HEADER_OVERHEAD)
34
Miklos Szeredia1482422005-08-14 23:00:27 +000035struct fuse_ll {
Miklos Szeredi659743b2005-12-09 17:41:42 +000036 int debug;
37 int allow_root;
Miklos Szeredia1482422005-08-14 23:00:27 +000038 struct fuse_lowlevel_ops op;
39 int got_init;
40 void *userdata;
41 int major;
42 int minor;
43 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000044};
45
Miklos Szeredi76c17522005-07-13 14:08:19 +000046struct fuse_req {
47 struct fuse_ll *f;
48 uint64_t unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000049 struct fuse_ctx ctx;
Miklos Szeredia1482422005-08-14 23:00:27 +000050 struct fuse_chan *ch;
Miklos Szeredi76c17522005-07-13 14:08:19 +000051};
52
Miklos Szeredi12744942005-07-11 12:32:31 +000053static const char *opname(enum fuse_opcode opcode)
54{
55 switch (opcode) {
56 case FUSE_LOOKUP: return "LOOKUP";
57 case FUSE_FORGET: return "FORGET";
58 case FUSE_GETATTR: return "GETATTR";
59 case FUSE_SETATTR: return "SETATTR";
60 case FUSE_READLINK: return "READLINK";
61 case FUSE_SYMLINK: return "SYMLINK";
62 case FUSE_MKNOD: return "MKNOD";
63 case FUSE_MKDIR: return "MKDIR";
64 case FUSE_UNLINK: return "UNLINK";
65 case FUSE_RMDIR: return "RMDIR";
66 case FUSE_RENAME: return "RENAME";
67 case FUSE_LINK: return "LINK";
68 case FUSE_OPEN: return "OPEN";
69 case FUSE_READ: return "READ";
70 case FUSE_WRITE: return "WRITE";
71 case FUSE_STATFS: return "STATFS";
72 case FUSE_FLUSH: return "FLUSH";
73 case FUSE_RELEASE: return "RELEASE";
74 case FUSE_FSYNC: return "FSYNC";
75 case FUSE_SETXATTR: return "SETXATTR";
76 case FUSE_GETXATTR: return "GETXATTR";
77 case FUSE_LISTXATTR: return "LISTXATTR";
78 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
79 case FUSE_INIT: return "INIT";
80 case FUSE_OPENDIR: return "OPENDIR";
81 case FUSE_READDIR: return "READDIR";
82 case FUSE_RELEASEDIR: return "RELEASEDIR";
83 case FUSE_FSYNCDIR: return "FSYNCDIR";
Miklos Szeredib0b13d12005-10-26 12:53:25 +000084 case FUSE_ACCESS: return "ACCESS";
Miklos Szeredid9079a72005-10-26 15:29:06 +000085 case FUSE_CREATE: return "CREATE";
Miklos Szeredi12744942005-07-11 12:32:31 +000086 default: return "???";
87 }
88}
89
Miklos Szeredi76c17522005-07-13 14:08:19 +000090static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000091{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000092 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000093 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000094 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000095 attr->uid = stbuf->st_uid;
96 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000097 attr->rdev = stbuf->st_rdev;
98 attr->size = stbuf->st_size;
99 attr->blocks = stbuf->st_blocks;
100 attr->atime = stbuf->st_atime;
101 attr->mtime = stbuf->st_mtime;
102 attr->ctime = stbuf->st_ctime;
103#ifdef HAVE_STRUCT_STAT_ST_ATIM
104 attr->atimensec = stbuf->st_atim.tv_nsec;
105 attr->mtimensec = stbuf->st_mtim.tv_nsec;
106 attr->ctimensec = stbuf->st_ctim.tv_nsec;
107#endif
108}
109
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000110static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000111{
112 stbuf->st_mode = attr->mode;
113 stbuf->st_uid = attr->uid;
114 stbuf->st_gid = attr->gid;
115 stbuf->st_size = attr->size;
116 stbuf->st_atime = attr->atime;
117 stbuf->st_mtime = attr->mtime;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000118#ifdef HAVE_STRUCT_STAT_ST_ATIM
119 stbuf->st_atim.tv_nsec = attr->atimensec;
120 stbuf->st_mtim.tv_nsec = attr->mtimensec;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000121#endif
122}
123
Miklos Szeredi12744942005-07-11 12:32:31 +0000124static size_t iov_length(const struct iovec *iov, size_t count)
125{
126 size_t seg;
127 size_t ret = 0;
128
129 for (seg = 0; seg < count; seg++)
130 ret += iov[seg].iov_len;
131 return ret;
132}
133
Miklos Szeredia1482422005-08-14 23:00:27 +0000134static void free_req(fuse_req_t req)
Miklos Szeredi12744942005-07-11 12:32:31 +0000135{
Miklos Szeredia1482422005-08-14 23:00:27 +0000136 free(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000137}
138
Miklos Szeredia1482422005-08-14 23:00:27 +0000139static int send_reply(fuse_req_t req, int error, const void *arg,
140 size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000141{
142 struct fuse_out_header out;
143 struct iovec iov[2];
144 size_t count;
Miklos Szeredia1482422005-08-14 23:00:27 +0000145 int res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000146
147 if (error <= -1000 || error > 0) {
148 fprintf(stderr, "fuse: bad error value: %i\n", error);
149 error = -ERANGE;
150 }
151
Miklos Szeredia1482422005-08-14 23:00:27 +0000152 out.unique = req->unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000153 out.error = error;
154 count = 1;
155 iov[0].iov_base = &out;
156 iov[0].iov_len = sizeof(struct fuse_out_header);
157 if (argsize && !error) {
158 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000159 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000160 iov[1].iov_len = argsize;
161 }
Miklos Szeredia1482422005-08-14 23:00:27 +0000162 out.len = iov_length(iov, count);
163
164 if (req->f->debug) {
165 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
166 out.unique, out.error, strerror(-out.error), out.len);
167 fflush(stdout);
168 }
169 res = fuse_chan_send(req->ch, iov, count);
170 free_req(req);
171
172 return res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000173}
174
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000175size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000176{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000177 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000178}
179
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000180char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000181 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000182{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000183 unsigned namelen = strlen(name);
184 unsigned entlen = FUSE_NAME_OFFSET + namelen;
185 unsigned entsize = fuse_dirent_size(namelen);
186 unsigned padlen = entsize - entlen;
187 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000188
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000189 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000190 dirent->off = off;
191 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000192 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000193 strncpy(dirent->name, name, namelen);
194 if (padlen)
195 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000196
Miklos Szeredi76c17522005-07-13 14:08:19 +0000197 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000198}
199
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000200static void convert_statfs(const struct statvfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000201 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000202{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000203 kstatfs->bsize = stbuf->f_bsize;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000204 kstatfs->frsize = stbuf->f_frsize;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000205 kstatfs->blocks = stbuf->f_blocks;
206 kstatfs->bfree = stbuf->f_bfree;
207 kstatfs->bavail = stbuf->f_bavail;
208 kstatfs->files = stbuf->f_files;
209 kstatfs->ffree = stbuf->f_ffree;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000210 kstatfs->namelen = stbuf->f_namemax;
Miklos Szeredi12744942005-07-11 12:32:31 +0000211}
212
Miklos Szeredia1482422005-08-14 23:00:27 +0000213static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000214{
Miklos Szeredia1482422005-08-14 23:00:27 +0000215 return send_reply(req, 0, arg, argsize);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000216}
217
218int fuse_reply_err(fuse_req_t req, int err)
219{
Miklos Szeredia1482422005-08-14 23:00:27 +0000220 return send_reply(req, -err, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000221}
222
Miklos Szeredi836ab712005-10-03 14:11:59 +0000223void fuse_reply_none(fuse_req_t req)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000224{
225 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000226}
227
228static unsigned long calc_timeout_sec(double t)
229{
230 if (t > (double) ULONG_MAX)
231 return ULONG_MAX;
232 else if (t < 0.0)
233 return 0;
234 else
235 return (unsigned long) t;
236}
237
238static unsigned int calc_timeout_nsec(double t)
239{
240 double f = t - (double) calc_timeout_sec(t);
241 if (f < 0.0)
242 return 0;
243 else if (f >= 0.999999999)
244 return 999999999;
245 else
246 return (unsigned int) (f * 1.0e9);
247}
248
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000249static void fill_entry(struct fuse_entry_out *arg,
250 const struct fuse_entry_param *e)
251{
252 arg->nodeid = e->ino;
253 arg->generation = e->generation;
254 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
255 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
256 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
257 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
258 convert_stat(&e->attr, &arg->attr);
259}
260
261static void fill_open(struct fuse_open_out *arg,
262 const struct fuse_file_info *f)
263{
264 arg->fh = f->fh;
265 if (f->direct_io)
266 arg->open_flags |= FOPEN_DIRECT_IO;
267 if (f->keep_cache)
268 arg->open_flags |= FOPEN_KEEP_CACHE;
269}
270
Miklos Szeredi76c17522005-07-13 14:08:19 +0000271int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
272{
273 struct fuse_entry_out arg;
274
Miklos Szeredi2b478112005-11-28 13:27:10 +0000275 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
276 negative entry */
277 if (!e->ino && req->f->minor < 4)
278 return fuse_reply_err(req, ENOENT);
279
Miklos Szeredi76c17522005-07-13 14:08:19 +0000280 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000281 fill_entry(&arg, e);
282 return send_reply_ok(req, &arg, sizeof(arg));
283}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000284
Miklos Szeredid9079a72005-10-26 15:29:06 +0000285int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
286 const struct fuse_file_info *f)
287{
288 struct {
289 struct fuse_entry_out e;
290 struct fuse_open_out o;
291 } arg;
292
293 memset(&arg, 0, sizeof(arg));
294 fill_entry(&arg.e, e);
295 fill_open(&arg.o, f);
296 return send_reply_ok(req, &arg, sizeof(arg));
297}
298
Miklos Szeredi76c17522005-07-13 14:08:19 +0000299int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
300 double attr_timeout)
301{
302 struct fuse_attr_out arg;
303
304 memset(&arg, 0, sizeof(arg));
305 arg.attr_valid = calc_timeout_sec(attr_timeout);
306 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
307 convert_stat(attr, &arg.attr);
308
Miklos Szeredia1482422005-08-14 23:00:27 +0000309 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000310}
311
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000312int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000313{
Miklos Szeredia1482422005-08-14 23:00:27 +0000314 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000315}
316
317int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
318{
319 struct fuse_open_out arg;
320
321 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000322 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000323 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000324}
325
326int fuse_reply_write(fuse_req_t req, size_t count)
327{
328 struct fuse_write_out arg;
329
330 memset(&arg, 0, sizeof(arg));
331 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000332
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
336int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
337{
Miklos Szeredia1482422005-08-14 23:00:27 +0000338 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000339}
340
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000341int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000342{
343 struct fuse_statfs_out arg;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000344 size_t size = req->f->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000345
346 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000347 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000348
Miklos Szeredi2b478112005-11-28 13:27:10 +0000349 return send_reply_ok(req, &arg, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000350}
351
352int fuse_reply_xattr(fuse_req_t req, size_t count)
353{
354 struct fuse_getxattr_out arg;
355
356 memset(&arg, 0, sizeof(arg));
357 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000358
Miklos Szeredia1482422005-08-14 23:00:27 +0000359 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000360}
361
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000362static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000363{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000364 if (req->f->op.lookup)
365 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000366 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000367 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000368}
369
Miklos Szeredi76c17522005-07-13 14:08:19 +0000370static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
371 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000372{
373 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000374 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000375}
376
377static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
378{
379 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000380 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000381 else
382 fuse_reply_err(req, ENOSYS);
383}
384
385static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000386 struct fuse_setattr_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000387{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000388 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000389 struct fuse_file_info *fi = NULL;
390 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000391 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000392 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000393 convert_attr(arg, &stbuf);
394 if (arg->valid & FATTR_FH) {
395 arg->valid &= ~FATTR_FH;
396 memset(&fi_store, 0, sizeof(fi_store));
397 fi = &fi_store;
398 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000399 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000400 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000401 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000402 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000403 fuse_reply_err(req, ENOSYS);
404}
405
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000406static void do_access(fuse_req_t req, fuse_ino_t nodeid,
407 struct fuse_access_in *arg)
408{
409 if (req->f->op.access)
410 req->f->op.access(req, nodeid, arg->mask);
411 else
412 fuse_reply_err(req, ENOSYS);
413}
414
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000415static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
416{
417 if (req->f->op.readlink)
418 req->f->op.readlink(req, nodeid);
419 else
420 fuse_reply_err(req, ENOSYS);
421}
422
423static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
424 struct fuse_mknod_in *arg)
425{
426 if (req->f->op.mknod)
427 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
428 else
429 fuse_reply_err(req, ENOSYS);
430}
431
432static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
433 struct fuse_mkdir_in *arg)
434{
435 if (req->f->op.mkdir)
436 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
437 else
438 fuse_reply_err(req, ENOSYS);
439}
440
441static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
442{
443 if (req->f->op.unlink)
444 req->f->op.unlink(req, nodeid, name);
445 else
446 fuse_reply_err(req, ENOSYS);
447}
448
449static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
450{
451 if (req->f->op.rmdir)
452 req->f->op.rmdir(req, nodeid, name);
453 else
454 fuse_reply_err(req, ENOSYS);
455}
456
457static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000458 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000459{
460 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000461 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000462 else
463 fuse_reply_err(req, ENOSYS);
464}
465
466static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
467 struct fuse_rename_in *arg)
468{
469 char *oldname = PARAM(arg);
470 char *newname = oldname + strlen(oldname) + 1;
471
472 if (req->f->op.rename)
473 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
474 else
475 fuse_reply_err(req, ENOSYS);
476}
477
478static void do_link(fuse_req_t req, fuse_ino_t nodeid,
479 struct fuse_link_in *arg)
480{
481 if (req->f->op.link)
482 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
483 else
484 fuse_reply_err(req, ENOSYS);
485}
486
Miklos Szeredid9079a72005-10-26 15:29:06 +0000487static void do_create(fuse_req_t req, fuse_ino_t nodeid,
488 struct fuse_open_in *arg)
489{
490 if (req->f->op.create) {
491 struct fuse_file_info fi;
492
493 memset(&fi, 0, sizeof(fi));
494 fi.flags = arg->flags;
495
496 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
497 } else
498 fuse_reply_err(req, ENOSYS);
499}
500
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000501static void do_open(fuse_req_t req, fuse_ino_t nodeid,
502 struct fuse_open_in *arg)
503{
504 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000505
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000506 memset(&fi, 0, sizeof(fi));
507 fi.flags = arg->flags;
508
509 if (req->f->op.open)
510 req->f->op.open(req, nodeid, &fi);
511 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000512 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000513}
514
515static void do_read(fuse_req_t req, fuse_ino_t nodeid,
516 struct fuse_read_in *arg)
517{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000518 if (req->f->op.read) {
519 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000520
Miklos Szeredi76c17522005-07-13 14:08:19 +0000521 memset(&fi, 0, sizeof(fi));
522 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000523 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000524 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000525 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000526 fuse_reply_err(req, ENOSYS);
527}
528
529static void do_write(fuse_req_t req, fuse_ino_t nodeid,
530 struct fuse_write_in *arg)
531{
532 struct fuse_file_info fi;
533
534 memset(&fi, 0, sizeof(fi));
535 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000536 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000537 fi.writepage = arg->write_flags & 1;
538
539 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000540 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
541 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000542 else
543 fuse_reply_err(req, ENOSYS);
544}
545
546static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
547 struct fuse_flush_in *arg)
548{
549 struct fuse_file_info fi;
550
551 memset(&fi, 0, sizeof(fi));
552 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000553 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000554
555 if (req->f->op.flush)
556 req->f->op.flush(req, nodeid, &fi);
557 else
558 fuse_reply_err(req, ENOSYS);
559}
560
561static void do_release(fuse_req_t req, fuse_ino_t nodeid,
562 struct fuse_release_in *arg)
563{
564 struct fuse_file_info fi;
565
566 memset(&fi, 0, sizeof(fi));
567 fi.flags = arg->flags;
568 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000569 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000570
571 if (req->f->op.release)
572 req->f->op.release(req, nodeid, &fi);
573 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000574 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000575}
576
577static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000578 struct fuse_fsync_in *inarg)
579{
Miklos Szeredi12744942005-07-11 12:32:31 +0000580 struct fuse_file_info fi;
581
582 memset(&fi, 0, sizeof(fi));
583 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000584 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000585
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000586 if (req->f->op.fsync)
587 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
588 else
589 fuse_reply_err(req, ENOSYS);
590}
591
592static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
593 struct fuse_open_in *arg)
594{
595 struct fuse_file_info fi;
596
597 memset(&fi, 0, sizeof(fi));
598 fi.flags = arg->flags;
599
600 if (req->f->op.opendir)
601 req->f->op.opendir(req, nodeid, &fi);
602 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000603 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000604}
605
606static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
607 struct fuse_read_in *arg)
608{
609 struct fuse_file_info fi;
610
611 memset(&fi, 0, sizeof(fi));
612 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000613 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000614
615 if (req->f->op.readdir)
616 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
617 else
618 fuse_reply_err(req, ENOSYS);
619}
620
621static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
622 struct fuse_release_in *arg)
623{
624 struct fuse_file_info fi;
625
626 memset(&fi, 0, sizeof(fi));
627 fi.flags = arg->flags;
628 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000629 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000630
631 if (req->f->op.releasedir)
632 req->f->op.releasedir(req, nodeid, &fi);
633 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000634 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000635}
636
637static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
638 struct fuse_fsync_in *inarg)
639{
640 struct fuse_file_info fi;
641
642 memset(&fi, 0, sizeof(fi));
643 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000644 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000645
646 if (req->f->op.fsyncdir)
647 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
648 else
649 fuse_reply_err(req, ENOSYS);
650}
651
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000652static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000653{
654 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000655 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000656 else
657 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000658}
659
Miklos Szeredi4331a272005-07-12 14:51:04 +0000660static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000661 struct fuse_setxattr_in *arg)
662{
Miklos Szeredi12744942005-07-11 12:32:31 +0000663 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000664 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000665
Miklos Szeredi4331a272005-07-12 14:51:04 +0000666 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000667 req->f->op.setxattr(req, nodeid, name, value, arg->size,
668 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000669 else
670 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000671}
672
Miklos Szeredi4331a272005-07-12 14:51:04 +0000673static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000674 struct fuse_getxattr_in *arg)
675{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000676 if (req->f->op.getxattr)
677 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000678 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000679 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000680}
681
Miklos Szeredi4331a272005-07-12 14:51:04 +0000682static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000683 struct fuse_getxattr_in *arg)
684{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000685 if (req->f->op.listxattr)
686 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000687 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000688 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000689}
690
Miklos Szeredi4331a272005-07-12 14:51:04 +0000691static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000692{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000693 if (req->f->op.removexattr)
694 req->f->op.removexattr(req, nodeid, name);
695 else
696 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000697}
698
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000699static void do_init(fuse_req_t req, struct fuse_init_in *arg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000700{
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000701 struct fuse_init_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000702 struct fuse_ll *f = req->f;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000703 size_t bufsize = fuse_chan_bufsize(req->ch);
Miklos Szeredi12744942005-07-11 12:32:31 +0000704
Miklos Szeredi76c17522005-07-13 14:08:19 +0000705 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000706 printf("INIT: %u.%u\n", arg->major, arg->minor);
707 fflush(stdout);
708 }
709 f->got_init = 1;
710 if (f->op.init)
Miklos Szeredia1482422005-08-14 23:00:27 +0000711 f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000712
Miklos Szeredi76c17522005-07-13 14:08:19 +0000713 f->major = FUSE_KERNEL_VERSION;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000714 f->minor = arg->minor;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000715
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000716 if (bufsize < MIN_BUFFER_SIZE) {
717 fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
718 bufsize = MIN_BUFFER_SIZE;
719 }
720
721 bufsize -= HEADER_OVERHEAD;
722
Miklos Szeredi12744942005-07-11 12:32:31 +0000723 memset(&outarg, 0, sizeof(outarg));
724 outarg.major = f->major;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000725 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi12744942005-07-11 12:32:31 +0000726
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000727 /* The calculated limits may be oversized, but because of the
728 limits in VFS names and symlinks are never larger than PATH_MAX - 1
729 and xattr values never larger than XATTR_SIZE_MAX */
730
731 /* Max two names per request */
732 outarg.symlink_max = outarg.name_max = bufsize / 2;
733 /* But if buffer is small, give more room to link name */
734 if (outarg.symlink_max < MIN_SYMLINK) {
735 outarg.symlink_max = MIN_SYMLINK;
736 /* Borrow from header overhead for the SYMLINK operation */
737 outarg.name_max = HEADER_OVERHEAD / 4;
738 }
739 outarg.xattr_size_max = outarg.max_write = bufsize;
740
Miklos Szeredi76c17522005-07-13 14:08:19 +0000741 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000742 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
743 fflush(stdout);
744 }
745
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000746 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000747}
748
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000749void *fuse_req_userdata(fuse_req_t req)
750{
751 return req->f->userdata;
752}
753
754const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
755{
756 return &req->ctx;
757}
758
Miklos Szeredia1482422005-08-14 23:00:27 +0000759static void fuse_ll_process(void *data, const char *buf, size_t len,
760 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000761{
Miklos Szeredia1482422005-08-14 23:00:27 +0000762 struct fuse_ll *f = (struct fuse_ll *) data;
763 struct fuse_in_header *in = (struct fuse_in_header *) buf;
764 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000765 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000766
Miklos Szeredi76c17522005-07-13 14:08:19 +0000767 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000768 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000769 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000770 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000771 fflush(stdout);
772 }
773
Miklos Szeredi76c17522005-07-13 14:08:19 +0000774 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
775 if (req == NULL) {
776 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000777 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000778 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000779
Miklos Szeredi76c17522005-07-13 14:08:19 +0000780 req->f = f;
781 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000782 req->ctx.uid = in->uid;
783 req->ctx.gid = in->gid;
784 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000785 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000786
Miklos Szeredia1482422005-08-14 23:00:27 +0000787 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +0000788 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +0000789 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
790 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
791 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
792 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
793 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
794 fuse_reply_err(req, EACCES);
795 } else switch (in->opcode) {
796 case FUSE_INIT:
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000797 do_init(req, (struct fuse_init_in *) inarg);
Miklos Szeredia1482422005-08-14 23:00:27 +0000798 break;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000799
Miklos Szeredi12744942005-07-11 12:32:31 +0000800 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000801 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000802 break;
803
Miklos Szeredi76c17522005-07-13 14:08:19 +0000804 case FUSE_FORGET:
805 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000806 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000807
Miklos Szeredi12744942005-07-11 12:32:31 +0000808 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000809 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000810 break;
811
812 case FUSE_SETATTR:
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000813 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000814 break;
815
Miklos Szeredi12744942005-07-11 12:32:31 +0000816 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000817 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000818 break;
819
820 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000821 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000822 break;
823
824 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000825 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000826 break;
827
828 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000829 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000830 break;
831
832 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000833 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000834 break;
835
836 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000837 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000838 ((char *) inarg) + strlen((char *) inarg) + 1);
839 break;
840
841 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000842 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000843 break;
844
845 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000846 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000847 break;
848
849 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000850 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000851 break;
852
853 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000854 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000855 break;
856
857 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000858 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000859 break;
860
861 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000862 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000863 break;
864
865 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000866 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000867 break;
868
869 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000870 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000871 break;
872
873 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000874 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000875 break;
876
877 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000878 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000879 break;
880
881 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000882 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000883 break;
884
885 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000886 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000887 break;
888
889 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000890 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000891 break;
892
893 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000894 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000895 break;
896
897 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000898 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000899 break;
900
901 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000902 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000903 break;
904
905 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000906 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000907 break;
908
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000909 case FUSE_ACCESS:
910 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
911 break;
912
Miklos Szeredid9079a72005-10-26 15:29:06 +0000913 case FUSE_CREATE:
914 do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
915 break;
916
Miklos Szeredi12744942005-07-11 12:32:31 +0000917 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000918 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000919 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000920}
921
Miklos Szeredi659743b2005-12-09 17:41:42 +0000922static struct fuse_opt fuse_ll_opts[] = {
923 { "debug", offsetof(struct fuse_ll, debug), 1 },
924 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
925 FUSE_OPT_END
926};
927
Miklos Szeredia1482422005-08-14 23:00:27 +0000928int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000929{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000930 return fuse_opt_match(fuse_ll_opts, opt);
Miklos Szeredi12744942005-07-11 12:32:31 +0000931}
932
Miklos Szeredia1482422005-08-14 23:00:27 +0000933static void fuse_ll_destroy(void *data)
934{
935 struct fuse_ll *f = (struct fuse_ll *) data;
936
937 if (f->op.destroy)
938 f->op.destroy(f->userdata);
939
940 free(f);
941}
942
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000943struct fuse_session *fuse_lowlevel_new(const char *opts,
Miklos Szeredia1482422005-08-14 23:00:27 +0000944 const struct fuse_lowlevel_ops *op,
945 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000946{
947 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +0000948 struct fuse_session *se;
949 struct fuse_session_ops sop = {
950 .process = fuse_ll_process,
951 .destroy = fuse_ll_destroy,
952 };
Miklos Szeredi12744942005-07-11 12:32:31 +0000953
Miklos Szeredia1482422005-08-14 23:00:27 +0000954 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +0000955 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000956 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +0000957 }
958
959 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
960 if (f == NULL) {
961 fprintf(stderr, "fuse: failed to allocate fuse object\n");
962 goto out;
963 }
964
Miklos Szeredi659743b2005-12-09 17:41:42 +0000965 if (opts) {
966 const char *argv[] = { "", "-o", opts, NULL };
967 if (fuse_opt_parse(3, (char **) argv, f, fuse_ll_opts, NULL,
968 NULL, NULL) == -1)
969 goto out_free;
970 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000971
Miklos Szeredi12744942005-07-11 12:32:31 +0000972 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000973 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000974 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +0000975
Miklos Szeredia1482422005-08-14 23:00:27 +0000976 se = fuse_session_new(&sop, f);
977 if (!se)
978 goto out_free;
979
980 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +0000981
982 out_free:
983 free(f);
984 out:
985 return NULL;
986}
Miklos Szeredic706ad92005-11-07 15:30:48 +0000987
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000988#ifndef __FreeBSD__
989
990#include "fuse_lowlevel_compat.h"
991
992static void fill_open_compat(struct fuse_open_out *arg,
993 const struct fuse_file_info_compat *f)
994{
995 arg->fh = f->fh;
996 if (f->direct_io)
997 arg->open_flags |= FOPEN_DIRECT_IO;
998 if (f->keep_cache)
999 arg->open_flags |= FOPEN_KEEP_CACHE;
1000}
1001
Miklos Szeredi2b478112005-11-28 13:27:10 +00001002static void convert_statfs_compat(const struct statfs *compatbuf,
1003 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001004{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001005 buf->f_bsize = compatbuf->f_bsize;
1006 buf->f_blocks = compatbuf->f_blocks;
1007 buf->f_bfree = compatbuf->f_bfree;
1008 buf->f_bavail = compatbuf->f_bavail;
1009 buf->f_files = compatbuf->f_files;
1010 buf->f_ffree = compatbuf->f_ffree;
1011 buf->f_namemax = compatbuf->f_namelen;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001012}
1013
1014int fuse_reply_open_compat(fuse_req_t req,
1015 const struct fuse_file_info_compat *f)
1016{
1017 struct fuse_open_out arg;
1018
1019 memset(&arg, 0, sizeof(arg));
1020 fill_open_compat(&arg, f);
1021 return send_reply_ok(req, &arg, sizeof(arg));
1022}
1023
1024int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1025{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001026 struct statvfs newbuf;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001027
Miklos Szeredi2b478112005-11-28 13:27:10 +00001028 memset(&newbuf, 0, sizeof(newbuf));
1029 convert_statfs_compat(stbuf, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001030
Miklos Szeredi2b478112005-11-28 13:27:10 +00001031 return fuse_reply_statfs(req, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001032}
1033
1034
Miklos Szeredic706ad92005-11-07 15:30:48 +00001035__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
Miklos Szeredi3a770472005-11-11 21:32:42 +00001036__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001037
Miklos Szeredi2b478112005-11-28 13:27:10 +00001038#endif /* __FreeBSD__ */