blob: 4e5c2ac9adc2e49eed656856cbe6802172564a95 [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 Szeredia1482422005-08-14 23:00:27 +000022struct fuse_ll {
23 unsigned int debug : 1;
24 unsigned int allow_root : 1;
25 struct fuse_lowlevel_ops op;
26 int got_init;
27 void *userdata;
28 int major;
29 int minor;
30 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000031};
32
Miklos Szeredi76c17522005-07-13 14:08:19 +000033struct fuse_req {
34 struct fuse_ll *f;
35 uint64_t unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000036 struct fuse_ctx ctx;
Miklos Szeredia1482422005-08-14 23:00:27 +000037 struct fuse_chan *ch;
Miklos Szeredi76c17522005-07-13 14:08:19 +000038};
39
Miklos Szeredi12744942005-07-11 12:32:31 +000040static const char *opname(enum fuse_opcode opcode)
41{
42 switch (opcode) {
43 case FUSE_LOOKUP: return "LOOKUP";
44 case FUSE_FORGET: return "FORGET";
45 case FUSE_GETATTR: return "GETATTR";
46 case FUSE_SETATTR: return "SETATTR";
47 case FUSE_READLINK: return "READLINK";
48 case FUSE_SYMLINK: return "SYMLINK";
49 case FUSE_MKNOD: return "MKNOD";
50 case FUSE_MKDIR: return "MKDIR";
51 case FUSE_UNLINK: return "UNLINK";
52 case FUSE_RMDIR: return "RMDIR";
53 case FUSE_RENAME: return "RENAME";
54 case FUSE_LINK: return "LINK";
55 case FUSE_OPEN: return "OPEN";
56 case FUSE_READ: return "READ";
57 case FUSE_WRITE: return "WRITE";
58 case FUSE_STATFS: return "STATFS";
59 case FUSE_FLUSH: return "FLUSH";
60 case FUSE_RELEASE: return "RELEASE";
61 case FUSE_FSYNC: return "FSYNC";
62 case FUSE_SETXATTR: return "SETXATTR";
63 case FUSE_GETXATTR: return "GETXATTR";
64 case FUSE_LISTXATTR: return "LISTXATTR";
65 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
66 case FUSE_INIT: return "INIT";
67 case FUSE_OPENDIR: return "OPENDIR";
68 case FUSE_READDIR: return "READDIR";
69 case FUSE_RELEASEDIR: return "RELEASEDIR";
70 case FUSE_FSYNCDIR: return "FSYNCDIR";
Miklos Szeredib0b13d12005-10-26 12:53:25 +000071 case FUSE_ACCESS: return "ACCESS";
Miklos Szeredid9079a72005-10-26 15:29:06 +000072 case FUSE_CREATE: return "CREATE";
Miklos Szeredi12744942005-07-11 12:32:31 +000073 default: return "???";
74 }
75}
76
Miklos Szeredi76c17522005-07-13 14:08:19 +000077static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000078{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000079 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000080 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000081 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000082 attr->uid = stbuf->st_uid;
83 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000084 attr->rdev = stbuf->st_rdev;
85 attr->size = stbuf->st_size;
86 attr->blocks = stbuf->st_blocks;
87 attr->atime = stbuf->st_atime;
88 attr->mtime = stbuf->st_mtime;
89 attr->ctime = stbuf->st_ctime;
90#ifdef HAVE_STRUCT_STAT_ST_ATIM
91 attr->atimensec = stbuf->st_atim.tv_nsec;
92 attr->mtimensec = stbuf->st_mtim.tv_nsec;
93 attr->ctimensec = stbuf->st_ctim.tv_nsec;
94#endif
95}
96
Miklos Szeredi11509ce2005-10-26 16:04:04 +000097static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +000098{
99 stbuf->st_mode = attr->mode;
100 stbuf->st_uid = attr->uid;
101 stbuf->st_gid = attr->gid;
102 stbuf->st_size = attr->size;
103 stbuf->st_atime = attr->atime;
104 stbuf->st_mtime = attr->mtime;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000105#ifdef HAVE_STRUCT_STAT_ST_ATIM
106 stbuf->st_atim.tv_nsec = attr->atimensec;
107 stbuf->st_mtim.tv_nsec = attr->mtimensec;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000108#endif
109}
110
Miklos Szeredi12744942005-07-11 12:32:31 +0000111static size_t iov_length(const struct iovec *iov, size_t count)
112{
113 size_t seg;
114 size_t ret = 0;
115
116 for (seg = 0; seg < count; seg++)
117 ret += iov[seg].iov_len;
118 return ret;
119}
120
Miklos Szeredia1482422005-08-14 23:00:27 +0000121static void free_req(fuse_req_t req)
Miklos Szeredi12744942005-07-11 12:32:31 +0000122{
Miklos Szeredia1482422005-08-14 23:00:27 +0000123 free(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000124}
125
Miklos Szeredia1482422005-08-14 23:00:27 +0000126static int send_reply(fuse_req_t req, int error, const void *arg,
127 size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000128{
129 struct fuse_out_header out;
130 struct iovec iov[2];
131 size_t count;
Miklos Szeredia1482422005-08-14 23:00:27 +0000132 int res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000133
134 if (error <= -1000 || error > 0) {
135 fprintf(stderr, "fuse: bad error value: %i\n", error);
136 error = -ERANGE;
137 }
138
Miklos Szeredia1482422005-08-14 23:00:27 +0000139 out.unique = req->unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000140 out.error = error;
141 count = 1;
142 iov[0].iov_base = &out;
143 iov[0].iov_len = sizeof(struct fuse_out_header);
144 if (argsize && !error) {
145 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000146 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000147 iov[1].iov_len = argsize;
148 }
Miklos Szeredia1482422005-08-14 23:00:27 +0000149 out.len = iov_length(iov, count);
150
151 if (req->f->debug) {
152 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
153 out.unique, out.error, strerror(-out.error), out.len);
154 fflush(stdout);
155 }
156 res = fuse_chan_send(req->ch, iov, count);
157 free_req(req);
158
159 return res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000160}
161
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000162size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000163{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000164 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000165}
166
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000167char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000168 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000169{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000170 unsigned namelen = strlen(name);
171 unsigned entlen = FUSE_NAME_OFFSET + namelen;
172 unsigned entsize = fuse_dirent_size(namelen);
173 unsigned padlen = entsize - entlen;
174 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000175
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000176 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000177 dirent->off = off;
178 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000179 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000180 strncpy(dirent->name, name, namelen);
181 if (padlen)
182 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000183
Miklos Szeredi76c17522005-07-13 14:08:19 +0000184 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000185}
186
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000187static void convert_statfs(const struct statvfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000188 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000189{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000190 kstatfs->bsize = stbuf->f_bsize;
191 kstatfs->blocks = stbuf->f_blocks;
192 kstatfs->bfree = stbuf->f_bfree;
193 kstatfs->bavail = stbuf->f_bavail;
194 kstatfs->files = stbuf->f_files;
195 kstatfs->ffree = stbuf->f_ffree;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000196 kstatfs->namelen = stbuf->f_namemax;
Miklos Szeredi12744942005-07-11 12:32:31 +0000197}
198
Miklos Szeredia1482422005-08-14 23:00:27 +0000199static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000200{
Miklos Szeredia1482422005-08-14 23:00:27 +0000201 return send_reply(req, 0, arg, argsize);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000202}
203
204int fuse_reply_err(fuse_req_t req, int err)
205{
Miklos Szeredia1482422005-08-14 23:00:27 +0000206 return send_reply(req, -err, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000207}
208
Miklos Szeredi836ab712005-10-03 14:11:59 +0000209void fuse_reply_none(fuse_req_t req)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000210{
211 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000212}
213
214static unsigned long calc_timeout_sec(double t)
215{
216 if (t > (double) ULONG_MAX)
217 return ULONG_MAX;
218 else if (t < 0.0)
219 return 0;
220 else
221 return (unsigned long) t;
222}
223
224static unsigned int calc_timeout_nsec(double t)
225{
226 double f = t - (double) calc_timeout_sec(t);
227 if (f < 0.0)
228 return 0;
229 else if (f >= 0.999999999)
230 return 999999999;
231 else
232 return (unsigned int) (f * 1.0e9);
233}
234
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000235static void fill_entry(struct fuse_entry_out *arg,
236 const struct fuse_entry_param *e)
237{
238 arg->nodeid = e->ino;
239 arg->generation = e->generation;
240 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
241 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
242 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
243 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
244 convert_stat(&e->attr, &arg->attr);
245}
246
247static void fill_open(struct fuse_open_out *arg,
248 const struct fuse_file_info *f)
249{
250 arg->fh = f->fh;
251 if (f->direct_io)
252 arg->open_flags |= FOPEN_DIRECT_IO;
253 if (f->keep_cache)
254 arg->open_flags |= FOPEN_KEEP_CACHE;
255}
256
Miklos Szeredi76c17522005-07-13 14:08:19 +0000257int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
258{
259 struct fuse_entry_out arg;
260
261 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000262 fill_entry(&arg, e);
263 return send_reply_ok(req, &arg, sizeof(arg));
264}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000265
Miklos Szeredid9079a72005-10-26 15:29:06 +0000266int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
267 const struct fuse_file_info *f)
268{
269 struct {
270 struct fuse_entry_out e;
271 struct fuse_open_out o;
272 } arg;
273
274 memset(&arg, 0, sizeof(arg));
275 fill_entry(&arg.e, e);
276 fill_open(&arg.o, f);
277 return send_reply_ok(req, &arg, sizeof(arg));
278}
279
Miklos Szeredi76c17522005-07-13 14:08:19 +0000280int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
281 double attr_timeout)
282{
283 struct fuse_attr_out arg;
284
285 memset(&arg, 0, sizeof(arg));
286 arg.attr_valid = calc_timeout_sec(attr_timeout);
287 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
288 convert_stat(attr, &arg.attr);
289
Miklos Szeredia1482422005-08-14 23:00:27 +0000290 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000291}
292
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000293int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000294{
Miklos Szeredia1482422005-08-14 23:00:27 +0000295 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000296}
297
298int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
299{
300 struct fuse_open_out arg;
301
302 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000303 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000304 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000305}
306
307int fuse_reply_write(fuse_req_t req, size_t count)
308{
309 struct fuse_write_out arg;
310
311 memset(&arg, 0, sizeof(arg));
312 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000313
Miklos Szeredia1482422005-08-14 23:00:27 +0000314 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000315}
316
317int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
318{
Miklos Szeredia1482422005-08-14 23:00:27 +0000319 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000320}
321
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000322int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000323{
324 struct fuse_statfs_out arg;
325
326 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000327 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000328
Miklos Szeredia1482422005-08-14 23:00:27 +0000329 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000330}
331
332int fuse_reply_xattr(fuse_req_t req, size_t count)
333{
334 struct fuse_getxattr_out arg;
335
336 memset(&arg, 0, sizeof(arg));
337 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000338
Miklos Szeredia1482422005-08-14 23:00:27 +0000339 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000340}
341
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000342static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000343{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000344 if (req->f->op.lookup)
345 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000346 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000347 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000348}
349
Miklos Szeredi76c17522005-07-13 14:08:19 +0000350static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
351 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000352{
353 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000354 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000355}
356
357static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
358{
359 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000360 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000361 else
362 fuse_reply_err(req, ENOSYS);
363}
364
365static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000366 struct fuse_setattr_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000367{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000368 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000369 struct fuse_file_info *fi = NULL;
370 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000371 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000372 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000373 convert_attr(arg, &stbuf);
374 if (arg->valid & FATTR_FH) {
375 arg->valid &= ~FATTR_FH;
376 memset(&fi_store, 0, sizeof(fi_store));
377 fi = &fi_store;
378 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000379 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000380 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000381 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000382 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000383 fuse_reply_err(req, ENOSYS);
384}
385
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000386static void do_access(fuse_req_t req, fuse_ino_t nodeid,
387 struct fuse_access_in *arg)
388{
389 if (req->f->op.access)
390 req->f->op.access(req, nodeid, arg->mask);
391 else
392 fuse_reply_err(req, ENOSYS);
393}
394
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000395static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
396{
397 if (req->f->op.readlink)
398 req->f->op.readlink(req, nodeid);
399 else
400 fuse_reply_err(req, ENOSYS);
401}
402
403static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
404 struct fuse_mknod_in *arg)
405{
406 if (req->f->op.mknod)
407 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
408 else
409 fuse_reply_err(req, ENOSYS);
410}
411
412static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
413 struct fuse_mkdir_in *arg)
414{
415 if (req->f->op.mkdir)
416 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
417 else
418 fuse_reply_err(req, ENOSYS);
419}
420
421static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
422{
423 if (req->f->op.unlink)
424 req->f->op.unlink(req, nodeid, name);
425 else
426 fuse_reply_err(req, ENOSYS);
427}
428
429static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
430{
431 if (req->f->op.rmdir)
432 req->f->op.rmdir(req, nodeid, name);
433 else
434 fuse_reply_err(req, ENOSYS);
435}
436
437static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000438 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000439{
440 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000441 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000442 else
443 fuse_reply_err(req, ENOSYS);
444}
445
446static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
447 struct fuse_rename_in *arg)
448{
449 char *oldname = PARAM(arg);
450 char *newname = oldname + strlen(oldname) + 1;
451
452 if (req->f->op.rename)
453 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
454 else
455 fuse_reply_err(req, ENOSYS);
456}
457
458static void do_link(fuse_req_t req, fuse_ino_t nodeid,
459 struct fuse_link_in *arg)
460{
461 if (req->f->op.link)
462 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
463 else
464 fuse_reply_err(req, ENOSYS);
465}
466
Miklos Szeredid9079a72005-10-26 15:29:06 +0000467static void do_create(fuse_req_t req, fuse_ino_t nodeid,
468 struct fuse_open_in *arg)
469{
470 if (req->f->op.create) {
471 struct fuse_file_info fi;
472
473 memset(&fi, 0, sizeof(fi));
474 fi.flags = arg->flags;
475
476 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
477 } else
478 fuse_reply_err(req, ENOSYS);
479}
480
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000481static void do_open(fuse_req_t req, fuse_ino_t nodeid,
482 struct fuse_open_in *arg)
483{
484 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000485
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000486 memset(&fi, 0, sizeof(fi));
487 fi.flags = arg->flags;
488
489 if (req->f->op.open)
490 req->f->op.open(req, nodeid, &fi);
491 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000492 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000493}
494
495static void do_read(fuse_req_t req, fuse_ino_t nodeid,
496 struct fuse_read_in *arg)
497{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000498 if (req->f->op.read) {
499 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000500
Miklos Szeredi76c17522005-07-13 14:08:19 +0000501 memset(&fi, 0, sizeof(fi));
502 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000503 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000504 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000505 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000506 fuse_reply_err(req, ENOSYS);
507}
508
509static void do_write(fuse_req_t req, fuse_ino_t nodeid,
510 struct fuse_write_in *arg)
511{
512 struct fuse_file_info fi;
513
514 memset(&fi, 0, sizeof(fi));
515 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000516 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000517 fi.writepage = arg->write_flags & 1;
518
519 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000520 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
521 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000522 else
523 fuse_reply_err(req, ENOSYS);
524}
525
526static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
527 struct fuse_flush_in *arg)
528{
529 struct fuse_file_info fi;
530
531 memset(&fi, 0, sizeof(fi));
532 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000533 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000534
535 if (req->f->op.flush)
536 req->f->op.flush(req, nodeid, &fi);
537 else
538 fuse_reply_err(req, ENOSYS);
539}
540
541static void do_release(fuse_req_t req, fuse_ino_t nodeid,
542 struct fuse_release_in *arg)
543{
544 struct fuse_file_info fi;
545
546 memset(&fi, 0, sizeof(fi));
547 fi.flags = arg->flags;
548 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000549 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000550
551 if (req->f->op.release)
552 req->f->op.release(req, nodeid, &fi);
553 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000554 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000555}
556
557static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000558 struct fuse_fsync_in *inarg)
559{
Miklos Szeredi12744942005-07-11 12:32:31 +0000560 struct fuse_file_info fi;
561
562 memset(&fi, 0, sizeof(fi));
563 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000564 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000565
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000566 if (req->f->op.fsync)
567 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
568 else
569 fuse_reply_err(req, ENOSYS);
570}
571
572static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
573 struct fuse_open_in *arg)
574{
575 struct fuse_file_info fi;
576
577 memset(&fi, 0, sizeof(fi));
578 fi.flags = arg->flags;
579
580 if (req->f->op.opendir)
581 req->f->op.opendir(req, nodeid, &fi);
582 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000583 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000584}
585
586static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
587 struct fuse_read_in *arg)
588{
589 struct fuse_file_info fi;
590
591 memset(&fi, 0, sizeof(fi));
592 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000593 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000594
595 if (req->f->op.readdir)
596 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
597 else
598 fuse_reply_err(req, ENOSYS);
599}
600
601static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
602 struct fuse_release_in *arg)
603{
604 struct fuse_file_info fi;
605
606 memset(&fi, 0, sizeof(fi));
607 fi.flags = arg->flags;
608 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000609 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000610
611 if (req->f->op.releasedir)
612 req->f->op.releasedir(req, nodeid, &fi);
613 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000614 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000615}
616
617static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
618 struct fuse_fsync_in *inarg)
619{
620 struct fuse_file_info fi;
621
622 memset(&fi, 0, sizeof(fi));
623 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000624 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000625
626 if (req->f->op.fsyncdir)
627 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
628 else
629 fuse_reply_err(req, ENOSYS);
630}
631
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000632static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000633{
634 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000635 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000636 else
637 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000638}
639
Miklos Szeredi4331a272005-07-12 14:51:04 +0000640static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000641 struct fuse_setxattr_in *arg)
642{
Miklos Szeredi12744942005-07-11 12:32:31 +0000643 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000644 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000645
Miklos Szeredi4331a272005-07-12 14:51:04 +0000646 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000647 req->f->op.setxattr(req, nodeid, name, value, arg->size,
648 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000649 else
650 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000651}
652
Miklos Szeredi4331a272005-07-12 14:51:04 +0000653static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000654 struct fuse_getxattr_in *arg)
655{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000656 if (req->f->op.getxattr)
657 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000658 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000659 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000660}
661
Miklos Szeredi4331a272005-07-12 14:51:04 +0000662static void do_listxattr(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.listxattr)
666 req->f->op.listxattr(req, nodeid, 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_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000672{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000673 if (req->f->op.removexattr)
674 req->f->op.removexattr(req, nodeid, name);
675 else
676 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000677}
678
Miklos Szeredia1482422005-08-14 23:00:27 +0000679static void do_init(fuse_req_t req, struct fuse_init_in_out *arg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000680{
681 struct fuse_init_in_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000682 struct fuse_ll *f = req->f;
Miklos Szeredi12744942005-07-11 12:32:31 +0000683
Miklos Szeredi76c17522005-07-13 14:08:19 +0000684 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000685 printf("INIT: %u.%u\n", arg->major, arg->minor);
686 fflush(stdout);
687 }
688 f->got_init = 1;
689 if (f->op.init)
Miklos Szeredia1482422005-08-14 23:00:27 +0000690 f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000691
Miklos Szeredi76c17522005-07-13 14:08:19 +0000692 f->major = FUSE_KERNEL_VERSION;
693 f->minor = FUSE_KERNEL_MINOR_VERSION;
694
Miklos Szeredi12744942005-07-11 12:32:31 +0000695 memset(&outarg, 0, sizeof(outarg));
696 outarg.major = f->major;
697 outarg.minor = f->minor;
698
Miklos Szeredi76c17522005-07-13 14:08:19 +0000699 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000700 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
701 fflush(stdout);
702 }
703
Miklos Szeredia1482422005-08-14 23:00:27 +0000704 send_reply_ok(req, &outarg, sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000705}
706
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000707void *fuse_req_userdata(fuse_req_t req)
708{
709 return req->f->userdata;
710}
711
712const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
713{
714 return &req->ctx;
715}
716
Miklos Szeredia1482422005-08-14 23:00:27 +0000717static void fuse_ll_process(void *data, const char *buf, size_t len,
718 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000719{
Miklos Szeredia1482422005-08-14 23:00:27 +0000720 struct fuse_ll *f = (struct fuse_ll *) data;
721 struct fuse_in_header *in = (struct fuse_in_header *) buf;
722 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000723 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000724
Miklos Szeredi76c17522005-07-13 14:08:19 +0000725 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000726 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000727 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000728 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000729 fflush(stdout);
730 }
731
Miklos Szeredi76c17522005-07-13 14:08:19 +0000732 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
733 if (req == NULL) {
734 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000735 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000736 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000737
Miklos Szeredi76c17522005-07-13 14:08:19 +0000738 req->f = f;
739 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000740 req->ctx.uid = in->uid;
741 req->ctx.gid = in->gid;
742 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000743 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000744
Miklos Szeredia1482422005-08-14 23:00:27 +0000745 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +0000746 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +0000747 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
748 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
749 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
750 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
751 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
752 fuse_reply_err(req, EACCES);
753 } else switch (in->opcode) {
754 case FUSE_INIT:
755 do_init(req, (struct fuse_init_in_out *) inarg);
756 break;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000757
Miklos Szeredi12744942005-07-11 12:32:31 +0000758 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000759 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000760 break;
761
Miklos Szeredi76c17522005-07-13 14:08:19 +0000762 case FUSE_FORGET:
763 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000764 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000765
Miklos Szeredi12744942005-07-11 12:32:31 +0000766 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000767 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000768 break;
769
770 case FUSE_SETATTR:
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000771 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000772 break;
773
Miklos Szeredi12744942005-07-11 12:32:31 +0000774 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000775 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000776 break;
777
778 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000779 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000780 break;
781
782 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000783 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000784 break;
785
786 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000787 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000788 break;
789
790 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000791 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000792 break;
793
794 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000795 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000796 ((char *) inarg) + strlen((char *) inarg) + 1);
797 break;
798
799 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000800 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000801 break;
802
803 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000804 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000805 break;
806
807 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000808 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000809 break;
810
811 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000812 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000813 break;
814
815 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000816 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000817 break;
818
819 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000820 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000821 break;
822
823 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000824 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000825 break;
826
827 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000828 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000829 break;
830
831 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000832 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000833 break;
834
835 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000836 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000837 break;
838
839 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000840 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000841 break;
842
843 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000844 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000845 break;
846
847 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000848 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000849 break;
850
851 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000852 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000853 break;
854
855 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 break;
858
859 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000860 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000861 break;
862
863 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000864 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000865 break;
866
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000867 case FUSE_ACCESS:
868 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
869 break;
870
Miklos Szeredid9079a72005-10-26 15:29:06 +0000871 case FUSE_CREATE:
872 do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
873 break;
874
Miklos Szeredi12744942005-07-11 12:32:31 +0000875 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000876 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000877 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000878}
879
Miklos Szeredia1482422005-08-14 23:00:27 +0000880int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000881{
882 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +0000883 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +0000884 return 1;
885 else
886 return 0;
887}
888
Miklos Szeredi76c17522005-07-13 14:08:19 +0000889static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +0000890{
891 if (opts) {
892 char *xopts = strdup(opts);
893 char *s = xopts;
894 char *opt;
895
896 if (xopts == NULL) {
897 fprintf(stderr, "fuse: memory allocation failed\n");
898 return -1;
899 }
900
901 while((opt = strsep(&s, ","))) {
902 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000903 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000904 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000905 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000906 else
907 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
908 }
909 free(xopts);
910 }
911 return 0;
912}
913
Miklos Szeredia1482422005-08-14 23:00:27 +0000914static void fuse_ll_destroy(void *data)
915{
916 struct fuse_ll *f = (struct fuse_ll *) data;
917
918 if (f->op.destroy)
919 f->op.destroy(f->userdata);
920
921 free(f);
922}
923
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000924struct fuse_session *fuse_lowlevel_new(const char *opts,
Miklos Szeredia1482422005-08-14 23:00:27 +0000925 const struct fuse_lowlevel_ops *op,
926 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000927{
928 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +0000929 struct fuse_session *se;
930 struct fuse_session_ops sop = {
931 .process = fuse_ll_process,
932 .destroy = fuse_ll_destroy,
933 };
Miklos Szeredi12744942005-07-11 12:32:31 +0000934
Miklos Szeredia1482422005-08-14 23:00:27 +0000935 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +0000936 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000937 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +0000938 }
939
940 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
941 if (f == NULL) {
942 fprintf(stderr, "fuse: failed to allocate fuse object\n");
943 goto out;
944 }
945
Miklos Szeredi76c17522005-07-13 14:08:19 +0000946 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +0000947 goto out_free;
948
Miklos Szeredi12744942005-07-11 12:32:31 +0000949 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000950 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000951 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +0000952
Miklos Szeredia1482422005-08-14 23:00:27 +0000953 se = fuse_session_new(&sop, f);
954 if (!se)
955 goto out_free;
956
957 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +0000958
959 out_free:
960 free(f);
961 out:
962 return NULL;
963}
Miklos Szeredic706ad92005-11-07 15:30:48 +0000964
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000965#ifndef __FreeBSD__
966
967#include "fuse_lowlevel_compat.h"
968
969static void fill_open_compat(struct fuse_open_out *arg,
970 const struct fuse_file_info_compat *f)
971{
972 arg->fh = f->fh;
973 if (f->direct_io)
974 arg->open_flags |= FOPEN_DIRECT_IO;
975 if (f->keep_cache)
976 arg->open_flags |= FOPEN_KEEP_CACHE;
977}
978
979static void convert_statfs_compat(const struct statfs *stbuf,
980 struct fuse_kstatfs *kstatfs)
981{
982 kstatfs->bsize = stbuf->f_bsize;
983 kstatfs->blocks = stbuf->f_blocks;
984 kstatfs->bfree = stbuf->f_bfree;
985 kstatfs->bavail = stbuf->f_bavail;
986 kstatfs->files = stbuf->f_files;
987 kstatfs->ffree = stbuf->f_ffree;
988 kstatfs->namelen = stbuf->f_namelen;
989}
990
991int fuse_reply_open_compat(fuse_req_t req,
992 const struct fuse_file_info_compat *f)
993{
994 struct fuse_open_out arg;
995
996 memset(&arg, 0, sizeof(arg));
997 fill_open_compat(&arg, f);
998 return send_reply_ok(req, &arg, sizeof(arg));
999}
1000
1001int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1002{
1003 struct fuse_statfs_out arg;
1004
1005 memset(&arg, 0, sizeof(arg));
1006 convert_statfs_compat(stbuf, &arg.st);
1007
1008 return send_reply_ok(req, &arg, sizeof(arg));
1009}
1010
1011
Miklos Szeredic706ad92005-11-07 15:30:48 +00001012__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
Miklos Szeredi3a770472005-11-11 21:32:42 +00001013__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001014
1015#endif __FreeBSD__