blob: 495eb1daf6d173af60c556075fff58170c0beacd [file] [log] [blame]
Miklos Szeredi12744942005-07-11 12:32:31 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
7*/
8
Miklos Szeredi76c17522005-07-13 14:08:19 +00009#include "fuse_lowlevel.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000010#include "fuse_kernel.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000011
12#include <stdio.h>
13#include <string.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <limits.h>
17#include <errno.h>
18#include <assert.h>
19#include <stdint.h>
20#include <sys/param.h>
21#include <sys/uio.h>
22
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000023#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000024
25struct fuse_ll {
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000026 unsigned int debug : 1;
27 unsigned int allow_root : 1;
Miklos Szeredi12744942005-07-11 12:32:31 +000028 int fd;
Miklos Szeredi76c17522005-07-13 14:08:19 +000029 struct fuse_ll_operations op;
Miklos Szeredi12744942005-07-11 12:32:31 +000030 volatile int exited;
31 int got_init;
32 void *user_data;
33 int major;
34 int minor;
35 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000036};
37
38struct fuse_cmd {
39 char *buf;
40 size_t buflen;
41};
42
Miklos Szeredi76c17522005-07-13 14:08:19 +000043struct fuse_req {
44 struct fuse_ll *f;
45 uint64_t unique;
46 uid_t uid;
47 gid_t gid;
48 pid_t pid;
49};
50
Miklos Szeredi12744942005-07-11 12:32:31 +000051static const char *opname(enum fuse_opcode opcode)
52{
53 switch (opcode) {
54 case FUSE_LOOKUP: return "LOOKUP";
55 case FUSE_FORGET: return "FORGET";
56 case FUSE_GETATTR: return "GETATTR";
57 case FUSE_SETATTR: return "SETATTR";
58 case FUSE_READLINK: return "READLINK";
59 case FUSE_SYMLINK: return "SYMLINK";
60 case FUSE_MKNOD: return "MKNOD";
61 case FUSE_MKDIR: return "MKDIR";
62 case FUSE_UNLINK: return "UNLINK";
63 case FUSE_RMDIR: return "RMDIR";
64 case FUSE_RENAME: return "RENAME";
65 case FUSE_LINK: return "LINK";
66 case FUSE_OPEN: return "OPEN";
67 case FUSE_READ: return "READ";
68 case FUSE_WRITE: return "WRITE";
69 case FUSE_STATFS: return "STATFS";
70 case FUSE_FLUSH: return "FLUSH";
71 case FUSE_RELEASE: return "RELEASE";
72 case FUSE_FSYNC: return "FSYNC";
73 case FUSE_SETXATTR: return "SETXATTR";
74 case FUSE_GETXATTR: return "GETXATTR";
75 case FUSE_LISTXATTR: return "LISTXATTR";
76 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
77 case FUSE_INIT: return "INIT";
78 case FUSE_OPENDIR: return "OPENDIR";
79 case FUSE_READDIR: return "READDIR";
80 case FUSE_RELEASEDIR: return "RELEASEDIR";
81 case FUSE_FSYNCDIR: return "FSYNCDIR";
82 default: return "???";
83 }
84}
85
Miklos Szeredi76c17522005-07-13 14:08:19 +000086static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000087{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000088 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000089 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000090 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000091 attr->uid = stbuf->st_uid;
92 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000093 attr->rdev = stbuf->st_rdev;
94 attr->size = stbuf->st_size;
95 attr->blocks = stbuf->st_blocks;
96 attr->atime = stbuf->st_atime;
97 attr->mtime = stbuf->st_mtime;
98 attr->ctime = stbuf->st_ctime;
99#ifdef HAVE_STRUCT_STAT_ST_ATIM
100 attr->atimensec = stbuf->st_atim.tv_nsec;
101 attr->mtimensec = stbuf->st_mtim.tv_nsec;
102 attr->ctimensec = stbuf->st_ctim.tv_nsec;
103#endif
104}
105
Miklos Szeredi76c17522005-07-13 14:08:19 +0000106static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf)
107{
108 stbuf->st_mode = attr->mode;
109 stbuf->st_uid = attr->uid;
110 stbuf->st_gid = attr->gid;
111 stbuf->st_size = attr->size;
112 stbuf->st_atime = attr->atime;
113 stbuf->st_mtime = attr->mtime;
114 stbuf->st_ctime = attr->ctime;
115#ifdef HAVE_STRUCT_STAT_ST_ATIM
116 stbuf->st_atim.tv_nsec = attr->atimensec;
117 stbuf->st_mtim.tv_nsec = attr->mtimensec;
118 stbuf->st_ctim.tv_nsec = attr->ctimensec;
119#endif
120}
121
Miklos Szeredi12744942005-07-11 12:32:31 +0000122static size_t iov_length(const struct iovec *iov, size_t count)
123{
124 size_t seg;
125 size_t ret = 0;
126
127 for (seg = 0; seg < count; seg++)
128 ret += iov[seg].iov_len;
129 return ret;
130}
131
132static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
133 size_t count)
134{
135 int res;
136 unsigned outsize = iov_length(iov, count);
137 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
138 out->len = outsize;
139
Miklos Szeredi76c17522005-07-13 14:08:19 +0000140 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000141 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
142 out->unique, out->error, strerror(-out->error), outsize);
143 fflush(stdout);
144 }
145
Miklos Szeredi12744942005-07-11 12:32:31 +0000146 res = writev(f->fd, iov, count);
147 if (res == -1) {
148 /* ENOENT means the operation was interrupted */
149 if (!f->exited && errno != ENOENT)
150 perror("fuse: writing device");
151 return -errno;
152 }
153 return 0;
154}
155
Miklos Szeredi76c17522005-07-13 14:08:19 +0000156static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
157 const void *arg, size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000158{
159 struct fuse_out_header out;
160 struct iovec iov[2];
161 size_t count;
162
163 if (error <= -1000 || error > 0) {
164 fprintf(stderr, "fuse: bad error value: %i\n", error);
165 error = -ERANGE;
166 }
167
Miklos Szeredi76c17522005-07-13 14:08:19 +0000168 out.unique = unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000169 out.error = error;
170 count = 1;
171 iov[0].iov_base = &out;
172 iov[0].iov_len = sizeof(struct fuse_out_header);
173 if (argsize && !error) {
174 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000175 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000176 iov[1].iov_len = argsize;
177 }
178 return send_reply_raw(f, iov, count);
179}
180
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000181size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000182{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000183 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000184}
185
Miklos Szeredi76c17522005-07-13 14:08:19 +0000186char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
187 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000188{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000189 unsigned namelen = strlen(name);
190 unsigned entlen = FUSE_NAME_OFFSET + namelen;
191 unsigned entsize = fuse_dirent_size(namelen);
192 unsigned padlen = entsize - entlen;
193 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000194
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000195 dirent->ino = stat->st_ino;
196 dirent->off = off;
197 dirent->namelen = namelen;
198 dirent->type = (stat->st_mode & 0170000) >> 12;
199 strncpy(dirent->name, name, namelen);
200 if (padlen)
201 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000202
Miklos Szeredi76c17522005-07-13 14:08:19 +0000203 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000204}
205
Miklos Szeredi76c17522005-07-13 14:08:19 +0000206static void convert_statfs(const struct statfs *statfs,
207 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000208{
209 kstatfs->bsize = statfs->f_bsize;
210 kstatfs->blocks = statfs->f_blocks;
211 kstatfs->bfree = statfs->f_bfree;
212 kstatfs->bavail = statfs->f_bavail;
213 kstatfs->files = statfs->f_files;
214 kstatfs->ffree = statfs->f_ffree;
215 kstatfs->namelen = statfs->f_namelen;
216}
217
Miklos Szeredi76c17522005-07-13 14:08:19 +0000218static void free_req(fuse_req_t req)
219{
220 free(req);
221}
222
223static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize)
224{
225 int res = send_reply(req->f, req->unique, 0, arg, argsize);
226 free_req(req);
227 return res;
228}
229
230int fuse_reply_err(fuse_req_t req, int err)
231{
232 int res = send_reply(req->f, req->unique, -err, NULL, 0);
233 free_req(req);
234 return res;
235}
236
237int fuse_reply_none(fuse_req_t req)
238{
239 free_req(req);
240 return 0;
241}
242
243static unsigned long calc_timeout_sec(double t)
244{
245 if (t > (double) ULONG_MAX)
246 return ULONG_MAX;
247 else if (t < 0.0)
248 return 0;
249 else
250 return (unsigned long) t;
251}
252
253static unsigned int calc_timeout_nsec(double t)
254{
255 double f = t - (double) calc_timeout_sec(t);
256 if (f < 0.0)
257 return 0;
258 else if (f >= 0.999999999)
259 return 999999999;
260 else
261 return (unsigned int) (f * 1.0e9);
262}
263
264int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
265{
266 struct fuse_entry_out arg;
267
268 memset(&arg, 0, sizeof(arg));
269 arg.nodeid = e->ino;
270 arg.generation = e->generation;
271 arg.entry_valid = calc_timeout_sec(e->entry_timeout);
272 arg.entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
273 arg.attr_valid = calc_timeout_sec(e->attr_timeout);
274 arg.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
275 convert_stat(&e->attr, &arg.attr);
276
277 return send_reply_req(req, &arg, sizeof(arg));
278}
279
280int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
281 double attr_timeout)
282{
283 struct fuse_attr_out arg;
284
285 memset(&arg, 0, sizeof(arg));
286 arg.attr_valid = calc_timeout_sec(attr_timeout);
287 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
288 convert_stat(attr, &arg.attr);
289
290 return send_reply_req(req, &arg, sizeof(arg));
291}
292
293int fuse_reply_readlink(fuse_req_t req, const char *link)
294{
295 return send_reply_req(req, link, strlen(link));
296}
297
298int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
299{
300 struct fuse_open_out arg;
301
302 memset(&arg, 0, sizeof(arg));
303 arg.fh = f->fh;
304
305 return send_reply_req(req, &arg, sizeof(arg));
306}
307
308int fuse_reply_write(fuse_req_t req, size_t count)
309{
310 struct fuse_write_out arg;
311
312 memset(&arg, 0, sizeof(arg));
313 arg.size = count;
314
315 return send_reply_req(req, &arg, sizeof(arg));
316}
317
318int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
319{
320 return send_reply_req(req, buf, size);
321}
322
323int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs)
324{
325 struct fuse_statfs_out arg;
326
327 memset(&arg, 0, sizeof(arg));
328 convert_statfs(statfs, &arg.st);
329
330 return send_reply_req(req, &arg, sizeof(arg));
331}
332
333int fuse_reply_xattr(fuse_req_t req, size_t count)
334{
335 struct fuse_getxattr_out arg;
336
337 memset(&arg, 0, sizeof(arg));
338 arg.size = count;
339
340 return send_reply_req(req, &arg, sizeof(arg));
341}
342
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000343static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000344{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000345 if (req->f->op.lookup)
346 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000347 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000348 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000349}
350
Miklos Szeredi76c17522005-07-13 14:08:19 +0000351static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
352 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000353{
354 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000355 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000356}
357
358static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
359{
360 if (req->f->op.getattr)
361 req->f->op.getattr(req, nodeid);
362 else
363 fuse_reply_err(req, ENOSYS);
364}
365
366static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
367 struct fuse_setattr_in *arg)
368{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000369 if (req->f->op.setattr) {
370 struct stat stbuf;
371 convert_attr(&arg->attr, &stbuf);
372 req->f->op.setattr(req, nodeid, &stbuf, arg->valid);
373 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000374 fuse_reply_err(req, ENOSYS);
375}
376
377static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
378{
379 if (req->f->op.readlink)
380 req->f->op.readlink(req, nodeid);
381 else
382 fuse_reply_err(req, ENOSYS);
383}
384
385static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
386 struct fuse_mknod_in *arg)
387{
388 if (req->f->op.mknod)
389 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
390 else
391 fuse_reply_err(req, ENOSYS);
392}
393
394static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
395 struct fuse_mkdir_in *arg)
396{
397 if (req->f->op.mkdir)
398 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
399 else
400 fuse_reply_err(req, ENOSYS);
401}
402
403static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
404{
405 if (req->f->op.unlink)
406 req->f->op.unlink(req, nodeid, name);
407 else
408 fuse_reply_err(req, ENOSYS);
409}
410
411static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
412{
413 if (req->f->op.rmdir)
414 req->f->op.rmdir(req, nodeid, name);
415 else
416 fuse_reply_err(req, ENOSYS);
417}
418
419static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
420 char *link)
421{
422 if (req->f->op.symlink)
423 req->f->op.symlink(req, link, nodeid, name);
424 else
425 fuse_reply_err(req, ENOSYS);
426}
427
428static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
429 struct fuse_rename_in *arg)
430{
431 char *oldname = PARAM(arg);
432 char *newname = oldname + strlen(oldname) + 1;
433
434 if (req->f->op.rename)
435 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
436 else
437 fuse_reply_err(req, ENOSYS);
438}
439
440static void do_link(fuse_req_t req, fuse_ino_t nodeid,
441 struct fuse_link_in *arg)
442{
443 if (req->f->op.link)
444 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
445 else
446 fuse_reply_err(req, ENOSYS);
447}
448
449static void do_open(fuse_req_t req, fuse_ino_t nodeid,
450 struct fuse_open_in *arg)
451{
452 struct fuse_file_info fi;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000453
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000454 memset(&fi, 0, sizeof(fi));
455 fi.flags = arg->flags;
456
457 if (req->f->op.open)
458 req->f->op.open(req, nodeid, &fi);
459 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000460 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000461}
462
463static void do_read(fuse_req_t req, fuse_ino_t nodeid,
464 struct fuse_read_in *arg)
465{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000466 if (req->f->op.read) {
467 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000468
Miklos Szeredi76c17522005-07-13 14:08:19 +0000469 memset(&fi, 0, sizeof(fi));
470 fi.fh = arg->fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000471 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000472 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000473 fuse_reply_err(req, ENOSYS);
474}
475
476static void do_write(fuse_req_t req, fuse_ino_t nodeid,
477 struct fuse_write_in *arg)
478{
479 struct fuse_file_info fi;
480
481 memset(&fi, 0, sizeof(fi));
482 fi.fh = arg->fh;
483 fi.writepage = arg->write_flags & 1;
484
485 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000486 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
487 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000488 else
489 fuse_reply_err(req, ENOSYS);
490}
491
492static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
493 struct fuse_flush_in *arg)
494{
495 struct fuse_file_info fi;
496
497 memset(&fi, 0, sizeof(fi));
498 fi.fh = arg->fh;
499
500 if (req->f->op.flush)
501 req->f->op.flush(req, nodeid, &fi);
502 else
503 fuse_reply_err(req, ENOSYS);
504}
505
506static void do_release(fuse_req_t req, fuse_ino_t nodeid,
507 struct fuse_release_in *arg)
508{
509 struct fuse_file_info fi;
510
511 memset(&fi, 0, sizeof(fi));
512 fi.flags = arg->flags;
513 fi.fh = arg->fh;
514
515 if (req->f->op.release)
516 req->f->op.release(req, nodeid, &fi);
517 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000518 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000519}
520
521static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000522 struct fuse_fsync_in *inarg)
523{
Miklos Szeredi12744942005-07-11 12:32:31 +0000524 struct fuse_file_info fi;
525
526 memset(&fi, 0, sizeof(fi));
527 fi.fh = inarg->fh;
528
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000529 if (req->f->op.fsync)
530 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
531 else
532 fuse_reply_err(req, ENOSYS);
533}
534
535static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
536 struct fuse_open_in *arg)
537{
538 struct fuse_file_info fi;
539
540 memset(&fi, 0, sizeof(fi));
541 fi.flags = arg->flags;
542
543 if (req->f->op.opendir)
544 req->f->op.opendir(req, nodeid, &fi);
545 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000546 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000547}
548
549static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
550 struct fuse_read_in *arg)
551{
552 struct fuse_file_info fi;
553
554 memset(&fi, 0, sizeof(fi));
555 fi.fh = arg->fh;
556
557 if (req->f->op.readdir)
558 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
559 else
560 fuse_reply_err(req, ENOSYS);
561}
562
563static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
564 struct fuse_release_in *arg)
565{
566 struct fuse_file_info fi;
567
568 memset(&fi, 0, sizeof(fi));
569 fi.flags = arg->flags;
570 fi.fh = arg->fh;
571
572 if (req->f->op.releasedir)
573 req->f->op.releasedir(req, nodeid, &fi);
574 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000575 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000576}
577
578static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
579 struct fuse_fsync_in *inarg)
580{
581 struct fuse_file_info fi;
582
583 memset(&fi, 0, sizeof(fi));
584 fi.fh = inarg->fh;
585
586 if (req->f->op.fsyncdir)
587 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
588 else
589 fuse_reply_err(req, ENOSYS);
590}
591
592static void do_statfs(fuse_req_t req, fuse_ino_t nodeid)
593{
594 if (req->f->op.statfs)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000595 req->f->op.statfs(req, nodeid);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000596 else
597 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000598}
599
Miklos Szeredi4331a272005-07-12 14:51:04 +0000600static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000601 struct fuse_setxattr_in *arg)
602{
Miklos Szeredi12744942005-07-11 12:32:31 +0000603 char *name = PARAM(arg);
604 unsigned char *value = name + strlen(name) + 1;
605
Miklos Szeredi4331a272005-07-12 14:51:04 +0000606 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000607 req->f->op.setxattr(req, nodeid, name, value, arg->size,
608 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000609 else
610 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000611}
612
Miklos Szeredi4331a272005-07-12 14:51:04 +0000613static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000614 struct fuse_getxattr_in *arg)
615{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000616 if (req->f->op.getxattr)
617 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000618 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000619 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000620}
621
Miklos Szeredi4331a272005-07-12 14:51:04 +0000622static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000623 struct fuse_getxattr_in *arg)
624{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000625 if (req->f->op.listxattr)
626 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000627 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000628 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000629}
630
Miklos Szeredi4331a272005-07-12 14:51:04 +0000631static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000632{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000633 if (req->f->op.removexattr)
634 req->f->op.removexattr(req, nodeid, name);
635 else
636 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000637}
638
Miklos Szeredi76c17522005-07-13 14:08:19 +0000639static void do_init(struct fuse_ll *f, uint64_t unique,
Miklos Szeredi12744942005-07-11 12:32:31 +0000640 struct fuse_init_in_out *arg)
641{
642 struct fuse_init_in_out outarg;
643
Miklos Szeredi76c17522005-07-13 14:08:19 +0000644 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000645 printf("INIT: %u.%u\n", arg->major, arg->minor);
646 fflush(stdout);
647 }
648 f->got_init = 1;
649 if (f->op.init)
650 f->user_data = f->op.init();
651
Miklos Szeredi76c17522005-07-13 14:08:19 +0000652 f->major = FUSE_KERNEL_VERSION;
653 f->minor = FUSE_KERNEL_MINOR_VERSION;
654
Miklos Szeredi12744942005-07-11 12:32:31 +0000655 memset(&outarg, 0, sizeof(outarg));
656 outarg.major = f->major;
657 outarg.minor = f->minor;
658
Miklos Szeredi76c17522005-07-13 14:08:19 +0000659 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000660 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
661 fflush(stdout);
662 }
663
Miklos Szeredi76c17522005-07-13 14:08:19 +0000664 send_reply(f, unique, 0, &outarg, sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000665}
666
Miklos Szeredi12744942005-07-11 12:32:31 +0000667static void free_cmd(struct fuse_cmd *cmd)
668{
669 free(cmd->buf);
670 free(cmd);
671}
672
Miklos Szeredi76c17522005-07-13 14:08:19 +0000673void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
Miklos Szeredi12744942005-07-11 12:32:31 +0000674{
675 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000676 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
677 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000678
Miklos Szeredi76c17522005-07-13 14:08:19 +0000679 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000680 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
681 in->unique, opname(in->opcode), in->opcode,
682 (unsigned long) in->nodeid, cmd->buflen);
683 fflush(stdout);
684 }
685
Miklos Szeredi76c17522005-07-13 14:08:19 +0000686 if (!f->got_init) {
687 if (in->opcode != FUSE_INIT)
688 send_reply(f, in->unique, -EPROTO, NULL, 0);
689 else
690 do_init(f, in->unique, (struct fuse_init_in_out *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000691 goto out;
692 }
693
Miklos Szeredi76c17522005-07-13 14:08:19 +0000694 if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
Miklos Szeredi12744942005-07-11 12:32:31 +0000695 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
696 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
697 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
698 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
Miklos Szeredi76c17522005-07-13 14:08:19 +0000699 send_reply(f, in->unique, -EACCES, NULL, 0);
Miklos Szeredi12744942005-07-11 12:32:31 +0000700 goto out;
701 }
702
Miklos Szeredi76c17522005-07-13 14:08:19 +0000703 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
704 if (req == NULL) {
705 fprintf(stderr, "fuse: failed to allocate request\n");
706 goto out;
707 }
708
709 req->f = f;
710 req->unique = in->unique;
711 req->uid = in->uid;
712 req->gid = in->gid;
713 req->pid = in->pid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000714
715 switch (in->opcode) {
716 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000717 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000718 break;
719
Miklos Szeredi76c17522005-07-13 14:08:19 +0000720 case FUSE_FORGET:
721 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000722 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000723
Miklos Szeredi12744942005-07-11 12:32:31 +0000724 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000725 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000726 break;
727
728 case FUSE_SETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000729 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000730 break;
731
732 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000733 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000734 break;
735
736 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000737 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000738 break;
739
740 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000741 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000742 break;
743
744 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000745 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000746 break;
747
748 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000749 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000750 break;
751
752 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000753 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000754 ((char *) inarg) + strlen((char *) inarg) + 1);
755 break;
756
757 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000758 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000759 break;
760
761 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000762 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000763 break;
764
765 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000766 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000767 break;
768
769 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000770 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000771 break;
772
773 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000774 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000775 break;
776
777 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000778 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000779 break;
780
781 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000782 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000783 break;
784
785 case FUSE_STATFS:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000786 do_statfs(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000787 break;
788
789 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000790 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000791 break;
792
793 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000794 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000795 break;
796
797 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000798 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000799 break;
800
801 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000802 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000803 break;
804
805 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000806 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000807 break;
808
809 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000810 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000811 break;
812
813 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000814 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000815 break;
816
817 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000818 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000819 break;
820
821 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000822 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000823 break;
824
825 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000826 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000827 }
828
829 out:
830 free_cmd(cmd);
831}
832
Miklos Szeredi76c17522005-07-13 14:08:19 +0000833int fuse_ll_exited(struct fuse_ll* f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000834{
835 return f->exited;
836}
837
Miklos Szeredi76c17522005-07-13 14:08:19 +0000838struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000839{
840 ssize_t res;
841 struct fuse_cmd *cmd;
842 struct fuse_in_header *in;
843 void *inarg;
844
845 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
846 if (cmd == NULL) {
847 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
848 return NULL;
849 }
850 cmd->buf = (char *) malloc(FUSE_MAX_IN);
851 if (cmd->buf == NULL) {
852 fprintf(stderr, "fuse: failed to allocate read buffer\n");
853 free(cmd);
854 return NULL;
855 }
856 in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000857 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi12744942005-07-11 12:32:31 +0000858
859 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
860 if (res == -1) {
861 free_cmd(cmd);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000862 if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000863 return NULL;
864
865 /* ENODEV means we got unmounted, so we silenty return failure */
866 if (errno != ENODEV) {
867 /* BAD... This will happen again */
868 perror("fuse: reading device");
869 }
870
Miklos Szeredi76c17522005-07-13 14:08:19 +0000871 f->exited = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000872 return NULL;
873 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000874 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000875 free_cmd(cmd);
876 /* Cannot happen */
877 fprintf(stderr, "short read on fuse device\n");
Miklos Szeredi76c17522005-07-13 14:08:19 +0000878 f->exited = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000879 return NULL;
880 }
881 cmd->buflen = res;
882
Miklos Szeredi12744942005-07-11 12:32:31 +0000883
884 return cmd;
885}
886
Miklos Szeredi76c17522005-07-13 14:08:19 +0000887int fuse_ll_loop(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000888{
889 if (f == NULL)
890 return -1;
891
892 while (1) {
893 struct fuse_cmd *cmd;
894
Miklos Szeredi76c17522005-07-13 14:08:19 +0000895 if (fuse_ll_exited(f))
Miklos Szeredi12744942005-07-11 12:32:31 +0000896 break;
897
Miklos Szeredi76c17522005-07-13 14:08:19 +0000898 cmd = fuse_ll_read_cmd(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000899 if (cmd == NULL)
900 continue;
901
Miklos Szeredi76c17522005-07-13 14:08:19 +0000902 fuse_ll_process_cmd(f, cmd);
Miklos Szeredi12744942005-07-11 12:32:31 +0000903 }
904 f->exited = 0;
905 return 0;
906}
907
Miklos Szeredi76c17522005-07-13 14:08:19 +0000908int fuse_ll_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000909{
910 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +0000911 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +0000912 return 1;
913 else
914 return 0;
915}
916
Miklos Szeredi76c17522005-07-13 14:08:19 +0000917static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +0000918{
919 if (opts) {
920 char *xopts = strdup(opts);
921 char *s = xopts;
922 char *opt;
923
924 if (xopts == NULL) {
925 fprintf(stderr, "fuse: memory allocation failed\n");
926 return -1;
927 }
928
929 while((opt = strsep(&s, ","))) {
930 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000931 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000932 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000933 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000934 else
935 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
936 }
937 free(xopts);
938 }
939 return 0;
940}
941
Miklos Szeredi76c17522005-07-13 14:08:19 +0000942struct fuse_ll *fuse_ll_new(int fd, const char *opts,
943 const struct fuse_ll_operations *op,
944 size_t op_size)
Miklos Szeredi12744942005-07-11 12:32:31 +0000945{
946 struct fuse_ll *f;
947
Miklos Szeredi76c17522005-07-13 14:08:19 +0000948 if (sizeof(struct fuse_ll_operations) < op_size) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000949 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi76c17522005-07-13 14:08:19 +0000950 op_size = sizeof(struct fuse_ll_operations);
Miklos Szeredi12744942005-07-11 12:32:31 +0000951 }
952
953 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
954 if (f == NULL) {
955 fprintf(stderr, "fuse: failed to allocate fuse object\n");
956 goto out;
957 }
958
Miklos Szeredi76c17522005-07-13 14:08:19 +0000959 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +0000960 goto out_free;
961
962 f->fd = fd;
963 memcpy(&f->op, op, op_size);
964 f->exited = 0;
965 f->owner = getuid();
966
967 return f;
968
969 out_free:
970 free(f);
971 out:
972 return NULL;
973}
974
Miklos Szeredi76c17522005-07-13 14:08:19 +0000975void fuse_ll_destroy(struct fuse_ll *f)
976{
977 free(f);
978}
Miklos Szeredi12744942005-07-11 12:32:31 +0000979