blob: f14aeeb09bcbb6b74b61581475b6581595684659 [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
9#include "fuse_i.h"
10#include "fuse_compat.h"
11#include "fuse_kernel.h"
12#include "fuse_kernel_compat5.h"
13
14#include <stdio.h>
15#include <string.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <limits.h>
19#include <errno.h>
20#include <assert.h>
21#include <stdint.h>
22#include <sys/param.h>
23#include <sys/uio.h>
24
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000025#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000026
27struct fuse_ll {
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000028 unsigned int debug : 1;
29 unsigned int allow_root : 1;
Miklos Szeredi12744942005-07-11 12:32:31 +000030 int fd;
31 struct fuse_lowlevel_operations op;
32 volatile int exited;
33 int got_init;
34 void *user_data;
35 int major;
36 int minor;
37 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000038};
39
40struct fuse_cmd {
41 char *buf;
42 size_t buflen;
43};
44
45static const char *opname(enum fuse_opcode opcode)
46{
47 switch (opcode) {
48 case FUSE_LOOKUP: return "LOOKUP";
49 case FUSE_FORGET: return "FORGET";
50 case FUSE_GETATTR: return "GETATTR";
51 case FUSE_SETATTR: return "SETATTR";
52 case FUSE_READLINK: return "READLINK";
53 case FUSE_SYMLINK: return "SYMLINK";
54 case FUSE_MKNOD: return "MKNOD";
55 case FUSE_MKDIR: return "MKDIR";
56 case FUSE_UNLINK: return "UNLINK";
57 case FUSE_RMDIR: return "RMDIR";
58 case FUSE_RENAME: return "RENAME";
59 case FUSE_LINK: return "LINK";
60 case FUSE_OPEN: return "OPEN";
61 case FUSE_READ: return "READ";
62 case FUSE_WRITE: return "WRITE";
63 case FUSE_STATFS: return "STATFS";
64 case FUSE_FLUSH: return "FLUSH";
65 case FUSE_RELEASE: return "RELEASE";
66 case FUSE_FSYNC: return "FSYNC";
67 case FUSE_SETXATTR: return "SETXATTR";
68 case FUSE_GETXATTR: return "GETXATTR";
69 case FUSE_LISTXATTR: return "LISTXATTR";
70 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
71 case FUSE_INIT: return "INIT";
72 case FUSE_OPENDIR: return "OPENDIR";
73 case FUSE_READDIR: return "READDIR";
74 case FUSE_RELEASEDIR: return "RELEASEDIR";
75 case FUSE_FSYNCDIR: return "FSYNCDIR";
76 default: return "???";
77 }
78}
79
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000080static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000081{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000082 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000083 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000084 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000085 attr->uid = stbuf->st_uid;
86 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000087 attr->rdev = stbuf->st_rdev;
88 attr->size = stbuf->st_size;
89 attr->blocks = stbuf->st_blocks;
90 attr->atime = stbuf->st_atime;
91 attr->mtime = stbuf->st_mtime;
92 attr->ctime = stbuf->st_ctime;
93#ifdef HAVE_STRUCT_STAT_ST_ATIM
94 attr->atimensec = stbuf->st_atim.tv_nsec;
95 attr->mtimensec = stbuf->st_mtim.tv_nsec;
96 attr->ctimensec = stbuf->st_ctim.tv_nsec;
97#endif
98}
99
100static size_t iov_length(const struct iovec *iov, size_t count)
101{
102 size_t seg;
103 size_t ret = 0;
104
105 for (seg = 0; seg < count; seg++)
106 ret += iov[seg].iov_len;
107 return ret;
108}
109
110static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
111 size_t count)
112{
113 int res;
114 unsigned outsize = iov_length(iov, count);
115 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
116 out->len = outsize;
117
118 if ((f->flags & FUSE_DEBUG)) {
119 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
120 out->unique, out->error, strerror(-out->error), outsize);
121 fflush(stdout);
122 }
123
124 /* This needs to be done before the reply, otherwise the scheduler
125 could play tricks with us, and only let the counter be
126 increased long after the operation is done */
127 fuse_inc_avail(f);
128
129 res = writev(f->fd, iov, count);
130 if (res == -1) {
131 /* ENOENT means the operation was interrupted */
132 if (!f->exited && errno != ENOENT)
133 perror("fuse: writing device");
134 return -errno;
135 }
136 return 0;
137}
138
139static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error,
140 void *arg, size_t argsize)
141{
142 struct fuse_out_header out;
143 struct iovec iov[2];
144 size_t count;
145
146 if (error <= -1000 || error > 0) {
147 fprintf(stderr, "fuse: bad error value: %i\n", error);
148 error = -ERANGE;
149 }
150
151 out.unique = in->unique;
152 out.error = error;
153 count = 1;
154 iov[0].iov_base = &out;
155 iov[0].iov_len = sizeof(struct fuse_out_header);
156 if (argsize && !error) {
157 count++;
158 iov[1].iov_base = arg;
159 iov[1].iov_len = argsize;
160 }
161 return send_reply_raw(f, iov, count);
162}
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 Szeredi2482fdb2005-07-12 13:23:53 +0000169void fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
170 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 Szeredi2482fdb2005-07-12 13:23:53 +0000178 dirent->ino = stat->st_ino;
179 dirent->off = off;
180 dirent->namelen = namelen;
181 dirent->type = (stat->st_mode & 0170000) >> 12;
182 strncpy(dirent->name, name, namelen);
183 if (padlen)
184 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000185
Miklos Szeredi12744942005-07-11 12:32:31 +0000186 return 0;
187}
188
Miklos Szeredi12744942005-07-11 12:32:31 +0000189static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
190{
191 kstatfs->bsize = statfs->f_bsize;
192 kstatfs->blocks = statfs->f_blocks;
193 kstatfs->bfree = statfs->f_bfree;
194 kstatfs->bavail = statfs->f_bavail;
195 kstatfs->files = statfs->f_files;
196 kstatfs->ffree = statfs->f_ffree;
197 kstatfs->namelen = statfs->f_namelen;
198}
199
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000200static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000201{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000202 if (req->f->op.lookup)
203 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000204 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000205 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000206}
207
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000208static void do_forget(fuse_req_t req, fuse_ino_t nodeid)
209{
210 if (req->f->op.forget)
211 req->f->op.forget(req, nodeid);
212}
213
214static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
215{
216 if (req->f->op.getattr)
217 req->f->op.getattr(req, nodeid);
218 else
219 fuse_reply_err(req, ENOSYS);
220}
221
222static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
223 struct fuse_setattr_in *arg)
224{
225 if (req->f->op.setattr)
226 req->f->op.setattr(req, nodeid, &arg->attr, arg->valid);
227 else
228 fuse_reply_err(req, ENOSYS);
229}
230
231static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
232{
233 if (req->f->op.readlink)
234 req->f->op.readlink(req, nodeid);
235 else
236 fuse_reply_err(req, ENOSYS);
237}
238
239static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
240 struct fuse_mknod_in *arg)
241{
242 if (req->f->op.mknod)
243 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
244 else
245 fuse_reply_err(req, ENOSYS);
246}
247
248static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
249 struct fuse_mkdir_in *arg)
250{
251 if (req->f->op.mkdir)
252 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
253 else
254 fuse_reply_err(req, ENOSYS);
255}
256
257static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
258{
259 if (req->f->op.unlink)
260 req->f->op.unlink(req, nodeid, name);
261 else
262 fuse_reply_err(req, ENOSYS);
263}
264
265static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
266{
267 if (req->f->op.rmdir)
268 req->f->op.rmdir(req, nodeid, name);
269 else
270 fuse_reply_err(req, ENOSYS);
271}
272
273static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
274 char *link)
275{
276 if (req->f->op.symlink)
277 req->f->op.symlink(req, link, nodeid, name);
278 else
279 fuse_reply_err(req, ENOSYS);
280}
281
282static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
283 struct fuse_rename_in *arg)
284{
285 char *oldname = PARAM(arg);
286 char *newname = oldname + strlen(oldname) + 1;
287
288 if (req->f->op.rename)
289 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
290 else
291 fuse_reply_err(req, ENOSYS);
292}
293
294static void do_link(fuse_req_t req, fuse_ino_t nodeid,
295 struct fuse_link_in *arg)
296{
297 if (req->f->op.link)
298 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
299 else
300 fuse_reply_err(req, ENOSYS);
301}
302
303static void do_open(fuse_req_t req, fuse_ino_t nodeid,
304 struct fuse_open_in *arg)
305{
306 struct fuse_file_info fi;
307
308 memset(&fi, 0, sizeof(fi));
309 fi.flags = arg->flags;
310
311 if (req->f->op.open)
312 req->f->op.open(req, nodeid, &fi);
313 else
314 fuse_reply_err(req, ENOSYS);
315}
316
317static void do_read(fuse_req_t req, fuse_ino_t nodeid,
318 struct fuse_read_in *arg)
319{
320 struct fuse_file_info fi;
321
322 memset(&fi, 0, sizeof(fi));
323 fi.fh = arg->fh;
324
325 if (req->f->op.read)
326 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
327 else
328 fuse_reply_err(req, ENOSYS);
329}
330
331static void do_write(fuse_req_t req, fuse_ino_t nodeid,
332 struct fuse_write_in *arg)
333{
334 struct fuse_file_info fi;
335
336 memset(&fi, 0, sizeof(fi));
337 fi.fh = arg->fh;
338 fi.writepage = arg->write_flags & 1;
339
340 if (req->f->op.write)
341 req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
342 else
343 fuse_reply_err(req, ENOSYS);
344}
345
346static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
347 struct fuse_flush_in *arg)
348{
349 struct fuse_file_info fi;
350
351 memset(&fi, 0, sizeof(fi));
352 fi.fh = arg->fh;
353
354 if (req->f->op.flush)
355 req->f->op.flush(req, nodeid, &fi);
356 else
357 fuse_reply_err(req, ENOSYS);
358}
359
360static void do_release(fuse_req_t req, fuse_ino_t nodeid,
361 struct fuse_release_in *arg)
362{
363 struct fuse_file_info fi;
364
365 memset(&fi, 0, sizeof(fi));
366 fi.flags = arg->flags;
367 fi.fh = arg->fh;
368
369 if (req->f->op.release)
370 req->f->op.release(req, nodeid, &fi);
371 else
372 fuse_reply_err(req, ENOSYS);
373}
374
375static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000376 struct fuse_fsync_in *inarg)
377{
Miklos Szeredi12744942005-07-11 12:32:31 +0000378 struct fuse_file_info fi;
379
380 memset(&fi, 0, sizeof(fi));
381 fi.fh = inarg->fh;
382
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000383 if (req->f->op.fsync)
384 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
385 else
386 fuse_reply_err(req, ENOSYS);
387}
388
389static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
390 struct fuse_open_in *arg)
391{
392 struct fuse_file_info fi;
393
394 memset(&fi, 0, sizeof(fi));
395 fi.flags = arg->flags;
396
397 if (req->f->op.opendir)
398 req->f->op.opendir(req, nodeid, &fi);
399 else
400 fuse_reply_err(req, ENOSYS);
401}
402
403static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
404 struct fuse_read_in *arg)
405{
406 struct fuse_file_info fi;
407
408 memset(&fi, 0, sizeof(fi));
409 fi.fh = arg->fh;
410
411 if (req->f->op.readdir)
412 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
413 else
414 fuse_reply_err(req, ENOSYS);
415}
416
417static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
418 struct fuse_release_in *arg)
419{
420 struct fuse_file_info fi;
421
422 memset(&fi, 0, sizeof(fi));
423 fi.flags = arg->flags;
424 fi.fh = arg->fh;
425
426 if (req->f->op.releasedir)
427 req->f->op.releasedir(req, nodeid, &fi);
428 else
429 fuse_reply_err(req, ENOSYS);
430}
431
432static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
433 struct fuse_fsync_in *inarg)
434{
435 struct fuse_file_info fi;
436
437 memset(&fi, 0, sizeof(fi));
438 fi.fh = inarg->fh;
439
440 if (req->f->op.fsyncdir)
441 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
442 else
443 fuse_reply_err(req, ENOSYS);
444}
445
446static void do_statfs(fuse_req_t req, fuse_ino_t nodeid)
447{
448 if (req->f->op.statfs)
449 res = req->f->op.statfs(req, nodeid);
450 else
451 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000452}
453
Miklos Szeredi4331a272005-07-12 14:51:04 +0000454static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000455 struct fuse_setxattr_in *arg)
456{
Miklos Szeredi12744942005-07-11 12:32:31 +0000457 char *name = PARAM(arg);
458 unsigned char *value = name + strlen(name) + 1;
459
Miklos Szeredi4331a272005-07-12 14:51:04 +0000460 if (req->f->op.setxattr)
461 req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
462 else
463 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000464}
465
Miklos Szeredi4331a272005-07-12 14:51:04 +0000466static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000467 struct fuse_getxattr_in *arg)
468{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000469 if (req->f->op.getxattr)
470 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000471 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000472 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000473}
474
Miklos Szeredi4331a272005-07-12 14:51:04 +0000475static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000476 struct fuse_getxattr_in *arg)
477{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000478 if (req->f->op.listxattr)
479 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000480 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000481 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000482}
483
Miklos Szeredi4331a272005-07-12 14:51:04 +0000484static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000485{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000486 if (req->f->op.removexattr)
487 req->f->op.removexattr(req, nodeid, name);
488 else
489 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000490}
491
492static void do_init(struct fuse_ll *f, struct fuse_in_header *in,
493 struct fuse_init_in_out *arg)
494{
495 struct fuse_init_in_out outarg;
496
497 if (in->padding == 5) {
498 arg->minor = arg->major;
499 arg->major = in->padding;
500 }
501
502 if (f->flags & FUSE_DEBUG) {
503 printf("INIT: %u.%u\n", arg->major, arg->minor);
504 fflush(stdout);
505 }
506 f->got_init = 1;
507 if (f->op.init)
508 f->user_data = f->op.init();
509
510 if (arg->major == 5) {
511 f->major = 5;
512 f->minor = 1;
513 } else if (arg->major == 6) {
514 f->major = 6;
515 f->minor = 1;
516 } else {
517 f->major = FUSE_KERNEL_VERSION;
518 f->minor = FUSE_KERNEL_MINOR_VERSION;
519 }
520 memset(&outarg, 0, sizeof(outarg));
521 outarg.major = f->major;
522 outarg.minor = f->minor;
523
524 if (f->flags & FUSE_DEBUG) {
525 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
526 fflush(stdout);
527 }
528
529 send_reply(f, in, 0, &outarg, sizeof(outarg));
530}
531
Miklos Szeredi12744942005-07-11 12:32:31 +0000532static void free_cmd(struct fuse_cmd *cmd)
533{
534 free(cmd->buf);
535 free(cmd);
536}
537
538void fuse_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
539{
540 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
541 void *inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
542 struct fuse_context *ctx = fuse_get_context();
543
544 fuse_dec_avail(f);
545
546 if ((f->flags & FUSE_DEBUG)) {
547 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
548 in->unique, opname(in->opcode), in->opcode,
549 (unsigned long) in->nodeid, cmd->buflen);
550 fflush(stdout);
551 }
552
553 if (!f->got_init && in->opcode != FUSE_INIT) {
554 /* Old kernel version probably */
555 send_reply(f, in, -EPROTO, NULL, 0);
556 goto out;
557 }
558
559 if ((f->flags & FUSE_ALLOW_ROOT) && in->uid != f->owner && in->uid != 0 &&
560 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
561 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
562 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
563 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
564 send_reply(f, in, -EACCES, NULL, 0);
565 goto out;
566 }
567
568 ctx->fuse = f;
569 ctx->uid = in->uid;
570 ctx->gid = in->gid;
571 ctx->pid = in->pid;
572 ctx->private_data = f->user_data;
573
574 switch (in->opcode) {
575 case FUSE_LOOKUP:
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000576 do_lookup(f, req, nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000577 break;
578
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000579 do_forget(f, in, (struct fuse_forget_in *) inarg);
580 break;
581 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000582 case FUSE_GETATTR:
583 do_getattr(f, in);
584 break;
585
586 case FUSE_SETATTR:
587 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
588 break;
589
590 case FUSE_READLINK:
591 do_readlink(f, in);
592 break;
593
594 case FUSE_MKNOD:
595 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
596 break;
597
598 case FUSE_MKDIR:
599 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
600 break;
601
602 case FUSE_UNLINK:
603 do_unlink(f, in, (char *) inarg);
604 break;
605
606 case FUSE_RMDIR:
607 do_rmdir(f, in, (char *) inarg);
608 break;
609
610 case FUSE_SYMLINK:
611 do_symlink(f, in, (char *) inarg,
612 ((char *) inarg) + strlen((char *) inarg) + 1);
613 break;
614
615 case FUSE_RENAME:
616 do_rename(f, in, (struct fuse_rename_in *) inarg);
617 break;
618
619 case FUSE_LINK:
620 do_link(f, in, (struct fuse_link_in *) inarg);
621 break;
622
623 case FUSE_OPEN:
624 do_open(f, in, (struct fuse_open_in *) inarg);
625 break;
626
627 case FUSE_FLUSH:
628 do_flush(f, in, (struct fuse_flush_in *) inarg);
629 break;
630
631 case FUSE_RELEASE:
632 do_release(f, in, (struct fuse_release_in *) inarg);
633 break;
634
635 case FUSE_READ:
636 do_read(f, in, (struct fuse_read_in *) inarg);
637 break;
638
639 case FUSE_WRITE:
640 do_write(f, in, (struct fuse_write_in *) inarg);
641 break;
642
643 case FUSE_STATFS:
644 do_statfs(f, in);
645 break;
646
647 case FUSE_FSYNC:
648 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
649 break;
650
651 case FUSE_SETXATTR:
652 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
653 break;
654
655 case FUSE_GETXATTR:
656 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
657 break;
658
659 case FUSE_LISTXATTR:
660 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
661 break;
662
663 case FUSE_REMOVEXATTR:
664 do_removexattr(f, in, (char *) inarg);
665 break;
666
667 case FUSE_INIT:
668 do_init(f, in, (struct fuse_init_in_out *) inarg);
669 break;
670
671 case FUSE_OPENDIR:
672 do_opendir(f, in, (struct fuse_open_in *) inarg);
673 break;
674
675 case FUSE_READDIR:
676 do_readdir(f, in, (struct fuse_read_in *) inarg);
677 break;
678
679 case FUSE_RELEASEDIR:
680 do_releasedir(f, in, (struct fuse_release_in *) inarg);
681 break;
682
683 case FUSE_FSYNCDIR:
684 do_fsyncdir(f, in, (struct fuse_fsync_in *) inarg);
685 break;
686
687 default:
688 send_reply(f, in, -ENOSYS, NULL, 0);
689 }
690
691 out:
692 free_cmd(cmd);
693}
694
695int fuse_exited(struct fuse_ll* f)
696{
697 return f->exited;
698}
699
700struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f)
701{
702 ssize_t res;
703 struct fuse_cmd *cmd;
704 struct fuse_in_header *in;
705 void *inarg;
706
707 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
708 if (cmd == NULL) {
709 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
710 return NULL;
711 }
712 cmd->buf = (char *) malloc(FUSE_MAX_IN);
713 if (cmd->buf == NULL) {
714 fprintf(stderr, "fuse: failed to allocate read buffer\n");
715 free(cmd);
716 return NULL;
717 }
718 in = (struct fuse_in_header *) cmd->buf;
719 inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
720
721 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
722 if (res == -1) {
723 free_cmd(cmd);
724 if (fuse_exited(f) || errno == EINTR || errno == ENOENT)
725 return NULL;
726
727 /* ENODEV means we got unmounted, so we silenty return failure */
728 if (errno != ENODEV) {
729 /* BAD... This will happen again */
730 perror("fuse: reading device");
731 }
732
733 fuse_exit(f);
734 return NULL;
735 }
736 if ((size_t) res < SIZEOF_COMPAT(f, fuse_in_header)) {
737 free_cmd(cmd);
738 /* Cannot happen */
739 fprintf(stderr, "short read on fuse device\n");
740 fuse_exit(f);
741 return NULL;
742 }
743 cmd->buflen = res;
744
Miklos Szeredi12744942005-07-11 12:32:31 +0000745
746 return cmd;
747}
748
749int fuse_loop(struct fuse_ll *f)
750{
751 if (f == NULL)
752 return -1;
753
754 while (1) {
755 struct fuse_cmd *cmd;
756
757 if (fuse_exited(f))
758 break;
759
760 cmd = fuse_read_cmd(f);
761 if (cmd == NULL)
762 continue;
763
764 fuse_process_cmd(f, cmd);
765 }
766 f->exited = 0;
767 return 0;
768}
769
770int fuse_invalidate(struct fuse_ll *f, const char *path)
771{
772 (void) f;
773 (void) path;
774 return -EINVAL;
775}
776
777void fuse_exit(struct fuse_ll *f)
778{
779 f->exited = 1;
780}
781
782struct fuse_context *fuse_get_context()
783{
784 static struct fuse_context context;
785 if (fuse_getcontext)
786 return fuse_getcontext();
787 else
788 return &context;
789}
790
791void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
792{
793 fuse_getcontext = func;
794}
795
796static int begins_with(const char *s, const char *beg)
797{
798 if (strncmp(s, beg, strlen(beg)) == 0)
799 return 1;
800 else
801 return 0;
802}
803
804int fuse_is_lib_option(const char *opt)
805{
806 if (strcmp(opt, "debug") == 0 ||
807 strcmp(opt, "hard_remove") == 0 ||
808 strcmp(opt, "use_ino") == 0 ||
809 strcmp(opt, "allow_root") == 0 ||
810 strcmp(opt, "readdir_ino") == 0 ||
811 begins_with(opt, "umask=") ||
812 begins_with(opt, "uid=") ||
813 begins_with(opt, "gid="))
814 return 1;
815 else
816 return 0;
817}
818
819static int parse_lib_opts(struct fuse_ll *f, const char *opts)
820{
821 if (opts) {
822 char *xopts = strdup(opts);
823 char *s = xopts;
824 char *opt;
825
826 if (xopts == NULL) {
827 fprintf(stderr, "fuse: memory allocation failed\n");
828 return -1;
829 }
830
831 while((opt = strsep(&s, ","))) {
832 if (strcmp(opt, "debug") == 0)
833 f->flags |= FUSE_DEBUG;
834 else if (strcmp(opt, "hard_remove") == 0)
835 f->flags |= FUSE_HARD_REMOVE;
836 else if (strcmp(opt, "use_ino") == 0)
837 f->flags |= FUSE_USE_INO;
838 else if (strcmp(opt, "allow_root") == 0)
839 f->flags |= FUSE_ALLOW_ROOT;
840 else if (strcmp(opt, "readdir_ino") == 0)
841 f->flags |= FUSE_READDIR_INO;
842 else if (sscanf(opt, "umask=%o", &f->umask) == 1)
843 f->flags |= FUSE_SET_MODE;
844 else if (sscanf(opt, "uid=%u", &f->uid) == 1)
845 f->flags |= FUSE_SET_UID;
846 else if(sscanf(opt, "gid=%u", &f->gid) == 1)
847 f->flags |= FUSE_SET_GID;
848 else
849 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
850 }
851 free(xopts);
852 }
853 return 0;
854}
855
856struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts,
857 const struct fuse_lowlevel_operations *op,
858 size_t op_size)
859{
860 struct fuse_ll *f;
861
862 if (sizeof(struct fuse_lowlevel_operations) < op_size) {
863 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
864 op_size = sizeof(struct fuse_lowlevel_operations);
865 }
866
867 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
868 if (f == NULL) {
869 fprintf(stderr, "fuse: failed to allocate fuse object\n");
870 goto out;
871 }
872
873 if (parse_lib_opts(f, opts) == -1)
874 goto out_free;
875
876 f->fd = fd;
877 memcpy(&f->op, op, op_size);
878 f->exited = 0;
879 f->owner = getuid();
880
881 return f;
882
883 out_free:
884 free(f);
885 out:
886 return NULL;
887}
888
889