blob: 7b5cb7b06a84d757f7a01dc3f0e43ca33166a431 [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{
Miklos Szeredi8d975f62006-03-17 15:56:05 +0000226 fuse_chan_send(req->ch, NULL, 0);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000227 free_req(req);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000228}
229
230static unsigned long calc_timeout_sec(double t)
231{
232 if (t > (double) ULONG_MAX)
233 return ULONG_MAX;
234 else if (t < 0.0)
235 return 0;
236 else
237 return (unsigned long) t;
238}
239
240static unsigned int calc_timeout_nsec(double t)
241{
242 double f = t - (double) calc_timeout_sec(t);
243 if (f < 0.0)
244 return 0;
245 else if (f >= 0.999999999)
246 return 999999999;
247 else
248 return (unsigned int) (f * 1.0e9);
249}
250
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000251static void fill_entry(struct fuse_entry_out *arg,
252 const struct fuse_entry_param *e)
253{
254 arg->nodeid = e->ino;
255 arg->generation = e->generation;
256 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
257 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
258 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
259 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
260 convert_stat(&e->attr, &arg->attr);
261}
262
263static void fill_open(struct fuse_open_out *arg,
264 const struct fuse_file_info *f)
265{
266 arg->fh = f->fh;
267 if (f->direct_io)
268 arg->open_flags |= FOPEN_DIRECT_IO;
269 if (f->keep_cache)
270 arg->open_flags |= FOPEN_KEEP_CACHE;
271}
272
Miklos Szeredi76c17522005-07-13 14:08:19 +0000273int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
274{
275 struct fuse_entry_out arg;
276
Miklos Szeredi2b478112005-11-28 13:27:10 +0000277 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
278 negative entry */
Miklos Szeredi065f2222006-01-20 15:15:21 +0000279 if (!e->ino && req->f->conn.proto_minor < 4)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000280 return fuse_reply_err(req, ENOENT);
281
Miklos Szeredi76c17522005-07-13 14:08:19 +0000282 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000283 fill_entry(&arg, e);
284 return send_reply_ok(req, &arg, sizeof(arg));
285}
Miklos Szeredi76c17522005-07-13 14:08:19 +0000286
Miklos Szeredid9079a72005-10-26 15:29:06 +0000287int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
288 const struct fuse_file_info *f)
289{
290 struct {
291 struct fuse_entry_out e;
292 struct fuse_open_out o;
293 } arg;
294
295 memset(&arg, 0, sizeof(arg));
296 fill_entry(&arg.e, e);
297 fill_open(&arg.o, f);
298 return send_reply_ok(req, &arg, sizeof(arg));
299}
300
Miklos Szeredi76c17522005-07-13 14:08:19 +0000301int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
302 double attr_timeout)
303{
304 struct fuse_attr_out arg;
305
306 memset(&arg, 0, sizeof(arg));
307 arg.attr_valid = calc_timeout_sec(attr_timeout);
308 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
309 convert_stat(attr, &arg.attr);
310
Miklos Szeredia1482422005-08-14 23:00:27 +0000311 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000312}
313
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000314int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000315{
Miklos Szeredia1482422005-08-14 23:00:27 +0000316 return send_reply_ok(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000317}
318
319int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
320{
321 struct fuse_open_out arg;
322
323 memset(&arg, 0, sizeof(arg));
Miklos Szeredib0c52c52005-08-23 15:39:43 +0000324 fill_open(&arg, f);
Miklos Szeredia1482422005-08-14 23:00:27 +0000325 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000326}
327
328int fuse_reply_write(fuse_req_t req, size_t count)
329{
330 struct fuse_write_out arg;
331
332 memset(&arg, 0, sizeof(arg));
333 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000334
Miklos Szeredia1482422005-08-14 23:00:27 +0000335 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000336}
337
338int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
339{
Miklos Szeredia1482422005-08-14 23:00:27 +0000340 return send_reply_ok(req, buf, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000341}
342
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000343int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000344{
345 struct fuse_statfs_out arg;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000346 size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000347
348 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000349 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000350
Miklos Szeredi2b478112005-11-28 13:27:10 +0000351 return send_reply_ok(req, &arg, size);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000352}
353
354int fuse_reply_xattr(fuse_req_t req, size_t count)
355{
356 struct fuse_getxattr_out arg;
357
358 memset(&arg, 0, sizeof(arg));
359 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000360
Miklos Szeredia1482422005-08-14 23:00:27 +0000361 return send_reply_ok(req, &arg, sizeof(arg));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000362}
363
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000364static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000365{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000366 char *name = (char *) inarg;
367
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000368 if (req->f->op.lookup)
369 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000370 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000371 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000372}
373
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000374static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000375{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000376 struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
377
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000378 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000379 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000380}
381
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000382static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000383{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000384 (void) inarg;
385
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000386 if (req->f->op.getattr)
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000387 req->f->op.getattr(req, nodeid, NULL);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000388 else
389 fuse_reply_err(req, ENOSYS);
390}
391
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000392static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000393{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000394 struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
395
Miklos Szeredi76c17522005-07-13 14:08:19 +0000396 if (req->f->op.setattr) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000397 struct fuse_file_info *fi = NULL;
398 struct fuse_file_info fi_store;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000399 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000400 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000401 convert_attr(arg, &stbuf);
402 if (arg->valid & FATTR_FH) {
403 arg->valid &= ~FATTR_FH;
404 memset(&fi_store, 0, sizeof(fi_store));
405 fi = &fi_store;
406 fi->fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000407 fi->fh_old = fi->fh;
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000408 }
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000409 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000410 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000411 fuse_reply_err(req, ENOSYS);
412}
413
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000414static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000415{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000416 struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
417
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000418 if (req->f->op.access)
419 req->f->op.access(req, nodeid, arg->mask);
420 else
421 fuse_reply_err(req, ENOSYS);
422}
423
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000424static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000425{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000426 (void) inarg;
427
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000428 if (req->f->op.readlink)
429 req->f->op.readlink(req, nodeid);
430 else
431 fuse_reply_err(req, ENOSYS);
432}
433
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000434static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000435{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000436 struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
437
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000438 if (req->f->op.mknod)
439 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
440 else
441 fuse_reply_err(req, ENOSYS);
442}
443
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000444static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000445{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000446 struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
447
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000448 if (req->f->op.mkdir)
449 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
450 else
451 fuse_reply_err(req, ENOSYS);
452}
453
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000454static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000455{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000456 char *name = (char *) inarg;
457
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000458 if (req->f->op.unlink)
459 req->f->op.unlink(req, nodeid, name);
460 else
461 fuse_reply_err(req, ENOSYS);
462}
463
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000464static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000465{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000466 char *name = (char *) inarg;
467
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000468 if (req->f->op.rmdir)
469 req->f->op.rmdir(req, nodeid, name);
470 else
471 fuse_reply_err(req, ENOSYS);
472}
473
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000474static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000475{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000476 char *name = (char *) inarg;
477 char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
478
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000479 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000480 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000481 else
482 fuse_reply_err(req, ENOSYS);
483}
484
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000485static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000486{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000487 struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000488 char *oldname = PARAM(arg);
489 char *newname = oldname + strlen(oldname) + 1;
490
491 if (req->f->op.rename)
492 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
493 else
494 fuse_reply_err(req, ENOSYS);
495}
496
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000497static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000498{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000499 struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
500
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000501 if (req->f->op.link)
502 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
503 else
504 fuse_reply_err(req, ENOSYS);
505}
506
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000507static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredid9079a72005-10-26 15:29:06 +0000508{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000509 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
510
Miklos Szeredid9079a72005-10-26 15:29:06 +0000511 if (req->f->op.create) {
512 struct fuse_file_info fi;
513
514 memset(&fi, 0, sizeof(fi));
515 fi.flags = arg->flags;
516
517 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
518 } else
519 fuse_reply_err(req, ENOSYS);
520}
521
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000522static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000523{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000524 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000525 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000526
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000527 memset(&fi, 0, sizeof(fi));
528 fi.flags = arg->flags;
529
530 if (req->f->op.open)
531 req->f->op.open(req, nodeid, &fi);
532 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000533 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000534}
535
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000536static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000537{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000538 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
539
Miklos Szeredi76c17522005-07-13 14:08:19 +0000540 if (req->f->op.read) {
541 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000542
Miklos Szeredi76c17522005-07-13 14:08:19 +0000543 memset(&fi, 0, sizeof(fi));
544 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000545 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000546 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000547 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000548 fuse_reply_err(req, ENOSYS);
549}
550
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000551static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000552{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000553 struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000554 struct fuse_file_info fi;
555
556 memset(&fi, 0, sizeof(fi));
557 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000558 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000559 fi.writepage = arg->write_flags & 1;
560
561 if (req->f->op.write)
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000562 req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000563 else
564 fuse_reply_err(req, ENOSYS);
565}
566
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000567static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000568{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000569 struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000570 struct fuse_file_info fi;
571
572 memset(&fi, 0, sizeof(fi));
573 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000574 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000575
576 if (req->f->op.flush)
577 req->f->op.flush(req, nodeid, &fi);
578 else
579 fuse_reply_err(req, ENOSYS);
580}
581
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000582static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000583{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000584 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000585 struct fuse_file_info fi;
586
587 memset(&fi, 0, sizeof(fi));
588 fi.flags = arg->flags;
589 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000590 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000591
592 if (req->f->op.release)
593 req->f->op.release(req, nodeid, &fi);
594 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000595 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000596}
597
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000598static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000599{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000600 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000601 struct fuse_file_info fi;
602
603 memset(&fi, 0, sizeof(fi));
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000604 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000605 fi.fh_old = fi.fh;
Miklos Szeredi12744942005-07-11 12:32:31 +0000606
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000607 if (req->f->op.fsync)
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000608 req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000609 else
610 fuse_reply_err(req, ENOSYS);
611}
612
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000613static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000614{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000615 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000616 struct fuse_file_info fi;
617
618 memset(&fi, 0, sizeof(fi));
619 fi.flags = arg->flags;
620
621 if (req->f->op.opendir)
622 req->f->op.opendir(req, nodeid, &fi);
623 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000624 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000625}
626
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000627static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000628{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000629 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000630 struct fuse_file_info fi;
631
632 memset(&fi, 0, sizeof(fi));
633 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000634 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000635
636 if (req->f->op.readdir)
637 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
638 else
639 fuse_reply_err(req, ENOSYS);
640}
641
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000642static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000643{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000644 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000645 struct fuse_file_info fi;
646
647 memset(&fi, 0, sizeof(fi));
648 fi.flags = arg->flags;
649 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000650 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000651
652 if (req->f->op.releasedir)
653 req->f->op.releasedir(req, nodeid, &fi);
654 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000655 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000656}
657
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000658static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000659{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000660 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000661 struct fuse_file_info fi;
662
663 memset(&fi, 0, sizeof(fi));
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000664 fi.fh = arg->fh;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000665 fi.fh_old = fi.fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000666
667 if (req->f->op.fsyncdir)
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000668 req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000669 else
670 fuse_reply_err(req, ENOSYS);
671}
672
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000673static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000674{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000675 (void) nodeid;
676 (void) inarg;
677
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000678 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000679 req->f->op.statfs(req);
Miklos Szerediaa8258e2006-02-25 14:42:03 +0000680 else {
681 struct statvfs buf = {
682 .f_namemax = 255,
683 .f_bsize = 512,
684 };
685 fuse_reply_statfs(req, &buf);
686 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000687}
688
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000689static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000690{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000691 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000692 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000693 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000694
Miklos Szeredi4331a272005-07-12 14:51:04 +0000695 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000696 req->f->op.setxattr(req, nodeid, name, value, arg->size,
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000697 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000698 else
699 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000700}
701
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000702static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000703{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000704 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
705
Miklos Szeredi4331a272005-07-12 14:51:04 +0000706 if (req->f->op.getxattr)
707 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000708 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000709 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000710}
711
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000712static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000713{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000714 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
715
Miklos Szeredi4331a272005-07-12 14:51:04 +0000716 if (req->f->op.listxattr)
717 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000718 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000719 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000720}
721
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000722static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000723{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000724 char *name = (char *) inarg;
725
Miklos Szeredi4331a272005-07-12 14:51:04 +0000726 if (req->f->op.removexattr)
727 req->f->op.removexattr(req, nodeid, name);
728 else
729 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000730}
731
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000732static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
Miklos Szeredi12744942005-07-11 12:32:31 +0000733{
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000734 struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000735 struct fuse_init_out outarg;
Miklos Szeredia1482422005-08-14 23:00:27 +0000736 struct fuse_ll *f = req->f;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000737 size_t bufsize = fuse_chan_bufsize(req->ch);
Miklos Szeredi12744942005-07-11 12:32:31 +0000738
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000739 (void) nodeid;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000740 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000741 printf("INIT: %u.%u\n", arg->major, arg->minor);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000742 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
743 printf("flags=0x%08x\n", arg->flags);
744 printf("max_readahead=0x%08x\n", arg->max_readahead);
745 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000746 fflush(stdout);
747 }
Miklos Szeredi065f2222006-01-20 15:15:21 +0000748 f->conn.proto_major = arg->major;
749 f->conn.proto_minor = arg->minor;
Miklos Szeredi12744942005-07-11 12:32:31 +0000750
Miklos Szeredi065f2222006-01-20 15:15:21 +0000751 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
752 if (f->conn.async_read)
753 f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
754 if (arg->max_readahead < f->conn.max_readahead)
755 f->conn.max_readahead = arg->max_readahead;
756 } else {
757 f->conn.async_read = 0;
758 f->conn.max_readahead = 0;
759 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000760
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000761 if (bufsize < FUSE_MIN_READ_BUFFER) {
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000762 fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000763 bufsize = FUSE_MIN_READ_BUFFER;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000764 }
765
Miklos Szeredi065f2222006-01-20 15:15:21 +0000766 bufsize -= 4096;
767 if (bufsize < f->conn.max_write)
768 f->conn.max_write = bufsize;
769
770 f->got_init = 1;
771 if (f->op.init)
772 f->op.init(f->userdata, &f->conn);
773
Miklos Szeredi12744942005-07-11 12:32:31 +0000774 memset(&outarg, 0, sizeof(outarg));
Miklos Szeredi065f2222006-01-20 15:15:21 +0000775 outarg.major = FUSE_KERNEL_VERSION;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000776 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000777 if (f->conn.async_read)
778 outarg.flags |= FUSE_ASYNC_READ;
779 outarg.max_readahead = f->conn.max_readahead;
780 outarg.max_write = f->conn.max_write;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000781
Miklos Szeredi76c17522005-07-13 14:08:19 +0000782 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000783 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000784 printf(" flags=0x%08x\n", outarg.flags);
785 printf(" max_readahead=0x%08x\n", outarg.max_readahead);
786 printf(" max_write=0x%08x\n", outarg.max_write);
Miklos Szeredi12744942005-07-11 12:32:31 +0000787 fflush(stdout);
788 }
789
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000790 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000791}
792
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000793void *fuse_req_userdata(fuse_req_t req)
794{
795 return req->f->userdata;
796}
797
798const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
799{
800 return &req->ctx;
801}
802
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000803static void (*fuse_ll_ops[FUSE_MAXOP])(fuse_req_t, fuse_ino_t, const void *) = {
804 [FUSE_LOOKUP] = do_lookup,
805 [FUSE_FORGET] = do_forget,
806 [FUSE_GETATTR] = do_getattr,
807 [FUSE_SETATTR] = do_setattr,
808 [FUSE_READLINK] = do_readlink,
809 [FUSE_SYMLINK] = do_symlink,
810 [FUSE_MKNOD] = do_mknod,
811 [FUSE_MKDIR] = do_mkdir,
812 [FUSE_UNLINK] = do_unlink,
813 [FUSE_RMDIR] = do_rmdir,
814 [FUSE_RENAME] = do_rename,
815 [FUSE_LINK] = do_link,
816 [FUSE_OPEN] = do_open,
817 [FUSE_READ] = do_read,
818 [FUSE_WRITE] = do_write,
819 [FUSE_STATFS] = do_statfs,
820 [FUSE_RELEASE] = do_release,
821 [FUSE_FSYNC] = do_fsync,
822 [FUSE_SETXATTR] = do_setxattr,
823 [FUSE_GETXATTR] = do_getxattr,
824 [FUSE_LISTXATTR] = do_listxattr,
825 [FUSE_REMOVEXATTR] = do_removexattr,
826 [FUSE_FLUSH] = do_flush,
827 [FUSE_INIT] = do_init,
828 [FUSE_OPENDIR] = do_opendir,
829 [FUSE_READDIR] = do_readdir,
830 [FUSE_RELEASEDIR] = do_releasedir,
831 [FUSE_FSYNCDIR] = do_fsyncdir,
832 [FUSE_ACCESS] = do_access,
833 [FUSE_CREATE] = do_create,
834};
835
Miklos Szeredia1482422005-08-14 23:00:27 +0000836static void fuse_ll_process(void *data, const char *buf, size_t len,
837 struct fuse_chan *ch)
Miklos Szeredi12744942005-07-11 12:32:31 +0000838{
Miklos Szeredia1482422005-08-14 23:00:27 +0000839 struct fuse_ll *f = (struct fuse_ll *) data;
840 struct fuse_in_header *in = (struct fuse_in_header *) buf;
841 const void *inarg = buf + sizeof(struct fuse_in_header);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000842 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000843
Miklos Szeredi76c17522005-07-13 14:08:19 +0000844 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000845 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000846 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredia1482422005-08-14 23:00:27 +0000847 (unsigned long) in->nodeid, len);
Miklos Szeredi12744942005-07-11 12:32:31 +0000848 fflush(stdout);
849 }
850
Miklos Szeredi76c17522005-07-13 14:08:19 +0000851 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
852 if (req == NULL) {
853 fprintf(stderr, "fuse: failed to allocate request\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000854 return;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000855 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000856
Miklos Szeredi76c17522005-07-13 14:08:19 +0000857 req->f = f;
858 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000859 req->ctx.uid = in->uid;
860 req->ctx.gid = in->gid;
861 req->ctx.pid = in->pid;
Miklos Szeredia1482422005-08-14 23:00:27 +0000862 req->ch = ch;
Miklos Szeredi12744942005-07-11 12:32:31 +0000863
Miklos Szeredia1482422005-08-14 23:00:27 +0000864 if (!f->got_init && in->opcode != FUSE_INIT)
Miklos Szeredib3f99722005-11-16 13:00:24 +0000865 fuse_reply_err(req, EIO);
Miklos Szeredia1482422005-08-14 23:00:27 +0000866 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
867 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
868 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
869 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
870 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
871 fuse_reply_err(req, EACCES);
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000872 } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode])
Miklos Szeredi76c17522005-07-13 14:08:19 +0000873 fuse_reply_err(req, ENOSYS);
Miklos Szeredi2c1381f2006-03-15 20:34:10 +0000874 else
875 fuse_ll_ops[in->opcode](req, in->nodeid, inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000876}
877
Miklos Szerediad005972006-01-07 10:14:34 +0000878enum {
879 KEY_HELP,
880 KEY_VERSION,
881};
882
Miklos Szeredi659743b2005-12-09 17:41:42 +0000883static struct fuse_opt fuse_ll_opts[] = {
884 { "debug", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi95da8602006-01-06 18:29:40 +0000885 { "-d", offsetof(struct fuse_ll, debug), 1 },
Miklos Szeredi659743b2005-12-09 17:41:42 +0000886 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
Miklos Szeredi065f2222006-01-20 15:15:21 +0000887 { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
888 { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
889 { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
890 { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
891 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
Miklos Szerediad005972006-01-07 10:14:34 +0000892 FUSE_OPT_KEY("-h", KEY_HELP),
893 FUSE_OPT_KEY("--help", KEY_HELP),
894 FUSE_OPT_KEY("-V", KEY_VERSION),
895 FUSE_OPT_KEY("--version", KEY_VERSION),
Miklos Szeredi659743b2005-12-09 17:41:42 +0000896 FUSE_OPT_END
897};
898
Miklos Szerediad005972006-01-07 10:14:34 +0000899static void fuse_ll_version(void)
900{
901 fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
902 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
903}
904
Miklos Szeredi065f2222006-01-20 15:15:21 +0000905static void fuse_ll_help(void)
906{
907 fprintf(stderr,
908" -o max_write=N set maximum size of write requests\n"
909" -o max_readahead=N set maximum readahead\n"
910" -o async_read perform reads asynchronously (default)\n"
911" -o sync_read perform reads synchronously\n");
912}
913
Miklos Szeredicaa09312005-12-14 23:25:00 +0000914static int fuse_ll_opt_proc(void *data, const char *arg, int key,
Miklos Szeredi73f41392005-12-16 11:12:16 +0000915 struct fuse_args *outargs)
Miklos Szeredi3b534a42005-12-09 20:09:42 +0000916{
Miklos Szerediad005972006-01-07 10:14:34 +0000917 (void) data; (void) outargs;
Miklos Szeredicb402b02006-01-09 14:44:23 +0000918
Miklos Szerediad005972006-01-07 10:14:34 +0000919 switch (key) {
920 case KEY_HELP:
Miklos Szeredi065f2222006-01-20 15:15:21 +0000921 fuse_ll_help();
Miklos Szerediad005972006-01-07 10:14:34 +0000922 break;
Miklos Szeredicb402b02006-01-09 14:44:23 +0000923
Miklos Szerediad005972006-01-07 10:14:34 +0000924 case KEY_VERSION:
925 fuse_ll_version();
926 break;
927
928 default:
929 fprintf(stderr, "fuse: unknown option `%s'\n", arg);
930 }
Miklos Szeredicb402b02006-01-09 14:44:23 +0000931
Miklos Szeredi3b534a42005-12-09 20:09:42 +0000932 return -1;
933}
934
Miklos Szeredia1482422005-08-14 23:00:27 +0000935int fuse_lowlevel_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000936{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000937 return fuse_opt_match(fuse_ll_opts, opt);
Miklos Szeredi12744942005-07-11 12:32:31 +0000938}
939
Miklos Szeredia1482422005-08-14 23:00:27 +0000940static void fuse_ll_destroy(void *data)
941{
942 struct fuse_ll *f = (struct fuse_ll *) data;
943
944 if (f->op.destroy)
945 f->op.destroy(f->userdata);
946
947 free(f);
948}
949
Miklos Szeredi1ee1a112006-02-15 14:28:22 +0000950/*
951 * always call fuse_lowlevel_new_common() internally, to work around a
952 * misfeature in the FreeBSD runtime linker, which links the old
953 * version of a symbol to internal references.
954 */
Miklos Szeredid65cdfe2006-02-15 14:25:17 +0000955struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
Miklos Szeredia1482422005-08-14 23:00:27 +0000956 const struct fuse_lowlevel_ops *op,
957 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000958{
959 struct fuse_ll *f;
Miklos Szeredia1482422005-08-14 23:00:27 +0000960 struct fuse_session *se;
961 struct fuse_session_ops sop = {
962 .process = fuse_ll_process,
963 .destroy = fuse_ll_destroy,
964 };
Miklos Szeredi12744942005-07-11 12:32:31 +0000965
Miklos Szeredia1482422005-08-14 23:00:27 +0000966 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
Miklos Szeredib75d4b92005-10-11 10:12:08 +0000967 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
Miklos Szeredia1482422005-08-14 23:00:27 +0000968 op_size = sizeof(struct fuse_lowlevel_ops);
Miklos Szeredi12744942005-07-11 12:32:31 +0000969 }
970
971 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
972 if (f == NULL) {
973 fprintf(stderr, "fuse: failed to allocate fuse object\n");
974 goto out;
975 }
976
Miklos Szeredi065f2222006-01-20 15:15:21 +0000977 f->conn.async_read = 1;
978 f->conn.max_write = UINT_MAX;
979 f->conn.max_readahead = UINT_MAX;
980
Miklos Szeredi95da8602006-01-06 18:29:40 +0000981 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
982 goto out_free;
Miklos Szeredi12744942005-07-11 12:32:31 +0000983
Miklos Szeredi12744942005-07-11 12:32:31 +0000984 memcpy(&f->op, op, op_size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000985 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000986 f->userdata = userdata;
Miklos Szeredi12744942005-07-11 12:32:31 +0000987
Miklos Szeredia1482422005-08-14 23:00:27 +0000988 se = fuse_session_new(&sop, f);
989 if (!se)
990 goto out_free;
991
992 return se;
Miklos Szeredi12744942005-07-11 12:32:31 +0000993
994 out_free:
995 free(f);
996 out:
997 return NULL;
998}
Miklos Szeredic706ad92005-11-07 15:30:48 +0000999
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001000
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001001struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
1002 const struct fuse_lowlevel_ops *op,
1003 size_t op_size, void *userdata)
1004{
1005 return fuse_lowlevel_new_common(args, op, op_size, userdata);
1006}
1007
1008
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001009#include "fuse_lowlevel_compat.h"
1010
Miklos Szeredi065f2222006-01-20 15:15:21 +00001011#ifndef __FreeBSD__
1012
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001013static void fill_open_compat(struct fuse_open_out *arg,
1014 const struct fuse_file_info_compat *f)
1015{
1016 arg->fh = f->fh;
1017 if (f->direct_io)
1018 arg->open_flags |= FOPEN_DIRECT_IO;
1019 if (f->keep_cache)
1020 arg->open_flags |= FOPEN_KEEP_CACHE;
1021}
1022
Miklos Szeredi2b478112005-11-28 13:27:10 +00001023static void convert_statfs_compat(const struct statfs *compatbuf,
1024 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001025{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001026 buf->f_bsize = compatbuf->f_bsize;
1027 buf->f_blocks = compatbuf->f_blocks;
1028 buf->f_bfree = compatbuf->f_bfree;
1029 buf->f_bavail = compatbuf->f_bavail;
1030 buf->f_files = compatbuf->f_files;
1031 buf->f_ffree = compatbuf->f_ffree;
1032 buf->f_namemax = compatbuf->f_namelen;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001033}
1034
1035int fuse_reply_open_compat(fuse_req_t req,
1036 const struct fuse_file_info_compat *f)
1037{
1038 struct fuse_open_out arg;
1039
1040 memset(&arg, 0, sizeof(arg));
1041 fill_open_compat(&arg, f);
1042 return send_reply_ok(req, &arg, sizeof(arg));
1043}
1044
1045int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1046{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001047 struct statvfs newbuf;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001048
Miklos Szeredi2b478112005-11-28 13:27:10 +00001049 memset(&newbuf, 0, sizeof(newbuf));
1050 convert_statfs_compat(stbuf, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001051
Miklos Szeredi2b478112005-11-28 13:27:10 +00001052 return fuse_reply_statfs(req, &newbuf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001053}
1054
Miklos Szeredi95da8602006-01-06 18:29:40 +00001055struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
1056 const struct fuse_lowlevel_ops *op,
1057 size_t op_size, void *userdata)
1058{
1059 struct fuse_session *se;
1060 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
1061
1062 if (opts &&
1063 (fuse_opt_add_arg(&args, "") == -1 ||
1064 fuse_opt_add_arg(&args, "-o") == -1 ||
1065 fuse_opt_add_arg(&args, opts) == -1)) {
1066 fuse_opt_free_args(&args);
1067 return NULL;
1068 }
1069 se = fuse_lowlevel_new(&args, op, op_size, userdata);
1070 fuse_opt_free_args(&args);
1071
1072 return se;
1073}
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001074
Miklos Szeredi065f2222006-01-20 15:15:21 +00001075struct fuse_ll_compat_conf {
1076 unsigned max_read;
1077 int set_max_read;
1078};
1079
1080static const struct fuse_opt fuse_ll_opts_compat[] = {
1081 { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },
1082 { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },
1083 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
1084 FUSE_OPT_END
1085};
1086
1087int fuse_sync_compat_args(struct fuse_args *args)
1088{
1089 struct fuse_ll_compat_conf conf;
1090
Miklos Szeredi67d26d42006-03-13 17:39:56 +00001091 memset(&conf, 0, sizeof(conf));
Miklos Szeredi065f2222006-01-20 15:15:21 +00001092 if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)
1093 return -1;
1094
1095 if (fuse_opt_insert_arg(args, 1, "-osync_read"))
1096 return -1;
1097
1098 if (conf.set_max_read) {
1099 char tmpbuf[64];
1100
1101 sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);
1102 if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)
1103 return -1;
1104 }
1105 return 0;
1106}
1107
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001108__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
1109__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
1110__asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
1111
1112#else /* __FreeBSD__ */
1113
1114int fuse_sync_compat_args(struct fuse_args *args)
1115{
1116 (void) args;
1117 return 0;
1118}
1119
1120#endif /* __FreeBSD__ */
1121
Miklos Szeredi065f2222006-01-20 15:15:21 +00001122struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
1123 const struct fuse_lowlevel_ops_compat25 *op,
1124 size_t op_size, void *userdata)
1125{
1126 if (fuse_sync_compat_args(args) == -1)
1127 return NULL;
1128
Miklos Szeredid65cdfe2006-02-15 14:25:17 +00001129 return fuse_lowlevel_new_common(args,
1130 (const struct fuse_lowlevel_ops *) op,
1131 op_size, userdata);
Miklos Szeredi065f2222006-01-20 15:15:21 +00001132}
1133
Miklos Szeredi065f2222006-01-20 15:15:21 +00001134__asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");