blob: 0bd6c995902270948e827c65f1d9a40175b60b49 [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 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 Szeredia1482422005-08-14 23:00:27 +000024struct fuse_ll {
Miklos Szeredi659743b2005-12-09 17:41:42 +000025 int debug;
26 int allow_root;
Miklos Szeredia1482422005-08-14 23:00:27 +000027 struct fuse_lowlevel_ops op;
28 int got_init;
29 void *userdata;
30 int major;
31 int minor;
32 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000033};
34
Miklos Szeredi76c17522005-07-13 14:08:19 +000035struct fuse_req {
36 struct fuse_ll *f;
37 uint64_t unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000038 struct fuse_ctx ctx;
Miklos Szeredia1482422005-08-14 23:00:27 +000039 struct fuse_chan *ch;
Miklos Szeredi76c17522005-07-13 14:08:19 +000040};
41
Miklos Szeredi12744942005-07-11 12:32:31 +000042static const char *opname(enum fuse_opcode opcode)
43{
44 switch (opcode) {
45 case FUSE_LOOKUP: return "LOOKUP";
46 case FUSE_FORGET: return "FORGET";
47 case FUSE_GETATTR: return "GETATTR";
48 case FUSE_SETATTR: return "SETATTR";
49 case FUSE_READLINK: return "READLINK";
50 case FUSE_SYMLINK: return "SYMLINK";
51 case FUSE_MKNOD: return "MKNOD";
52 case FUSE_MKDIR: return "MKDIR";
53 case FUSE_UNLINK: return "UNLINK";
54 case FUSE_RMDIR: return "RMDIR";
55 case FUSE_RENAME: return "RENAME";
56 case FUSE_LINK: return "LINK";
57 case FUSE_OPEN: return "OPEN";
58 case FUSE_READ: return "READ";
59 case FUSE_WRITE: return "WRITE";
60 case FUSE_STATFS: return "STATFS";
61 case FUSE_FLUSH: return "FLUSH";
62 case FUSE_RELEASE: return "RELEASE";
63 case FUSE_FSYNC: return "FSYNC";
64 case FUSE_SETXATTR: return "SETXATTR";
65 case FUSE_GETXATTR: return "GETXATTR";
66 case FUSE_LISTXATTR: return "LISTXATTR";
67 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
68 case FUSE_INIT: return "INIT";
69 case FUSE_OPENDIR: return "OPENDIR";
70 case FUSE_READDIR: return "READDIR";
71 case FUSE_RELEASEDIR: return "RELEASEDIR";
72 case FUSE_FSYNCDIR: return "FSYNCDIR";
Miklos Szeredib0b13d12005-10-26 12:53:25 +000073 case FUSE_ACCESS: return "ACCESS";
Miklos Szeredid9079a72005-10-26 15:29:06 +000074 case FUSE_CREATE: return "CREATE";
Miklos Szeredi12744942005-07-11 12:32:31 +000075 default: return "???";
76 }
77}
78
Miklos Szeredi76c17522005-07-13 14:08:19 +000079static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000080{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000081 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000082 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000083 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000084 attr->uid = stbuf->st_uid;
85 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000086 attr->rdev = stbuf->st_rdev;
87 attr->size = stbuf->st_size;
88 attr->blocks = stbuf->st_blocks;
89 attr->atime = stbuf->st_atime;
90 attr->mtime = stbuf->st_mtime;
91 attr->ctime = stbuf->st_ctime;
92#ifdef HAVE_STRUCT_STAT_ST_ATIM
93 attr->atimensec = stbuf->st_atim.tv_nsec;
94 attr->mtimensec = stbuf->st_mtim.tv_nsec;
95 attr->ctimensec = stbuf->st_ctim.tv_nsec;
96#endif
97}
98
Miklos Szeredi11509ce2005-10-26 16:04:04 +000099static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000100{
101 stbuf->st_mode = attr->mode;
102 stbuf->st_uid = attr->uid;
103 stbuf->st_gid = attr->gid;
104 stbuf->st_size = attr->size;
105 stbuf->st_atime = attr->atime;
106 stbuf->st_mtime = attr->mtime;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000107#ifdef HAVE_STRUCT_STAT_ST_ATIM
108 stbuf->st_atim.tv_nsec = attr->atimensec;
109 stbuf->st_mtim.tv_nsec = attr->mtimensec;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000110#endif
111}
112
Miklos Szeredi12744942005-07-11 12:32:31 +0000113static size_t iov_length(const struct iovec *iov, size_t count)
114{
115 size_t seg;
116 size_t ret = 0;
117
118 for (seg = 0; seg < count; seg++)
119 ret += iov[seg].iov_len;
120 return ret;
121}
122
Miklos Szeredia1482422005-08-14 23:00:27 +0000123static void free_req(fuse_req_t req)
Miklos Szeredi12744942005-07-11 12:32:31 +0000124{
Miklos Szeredia1482422005-08-14 23:00:27 +0000125 free(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000126}
127
Miklos Szeredia1482422005-08-14 23:00:27 +0000128static int send_reply(fuse_req_t req, int error, const void *arg,
129 size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000130{
131 struct fuse_out_header out;
132 struct iovec iov[2];
133 size_t count;
Miklos Szeredia1482422005-08-14 23:00:27 +0000134 int res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000135
136 if (error <= -1000 || error > 0) {
137 fprintf(stderr, "fuse: bad error value: %i\n", error);
138 error = -ERANGE;
139 }
140
Miklos Szeredia1482422005-08-14 23:00:27 +0000141 out.unique = req->unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000142 out.error = error;
143 count = 1;
144 iov[0].iov_base = &out;
145 iov[0].iov_len = sizeof(struct fuse_out_header);
146 if (argsize && !error) {
147 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000148 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000149 iov[1].iov_len = argsize;
150 }
Miklos Szeredia1482422005-08-14 23:00:27 +0000151 out.len = iov_length(iov, count);
152
153 if (req->f->debug) {
154 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
155 out.unique, out.error, strerror(-out.error), out.len);
156 fflush(stdout);
157 }
158 res = fuse_chan_send(req->ch, iov, count);
159 free_req(req);
160
161 return res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000162}
163
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000164size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000165{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000166 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000167}
168
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000169char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000170 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000171{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000172 unsigned namelen = strlen(name);
173 unsigned entlen = FUSE_NAME_OFFSET + namelen;
174 unsigned entsize = fuse_dirent_size(namelen);
175 unsigned padlen = entsize - entlen;
176 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000177
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000178 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000179 dirent->off = off;
180 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000181 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000182 strncpy(dirent->name, name, namelen);
183 if (padlen)
184 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000185
Miklos Szeredi76c17522005-07-13 14:08:19 +0000186 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000187}
188
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000189static void convert_statfs(const struct statvfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000190 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000191{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000192 kstatfs->bsize = stbuf->f_bsize;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000193 kstatfs->frsize = stbuf->f_frsize;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000194 kstatfs->blocks = stbuf->f_blocks;
195 kstatfs->bfree = stbuf->f_bfree;
196 kstatfs->bavail = stbuf->f_bavail;
197 kstatfs->files = stbuf->f_files;
198 kstatfs->ffree = stbuf->f_ffree;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000199 kstatfs->namelen = stbuf->f_namemax;
Miklos Szeredi12744942005-07-11 12:32:31 +0000200}
201
Miklos Szeredia1482422005-08-14 23:00:27 +0000202static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000203{
Miklos Szeredia1482422005-08-14 23:00:27 +0000204 return send_reply(req, 0, arg, argsize);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000205}
206
207int fuse_reply_err(fuse_req_t req, int err)
208{
Miklos Szeredia1482422005-08-14 23:00:27 +0000209 return send_reply(req, -err, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000210}
211
Miklos Szeredi836ab712005-10-03 14:11:59 +0000212void fuse_reply_none(fuse_req_t req)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000213{
214 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000215}
216
217static unsigned long calc_timeout_sec(double t)
218{
219 if (t > (double) ULONG_MAX)
220 return ULONG_MAX;
221 else if (t < 0.0)
222 return 0;
223 else
224 return (unsigned long) t;
225}
226
227static unsigned int calc_timeout_nsec(double t)
228{
229 double f = t - (double) calc_timeout_sec(t);
230 if (f < 0.0)
231 return 0;
232 else if (f >= 0.999999999)
233 return 999999999;
234 else
235 return (unsigned int) (f * 1.0e9);
236}
237
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000238static void fill_entry(struct fuse_entry_out *arg,
239 const struct fuse_entry_param *e)
240{
241 arg->nodeid = e->ino;
242 arg->generation = e->generation;
243 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
244 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
245 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
246 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
247 convert_stat(&e->attr, &arg->attr);
248}
249
250static void fill_open(struct fuse_open_out *arg,
251 const struct fuse_file_info *f)
252{
253 arg->fh = f->fh;
254 if (f->direct_io)
255 arg->open_flags |= FOPEN_DIRECT_IO;
256 if (f->keep_cache)
257 arg->open_flags |= FOPEN_KEEP_CACHE;
258}
259
Miklos Szeredi76c17522005-07-13 14:08:19 +0000260int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
261{
262 struct fuse_entry_out arg;
263
Miklos Szeredi2b478112005-11-28 13:27:10 +0000264 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
265 negative entry */
266 if (!e->ino && req->f->minor < 4)
267 return fuse_reply_err(req, ENOENT);
268
Miklos Szeredi76c17522005-07-13 14:08:19 +0000269 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000270 fill_entry(&arg, e);
271 return send_reply_ok(req, &arg, sizeof(arg));
272}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000273
Miklos Szeredid9079a72005-10-26 15:29:06 +0000274int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
275 const struct fuse_file_info *f)
276{
277 struct {
278 struct fuse_entry_out e;
279 struct fuse_open_out o;
280 } arg;
281
282 memset(&arg, 0, sizeof(arg));
283 fill_entry(&arg.e, e);
284 fill_open(&arg.o, f);
285 return send_reply_ok(req, &arg, sizeof(arg));
286}
287
Miklos Szeredi76c17522005-07-13 14:08:19 +0000288int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
289 double attr_timeout)
290{
291 struct fuse_attr_out arg;
292
293 memset(&arg, 0, sizeof(arg));
294 arg.attr_valid = calc_timeout_sec(attr_timeout);
295 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
296 convert_stat(attr, &arg.attr);
297
Miklos Szeredia1482422005-08-14 23:00:27 +0000298 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000299}
300
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000301int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000302{
Miklos Szeredia1482422005-08-14 23:00:27 +0000303 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000304}
305
306int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
307{
308 struct fuse_open_out arg;
309
310 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000311 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000312 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000313}
314
315int fuse_reply_write(fuse_req_t req, size_t count)
316{
317 struct fuse_write_out arg;
318
319 memset(&arg, 0, sizeof(arg));
320 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000321
Miklos Szeredia1482422005-08-14 23:00:27 +0000322 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000323}
324
325int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
326{
Miklos Szeredia1482422005-08-14 23:00:27 +0000327 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000328}
329
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000330int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000331{
332 struct fuse_statfs_out arg;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000333 size_t size = req->f->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000334
335 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000336 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000337
Miklos Szeredi2b478112005-11-28 13:27:10 +0000338 return send_reply_ok(req, &arg, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000339}
340
341int fuse_reply_xattr(fuse_req_t req, size_t count)
342{
343 struct fuse_getxattr_out arg;
344
345 memset(&arg, 0, sizeof(arg));
346 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000347
Miklos Szeredia1482422005-08-14 23:00:27 +0000348 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000349}
350
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000351static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000352{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000353 if (req->f->op.lookup)
354 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000355 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000356 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000357}
358
Miklos Szeredi76c17522005-07-13 14:08:19 +0000359static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
360 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000361{
362 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000363 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000364}
365
366static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
367{
368 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000369 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000370 else
371 fuse_reply_err(req, ENOSYS);
372}
373
374static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000375 struct fuse_setattr_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000376{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000377 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000378 struct fuse_file_info *fi = NULL;
379 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000380 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000381 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000382 convert_attr(arg, &stbuf);
383 if (arg->valid & FATTR_FH) {
384 arg->valid &= ~FATTR_FH;
385 memset(&fi_store, 0, sizeof(fi_store));
386 fi = &fi_store;
387 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000388 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000389 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000390 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000391 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000392 fuse_reply_err(req, ENOSYS);
393}
394
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000395static void do_access(fuse_req_t req, fuse_ino_t nodeid,
396 struct fuse_access_in *arg)
397{
398 if (req->f->op.access)
399 req->f->op.access(req, nodeid, arg->mask);
400 else
401 fuse_reply_err(req, ENOSYS);
402}
403
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000404static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
405{
406 if (req->f->op.readlink)
407 req->f->op.readlink(req, nodeid);
408 else
409 fuse_reply_err(req, ENOSYS);
410}
411
412static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
413 struct fuse_mknod_in *arg)
414{
415 if (req->f->op.mknod)
416 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
417 else
418 fuse_reply_err(req, ENOSYS);
419}
420
421static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
422 struct fuse_mkdir_in *arg)
423{
424 if (req->f->op.mkdir)
425 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
426 else
427 fuse_reply_err(req, ENOSYS);
428}
429
430static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
431{
432 if (req->f->op.unlink)
433 req->f->op.unlink(req, nodeid, name);
434 else
435 fuse_reply_err(req, ENOSYS);
436}
437
438static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
439{
440 if (req->f->op.rmdir)
441 req->f->op.rmdir(req, nodeid, name);
442 else
443 fuse_reply_err(req, ENOSYS);
444}
445
446static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000447 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000448{
449 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000450 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000451 else
452 fuse_reply_err(req, ENOSYS);
453}
454
455static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
456 struct fuse_rename_in *arg)
457{
458 char *oldname = PARAM(arg);
459 char *newname = oldname + strlen(oldname) + 1;
460
461 if (req->f->op.rename)
462 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
463 else
464 fuse_reply_err(req, ENOSYS);
465}
466
467static void do_link(fuse_req_t req, fuse_ino_t nodeid,
468 struct fuse_link_in *arg)
469{
470 if (req->f->op.link)
471 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
472 else
473 fuse_reply_err(req, ENOSYS);
474}
475
Miklos Szeredid9079a72005-10-26 15:29:06 +0000476static void do_create(fuse_req_t req, fuse_ino_t nodeid,
477 struct fuse_open_in *arg)
478{
479 if (req->f->op.create) {
480 struct fuse_file_info fi;
481
482 memset(&fi, 0, sizeof(fi));
483 fi.flags = arg->flags;
484
485 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
486 } else
487 fuse_reply_err(req, ENOSYS);
488}
489
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000490static void do_open(fuse_req_t req, fuse_ino_t nodeid,
491 struct fuse_open_in *arg)
492{
493 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000494
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000495 memset(&fi, 0, sizeof(fi));
496 fi.flags = arg->flags;
497
498 if (req->f->op.open)
499 req->f->op.open(req, nodeid, &fi);
500 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000501 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000502}
503
504static void do_read(fuse_req_t req, fuse_ino_t nodeid,
505 struct fuse_read_in *arg)
506{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000507 if (req->f->op.read) {
508 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000509
Miklos Szeredi76c17522005-07-13 14:08:19 +0000510 memset(&fi, 0, sizeof(fi));
511 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000512 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000513 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000514 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000515 fuse_reply_err(req, ENOSYS);
516}
517
518static void do_write(fuse_req_t req, fuse_ino_t nodeid,
519 struct fuse_write_in *arg)
520{
521 struct fuse_file_info fi;
522
523 memset(&fi, 0, sizeof(fi));
524 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000525 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000526 fi.writepage = arg->write_flags & 1;
527
528 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000529 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
530 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000531 else
532 fuse_reply_err(req, ENOSYS);
533}
534
535static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
536 struct fuse_flush_in *arg)
537{
538 struct fuse_file_info fi;
539
540 memset(&fi, 0, sizeof(fi));
541 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000542 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000543
544 if (req->f->op.flush)
545 req->f->op.flush(req, nodeid, &fi);
546 else
547 fuse_reply_err(req, ENOSYS);
548}
549
550static void do_release(fuse_req_t req, fuse_ino_t nodeid,
551 struct fuse_release_in *arg)
552{
553 struct fuse_file_info fi;
554
555 memset(&fi, 0, sizeof(fi));
556 fi.flags = arg->flags;
557 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000558 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000559
560 if (req->f->op.release)
561 req->f->op.release(req, nodeid, &fi);
562 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000563 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000564}
565
566static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000567 struct fuse_fsync_in *inarg)
568{
Miklos Szeredi12744942005-07-11 12:32:31 +0000569 struct fuse_file_info fi;
570
571 memset(&fi, 0, sizeof(fi));
572 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000573 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000574
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000575 if (req->f->op.fsync)
576 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
577 else
578 fuse_reply_err(req, ENOSYS);
579}
580
581static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
582 struct fuse_open_in *arg)
583{
584 struct fuse_file_info fi;
585
586 memset(&fi, 0, sizeof(fi));
587 fi.flags = arg->flags;
588
589 if (req->f->op.opendir)
590 req->f->op.opendir(req, nodeid, &fi);
591 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000592 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000593}
594
595static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
596 struct fuse_read_in *arg)
597{
598 struct fuse_file_info fi;
599
600 memset(&fi, 0, sizeof(fi));
601 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000602 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000603
604 if (req->f->op.readdir)
605 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
606 else
607 fuse_reply_err(req, ENOSYS);
608}
609
610static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
611 struct fuse_release_in *arg)
612{
613 struct fuse_file_info fi;
614
615 memset(&fi, 0, sizeof(fi));
616 fi.flags = arg->flags;
617 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000618 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000619
620 if (req->f->op.releasedir)
621 req->f->op.releasedir(req, nodeid, &fi);
622 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000623 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000624}
625
626static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
627 struct fuse_fsync_in *inarg)
628{
629 struct fuse_file_info fi;
630
631 memset(&fi, 0, sizeof(fi));
632 fi.fh = inarg->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.fsyncdir)
636 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
637 else
638 fuse_reply_err(req, ENOSYS);
639}
640
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000641static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000642{
643 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000644 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000645 else
646 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000647}
648
Miklos Szeredi4331a272005-07-12 14:51:04 +0000649static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000650 struct fuse_setxattr_in *arg)
651{
Miklos Szeredi12744942005-07-11 12:32:31 +0000652 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000653 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000654
Miklos Szeredi4331a272005-07-12 14:51:04 +0000655 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000656 req->f->op.setxattr(req, nodeid, name, value, arg->size,
657 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000658 else
659 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000660}
661
Miklos Szeredi4331a272005-07-12 14:51:04 +0000662static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000663 struct fuse_getxattr_in *arg)
664{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000665 if (req->f->op.getxattr)
666 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000667 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000668 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000669}
670
Miklos Szeredi4331a272005-07-12 14:51:04 +0000671static void do_listxattr(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.listxattr)
675 req->f->op.listxattr(req, nodeid, 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_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000681{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000682 if (req->f->op.removexattr)
683 req->f->op.removexattr(req, nodeid, name);
684 else
685 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000686}
687
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000688static void do_init(fuse_req_t req, struct fuse_init_in *arg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000689{
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000690 struct fuse_init_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000691 struct fuse_ll *f = req->f;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000692 size_t bufsize = fuse_chan_bufsize(req->ch);
Miklos Szeredi12744942005-07-11 12:32:31 +0000693
Miklos Szeredi76c17522005-07-13 14:08:19 +0000694 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000695 printf("INIT: %u.%u\n", arg->major, arg->minor);
696 fflush(stdout);
697 }
698 f->got_init = 1;
699 if (f->op.init)
Miklos Szeredia1482422005-08-14 23:00:27 +0000700 f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000701
Miklos Szeredi76c17522005-07-13 14:08:19 +0000702 f->major = FUSE_KERNEL_VERSION;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000703 f->minor = arg->minor;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000704
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000705 if (bufsize < FUSE_MIN_READ_BUFFER) {
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000706 fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000707 bufsize = FUSE_MIN_READ_BUFFER;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000708 }
709
Miklos Szeredi12744942005-07-11 12:32:31 +0000710 memset(&outarg, 0, sizeof(outarg));
711 outarg.major = f->major;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000712 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000713 outarg.max_write = bufsize - 4096;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000714
Miklos Szeredi76c17522005-07-13 14:08:19 +0000715 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000716 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
717 fflush(stdout);
718 }
719
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000720 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000721}
722
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000723void *fuse_req_userdata(fuse_req_t req)
724{
725 return req->f->userdata;
726}
727
728const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
729{
730 return &req->ctx;
731}
732
Miklos Szeredia1482422005-08-14 23:00:27 +0000733static void fuse_ll_process(void *data, const char *buf, size_t len,
734 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000735{
Miklos Szeredia1482422005-08-14 23:00:27 +0000736 struct fuse_ll *f = (struct fuse_ll *) data;
737 struct fuse_in_header *in = (struct fuse_in_header *) buf;
738 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000739 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000740
Miklos Szeredi76c17522005-07-13 14:08:19 +0000741 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000742 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000743 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000744 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000745 fflush(stdout);
746 }
747
Miklos Szeredi76c17522005-07-13 14:08:19 +0000748 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
749 if (req == NULL) {
750 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000751 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000752 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000753
Miklos Szeredi76c17522005-07-13 14:08:19 +0000754 req->f = f;
755 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000756 req->ctx.uid = in->uid;
757 req->ctx.gid = in->gid;
758 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000759 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000760
Miklos Szeredia1482422005-08-14 23:00:27 +0000761 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +0000762 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +0000763 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
764 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
765 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
766 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
767 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
768 fuse_reply_err(req, EACCES);
769 } else switch (in->opcode) {
770 case FUSE_INIT:
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000771 do_init(req, (struct fuse_init_in *) inarg);
Miklos Szeredia1482422005-08-14 23:00:27 +0000772 break;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000773
Miklos Szeredi12744942005-07-11 12:32:31 +0000774 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000775 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000776 break;
777
Miklos Szeredi76c17522005-07-13 14:08:19 +0000778 case FUSE_FORGET:
779 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000780 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000781
Miklos Szeredi12744942005-07-11 12:32:31 +0000782 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000783 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000784 break;
785
786 case FUSE_SETATTR:
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000787 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000788 break;
789
Miklos Szeredi12744942005-07-11 12:32:31 +0000790 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000791 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000792 break;
793
794 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000795 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000796 break;
797
798 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000799 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000800 break;
801
802 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000803 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000804 break;
805
806 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000807 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000808 break;
809
810 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000811 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000812 ((char *) inarg) + strlen((char *) inarg) + 1);
813 break;
814
815 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000816 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000817 break;
818
819 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000820 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000821 break;
822
823 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000824 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000825 break;
826
827 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000828 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000829 break;
830
831 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000832 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000833 break;
834
835 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000836 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000837 break;
838
839 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000840 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000841 break;
842
843 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000844 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000845 break;
846
847 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000848 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000849 break;
850
851 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000852 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000853 break;
854
855 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 break;
858
859 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000860 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000861 break;
862
863 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000864 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000865 break;
866
867 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000868 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000869 break;
870
871 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000872 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000873 break;
874
875 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000876 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000877 break;
878
879 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000880 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000881 break;
882
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000883 case FUSE_ACCESS:
884 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
885 break;
886
Miklos Szeredid9079a72005-10-26 15:29:06 +0000887 case FUSE_CREATE:
888 do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
889 break;
890
Miklos Szeredi12744942005-07-11 12:32:31 +0000891 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000892 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000893 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000894}
895
Miklos Szerediad005972006-01-07 10:14:34 +0000896enum {
897 KEY_HELP,
898 KEY_VERSION,
899};
900
Miklos Szeredi659743b2005-12-09 17:41:42 +0000901static struct fuse_opt fuse_ll_opts[] = {
902 { "debug", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi95da8602006-01-06 18:29:40 +0000903 { "-d", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi659743b2005-12-09 17:41:42 +0000904 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
Miklos Szerediad005972006-01-07 10:14:34 +0000905 FUSE_OPT_KEY("-h", KEY_HELP),
906 FUSE_OPT_KEY("--help", KEY_HELP),
907 FUSE_OPT_KEY("-V", KEY_VERSION),
908 FUSE_OPT_KEY("--version", KEY_VERSION),
Miklos Szeredi659743b2005-12-09 17:41:42 +0000909 FUSE_OPT_END
910};
911
Miklos Szerediad005972006-01-07 10:14:34 +0000912static void fuse_ll_version(void)
913{
914 fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
915 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
916}
917
Miklos Szeredicaa09312005-12-14 23:25:00 +0000918static int fuse_ll_opt_proc(void *data, const char *arg, int key,
Miklos Szeredi73f41392005-12-16 11:12:16 +0000919 struct fuse_args *outargs)
Miklos Szeredi3b534a42005-12-09 20:09:42 +0000920{
Miklos Szerediad005972006-01-07 10:14:34 +0000921 (void) data; (void) outargs;
Miklos Szeredicb402b02006-01-09 14:44:23 +0000922
Miklos Szerediad005972006-01-07 10:14:34 +0000923 switch (key) {
924 case KEY_HELP:
925 break;
Miklos Szeredicb402b02006-01-09 14:44:23 +0000926
Miklos Szerediad005972006-01-07 10:14:34 +0000927 case KEY_VERSION:
928 fuse_ll_version();
929 break;
930
931 default:
932 fprintf(stderr, "fuse: unknown option `%s'\n", arg);
933 }
Miklos Szeredicb402b02006-01-09 14:44:23 +0000934
Miklos Szeredi3b534a42005-12-09 20:09:42 +0000935 return -1;
936}
937
Miklos Szeredia1482422005-08-14 23:00:27 +0000938int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000939{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000940 return fuse_opt_match(fuse_ll_opts, opt);
Miklos Szeredi12744942005-07-11 12:32:31 +0000941}
942
Miklos Szeredia1482422005-08-14 23:00:27 +0000943static void fuse_ll_destroy(void *data)
944{
945 struct fuse_ll *f = (struct fuse_ll *) data;
946
947 if (f->op.destroy)
948 f->op.destroy(f->userdata);
949
950 free(f);
951}
952
Miklos Szeredi95da8602006-01-06 18:29:40 +0000953struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
Miklos Szeredia1482422005-08-14 23:00:27 +0000954 const struct fuse_lowlevel_ops *op,
955 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000956{
957 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +0000958 struct fuse_session *se;
959 struct fuse_session_ops sop = {
960 .process = fuse_ll_process,
961 .destroy = fuse_ll_destroy,
962 };
Miklos Szeredi12744942005-07-11 12:32:31 +0000963
Miklos Szeredia1482422005-08-14 23:00:27 +0000964 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +0000965 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000966 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +0000967 }
968
969 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
970 if (f == NULL) {
971 fprintf(stderr, "fuse: failed to allocate fuse object\n");
972 goto out;
973 }
974
Miklos Szeredi95da8602006-01-06 18:29:40 +0000975 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
976 goto out_free;
Miklos Szeredi12744942005-07-11 12:32:31 +0000977
Miklos Szeredi12744942005-07-11 12:32:31 +0000978 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000979 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000980 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +0000981
Miklos Szeredia1482422005-08-14 23:00:27 +0000982 se = fuse_session_new(&sop, f);
983 if (!se)
984 goto out_free;
985
986 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +0000987
988 out_free:
989 free(f);
990 out:
991 return NULL;
992}
Miklos Szeredic706ad92005-11-07 15:30:48 +0000993
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000994#ifndef __FreeBSD__
995
996#include "fuse_lowlevel_compat.h"
997
998static void fill_open_compat(struct fuse_open_out *arg,
999 const struct fuse_file_info_compat *f)
1000{
1001 arg->fh = f->fh;
1002 if (f->direct_io)
1003 arg->open_flags |= FOPEN_DIRECT_IO;
1004 if (f->keep_cache)
1005 arg->open_flags |= FOPEN_KEEP_CACHE;
1006}
1007
Miklos Szeredi2b478112005-11-28 13:27:10 +00001008static void convert_statfs_compat(const struct statfs *compatbuf,
1009 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001010{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001011 buf->f_bsize = compatbuf->f_bsize;
1012 buf->f_blocks = compatbuf->f_blocks;
1013 buf->f_bfree = compatbuf->f_bfree;
1014 buf->f_bavail = compatbuf->f_bavail;
1015 buf->f_files = compatbuf->f_files;
1016 buf->f_ffree = compatbuf->f_ffree;
1017 buf->f_namemax = compatbuf->f_namelen;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001018}
1019
1020int fuse_reply_open_compat(fuse_req_t req,
1021 const struct fuse_file_info_compat *f)
1022{
1023 struct fuse_open_out arg;
1024
1025 memset(&arg, 0, sizeof(arg));
1026 fill_open_compat(&arg, f);
1027 return send_reply_ok(req, &arg, sizeof(arg));
1028}
1029
1030int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1031{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001032 struct statvfs newbuf;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001033
Miklos Szeredi2b478112005-11-28 13:27:10 +00001034 memset(&newbuf, 0, sizeof(newbuf));
1035 convert_statfs_compat(stbuf, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001036
Miklos Szeredi2b478112005-11-28 13:27:10 +00001037 return fuse_reply_statfs(req, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001038}
1039
Miklos Szeredi95da8602006-01-06 18:29:40 +00001040struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
1041 const struct fuse_lowlevel_ops *op,
1042 size_t op_size, void *userdata)
1043{
1044 struct fuse_session *se;
1045 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
1046
1047 if (opts &&
1048 (fuse_opt_add_arg(&args, "") == -1 ||
1049 fuse_opt_add_arg(&args, "-o") == -1 ||
1050 fuse_opt_add_arg(&args, opts) == -1)) {
1051 fuse_opt_free_args(&args);
1052 return NULL;
1053 }
1054 se = fuse_lowlevel_new(&args, op, op_size, userdata);
1055 fuse_opt_free_args(&args);
1056
1057 return se;
1058}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001059
Miklos Szeredic706ad92005-11-07 15:30:48 +00001060__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
Miklos Szeredi3a770472005-11-11 21:32:42 +00001061__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
Miklos Szeredi95da8602006-01-06 18:29:40 +00001062__asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001063
Miklos Szeredi2b478112005-11-28 13:27:10 +00001064#endif /* __FreeBSD__ */