blob: 9379968401254ac18ffdaef5507f98e7dd6f98cc [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#include <stdint.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000020
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000021#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000022
Miklos Szeredia1482422005-08-14 23:00:27 +000023struct fuse_ll {
24 unsigned int debug : 1;
25 unsigned int allow_root : 1;
26 struct fuse_lowlevel_ops op;
27 int got_init;
28 void *userdata;
29 int major;
30 int minor;
31 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000032};
33
Miklos Szeredi76c17522005-07-13 14:08:19 +000034struct fuse_req {
35 struct fuse_ll *f;
36 uint64_t unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000037 struct fuse_ctx ctx;
Miklos Szeredia1482422005-08-14 23:00:27 +000038 struct fuse_chan *ch;
Miklos Szeredi76c17522005-07-13 14:08:19 +000039};
40
Miklos Szeredi12744942005-07-11 12:32:31 +000041static const char *opname(enum fuse_opcode opcode)
42{
43 switch (opcode) {
44 case FUSE_LOOKUP: return "LOOKUP";
45 case FUSE_FORGET: return "FORGET";
46 case FUSE_GETATTR: return "GETATTR";
47 case FUSE_SETATTR: return "SETATTR";
48 case FUSE_READLINK: return "READLINK";
49 case FUSE_SYMLINK: return "SYMLINK";
50 case FUSE_MKNOD: return "MKNOD";
51 case FUSE_MKDIR: return "MKDIR";
52 case FUSE_UNLINK: return "UNLINK";
53 case FUSE_RMDIR: return "RMDIR";
54 case FUSE_RENAME: return "RENAME";
55 case FUSE_LINK: return "LINK";
56 case FUSE_OPEN: return "OPEN";
57 case FUSE_READ: return "READ";
58 case FUSE_WRITE: return "WRITE";
59 case FUSE_STATFS: return "STATFS";
60 case FUSE_FLUSH: return "FLUSH";
61 case FUSE_RELEASE: return "RELEASE";
62 case FUSE_FSYNC: return "FSYNC";
63 case FUSE_SETXATTR: return "SETXATTR";
64 case FUSE_GETXATTR: return "GETXATTR";
65 case FUSE_LISTXATTR: return "LISTXATTR";
66 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
67 case FUSE_INIT: return "INIT";
68 case FUSE_OPENDIR: return "OPENDIR";
69 case FUSE_READDIR: return "READDIR";
70 case FUSE_RELEASEDIR: return "RELEASEDIR";
71 case FUSE_FSYNCDIR: return "FSYNCDIR";
Miklos Szeredib0b13d12005-10-26 12:53:25 +000072 case FUSE_ACCESS: return "ACCESS";
Miklos Szeredid9079a72005-10-26 15:29:06 +000073 case FUSE_CREATE: return "CREATE";
Miklos Szeredi12744942005-07-11 12:32:31 +000074 default: return "???";
75 }
76}
77
Miklos Szeredi76c17522005-07-13 14:08:19 +000078static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000079{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000080 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000081 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000082 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000083 attr->uid = stbuf->st_uid;
84 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000085 attr->rdev = stbuf->st_rdev;
86 attr->size = stbuf->st_size;
87 attr->blocks = stbuf->st_blocks;
88 attr->atime = stbuf->st_atime;
89 attr->mtime = stbuf->st_mtime;
90 attr->ctime = stbuf->st_ctime;
91#ifdef HAVE_STRUCT_STAT_ST_ATIM
92 attr->atimensec = stbuf->st_atim.tv_nsec;
93 attr->mtimensec = stbuf->st_mtim.tv_nsec;
94 attr->ctimensec = stbuf->st_ctim.tv_nsec;
95#endif
96}
97
Miklos Szeredi76c17522005-07-13 14:08:19 +000098static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf)
99{
100 stbuf->st_mode = attr->mode;
101 stbuf->st_uid = attr->uid;
102 stbuf->st_gid = attr->gid;
103 stbuf->st_size = attr->size;
104 stbuf->st_atime = attr->atime;
105 stbuf->st_mtime = attr->mtime;
106 stbuf->st_ctime = attr->ctime;
107#ifdef HAVE_STRUCT_STAT_ST_ATIM
108 stbuf->st_atim.tv_nsec = attr->atimensec;
109 stbuf->st_mtim.tv_nsec = attr->mtimensec;
110 stbuf->st_ctim.tv_nsec = attr->ctimensec;
111#endif
112}
113
Miklos Szeredi12744942005-07-11 12:32:31 +0000114static size_t iov_length(const struct iovec *iov, size_t count)
115{
116 size_t seg;
117 size_t ret = 0;
118
119 for (seg = 0; seg < count; seg++)
120 ret += iov[seg].iov_len;
121 return ret;
122}
123
Miklos Szeredia1482422005-08-14 23:00:27 +0000124static void free_req(fuse_req_t req)
Miklos Szeredi12744942005-07-11 12:32:31 +0000125{
Miklos Szeredia1482422005-08-14 23:00:27 +0000126 free(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000127}
128
Miklos Szeredia1482422005-08-14 23:00:27 +0000129static int send_reply(fuse_req_t req, int error, const void *arg,
130 size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000131{
132 struct fuse_out_header out;
133 struct iovec iov[2];
134 size_t count;
Miklos Szeredia1482422005-08-14 23:00:27 +0000135 int res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000136
137 if (error <= -1000 || error > 0) {
138 fprintf(stderr, "fuse: bad error value: %i\n", error);
139 error = -ERANGE;
140 }
141
Miklos Szeredia1482422005-08-14 23:00:27 +0000142 out.unique = req->unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000143 out.error = error;
144 count = 1;
145 iov[0].iov_base = &out;
146 iov[0].iov_len = sizeof(struct fuse_out_header);
147 if (argsize && !error) {
148 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000149 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000150 iov[1].iov_len = argsize;
151 }
Miklos Szeredia1482422005-08-14 23:00:27 +0000152 out.len = iov_length(iov, count);
153
154 if (req->f->debug) {
155 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
156 out.unique, out.error, strerror(-out.error), out.len);
157 fflush(stdout);
158 }
159 res = fuse_chan_send(req->ch, iov, count);
160 free_req(req);
161
162 return res;
Miklos Szeredi12744942005-07-11 12:32:31 +0000163}
164
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000165size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000166{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000167 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000168}
169
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000170char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000171 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000172{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000173 unsigned namelen = strlen(name);
174 unsigned entlen = FUSE_NAME_OFFSET + namelen;
175 unsigned entsize = fuse_dirent_size(namelen);
176 unsigned padlen = entsize - entlen;
177 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000178
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000179 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000180 dirent->off = off;
181 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000182 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000183 strncpy(dirent->name, name, namelen);
184 if (padlen)
185 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000186
Miklos Szeredi76c17522005-07-13 14:08:19 +0000187 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000188}
189
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000190static void convert_statfs(const struct statfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000191 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000192{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000193 kstatfs->bsize = stbuf->f_bsize;
194 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;
199 kstatfs->namelen = stbuf->f_namelen;
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
264 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000265 fill_entry(&arg, e);
266 return send_reply_ok(req, &arg, sizeof(arg));
267}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000268
Miklos Szeredid9079a72005-10-26 15:29:06 +0000269int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
270 const struct fuse_file_info *f)
271{
272 struct {
273 struct fuse_entry_out e;
274 struct fuse_open_out o;
275 } arg;
276
277 memset(&arg, 0, sizeof(arg));
278 fill_entry(&arg.e, e);
279 fill_open(&arg.o, f);
280 return send_reply_ok(req, &arg, sizeof(arg));
281}
282
Miklos Szeredi76c17522005-07-13 14:08:19 +0000283int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
284 double attr_timeout)
285{
286 struct fuse_attr_out arg;
287
288 memset(&arg, 0, sizeof(arg));
289 arg.attr_valid = calc_timeout_sec(attr_timeout);
290 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
291 convert_stat(attr, &arg.attr);
292
Miklos Szeredia1482422005-08-14 23:00:27 +0000293 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000294}
295
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000296int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000297{
Miklos Szeredia1482422005-08-14 23:00:27 +0000298 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000299}
300
301int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
302{
303 struct fuse_open_out arg;
304
305 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000306 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000307 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000308}
309
310int fuse_reply_write(fuse_req_t req, size_t count)
311{
312 struct fuse_write_out arg;
313
314 memset(&arg, 0, sizeof(arg));
315 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000316
Miklos Szeredia1482422005-08-14 23:00:27 +0000317 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000318}
319
320int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
321{
Miklos Szeredia1482422005-08-14 23:00:27 +0000322 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000323}
324
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000325int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000326{
327 struct fuse_statfs_out arg;
328
329 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000330 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000331
Miklos Szeredia1482422005-08-14 23:00:27 +0000332 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000333}
334
335int fuse_reply_xattr(fuse_req_t req, size_t count)
336{
337 struct fuse_getxattr_out arg;
338
339 memset(&arg, 0, sizeof(arg));
340 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000341
Miklos Szeredia1482422005-08-14 23:00:27 +0000342 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000343}
344
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000345static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000346{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000347 if (req->f->op.lookup)
348 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000349 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000350 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000351}
352
Miklos Szeredi76c17522005-07-13 14:08:19 +0000353static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
354 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000355{
356 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000357 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000358}
359
360static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
361{
362 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000363 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000364 else
365 fuse_reply_err(req, ENOSYS);
366}
367
368static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000369 struct fuse_setattr_in *arg, struct fuse_file_info *fi)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000370{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000371 if (req->f->op.setattr) {
372 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000373 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000374 convert_attr(&arg->attr, &stbuf);
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000375 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000376 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000377 fuse_reply_err(req, ENOSYS);
378}
379
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000380static void do_access(fuse_req_t req, fuse_ino_t nodeid,
381 struct fuse_access_in *arg)
382{
383 if (req->f->op.access)
384 req->f->op.access(req, nodeid, arg->mask);
385 else
386 fuse_reply_err(req, ENOSYS);
387}
388
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000389static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
390{
391 if (req->f->op.readlink)
392 req->f->op.readlink(req, nodeid);
393 else
394 fuse_reply_err(req, ENOSYS);
395}
396
397static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
398 struct fuse_mknod_in *arg)
399{
400 if (req->f->op.mknod)
401 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
402 else
403 fuse_reply_err(req, ENOSYS);
404}
405
406static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
407 struct fuse_mkdir_in *arg)
408{
409 if (req->f->op.mkdir)
410 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
411 else
412 fuse_reply_err(req, ENOSYS);
413}
414
415static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
416{
417 if (req->f->op.unlink)
418 req->f->op.unlink(req, nodeid, name);
419 else
420 fuse_reply_err(req, ENOSYS);
421}
422
423static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
424{
425 if (req->f->op.rmdir)
426 req->f->op.rmdir(req, nodeid, name);
427 else
428 fuse_reply_err(req, ENOSYS);
429}
430
431static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000432 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000433{
434 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000435 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000436 else
437 fuse_reply_err(req, ENOSYS);
438}
439
440static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
441 struct fuse_rename_in *arg)
442{
443 char *oldname = PARAM(arg);
444 char *newname = oldname + strlen(oldname) + 1;
445
446 if (req->f->op.rename)
447 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
448 else
449 fuse_reply_err(req, ENOSYS);
450}
451
452static void do_link(fuse_req_t req, fuse_ino_t nodeid,
453 struct fuse_link_in *arg)
454{
455 if (req->f->op.link)
456 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
457 else
458 fuse_reply_err(req, ENOSYS);
459}
460
Miklos Szeredid9079a72005-10-26 15:29:06 +0000461static void do_create(fuse_req_t req, fuse_ino_t nodeid,
462 struct fuse_open_in *arg)
463{
464 if (req->f->op.create) {
465 struct fuse_file_info fi;
466
467 memset(&fi, 0, sizeof(fi));
468 fi.flags = arg->flags;
469
470 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
471 } else
472 fuse_reply_err(req, ENOSYS);
473}
474
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000475static void do_open(fuse_req_t req, fuse_ino_t nodeid,
476 struct fuse_open_in *arg)
477{
478 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000479
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000480 memset(&fi, 0, sizeof(fi));
481 fi.flags = arg->flags;
482
483 if (req->f->op.open)
484 req->f->op.open(req, nodeid, &fi);
485 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000486 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000487}
488
489static void do_read(fuse_req_t req, fuse_ino_t nodeid,
490 struct fuse_read_in *arg)
491{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000492 if (req->f->op.read) {
493 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000494
Miklos Szeredi76c17522005-07-13 14:08:19 +0000495 memset(&fi, 0, sizeof(fi));
496 fi.fh = arg->fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000497 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000498 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000499 fuse_reply_err(req, ENOSYS);
500}
501
502static void do_write(fuse_req_t req, fuse_ino_t nodeid,
503 struct fuse_write_in *arg)
504{
505 struct fuse_file_info fi;
506
507 memset(&fi, 0, sizeof(fi));
508 fi.fh = arg->fh;
509 fi.writepage = arg->write_flags & 1;
510
511 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000512 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
513 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000514 else
515 fuse_reply_err(req, ENOSYS);
516}
517
518static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
519 struct fuse_flush_in *arg)
520{
521 struct fuse_file_info fi;
522
523 memset(&fi, 0, sizeof(fi));
524 fi.fh = arg->fh;
525
526 if (req->f->op.flush)
527 req->f->op.flush(req, nodeid, &fi);
528 else
529 fuse_reply_err(req, ENOSYS);
530}
531
532static void do_release(fuse_req_t req, fuse_ino_t nodeid,
533 struct fuse_release_in *arg)
534{
535 struct fuse_file_info fi;
536
537 memset(&fi, 0, sizeof(fi));
538 fi.flags = arg->flags;
539 fi.fh = arg->fh;
540
541 if (req->f->op.release)
542 req->f->op.release(req, nodeid, &fi);
543 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000544 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000545}
546
547static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000548 struct fuse_fsync_in *inarg)
549{
Miklos Szeredi12744942005-07-11 12:32:31 +0000550 struct fuse_file_info fi;
551
552 memset(&fi, 0, sizeof(fi));
553 fi.fh = inarg->fh;
554
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000555 if (req->f->op.fsync)
556 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
557 else
558 fuse_reply_err(req, ENOSYS);
559}
560
561static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
562 struct fuse_open_in *arg)
563{
564 struct fuse_file_info fi;
565
566 memset(&fi, 0, sizeof(fi));
567 fi.flags = arg->flags;
568
569 if (req->f->op.opendir)
570 req->f->op.opendir(req, nodeid, &fi);
571 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000572 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000573}
574
575static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
576 struct fuse_read_in *arg)
577{
578 struct fuse_file_info fi;
579
580 memset(&fi, 0, sizeof(fi));
581 fi.fh = arg->fh;
582
583 if (req->f->op.readdir)
584 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
585 else
586 fuse_reply_err(req, ENOSYS);
587}
588
589static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
590 struct fuse_release_in *arg)
591{
592 struct fuse_file_info fi;
593
594 memset(&fi, 0, sizeof(fi));
595 fi.flags = arg->flags;
596 fi.fh = arg->fh;
597
598 if (req->f->op.releasedir)
599 req->f->op.releasedir(req, nodeid, &fi);
600 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000601 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000602}
603
604static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
605 struct fuse_fsync_in *inarg)
606{
607 struct fuse_file_info fi;
608
609 memset(&fi, 0, sizeof(fi));
610 fi.fh = inarg->fh;
611
612 if (req->f->op.fsyncdir)
613 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
614 else
615 fuse_reply_err(req, ENOSYS);
616}
617
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000618static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000619{
620 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000621 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000622 else
623 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000624}
625
Miklos Szeredi4331a272005-07-12 14:51:04 +0000626static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000627 struct fuse_setxattr_in *arg)
628{
Miklos Szeredi12744942005-07-11 12:32:31 +0000629 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000630 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000631
Miklos Szeredi4331a272005-07-12 14:51:04 +0000632 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000633 req->f->op.setxattr(req, nodeid, name, value, arg->size,
634 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000635 else
636 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000637}
638
Miklos Szeredi4331a272005-07-12 14:51:04 +0000639static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000640 struct fuse_getxattr_in *arg)
641{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000642 if (req->f->op.getxattr)
643 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000644 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000645 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000646}
647
Miklos Szeredi4331a272005-07-12 14:51:04 +0000648static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000649 struct fuse_getxattr_in *arg)
650{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000651 if (req->f->op.listxattr)
652 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000653 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000654 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000655}
656
Miklos Szeredi4331a272005-07-12 14:51:04 +0000657static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000658{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000659 if (req->f->op.removexattr)
660 req->f->op.removexattr(req, nodeid, name);
661 else
662 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000663}
664
Miklos Szeredia1482422005-08-14 23:00:27 +0000665static void do_init(fuse_req_t req, struct fuse_init_in_out *arg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000666{
667 struct fuse_init_in_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000668 struct fuse_ll *f = req->f;
Miklos Szeredi12744942005-07-11 12:32:31 +0000669
Miklos Szeredi76c17522005-07-13 14:08:19 +0000670 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000671 printf("INIT: %u.%u\n", arg->major, arg->minor);
672 fflush(stdout);
673 }
674 f->got_init = 1;
675 if (f->op.init)
Miklos Szeredia1482422005-08-14 23:00:27 +0000676 f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000677
Miklos Szeredi76c17522005-07-13 14:08:19 +0000678 f->major = FUSE_KERNEL_VERSION;
679 f->minor = FUSE_KERNEL_MINOR_VERSION;
680
Miklos Szeredi12744942005-07-11 12:32:31 +0000681 memset(&outarg, 0, sizeof(outarg));
682 outarg.major = f->major;
683 outarg.minor = f->minor;
684
Miklos Szeredi76c17522005-07-13 14:08:19 +0000685 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000686 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
687 fflush(stdout);
688 }
689
Miklos Szeredia1482422005-08-14 23:00:27 +0000690 send_reply_ok(req, &outarg, sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000691}
692
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000693void *fuse_req_userdata(fuse_req_t req)
694{
695 return req->f->userdata;
696}
697
698const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
699{
700 return &req->ctx;
701}
702
Miklos Szeredia1482422005-08-14 23:00:27 +0000703static void fuse_ll_process(void *data, const char *buf, size_t len,
704 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000705{
Miklos Szeredia1482422005-08-14 23:00:27 +0000706 struct fuse_ll *f = (struct fuse_ll *) data;
707 struct fuse_in_header *in = (struct fuse_in_header *) buf;
708 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000709 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000710
Miklos Szeredi76c17522005-07-13 14:08:19 +0000711 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000712 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000713 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000714 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000715 fflush(stdout);
716 }
717
Miklos Szeredi76c17522005-07-13 14:08:19 +0000718 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
719 if (req == NULL) {
720 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000721 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000722 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000723
Miklos Szeredi76c17522005-07-13 14:08:19 +0000724 req->f = f;
725 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000726 req->ctx.uid = in->uid;
727 req->ctx.gid = in->gid;
728 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000729 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000730
Miklos Szeredia1482422005-08-14 23:00:27 +0000731 if (!f->got_init && in->opcode != FUSE_INIT)
732 fuse_reply_err(req, EPROTO);
733 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
734 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
735 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
736 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
737 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
738 fuse_reply_err(req, EACCES);
739 } else switch (in->opcode) {
740 case FUSE_INIT:
741 do_init(req, (struct fuse_init_in_out *) inarg);
742 break;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000743
Miklos Szeredi12744942005-07-11 12:32:31 +0000744 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000745 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000746 break;
747
Miklos Szeredi76c17522005-07-13 14:08:19 +0000748 case FUSE_FORGET:
749 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000750 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000751
Miklos Szeredi12744942005-07-11 12:32:31 +0000752 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000753 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000754 break;
755
756 case FUSE_SETATTR:
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000757 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg, NULL);
758 break;
759
Miklos Szeredi12744942005-07-11 12:32:31 +0000760 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000761 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000762 break;
763
764 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000765 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000766 break;
767
768 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000769 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000770 break;
771
772 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000773 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000774 break;
775
776 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000777 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000778 break;
779
780 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000781 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000782 ((char *) inarg) + strlen((char *) inarg) + 1);
783 break;
784
785 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000786 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000787 break;
788
789 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000790 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000791 break;
792
793 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000794 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000795 break;
796
797 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000798 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000799 break;
800
801 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000802 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000803 break;
804
805 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000806 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000807 break;
808
809 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000810 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000811 break;
812
813 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000814 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000815 break;
816
817 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000818 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000819 break;
820
821 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000822 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000823 break;
824
825 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000826 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000827 break;
828
829 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000830 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000831 break;
832
833 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000834 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000835 break;
836
837 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000838 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000839 break;
840
841 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000842 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000843 break;
844
845 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000846 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000847 break;
848
849 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000850 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000851 break;
852
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000853 case FUSE_ACCESS:
854 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
855 break;
856
Miklos Szeredid9079a72005-10-26 15:29:06 +0000857 case FUSE_CREATE:
858 do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
859 break;
860
Miklos Szeredi12744942005-07-11 12:32:31 +0000861 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000862 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000863 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000864}
865
Miklos Szeredia1482422005-08-14 23:00:27 +0000866int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000867{
868 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +0000869 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +0000870 return 1;
871 else
872 return 0;
873}
874
Miklos Szeredi76c17522005-07-13 14:08:19 +0000875static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +0000876{
877 if (opts) {
878 char *xopts = strdup(opts);
879 char *s = xopts;
880 char *opt;
881
882 if (xopts == NULL) {
883 fprintf(stderr, "fuse: memory allocation failed\n");
884 return -1;
885 }
886
887 while((opt = strsep(&s, ","))) {
888 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000889 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000890 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000891 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000892 else
893 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
894 }
895 free(xopts);
896 }
897 return 0;
898}
899
Miklos Szeredia1482422005-08-14 23:00:27 +0000900static void fuse_ll_destroy(void *data)
901{
902 struct fuse_ll *f = (struct fuse_ll *) data;
903
904 if (f->op.destroy)
905 f->op.destroy(f->userdata);
906
907 free(f);
908}
909
910
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000911struct fuse_session *fuse_lowlevel_new(const char *opts,
Miklos Szeredia1482422005-08-14 23:00:27 +0000912 const struct fuse_lowlevel_ops *op,
913 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000914{
915 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +0000916 struct fuse_session *se;
917 struct fuse_session_ops sop = {
918 .process = fuse_ll_process,
919 .destroy = fuse_ll_destroy,
920 };
Miklos Szeredi12744942005-07-11 12:32:31 +0000921
Miklos Szeredia1482422005-08-14 23:00:27 +0000922 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +0000923 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000924 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +0000925 }
926
927 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
928 if (f == NULL) {
929 fprintf(stderr, "fuse: failed to allocate fuse object\n");
930 goto out;
931 }
932
Miklos Szeredi76c17522005-07-13 14:08:19 +0000933 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +0000934 goto out_free;
935
Miklos Szeredi12744942005-07-11 12:32:31 +0000936 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000937 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000938 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +0000939
Miklos Szeredia1482422005-08-14 23:00:27 +0000940 se = fuse_session_new(&sop, f);
941 if (!se)
942 goto out_free;
943
944 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +0000945
946 out_free:
947 free(f);
948 out:
949 return NULL;
950}