blob: 421aedf8d6ddb908ac18bf2d08605a3875d683c3 [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 Szeredi065f2222006-01-20 15:15:21 +000013#include "fuse_i.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000014
15#include <stdio.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000016#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000017#include <stddef.h>
18#include <string.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000019#include <unistd.h>
20#include <limits.h>
21#include <errno.h>
Miklos Szeredi12744942005-07-11 12:32:31 +000022
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000023#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000024
Miklos Szeredia1482422005-08-14 23:00:27 +000025struct fuse_ll {
Miklos Szeredi659743b2005-12-09 17:41:42 +000026 int debug;
27 int allow_root;
Miklos Szeredia1482422005-08-14 23:00:27 +000028 struct fuse_lowlevel_ops op;
29 int got_init;
30 void *userdata;
Miklos Szeredia1482422005-08-14 23:00:27 +000031 uid_t owner;
Miklos Szeredi065f2222006-01-20 15:15:21 +000032 struct fuse_conn_info conn;
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 Szeredi1bf64f42006-02-17 15:49:25 +0000189size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
190 const char *name, const struct stat *stbuf, off_t off)
191{
192 size_t entsize;
193
194 (void) req;
195 entsize = fuse_dirent_size(strlen(name));
196 if (entsize <= bufsize && buf)
197 fuse_add_dirent(buf, name, stbuf, off);
198 return entsize;
199}
200
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000201static void convert_statfs(const struct statvfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000202 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000203{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000204 kstatfs->bsize = stbuf->f_bsize;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000205 kstatfs->frsize = stbuf->f_frsize;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000206 kstatfs->blocks = stbuf->f_blocks;
207 kstatfs->bfree = stbuf->f_bfree;
208 kstatfs->bavail = stbuf->f_bavail;
209 kstatfs->files = stbuf->f_files;
210 kstatfs->ffree = stbuf->f_ffree;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000211 kstatfs->namelen = stbuf->f_namemax;
Miklos Szeredi12744942005-07-11 12:32:31 +0000212}
213
Miklos Szeredia1482422005-08-14 23:00:27 +0000214static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000215{
Miklos Szeredia1482422005-08-14 23:00:27 +0000216 return send_reply(req, 0, arg, argsize);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000217}
218
219int fuse_reply_err(fuse_req_t req, int err)
220{
Miklos Szeredia1482422005-08-14 23:00:27 +0000221 return send_reply(req, -err, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000222}
223
Miklos Szeredi836ab712005-10-03 14:11:59 +0000224void fuse_reply_none(fuse_req_t req)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000225{
226 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000227}
228
229static unsigned long calc_timeout_sec(double t)
230{
231 if (t > (double) ULONG_MAX)
232 return ULONG_MAX;
233 else if (t < 0.0)
234 return 0;
235 else
236 return (unsigned long) t;
237}
238
239static unsigned int calc_timeout_nsec(double t)
240{
241 double f = t - (double) calc_timeout_sec(t);
242 if (f < 0.0)
243 return 0;
244 else if (f >= 0.999999999)
245 return 999999999;
246 else
247 return (unsigned int) (f * 1.0e9);
248}
249
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000250static void fill_entry(struct fuse_entry_out *arg,
251 const struct fuse_entry_param *e)
252{
253 arg->nodeid = e->ino;
254 arg->generation = e->generation;
255 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
256 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
257 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
258 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
259 convert_stat(&e->attr, &arg->attr);
260}
261
262static void fill_open(struct fuse_open_out *arg,
263 const struct fuse_file_info *f)
264{
265 arg->fh = f->fh;
266 if (f->direct_io)
267 arg->open_flags |= FOPEN_DIRECT_IO;
268 if (f->keep_cache)
269 arg->open_flags |= FOPEN_KEEP_CACHE;
270}
271
Miklos Szeredi76c17522005-07-13 14:08:19 +0000272int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
273{
274 struct fuse_entry_out arg;
275
Miklos Szeredi2b478112005-11-28 13:27:10 +0000276 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
277 negative entry */
Miklos Szeredi065f2222006-01-20 15:15:21 +0000278 if (!e->ino && req->f->conn.proto_minor < 4)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000279 return fuse_reply_err(req, ENOENT);
280
Miklos Szeredi76c17522005-07-13 14:08:19 +0000281 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000282 fill_entry(&arg, e);
283 return send_reply_ok(req, &arg, sizeof(arg));
284}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000285
Miklos Szeredid9079a72005-10-26 15:29:06 +0000286int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
287 const struct fuse_file_info *f)
288{
289 struct {
290 struct fuse_entry_out e;
291 struct fuse_open_out o;
292 } arg;
293
294 memset(&arg, 0, sizeof(arg));
295 fill_entry(&arg.e, e);
296 fill_open(&arg.o, f);
297 return send_reply_ok(req, &arg, sizeof(arg));
298}
299
Miklos Szeredi76c17522005-07-13 14:08:19 +0000300int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
301 double attr_timeout)
302{
303 struct fuse_attr_out arg;
304
305 memset(&arg, 0, sizeof(arg));
306 arg.attr_valid = calc_timeout_sec(attr_timeout);
307 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
308 convert_stat(attr, &arg.attr);
309
Miklos Szeredia1482422005-08-14 23:00:27 +0000310 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000311}
312
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000313int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000314{
Miklos Szeredia1482422005-08-14 23:00:27 +0000315 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000316}
317
318int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
319{
320 struct fuse_open_out arg;
321
322 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000323 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000324 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000325}
326
327int fuse_reply_write(fuse_req_t req, size_t count)
328{
329 struct fuse_write_out arg;
330
331 memset(&arg, 0, sizeof(arg));
332 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000333
Miklos Szeredia1482422005-08-14 23:00:27 +0000334 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000335}
336
337int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
338{
Miklos Szeredia1482422005-08-14 23:00:27 +0000339 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000340}
341
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000342int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000343{
344 struct fuse_statfs_out arg;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000345 size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000346
347 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000348 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000349
Miklos Szeredi2b478112005-11-28 13:27:10 +0000350 return send_reply_ok(req, &arg, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000351}
352
353int fuse_reply_xattr(fuse_req_t req, size_t count)
354{
355 struct fuse_getxattr_out arg;
356
357 memset(&arg, 0, sizeof(arg));
358 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000359
Miklos Szeredia1482422005-08-14 23:00:27 +0000360 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000361}
362
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000363static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000364{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000365 if (req->f->op.lookup)
366 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000367 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000368 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000369}
370
Miklos Szeredi76c17522005-07-13 14:08:19 +0000371static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
372 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000373{
374 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000375 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000376}
377
378static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
379{
380 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000381 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000382 else
383 fuse_reply_err(req, ENOSYS);
384}
385
386static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000387 struct fuse_setattr_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000388{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000389 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000390 struct fuse_file_info *fi = NULL;
391 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000392 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000393 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000394 convert_attr(arg, &stbuf);
395 if (arg->valid & FATTR_FH) {
396 arg->valid &= ~FATTR_FH;
397 memset(&fi_store, 0, sizeof(fi_store));
398 fi = &fi_store;
399 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000400 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000401 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000402 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000403 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000404 fuse_reply_err(req, ENOSYS);
405}
406
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000407static void do_access(fuse_req_t req, fuse_ino_t nodeid,
408 struct fuse_access_in *arg)
409{
410 if (req->f->op.access)
411 req->f->op.access(req, nodeid, arg->mask);
412 else
413 fuse_reply_err(req, ENOSYS);
414}
415
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000416static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
417{
418 if (req->f->op.readlink)
419 req->f->op.readlink(req, nodeid);
420 else
421 fuse_reply_err(req, ENOSYS);
422}
423
424static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
425 struct fuse_mknod_in *arg)
426{
427 if (req->f->op.mknod)
428 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
429 else
430 fuse_reply_err(req, ENOSYS);
431}
432
433static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
434 struct fuse_mkdir_in *arg)
435{
436 if (req->f->op.mkdir)
437 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
438 else
439 fuse_reply_err(req, ENOSYS);
440}
441
442static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
443{
444 if (req->f->op.unlink)
445 req->f->op.unlink(req, nodeid, name);
446 else
447 fuse_reply_err(req, ENOSYS);
448}
449
450static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
451{
452 if (req->f->op.rmdir)
453 req->f->op.rmdir(req, nodeid, name);
454 else
455 fuse_reply_err(req, ENOSYS);
456}
457
458static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000459 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000460{
461 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000462 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000463 else
464 fuse_reply_err(req, ENOSYS);
465}
466
467static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
468 struct fuse_rename_in *arg)
469{
470 char *oldname = PARAM(arg);
471 char *newname = oldname + strlen(oldname) + 1;
472
473 if (req->f->op.rename)
474 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
475 else
476 fuse_reply_err(req, ENOSYS);
477}
478
479static void do_link(fuse_req_t req, fuse_ino_t nodeid,
480 struct fuse_link_in *arg)
481{
482 if (req->f->op.link)
483 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
484 else
485 fuse_reply_err(req, ENOSYS);
486}
487
Miklos Szeredid9079a72005-10-26 15:29:06 +0000488static void do_create(fuse_req_t req, fuse_ino_t nodeid,
489 struct fuse_open_in *arg)
490{
491 if (req->f->op.create) {
492 struct fuse_file_info fi;
493
494 memset(&fi, 0, sizeof(fi));
495 fi.flags = arg->flags;
496
497 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
498 } else
499 fuse_reply_err(req, ENOSYS);
500}
501
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000502static void do_open(fuse_req_t req, fuse_ino_t nodeid,
503 struct fuse_open_in *arg)
504{
505 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000506
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000507 memset(&fi, 0, sizeof(fi));
508 fi.flags = arg->flags;
509
510 if (req->f->op.open)
511 req->f->op.open(req, nodeid, &fi);
512 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000513 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000514}
515
516static void do_read(fuse_req_t req, fuse_ino_t nodeid,
517 struct fuse_read_in *arg)
518{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000519 if (req->f->op.read) {
520 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000521
Miklos Szeredi76c17522005-07-13 14:08:19 +0000522 memset(&fi, 0, sizeof(fi));
523 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000524 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000525 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000526 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000527 fuse_reply_err(req, ENOSYS);
528}
529
530static void do_write(fuse_req_t req, fuse_ino_t nodeid,
531 struct fuse_write_in *arg)
532{
533 struct fuse_file_info fi;
534
535 memset(&fi, 0, sizeof(fi));
536 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000537 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000538 fi.writepage = arg->write_flags & 1;
539
540 if (req->f->op.write)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000541 req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000542 else
543 fuse_reply_err(req, ENOSYS);
544}
545
546static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
547 struct fuse_flush_in *arg)
548{
549 struct fuse_file_info fi;
550
551 memset(&fi, 0, sizeof(fi));
552 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000553 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000554
555 if (req->f->op.flush)
556 req->f->op.flush(req, nodeid, &fi);
557 else
558 fuse_reply_err(req, ENOSYS);
559}
560
561static void do_release(fuse_req_t req, fuse_ino_t nodeid,
562 struct fuse_release_in *arg)
563{
564 struct fuse_file_info fi;
565
566 memset(&fi, 0, sizeof(fi));
567 fi.flags = arg->flags;
568 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000569 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000570
571 if (req->f->op.release)
572 req->f->op.release(req, nodeid, &fi);
573 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000574 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000575}
576
577static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000578 struct fuse_fsync_in *inarg)
579{
Miklos Szeredi12744942005-07-11 12:32:31 +0000580 struct fuse_file_info fi;
581
582 memset(&fi, 0, sizeof(fi));
583 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000584 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000585
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000586 if (req->f->op.fsync)
587 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
588 else
589 fuse_reply_err(req, ENOSYS);
590}
591
592static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
593 struct fuse_open_in *arg)
594{
595 struct fuse_file_info fi;
596
597 memset(&fi, 0, sizeof(fi));
598 fi.flags = arg->flags;
599
600 if (req->f->op.opendir)
601 req->f->op.opendir(req, nodeid, &fi);
602 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000603 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000604}
605
606static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
607 struct fuse_read_in *arg)
608{
609 struct fuse_file_info fi;
610
611 memset(&fi, 0, sizeof(fi));
612 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000613 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000614
615 if (req->f->op.readdir)
616 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
617 else
618 fuse_reply_err(req, ENOSYS);
619}
620
621static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
622 struct fuse_release_in *arg)
623{
624 struct fuse_file_info fi;
625
626 memset(&fi, 0, sizeof(fi));
627 fi.flags = arg->flags;
628 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000629 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000630
631 if (req->f->op.releasedir)
632 req->f->op.releasedir(req, nodeid, &fi);
633 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000634 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000635}
636
637static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
638 struct fuse_fsync_in *inarg)
639{
640 struct fuse_file_info fi;
641
642 memset(&fi, 0, sizeof(fi));
643 fi.fh = inarg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000644 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000645
646 if (req->f->op.fsyncdir)
647 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
648 else
649 fuse_reply_err(req, ENOSYS);
650}
651
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000652static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000653{
654 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000655 req->f->op.statfs(req);
Miklos Szerediaa8258e2006-02-25 14:42:03 +0000656 else {
657 struct statvfs buf = {
658 .f_namemax = 255,
659 .f_bsize = 512,
660 };
661 fuse_reply_statfs(req, &buf);
662 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000663}
664
Miklos Szeredi4331a272005-07-12 14:51:04 +0000665static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000666 struct fuse_setxattr_in *arg)
667{
Miklos Szeredi12744942005-07-11 12:32:31 +0000668 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000669 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000670
Miklos Szeredi4331a272005-07-12 14:51:04 +0000671 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000672 req->f->op.setxattr(req, nodeid, name, value, arg->size,
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000673 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000674 else
675 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000676}
677
Miklos Szeredi4331a272005-07-12 14:51:04 +0000678static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000679 struct fuse_getxattr_in *arg)
680{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000681 if (req->f->op.getxattr)
682 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000683 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000684 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000685}
686
Miklos Szeredi4331a272005-07-12 14:51:04 +0000687static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000688 struct fuse_getxattr_in *arg)
689{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000690 if (req->f->op.listxattr)
691 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000692 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000693 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000694}
695
Miklos Szeredi4331a272005-07-12 14:51:04 +0000696static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000697{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000698 if (req->f->op.removexattr)
699 req->f->op.removexattr(req, nodeid, name);
700 else
701 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000702}
703
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000704static void do_init(fuse_req_t req, struct fuse_init_in *arg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000705{
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000706 struct fuse_init_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000707 struct fuse_ll *f = req->f;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000708 size_t bufsize = fuse_chan_bufsize(req->ch);
Miklos Szeredi12744942005-07-11 12:32:31 +0000709
Miklos Szeredi76c17522005-07-13 14:08:19 +0000710 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000711 printf("INIT: %u.%u\n", arg->major, arg->minor);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000712 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
713 printf("flags=0x%08x\n", arg->flags);
714 printf("max_readahead=0x%08x\n", arg->max_readahead);
715 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000716 fflush(stdout);
717 }
Miklos Szeredi065f2222006-01-20 15:15:21 +0000718 f->conn.proto_major = arg->major;
719 f->conn.proto_minor = arg->minor;
Miklos Szeredi12744942005-07-11 12:32:31 +0000720
Miklos Szeredi065f2222006-01-20 15:15:21 +0000721 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
722 if (f->conn.async_read)
723 f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
724 if (arg->max_readahead < f->conn.max_readahead)
725 f->conn.max_readahead = arg->max_readahead;
726 } else {
727 f->conn.async_read = 0;
728 f->conn.max_readahead = 0;
729 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000730
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000731 if (bufsize < FUSE_MIN_READ_BUFFER) {
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000732 fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000733 bufsize = FUSE_MIN_READ_BUFFER;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000734 }
735
Miklos Szeredi065f2222006-01-20 15:15:21 +0000736 bufsize -= 4096;
737 if (bufsize < f->conn.max_write)
738 f->conn.max_write = bufsize;
739
740 f->got_init = 1;
741 if (f->op.init)
742 f->op.init(f->userdata, &f->conn);
743
Miklos Szeredi12744942005-07-11 12:32:31 +0000744 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi065f2222006-01-20 15:15:21 +0000745 outarg.major = FUSE_KERNEL_VERSION;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000746 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000747 if (f->conn.async_read)
748 outarg.flags |= FUSE_ASYNC_READ;
749 outarg.max_readahead = f->conn.max_readahead;
750 outarg.max_write = f->conn.max_write;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000751
Miklos Szeredi76c17522005-07-13 14:08:19 +0000752 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000753 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000754 printf(" flags=0x%08x\n", outarg.flags);
755 printf(" max_readahead=0x%08x\n", outarg.max_readahead);
756 printf(" max_write=0x%08x\n", outarg.max_write);
Miklos Szeredi12744942005-07-11 12:32:31 +0000757 fflush(stdout);
758 }
759
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000760 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000761}
762
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000763void *fuse_req_userdata(fuse_req_t req)
764{
765 return req->f->userdata;
766}
767
768const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
769{
770 return &req->ctx;
771}
772
Miklos Szeredia1482422005-08-14 23:00:27 +0000773static void fuse_ll_process(void *data, const char *buf, size_t len,
774 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000775{
Miklos Szeredia1482422005-08-14 23:00:27 +0000776 struct fuse_ll *f = (struct fuse_ll *) data;
777 struct fuse_in_header *in = (struct fuse_in_header *) buf;
778 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000779 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000780
Miklos Szeredi76c17522005-07-13 14:08:19 +0000781 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000782 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000783 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000784 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000785 fflush(stdout);
786 }
787
Miklos Szeredi76c17522005-07-13 14:08:19 +0000788 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
789 if (req == NULL) {
790 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000791 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000792 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000793
Miklos Szeredi76c17522005-07-13 14:08:19 +0000794 req->f = f;
795 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000796 req->ctx.uid = in->uid;
797 req->ctx.gid = in->gid;
798 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000799 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000800
Miklos Szeredia1482422005-08-14 23:00:27 +0000801 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +0000802 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +0000803 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
804 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
805 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
806 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
807 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
808 fuse_reply_err(req, EACCES);
809 } else switch (in->opcode) {
810 case FUSE_INIT:
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000811 do_init(req, (struct fuse_init_in *) inarg);
Miklos Szeredia1482422005-08-14 23:00:27 +0000812 break;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000813
Miklos Szeredi12744942005-07-11 12:32:31 +0000814 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000815 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000816 break;
817
Miklos Szeredi76c17522005-07-13 14:08:19 +0000818 case FUSE_FORGET:
819 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000820 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000821
Miklos Szeredi12744942005-07-11 12:32:31 +0000822 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000823 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000824 break;
825
826 case FUSE_SETATTR:
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000827 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000828 break;
829
Miklos Szeredi12744942005-07-11 12:32:31 +0000830 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000831 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000832 break;
833
834 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000835 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000836 break;
837
838 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000839 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000840 break;
841
842 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000843 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000844 break;
845
846 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000847 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000848 break;
849
850 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000851 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000852 ((char *) inarg) + strlen((char *) inarg) + 1);
853 break;
854
855 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 break;
858
859 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000860 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000861 break;
862
863 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000864 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000865 break;
866
867 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000868 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000869 break;
870
871 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000872 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000873 break;
874
875 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000876 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000877 break;
878
879 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000880 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000881 break;
882
883 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000884 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000885 break;
886
887 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000888 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000889 break;
890
891 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000892 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000893 break;
894
895 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000896 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000897 break;
898
899 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000900 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000901 break;
902
903 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000904 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000905 break;
906
907 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000908 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000909 break;
910
911 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000912 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000913 break;
914
915 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000916 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000917 break;
918
919 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000920 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000921 break;
922
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000923 case FUSE_ACCESS:
924 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
925 break;
926
Miklos Szeredid9079a72005-10-26 15:29:06 +0000927 case FUSE_CREATE:
928 do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
929 break;
930
Miklos Szeredi12744942005-07-11 12:32:31 +0000931 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000932 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000933 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000934}
935
Miklos Szerediad005972006-01-07 10:14:34 +0000936enum {
937 KEY_HELP,
938 KEY_VERSION,
939};
940
Miklos Szeredi659743b2005-12-09 17:41:42 +0000941static struct fuse_opt fuse_ll_opts[] = {
942 { "debug", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi95da8602006-01-06 18:29:40 +0000943 { "-d", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi659743b2005-12-09 17:41:42 +0000944 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
Miklos Szeredi065f2222006-01-20 15:15:21 +0000945 { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
946 { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
947 { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
948 { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
949 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
Miklos Szerediad005972006-01-07 10:14:34 +0000950 FUSE_OPT_KEY("-h", KEY_HELP),
951 FUSE_OPT_KEY("--help", KEY_HELP),
952 FUSE_OPT_KEY("-V", KEY_VERSION),
953 FUSE_OPT_KEY("--version", KEY_VERSION),
Miklos Szeredi659743b2005-12-09 17:41:42 +0000954 FUSE_OPT_END
955};
956
Miklos Szerediad005972006-01-07 10:14:34 +0000957static void fuse_ll_version(void)
958{
959 fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
960 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
961}
962
Miklos Szeredi065f2222006-01-20 15:15:21 +0000963static void fuse_ll_help(void)
964{
965 fprintf(stderr,
966" -o max_write=N set maximum size of write requests\n"
967" -o max_readahead=N set maximum readahead\n"
968" -o async_read perform reads asynchronously (default)\n"
969" -o sync_read perform reads synchronously\n");
970}
971
Miklos Szeredicaa09312005-12-14 23:25:00 +0000972static int fuse_ll_opt_proc(void *data, const char *arg, int key,
Miklos Szeredi73f41392005-12-16 11:12:16 +0000973 struct fuse_args *outargs)
Miklos Szeredi3b534a42005-12-09 20:09:42 +0000974{
Miklos Szerediad005972006-01-07 10:14:34 +0000975 (void) data; (void) outargs;
Miklos Szeredicb402b02006-01-09 14:44:23 +0000976
Miklos Szerediad005972006-01-07 10:14:34 +0000977 switch (key) {
978 case KEY_HELP:
Miklos Szeredi065f2222006-01-20 15:15:21 +0000979 fuse_ll_help();
Miklos Szerediad005972006-01-07 10:14:34 +0000980 break;
Miklos Szeredicb402b02006-01-09 14:44:23 +0000981
Miklos Szerediad005972006-01-07 10:14:34 +0000982 case KEY_VERSION:
983 fuse_ll_version();
984 break;
985
986 default:
987 fprintf(stderr, "fuse: unknown option `%s'\n", arg);
988 }
Miklos Szeredicb402b02006-01-09 14:44:23 +0000989
Miklos Szeredi3b534a42005-12-09 20:09:42 +0000990 return -1;
991}
992
Miklos Szeredia1482422005-08-14 23:00:27 +0000993int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000994{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000995 return fuse_opt_match(fuse_ll_opts, opt);
Miklos Szeredi12744942005-07-11 12:32:31 +0000996}
997
Miklos Szeredia1482422005-08-14 23:00:27 +0000998static void fuse_ll_destroy(void *data)
999{
1000 struct fuse_ll *f = (struct fuse_ll *) data;
1001
1002 if (f->op.destroy)
1003 f->op.destroy(f->userdata);
1004
1005 free(f);
1006}
1007
Miklos Szeredi1ee1a112006-02-15 14:28:22 +00001008/*
1009 * always call fuse_lowlevel_new_common() internally, to work around a
1010 * misfeature in the FreeBSD runtime linker, which links the old
1011 * version of a symbol to internal references.
1012 */
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001013struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
Miklos Szeredia1482422005-08-14 23:00:27 +00001014 const struct fuse_lowlevel_ops *op,
1015 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +00001016{
1017 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +00001018 struct fuse_session *se;
1019 struct fuse_session_ops sop = {
1020 .process = fuse_ll_process,
1021 .destroy = fuse_ll_destroy,
1022 };
Miklos Szeredi12744942005-07-11 12:32:31 +00001023
Miklos Szeredia1482422005-08-14 23:00:27 +00001024 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +00001025 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00001026 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +00001027 }
1028
1029 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1030 if (f == NULL) {
1031 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1032 goto out;
1033 }
1034
Miklos Szeredi065f2222006-01-20 15:15:21 +00001035 f->conn.async_read = 1;
1036 f->conn.max_write = UINT_MAX;
1037 f->conn.max_readahead = UINT_MAX;
1038
Miklos Szeredi95da8602006-01-06 18:29:40 +00001039 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
1040 goto out_free;
Miklos Szeredi12744942005-07-11 12:32:31 +00001041
Miklos Szeredi12744942005-07-11 12:32:31 +00001042 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +00001043 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001044 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +00001045
Miklos Szeredia1482422005-08-14 23:00:27 +00001046 se = fuse_session_new(&sop, f);
1047 if (!se)
1048 goto out_free;
1049
1050 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +00001051
1052 out_free:
1053 free(f);
1054 out:
1055 return NULL;
1056}
Miklos Szeredic706ad92005-11-07 15:30:48 +00001057
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001058
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001059struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
1060 const struct fuse_lowlevel_ops *op,
1061 size_t op_size, void *userdata)
1062{
1063 return fuse_lowlevel_new_common(args, op, op_size, userdata);
1064}
1065
1066
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001067#include "fuse_lowlevel_compat.h"
1068
Miklos Szeredi065f2222006-01-20 15:15:21 +00001069#ifndef __FreeBSD__
1070
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001071static void fill_open_compat(struct fuse_open_out *arg,
1072 const struct fuse_file_info_compat *f)
1073{
1074 arg->fh = f->fh;
1075 if (f->direct_io)
1076 arg->open_flags |= FOPEN_DIRECT_IO;
1077 if (f->keep_cache)
1078 arg->open_flags |= FOPEN_KEEP_CACHE;
1079}
1080
Miklos Szeredi2b478112005-11-28 13:27:10 +00001081static void convert_statfs_compat(const struct statfs *compatbuf,
1082 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001083{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001084 buf->f_bsize = compatbuf->f_bsize;
1085 buf->f_blocks = compatbuf->f_blocks;
1086 buf->f_bfree = compatbuf->f_bfree;
1087 buf->f_bavail = compatbuf->f_bavail;
1088 buf->f_files = compatbuf->f_files;
1089 buf->f_ffree = compatbuf->f_ffree;
1090 buf->f_namemax = compatbuf->f_namelen;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001091}
1092
1093int fuse_reply_open_compat(fuse_req_t req,
1094 const struct fuse_file_info_compat *f)
1095{
1096 struct fuse_open_out arg;
1097
1098 memset(&arg, 0, sizeof(arg));
1099 fill_open_compat(&arg, f);
1100 return send_reply_ok(req, &arg, sizeof(arg));
1101}
1102
1103int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1104{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001105 struct statvfs newbuf;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001106
Miklos Szeredi2b478112005-11-28 13:27:10 +00001107 memset(&newbuf, 0, sizeof(newbuf));
1108 convert_statfs_compat(stbuf, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001109
Miklos Szeredi2b478112005-11-28 13:27:10 +00001110 return fuse_reply_statfs(req, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001111}
1112
Miklos Szeredi95da8602006-01-06 18:29:40 +00001113struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
1114 const struct fuse_lowlevel_ops *op,
1115 size_t op_size, void *userdata)
1116{
1117 struct fuse_session *se;
1118 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
1119
1120 if (opts &&
1121 (fuse_opt_add_arg(&args, "") == -1 ||
1122 fuse_opt_add_arg(&args, "-o") == -1 ||
1123 fuse_opt_add_arg(&args, opts) == -1)) {
1124 fuse_opt_free_args(&args);
1125 return NULL;
1126 }
1127 se = fuse_lowlevel_new(&args, op, op_size, userdata);
1128 fuse_opt_free_args(&args);
1129
1130 return se;
1131}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001132
Miklos Szeredi065f2222006-01-20 15:15:21 +00001133struct fuse_ll_compat_conf {
1134 unsigned max_read;
1135 int set_max_read;
1136};
1137
1138static const struct fuse_opt fuse_ll_opts_compat[] = {
1139 { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },
1140 { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },
1141 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
1142 FUSE_OPT_END
1143};
1144
1145int fuse_sync_compat_args(struct fuse_args *args)
1146{
1147 struct fuse_ll_compat_conf conf;
1148
Miklos Szeredi67d26d42006-03-13 17:39:56 +00001149 memset(&conf, 0, sizeof(conf));
Miklos Szeredi065f2222006-01-20 15:15:21 +00001150 if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)
1151 return -1;
1152
1153 if (fuse_opt_insert_arg(args, 1, "-osync_read"))
1154 return -1;
1155
1156 if (conf.set_max_read) {
1157 char tmpbuf[64];
1158
1159 sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);
1160 if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)
1161 return -1;
1162 }
1163 return 0;
1164}
1165
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001166__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
1167__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
1168__asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
1169
1170#else /* __FreeBSD__ */
1171
1172int fuse_sync_compat_args(struct fuse_args *args)
1173{
1174 (void) args;
1175 return 0;
1176}
1177
1178#endif /* __FreeBSD__ */
1179
Miklos Szeredi065f2222006-01-20 15:15:21 +00001180struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
1181 const struct fuse_lowlevel_ops_compat25 *op,
1182 size_t op_size, void *userdata)
1183{
1184 if (fuse_sync_compat_args(args) == -1)
1185 return NULL;
1186
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001187 return fuse_lowlevel_new_common(args,
1188 (const struct fuse_lowlevel_ops *) op,
1189 op_size, userdata);
Miklos Szeredi065f2222006-01-20 15:15:21 +00001190}
1191
Miklos Szeredi065f2222006-01-20 15:15:21 +00001192__asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");