2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
9 #include "fuse_lowlevel.h"
10 #include "fuse_kernel.h"
13 #include "fuse_misc.h"
23 #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
24 #define OFFSET_MAX 0x7fffffffffffffffLL
41 fuse_interrupt_func_t func
;
45 struct fuse_req
*next
;
46 struct fuse_req
*prev
;
52 struct fuse_lowlevel_ops op
;
56 struct fuse_conn_info conn
;
58 struct fuse_req interrupts
;
63 static void convert_stat(const struct stat
*stbuf
, struct fuse_attr
*attr
)
65 attr
->ino
= stbuf
->st_ino
;
66 attr
->mode
= stbuf
->st_mode
;
67 attr
->nlink
= stbuf
->st_nlink
;
68 attr
->uid
= stbuf
->st_uid
;
69 attr
->gid
= stbuf
->st_gid
;
70 attr
->rdev
= stbuf
->st_rdev
;
71 attr
->size
= stbuf
->st_size
;
72 attr
->blocks
= stbuf
->st_blocks
;
73 attr
->atime
= stbuf
->st_atime
;
74 attr
->mtime
= stbuf
->st_mtime
;
75 attr
->ctime
= stbuf
->st_ctime
;
76 #ifdef FUSE_STAT_HAS_NANOSEC
77 attr
->atimensec
= ST_ATIM(stbuf
).tv_nsec
;
78 attr
->mtimensec
= ST_MTIM(stbuf
).tv_nsec
;
79 attr
->ctimensec
= ST_CTIM(stbuf
).tv_nsec
;
83 static void convert_attr(const struct fuse_setattr_in
*attr
, struct stat
*stbuf
)
85 stbuf
->st_mode
= attr
->mode
;
86 stbuf
->st_uid
= attr
->uid
;
87 stbuf
->st_gid
= attr
->gid
;
88 stbuf
->st_size
= attr
->size
;
89 stbuf
->st_atime
= attr
->atime
;
90 stbuf
->st_mtime
= attr
->mtime
;
91 #ifdef FUSE_STAT_HAS_NANOSEC
92 ST_ATIM(stbuf
).tv_nsec
= attr
->atimensec
;
93 ST_MTIM(stbuf
).tv_nsec
= attr
->mtimensec
;
97 static size_t iov_length(const struct iovec
*iov
, size_t count
)
102 for (seg
= 0; seg
< count
; seg
++)
103 ret
+= iov
[seg
].iov_len
;
107 static void list_init_req(struct fuse_req
*req
)
113 static void list_del_req(struct fuse_req
*req
)
115 struct fuse_req
*prev
= req
->prev
;
116 struct fuse_req
*next
= req
->next
;
121 static void list_add_req(struct fuse_req
*req
, struct fuse_req
*next
)
123 struct fuse_req
*prev
= next
->prev
;
130 static void destroy_req(fuse_req_t req
)
132 pthread_mutex_destroy(&req
->lock
);
136 static void free_req(fuse_req_t req
)
139 struct fuse_ll
*f
= req
->f
;
141 pthread_mutex_lock(&req
->lock
);
142 req
->u
.ni
.func
= NULL
;
143 req
->u
.ni
.data
= NULL
;
144 pthread_mutex_unlock(&req
->lock
);
146 pthread_mutex_lock(&f
->lock
);
149 pthread_mutex_unlock(&f
->lock
);
154 static int send_reply(fuse_req_t req
, int error
, const void *arg
,
157 struct fuse_out_header out
;
162 if (error
<= -1000 || error
> 0) {
163 fprintf(stderr
, "fuse: bad error value: %i\n", error
);
167 out
.unique
= req
->unique
;
170 iov
[0].iov_base
= &out
;
171 iov
[0].iov_len
= sizeof(struct fuse_out_header
);
172 if (argsize
&& !error
) {
174 iov
[1].iov_base
= (void *) arg
;
175 iov
[1].iov_len
= argsize
;
177 out
.len
= iov_length(iov
, count
);
180 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
181 out
.unique
, out
.error
, strerror(-out
.error
), out
.len
);
184 res
= fuse_chan_send(req
->ch
, iov
, count
);
190 size_t fuse_dirent_size(size_t namelen
)
192 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET
+ namelen
);
195 char *fuse_add_dirent(char *buf
, const char *name
, const struct stat
*stbuf
,
198 unsigned namelen
= strlen(name
);
199 unsigned entlen
= FUSE_NAME_OFFSET
+ namelen
;
200 unsigned entsize
= fuse_dirent_size(namelen
);
201 unsigned padlen
= entsize
- entlen
;
202 struct fuse_dirent
*dirent
= (struct fuse_dirent
*) buf
;
204 dirent
->ino
= stbuf
->st_ino
;
206 dirent
->namelen
= namelen
;
207 dirent
->type
= (stbuf
->st_mode
& 0170000) >> 12;
208 strncpy(dirent
->name
, name
, namelen
);
210 memset(buf
+ entlen
, 0, padlen
);
212 return buf
+ entsize
;
215 size_t fuse_add_direntry(fuse_req_t req
, char *buf
, size_t bufsize
,
216 const char *name
, const struct stat
*stbuf
, off_t off
)
221 entsize
= fuse_dirent_size(strlen(name
));
222 if (entsize
<= bufsize
&& buf
)
223 fuse_add_dirent(buf
, name
, stbuf
, off
);
227 static void convert_statfs(const struct statvfs
*stbuf
,
228 struct fuse_kstatfs
*kstatfs
)
230 kstatfs
->bsize
= stbuf
->f_bsize
;
231 kstatfs
->frsize
= stbuf
->f_frsize
;
232 kstatfs
->blocks
= stbuf
->f_blocks
;
233 kstatfs
->bfree
= stbuf
->f_bfree
;
234 kstatfs
->bavail
= stbuf
->f_bavail
;
235 kstatfs
->files
= stbuf
->f_files
;
236 kstatfs
->ffree
= stbuf
->f_ffree
;
237 kstatfs
->namelen
= stbuf
->f_namemax
;
240 static int send_reply_ok(fuse_req_t req
, const void *arg
, size_t argsize
)
242 return send_reply(req
, 0, arg
, argsize
);
245 int fuse_reply_err(fuse_req_t req
, int err
)
247 return send_reply(req
, -err
, NULL
, 0);
250 void fuse_reply_none(fuse_req_t req
)
252 fuse_chan_send(req
->ch
, NULL
, 0);
256 static unsigned long calc_timeout_sec(double t
)
258 if (t
> (double) ULONG_MAX
)
263 return (unsigned long) t
;
266 static unsigned int calc_timeout_nsec(double t
)
268 double f
= t
- (double) calc_timeout_sec(t
);
271 else if (f
>= 0.999999999)
274 return (unsigned int) (f
* 1.0e9
);
277 static void fill_entry(struct fuse_entry_out
*arg
,
278 const struct fuse_entry_param
*e
)
280 arg
->nodeid
= e
->ino
;
281 arg
->generation
= e
->generation
;
282 arg
->entry_valid
= calc_timeout_sec(e
->entry_timeout
);
283 arg
->entry_valid_nsec
= calc_timeout_nsec(e
->entry_timeout
);
284 arg
->attr_valid
= calc_timeout_sec(e
->attr_timeout
);
285 arg
->attr_valid_nsec
= calc_timeout_nsec(e
->attr_timeout
);
286 convert_stat(&e
->attr
, &arg
->attr
);
289 static void fill_open(struct fuse_open_out
*arg
,
290 const struct fuse_file_info
*f
)
294 arg
->open_flags
|= FOPEN_DIRECT_IO
;
296 arg
->open_flags
|= FOPEN_KEEP_CACHE
;
299 int fuse_reply_entry(fuse_req_t req
, const struct fuse_entry_param
*e
)
301 struct fuse_entry_out arg
;
303 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
305 if (!e
->ino
&& req
->f
->conn
.proto_minor
< 4)
306 return fuse_reply_err(req
, ENOENT
);
308 memset(&arg
, 0, sizeof(arg
));
310 return send_reply_ok(req
, &arg
, sizeof(arg
));
313 int fuse_reply_create(fuse_req_t req
, const struct fuse_entry_param
*e
,
314 const struct fuse_file_info
*f
)
317 struct fuse_entry_out e
;
318 struct fuse_open_out o
;
321 memset(&arg
, 0, sizeof(arg
));
322 fill_entry(&arg
.e
, e
);
323 fill_open(&arg
.o
, f
);
324 return send_reply_ok(req
, &arg
, sizeof(arg
));
327 int fuse_reply_attr(fuse_req_t req
, const struct stat
*attr
,
330 struct fuse_attr_out arg
;
332 memset(&arg
, 0, sizeof(arg
));
333 arg
.attr_valid
= calc_timeout_sec(attr_timeout
);
334 arg
.attr_valid_nsec
= calc_timeout_nsec(attr_timeout
);
335 convert_stat(attr
, &arg
.attr
);
337 return send_reply_ok(req
, &arg
, sizeof(arg
));
340 int fuse_reply_readlink(fuse_req_t req
, const char *linkname
)
342 return send_reply_ok(req
, linkname
, strlen(linkname
));
345 int fuse_reply_open(fuse_req_t req
, const struct fuse_file_info
*f
)
347 struct fuse_open_out arg
;
349 memset(&arg
, 0, sizeof(arg
));
351 return send_reply_ok(req
, &arg
, sizeof(arg
));
354 int fuse_reply_write(fuse_req_t req
, size_t count
)
356 struct fuse_write_out arg
;
358 memset(&arg
, 0, sizeof(arg
));
361 return send_reply_ok(req
, &arg
, sizeof(arg
));
364 int fuse_reply_buf(fuse_req_t req
, const char *buf
, size_t size
)
366 return send_reply_ok(req
, buf
, size
);
369 int fuse_reply_statfs(fuse_req_t req
, const struct statvfs
*stbuf
)
371 struct fuse_statfs_out arg
;
372 size_t size
= req
->f
->conn
.proto_minor
< 4 ? FUSE_COMPAT_STATFS_SIZE
: sizeof(arg
);
374 memset(&arg
, 0, sizeof(arg
));
375 convert_statfs(stbuf
, &arg
.st
);
377 return send_reply_ok(req
, &arg
, size
);
380 int fuse_reply_xattr(fuse_req_t req
, size_t count
)
382 struct fuse_getxattr_out arg
;
384 memset(&arg
, 0, sizeof(arg
));
387 return send_reply_ok(req
, &arg
, sizeof(arg
));
390 int fuse_reply_lock(fuse_req_t req
, struct flock
*lock
)
392 struct fuse_lk_out arg
;
394 memset(&arg
, 0, sizeof(arg
));
395 arg
.lk
.type
= lock
->l_type
;
396 if (lock
->l_type
!= F_UNLCK
) {
397 arg
.lk
.start
= lock
->l_start
;
398 if (lock
->l_len
== 0)
399 arg
.lk
.end
= OFFSET_MAX
;
401 arg
.lk
.end
= lock
->l_start
+ lock
->l_len
- 1;
403 arg
.lk
.pid
= lock
->l_pid
;
404 return send_reply_ok(req
, &arg
, sizeof(arg
));
407 int fuse_reply_bmap(fuse_req_t req
, uint64_t idx
)
409 struct fuse_bmap_out arg
;
411 memset(&arg
, 0, sizeof(arg
));
414 return send_reply_ok(req
, &arg
, sizeof(arg
));
417 static void do_lookup(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
419 char *name
= (char *) inarg
;
421 if (req
->f
->op
.lookup
)
422 req
->f
->op
.lookup(req
, nodeid
, name
);
424 fuse_reply_err(req
, ENOSYS
);
427 static void do_forget(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
429 struct fuse_forget_in
*arg
= (struct fuse_forget_in
*) inarg
;
431 if (req
->f
->op
.forget
)
432 req
->f
->op
.forget(req
, nodeid
, arg
->nlookup
);
435 static void do_getattr(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
439 if (req
->f
->op
.getattr
)
440 req
->f
->op
.getattr(req
, nodeid
, NULL
);
442 fuse_reply_err(req
, ENOSYS
);
445 static void do_setattr(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
447 struct fuse_setattr_in
*arg
= (struct fuse_setattr_in
*) inarg
;
449 if (req
->f
->op
.setattr
) {
450 struct fuse_file_info
*fi
= NULL
;
451 struct fuse_file_info fi_store
;
453 memset(&stbuf
, 0, sizeof(stbuf
));
454 convert_attr(arg
, &stbuf
);
455 if (arg
->valid
& FATTR_FH
) {
456 arg
->valid
&= ~FATTR_FH
;
457 memset(&fi_store
, 0, sizeof(fi_store
));
462 req
->f
->op
.setattr(req
, nodeid
, &stbuf
, arg
->valid
, fi
);
464 fuse_reply_err(req
, ENOSYS
);
467 static void do_access(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
469 struct fuse_access_in
*arg
= (struct fuse_access_in
*) inarg
;
471 if (req
->f
->op
.access
)
472 req
->f
->op
.access(req
, nodeid
, arg
->mask
);
474 fuse_reply_err(req
, ENOSYS
);
477 static void do_readlink(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
481 if (req
->f
->op
.readlink
)
482 req
->f
->op
.readlink(req
, nodeid
);
484 fuse_reply_err(req
, ENOSYS
);
487 static void do_mknod(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
489 struct fuse_mknod_in
*arg
= (struct fuse_mknod_in
*) inarg
;
491 if (req
->f
->op
.mknod
)
492 req
->f
->op
.mknod(req
, nodeid
, PARAM(arg
), arg
->mode
, arg
->rdev
);
494 fuse_reply_err(req
, ENOSYS
);
497 static void do_mkdir(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
499 struct fuse_mkdir_in
*arg
= (struct fuse_mkdir_in
*) inarg
;
501 if (req
->f
->op
.mkdir
)
502 req
->f
->op
.mkdir(req
, nodeid
, PARAM(arg
), arg
->mode
);
504 fuse_reply_err(req
, ENOSYS
);
507 static void do_unlink(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
509 char *name
= (char *) inarg
;
511 if (req
->f
->op
.unlink
)
512 req
->f
->op
.unlink(req
, nodeid
, name
);
514 fuse_reply_err(req
, ENOSYS
);
517 static void do_rmdir(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
519 char *name
= (char *) inarg
;
521 if (req
->f
->op
.rmdir
)
522 req
->f
->op
.rmdir(req
, nodeid
, name
);
524 fuse_reply_err(req
, ENOSYS
);
527 static void do_symlink(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
529 char *name
= (char *) inarg
;
530 char *linkname
= ((char *) inarg
) + strlen((char *) inarg
) + 1;
532 if (req
->f
->op
.symlink
)
533 req
->f
->op
.symlink(req
, linkname
, nodeid
, name
);
535 fuse_reply_err(req
, ENOSYS
);
538 static void do_rename(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
540 struct fuse_rename_in
*arg
= (struct fuse_rename_in
*) inarg
;
541 char *oldname
= PARAM(arg
);
542 char *newname
= oldname
+ strlen(oldname
) + 1;
544 if (req
->f
->op
.rename
)
545 req
->f
->op
.rename(req
, nodeid
, oldname
, arg
->newdir
, newname
);
547 fuse_reply_err(req
, ENOSYS
);
550 static void do_link(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
552 struct fuse_link_in
*arg
= (struct fuse_link_in
*) inarg
;
555 req
->f
->op
.link(req
, arg
->oldnodeid
, nodeid
, PARAM(arg
));
557 fuse_reply_err(req
, ENOSYS
);
560 static void do_create(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
562 struct fuse_open_in
*arg
= (struct fuse_open_in
*) inarg
;
564 if (req
->f
->op
.create
) {
565 struct fuse_file_info fi
;
567 memset(&fi
, 0, sizeof(fi
));
568 fi
.flags
= arg
->flags
;
570 req
->f
->op
.create(req
, nodeid
, PARAM(arg
), arg
->mode
, &fi
);
572 fuse_reply_err(req
, ENOSYS
);
575 static void do_open(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
577 struct fuse_open_in
*arg
= (struct fuse_open_in
*) inarg
;
578 struct fuse_file_info fi
;
580 memset(&fi
, 0, sizeof(fi
));
581 fi
.flags
= arg
->flags
;
584 req
->f
->op
.open(req
, nodeid
, &fi
);
586 fuse_reply_open(req
, &fi
);
589 static void do_read(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
591 struct fuse_read_in
*arg
= (struct fuse_read_in
*) inarg
;
593 if (req
->f
->op
.read
) {
594 struct fuse_file_info fi
;
596 memset(&fi
, 0, sizeof(fi
));
599 req
->f
->op
.read(req
, nodeid
, arg
->size
, arg
->offset
, &fi
);
601 fuse_reply_err(req
, ENOSYS
);
604 static void do_write(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
606 struct fuse_write_in
*arg
= (struct fuse_write_in
*) inarg
;
607 struct fuse_file_info fi
;
609 memset(&fi
, 0, sizeof(fi
));
612 fi
.writepage
= arg
->write_flags
& 1;
614 if (req
->f
->op
.write
)
615 req
->f
->op
.write(req
, nodeid
, PARAM(arg
), arg
->size
, arg
->offset
, &fi
);
617 fuse_reply_err(req
, ENOSYS
);
620 static void do_flush(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
622 struct fuse_flush_in
*arg
= (struct fuse_flush_in
*) inarg
;
623 struct fuse_file_info fi
;
625 memset(&fi
, 0, sizeof(fi
));
629 if (req
->f
->conn
.proto_minor
>= 7)
630 fi
.lock_owner
= arg
->lock_owner
;
632 if (req
->f
->op
.flush
)
633 req
->f
->op
.flush(req
, nodeid
, &fi
);
635 fuse_reply_err(req
, ENOSYS
);
638 static void do_release(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
640 struct fuse_release_in
*arg
= (struct fuse_release_in
*) inarg
;
641 struct fuse_file_info fi
;
643 memset(&fi
, 0, sizeof(fi
));
644 fi
.flags
= arg
->flags
;
647 if (req
->f
->conn
.proto_minor
>= 8) {
648 fi
.flush
= (arg
->release_flags
& FUSE_RELEASE_FLUSH
) ? 1 : 0;
649 fi
.lock_owner
= arg
->lock_owner
;
652 if (req
->f
->op
.release
)
653 req
->f
->op
.release(req
, nodeid
, &fi
);
655 fuse_reply_err(req
, 0);
658 static void do_fsync(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
660 struct fuse_fsync_in
*arg
= (struct fuse_fsync_in
*) inarg
;
661 struct fuse_file_info fi
;
663 memset(&fi
, 0, sizeof(fi
));
667 if (req
->f
->op
.fsync
)
668 req
->f
->op
.fsync(req
, nodeid
, arg
->fsync_flags
& 1, &fi
);
670 fuse_reply_err(req
, ENOSYS
);
673 static void do_opendir(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
675 struct fuse_open_in
*arg
= (struct fuse_open_in
*) inarg
;
676 struct fuse_file_info fi
;
678 memset(&fi
, 0, sizeof(fi
));
679 fi
.flags
= arg
->flags
;
681 if (req
->f
->op
.opendir
)
682 req
->f
->op
.opendir(req
, nodeid
, &fi
);
684 fuse_reply_open(req
, &fi
);
687 static void do_readdir(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
689 struct fuse_read_in
*arg
= (struct fuse_read_in
*) inarg
;
690 struct fuse_file_info fi
;
692 memset(&fi
, 0, sizeof(fi
));
696 if (req
->f
->op
.readdir
)
697 req
->f
->op
.readdir(req
, nodeid
, arg
->size
, arg
->offset
, &fi
);
699 fuse_reply_err(req
, ENOSYS
);
702 static void do_releasedir(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
704 struct fuse_release_in
*arg
= (struct fuse_release_in
*) inarg
;
705 struct fuse_file_info fi
;
707 memset(&fi
, 0, sizeof(fi
));
708 fi
.flags
= arg
->flags
;
712 if (req
->f
->op
.releasedir
)
713 req
->f
->op
.releasedir(req
, nodeid
, &fi
);
715 fuse_reply_err(req
, 0);
718 static void do_fsyncdir(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
720 struct fuse_fsync_in
*arg
= (struct fuse_fsync_in
*) inarg
;
721 struct fuse_file_info fi
;
723 memset(&fi
, 0, sizeof(fi
));
727 if (req
->f
->op
.fsyncdir
)
728 req
->f
->op
.fsyncdir(req
, nodeid
, arg
->fsync_flags
& 1, &fi
);
730 fuse_reply_err(req
, ENOSYS
);
733 static void do_statfs(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
738 if (req
->f
->op
.statfs
)
739 req
->f
->op
.statfs(req
, nodeid
);
741 struct statvfs buf
= {
745 fuse_reply_statfs(req
, &buf
);
749 static void do_setxattr(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
751 struct fuse_setxattr_in
*arg
= (struct fuse_setxattr_in
*) inarg
;
752 char *name
= PARAM(arg
);
753 char *value
= name
+ strlen(name
) + 1;
755 if (req
->f
->op
.setxattr
)
756 req
->f
->op
.setxattr(req
, nodeid
, name
, value
, arg
->size
, arg
->flags
);
758 fuse_reply_err(req
, ENOSYS
);
761 static void do_getxattr(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
763 struct fuse_getxattr_in
*arg
= (struct fuse_getxattr_in
*) inarg
;
765 if (req
->f
->op
.getxattr
)
766 req
->f
->op
.getxattr(req
, nodeid
, PARAM(arg
), arg
->size
);
768 fuse_reply_err(req
, ENOSYS
);
771 static void do_listxattr(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
773 struct fuse_getxattr_in
*arg
= (struct fuse_getxattr_in
*) inarg
;
775 if (req
->f
->op
.listxattr
)
776 req
->f
->op
.listxattr(req
, nodeid
, arg
->size
);
778 fuse_reply_err(req
, ENOSYS
);
781 static void do_removexattr(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
783 char *name
= (char *) inarg
;
785 if (req
->f
->op
.removexattr
)
786 req
->f
->op
.removexattr(req
, nodeid
, name
);
788 fuse_reply_err(req
, ENOSYS
);
791 static void convert_fuse_file_lock(struct fuse_file_lock
*fl
,
794 memset(flock
, 0, sizeof(struct flock
));
795 flock
->l_type
= fl
->type
;
796 flock
->l_whence
= SEEK_SET
;
797 flock
->l_start
= fl
->start
;
798 if (fl
->end
== OFFSET_MAX
)
801 flock
->l_len
= fl
->end
- fl
->start
+ 1;
802 flock
->l_pid
= fl
->pid
;
805 static void do_getlk(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
807 struct fuse_lk_in
*arg
= (struct fuse_lk_in
*) inarg
;
808 struct fuse_file_info fi
;
811 memset(&fi
, 0, sizeof(fi
));
813 fi
.lock_owner
= arg
->owner
;
815 convert_fuse_file_lock(&arg
->lk
, &flock
);
816 if (req
->f
->op
.getlk
)
817 req
->f
->op
.getlk(req
, nodeid
, &fi
, &flock
);
819 fuse_reply_err(req
, ENOSYS
);
822 static void do_setlk_common(fuse_req_t req
, fuse_ino_t nodeid
,
823 const void *inarg
, int sleep
)
825 struct fuse_lk_in
*arg
= (struct fuse_lk_in
*) inarg
;
826 struct fuse_file_info fi
;
829 memset(&fi
, 0, sizeof(fi
));
831 fi
.lock_owner
= arg
->owner
;
833 convert_fuse_file_lock(&arg
->lk
, &flock
);
834 if (req
->f
->op
.setlk
)
835 req
->f
->op
.setlk(req
, nodeid
, &fi
, &flock
, sleep
);
837 fuse_reply_err(req
, ENOSYS
);
840 static void do_setlk(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
842 do_setlk_common(req
, nodeid
, inarg
, 0);
845 static void do_setlkw(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
847 do_setlk_common(req
, nodeid
, inarg
, 1);
850 static int find_interrupted(struct fuse_ll
*f
, struct fuse_req
*req
)
852 struct fuse_req
*curr
;
854 for (curr
= f
->list
.next
; curr
!= &f
->list
; curr
= curr
->next
) {
855 if (curr
->unique
== req
->u
.i
.unique
) {
857 pthread_mutex_unlock(&f
->lock
);
859 /* Ugh, ugly locking */
860 pthread_mutex_lock(&curr
->lock
);
861 pthread_mutex_lock(&f
->lock
);
862 curr
->interrupted
= 1;
863 pthread_mutex_unlock(&f
->lock
);
865 curr
->u
.ni
.func(curr
, curr
->u
.ni
.data
);
866 pthread_mutex_unlock(&curr
->lock
);
868 pthread_mutex_lock(&f
->lock
);
876 for (curr
= f
->interrupts
.next
; curr
!= &f
->interrupts
;
878 if (curr
->u
.i
.unique
== req
->u
.i
.unique
)
884 static void do_interrupt(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
886 struct fuse_interrupt_in
*arg
= (struct fuse_interrupt_in
*) inarg
;
887 struct fuse_ll
*f
= req
->f
;
891 printf("INTERRUPT: %llu\n", (unsigned long long) arg
->unique
);
895 req
->u
.i
.unique
= arg
->unique
;
897 pthread_mutex_lock(&f
->lock
);
898 if (find_interrupted(f
, req
))
901 list_add_req(req
, &f
->interrupts
);
902 pthread_mutex_unlock(&f
->lock
);
905 static struct fuse_req
*check_interrupt(struct fuse_ll
*f
, struct fuse_req
*req
)
907 struct fuse_req
*curr
;
909 for (curr
= f
->interrupts
.next
; curr
!= &f
->interrupts
; curr
= curr
->next
) {
910 if (curr
->u
.i
.unique
== req
->unique
) {
911 req
->interrupted
= 1;
917 curr
= f
->interrupts
.next
;
918 if (curr
!= &f
->interrupts
) {
926 static void do_bmap(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
928 struct fuse_bmap_in
*arg
= (struct fuse_bmap_in
*) inarg
;
931 req
->f
->op
.bmap(req
, nodeid
, arg
->blocksize
, arg
->block
);
933 fuse_reply_err(req
, ENOSYS
);
936 static void do_init(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
938 struct fuse_init_in
*arg
= (struct fuse_init_in
*) inarg
;
939 struct fuse_init_out outarg
;
940 struct fuse_ll
*f
= req
->f
;
941 size_t bufsize
= fuse_chan_bufsize(req
->ch
);
945 printf("INIT: %u.%u\n", arg
->major
, arg
->minor
);
946 if (arg
->major
> 7 || (arg
->major
== 7 && arg
->minor
>= 6)) {
947 printf("flags=0x%08x\n", arg
->flags
);
948 printf("max_readahead=0x%08x\n", arg
->max_readahead
);
952 f
->conn
.proto_major
= arg
->major
;
953 f
->conn
.proto_minor
= arg
->minor
;
955 if (arg
->major
< 7) {
956 fprintf(stderr
, "fuse: unsupported protocol version: %u.%u\n",
957 arg
->major
, arg
->minor
);
958 fuse_reply_err(req
, EPROTO
);
962 if (arg
->major
> 7 || (arg
->major
== 7 && arg
->minor
>= 6)) {
963 if (f
->conn
.async_read
)
964 f
->conn
.async_read
= arg
->flags
& FUSE_ASYNC_READ
;
965 if (arg
->max_readahead
< f
->conn
.max_readahead
)
966 f
->conn
.max_readahead
= arg
->max_readahead
;
968 f
->conn
.async_read
= 0;
969 f
->conn
.max_readahead
= 0;
972 if (bufsize
< FUSE_MIN_READ_BUFFER
) {
973 fprintf(stderr
, "fuse: warning: buffer size too small: %i\n", bufsize
);
974 bufsize
= FUSE_MIN_READ_BUFFER
;
978 if (bufsize
< f
->conn
.max_write
)
979 f
->conn
.max_write
= bufsize
;
983 f
->op
.init(f
->userdata
, &f
->conn
);
985 memset(&outarg
, 0, sizeof(outarg
));
986 outarg
.major
= FUSE_KERNEL_VERSION
;
987 outarg
.minor
= FUSE_KERNEL_MINOR_VERSION
;
988 if (f
->conn
.async_read
)
989 outarg
.flags
|= FUSE_ASYNC_READ
;
990 if (f
->op
.getlk
&& f
->op
.setlk
)
991 outarg
.flags
|= FUSE_POSIX_LOCKS
;
992 outarg
.max_readahead
= f
->conn
.max_readahead
;
993 outarg
.max_write
= f
->conn
.max_write
;
996 printf(" INIT: %u.%u\n", outarg
.major
, outarg
.minor
);
997 printf(" flags=0x%08x\n", outarg
.flags
);
998 printf(" max_readahead=0x%08x\n", outarg
.max_readahead
);
999 printf(" max_write=0x%08x\n", outarg
.max_write
);
1003 send_reply_ok(req
, &outarg
, arg
->minor
< 5 ? 8 : sizeof(outarg
));
1006 static void do_destroy(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
1008 struct fuse_ll
*f
= req
->f
;
1015 f
->op
.destroy(f
->userdata
);
1017 send_reply_ok(req
, NULL
, 0);
1020 void *fuse_req_userdata(fuse_req_t req
)
1022 return req
->f
->userdata
;
1025 const struct fuse_ctx
*fuse_req_ctx(fuse_req_t req
)
1030 void fuse_req_interrupt_func(fuse_req_t req
, fuse_interrupt_func_t func
,
1033 pthread_mutex_lock(&req
->lock
);
1034 req
->u
.ni
.func
= func
;
1035 req
->u
.ni
.data
= data
;
1036 if (req
->interrupted
&& func
)
1038 pthread_mutex_unlock(&req
->lock
);
1041 int fuse_req_interrupted(fuse_req_t req
)
1045 pthread_mutex_lock(&req
->f
->lock
);
1046 interrupted
= req
->interrupted
;
1047 pthread_mutex_unlock(&req
->f
->lock
);
1053 void (*func
)(fuse_req_t
, fuse_ino_t
, const void *);
1056 [FUSE_LOOKUP
] = { do_lookup
, "LOOKUP" },
1057 [FUSE_FORGET
] = { do_forget
, "FORGET" },
1058 [FUSE_GETATTR
] = { do_getattr
, "GETATTR" },
1059 [FUSE_SETATTR
] = { do_setattr
, "SETATTR" },
1060 [FUSE_READLINK
] = { do_readlink
, "READLINK" },
1061 [FUSE_SYMLINK
] = { do_symlink
, "SYMLINK" },
1062 [FUSE_MKNOD
] = { do_mknod
, "MKNOD" },
1063 [FUSE_MKDIR
] = { do_mkdir
, "MKDIR" },
1064 [FUSE_UNLINK
] = { do_unlink
, "UNLINK" },
1065 [FUSE_RMDIR
] = { do_rmdir
, "RMDIR" },
1066 [FUSE_RENAME
] = { do_rename
, "RENAME" },
1067 [FUSE_LINK
] = { do_link
, "LINK" },
1068 [FUSE_OPEN
] = { do_open
, "OPEN" },
1069 [FUSE_READ
] = { do_read
, "READ" },
1070 [FUSE_WRITE
] = { do_write
, "WRITE" },
1071 [FUSE_STATFS
] = { do_statfs
, "STATFS" },
1072 [FUSE_RELEASE
] = { do_release
, "RELEASE" },
1073 [FUSE_FSYNC
] = { do_fsync
, "FSYNC" },
1074 [FUSE_SETXATTR
] = { do_setxattr
, "SETXATTR" },
1075 [FUSE_GETXATTR
] = { do_getxattr
, "GETXATTR" },
1076 [FUSE_LISTXATTR
] = { do_listxattr
, "LISTXATTR" },
1077 [FUSE_REMOVEXATTR
] = { do_removexattr
, "REMOVEXATTR" },
1078 [FUSE_FLUSH
] = { do_flush
, "FLUSH" },
1079 [FUSE_INIT
] = { do_init
, "INIT" },
1080 [FUSE_OPENDIR
] = { do_opendir
, "OPENDIR" },
1081 [FUSE_READDIR
] = { do_readdir
, "READDIR" },
1082 [FUSE_RELEASEDIR
] = { do_releasedir
, "RELEASEDIR" },
1083 [FUSE_FSYNCDIR
] = { do_fsyncdir
, "FSYNCDIR" },
1084 [FUSE_GETLK
] = { do_getlk
, "GETLK" },
1085 [FUSE_SETLK
] = { do_setlk
, "SETLK" },
1086 [FUSE_SETLKW
] = { do_setlkw
, "SETLKW" },
1087 [FUSE_ACCESS
] = { do_access
, "ACCESS" },
1088 [FUSE_CREATE
] = { do_create
, "CREATE" },
1089 [FUSE_INTERRUPT
] = { do_interrupt
, "INTERRUPT" },
1090 [FUSE_BMAP
] = { do_bmap
, "BMAP" },
1091 [FUSE_DESTROY
] = { do_destroy
, "DESTROY" },
1094 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
1096 static const char *opname(enum fuse_opcode opcode
)
1098 if (opcode
>= FUSE_MAXOP
|| !fuse_ll_ops
[opcode
].name
)
1101 return fuse_ll_ops
[opcode
].name
;
1104 static void fuse_ll_process(void *data
, const char *buf
, size_t len
,
1105 struct fuse_chan
*ch
)
1107 struct fuse_ll
*f
= (struct fuse_ll
*) data
;
1108 struct fuse_in_header
*in
= (struct fuse_in_header
*) buf
;
1109 const void *inarg
= buf
+ sizeof(struct fuse_in_header
);
1110 struct fuse_req
*req
;
1113 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
1114 (unsigned long long) in
->unique
,
1115 opname((enum fuse_opcode
) in
->opcode
), in
->opcode
,
1116 (unsigned long) in
->nodeid
, len
);
1120 req
= (struct fuse_req
*) calloc(1, sizeof(struct fuse_req
));
1122 fprintf(stderr
, "fuse: failed to allocate request\n");
1127 req
->unique
= in
->unique
;
1128 req
->ctx
.uid
= in
->uid
;
1129 req
->ctx
.gid
= in
->gid
;
1130 req
->ctx
.pid
= in
->pid
;
1134 fuse_mutex_init(&req
->lock
);
1136 if (!f
->got_init
&& in
->opcode
!= FUSE_INIT
)
1137 fuse_reply_err(req
, EIO
);
1138 else if (f
->allow_root
&& in
->uid
!= f
->owner
&& in
->uid
!= 0 &&
1139 in
->opcode
!= FUSE_INIT
&& in
->opcode
!= FUSE_READ
&&
1140 in
->opcode
!= FUSE_WRITE
&& in
->opcode
!= FUSE_FSYNC
&&
1141 in
->opcode
!= FUSE_RELEASE
&& in
->opcode
!= FUSE_READDIR
&&
1142 in
->opcode
!= FUSE_FSYNCDIR
&& in
->opcode
!= FUSE_RELEASEDIR
) {
1143 fuse_reply_err(req
, EACCES
);
1144 } else if (in
->opcode
>= FUSE_MAXOP
|| !fuse_ll_ops
[in
->opcode
].func
)
1145 fuse_reply_err(req
, ENOSYS
);
1147 if (in
->opcode
!= FUSE_INTERRUPT
) {
1148 struct fuse_req
*intr
;
1149 pthread_mutex_lock(&f
->lock
);
1150 intr
= check_interrupt(f
, req
);
1151 list_add_req(req
, &f
->list
);
1152 pthread_mutex_unlock(&f
->lock
);
1154 fuse_reply_err(intr
, EAGAIN
);
1156 fuse_ll_ops
[in
->opcode
].func(req
, in
->nodeid
, inarg
);
1165 static struct fuse_opt fuse_ll_opts
[] = {
1166 { "debug", offsetof(struct fuse_ll
, debug
), 1 },
1167 { "-d", offsetof(struct fuse_ll
, debug
), 1 },
1168 { "allow_root", offsetof(struct fuse_ll
, allow_root
), 1 },
1169 { "max_write=%u", offsetof(struct fuse_ll
, conn
.max_write
), 0 },
1170 { "max_readahead=%u", offsetof(struct fuse_ll
, conn
.max_readahead
), 0 },
1171 { "async_read", offsetof(struct fuse_ll
, conn
.async_read
), 1 },
1172 { "sync_read", offsetof(struct fuse_ll
, conn
.async_read
), 0 },
1173 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD
),
1174 FUSE_OPT_KEY("-h", KEY_HELP
),
1175 FUSE_OPT_KEY("--help", KEY_HELP
),
1176 FUSE_OPT_KEY("-V", KEY_VERSION
),
1177 FUSE_OPT_KEY("--version", KEY_VERSION
),
1181 static void fuse_ll_version(void)
1183 fprintf(stderr
, "using FUSE kernel interface version %i.%i\n",
1184 FUSE_KERNEL_VERSION
, FUSE_KERNEL_MINOR_VERSION
);
1187 static void fuse_ll_help(void)
1190 " -o max_write=N set maximum size of write requests\n"
1191 " -o max_readahead=N set maximum readahead\n"
1192 " -o async_read perform reads asynchronously (default)\n"
1193 " -o sync_read perform reads synchronously\n");
1196 static int fuse_ll_opt_proc(void *data
, const char *arg
, int key
,
1197 struct fuse_args
*outargs
)
1199 (void) data
; (void) outargs
;
1211 fprintf(stderr
, "fuse: unknown option `%s'\n", arg
);
1217 int fuse_lowlevel_is_lib_option(const char *opt
)
1219 return fuse_opt_match(fuse_ll_opts
, opt
);
1222 static void fuse_ll_destroy(void *data
)
1224 struct fuse_ll
*f
= (struct fuse_ll
*) data
;
1226 if (f
->got_init
&& !f
->got_destroy
) {
1228 f
->op
.destroy(f
->userdata
);
1231 pthread_mutex_destroy(&f
->lock
);
1236 * always call fuse_lowlevel_new_common() internally, to work around a
1237 * misfeature in the FreeBSD runtime linker, which links the old
1238 * version of a symbol to internal references.
1240 struct fuse_session
*fuse_lowlevel_new_common(struct fuse_args
*args
,
1241 const struct fuse_lowlevel_ops
*op
,
1242 size_t op_size
, void *userdata
)
1245 struct fuse_session
*se
;
1246 struct fuse_session_ops sop
= {
1247 .process
= fuse_ll_process
,
1248 .destroy
= fuse_ll_destroy
,
1251 if (sizeof(struct fuse_lowlevel_ops
) < op_size
) {
1252 fprintf(stderr
, "fuse: warning: library too old, some operations may not work\n");
1253 op_size
= sizeof(struct fuse_lowlevel_ops
);
1256 f
= (struct fuse_ll
*) calloc(1, sizeof(struct fuse_ll
));
1258 fprintf(stderr
, "fuse: failed to allocate fuse object\n");
1262 f
->conn
.async_read
= 1;
1263 f
->conn
.max_write
= UINT_MAX
;
1264 f
->conn
.max_readahead
= UINT_MAX
;
1265 list_init_req(&f
->list
);
1266 list_init_req(&f
->interrupts
);
1267 fuse_mutex_init(&f
->lock
);
1269 if (fuse_opt_parse(args
, f
, fuse_ll_opts
, fuse_ll_opt_proc
) == -1)
1272 memcpy(&f
->op
, op
, op_size
);
1273 f
->owner
= getuid();
1274 f
->userdata
= userdata
;
1276 se
= fuse_session_new(&sop
, f
);
1289 struct fuse_session
*fuse_lowlevel_new(struct fuse_args
*args
,
1290 const struct fuse_lowlevel_ops
*op
,
1291 size_t op_size
, void *userdata
)
1293 return fuse_lowlevel_new_common(args
, op
, op_size
, userdata
);
1297 #include "fuse_common_compat.h"
1298 #include "fuse_lowlevel_compat.h"
1302 static void fill_open_compat(struct fuse_open_out
*arg
,
1303 const struct fuse_file_info_compat
*f
)
1307 arg
->open_flags
|= FOPEN_DIRECT_IO
;
1309 arg
->open_flags
|= FOPEN_KEEP_CACHE
;
1312 static void convert_statfs_compat(const struct statfs
*compatbuf
,
1313 struct statvfs
*buf
)
1315 buf
->f_bsize
= compatbuf
->f_bsize
;
1316 buf
->f_blocks
= compatbuf
->f_blocks
;
1317 buf
->f_bfree
= compatbuf
->f_bfree
;
1318 buf
->f_bavail
= compatbuf
->f_bavail
;
1319 buf
->f_files
= compatbuf
->f_files
;
1320 buf
->f_ffree
= compatbuf
->f_ffree
;
1321 buf
->f_namemax
= compatbuf
->f_namelen
;
1324 int fuse_reply_open_compat(fuse_req_t req
,
1325 const struct fuse_file_info_compat
*f
)
1327 struct fuse_open_out arg
;
1329 memset(&arg
, 0, sizeof(arg
));
1330 fill_open_compat(&arg
, f
);
1331 return send_reply_ok(req
, &arg
, sizeof(arg
));
1334 int fuse_reply_statfs_compat(fuse_req_t req
, const struct statfs
*stbuf
)
1336 struct statvfs newbuf
;
1338 memset(&newbuf
, 0, sizeof(newbuf
));
1339 convert_statfs_compat(stbuf
, &newbuf
);
1341 return fuse_reply_statfs(req
, &newbuf
);
1344 struct fuse_session
*fuse_lowlevel_new_compat(const char *opts
,
1345 const struct fuse_lowlevel_ops_compat
*op
,
1346 size_t op_size
, void *userdata
)
1348 struct fuse_session
*se
;
1349 struct fuse_args args
= FUSE_ARGS_INIT(0, NULL
);
1352 (fuse_opt_add_arg(&args
, "") == -1 ||
1353 fuse_opt_add_arg(&args
, "-o") == -1 ||
1354 fuse_opt_add_arg(&args
, opts
) == -1)) {
1355 fuse_opt_free_args(&args
);
1358 se
= fuse_lowlevel_new(&args
, (const struct fuse_lowlevel_ops
*) op
,
1360 fuse_opt_free_args(&args
);
1365 struct fuse_ll_compat_conf
{
1370 static const struct fuse_opt fuse_ll_opts_compat
[] = {
1371 { "max_read=", offsetof(struct fuse_ll_compat_conf
, set_max_read
), 1 },
1372 { "max_read=%u", offsetof(struct fuse_ll_compat_conf
, max_read
), 0 },
1373 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP
),
1377 int fuse_sync_compat_args(struct fuse_args
*args
)
1379 struct fuse_ll_compat_conf conf
;
1381 memset(&conf
, 0, sizeof(conf
));
1382 if (fuse_opt_parse(args
, &conf
, fuse_ll_opts_compat
, NULL
) == -1)
1385 if (fuse_opt_insert_arg(args
, 1, "-osync_read"))
1388 if (conf
.set_max_read
) {
1391 sprintf(tmpbuf
, "-omax_readahead=%u", conf
.max_read
);
1392 if (fuse_opt_insert_arg(args
, 1, tmpbuf
) == -1)
1398 __asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
1399 __asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
1400 __asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
1402 #else /* __FreeBSD__ */
1404 int fuse_sync_compat_args(struct fuse_args
*args
)
1410 #endif /* __FreeBSD__ */
1412 struct fuse_session
*fuse_lowlevel_new_compat25(struct fuse_args
*args
,
1413 const struct fuse_lowlevel_ops_compat25
*op
,
1414 size_t op_size
, void *userdata
)
1416 if (fuse_sync_compat_args(args
) == -1)
1419 return fuse_lowlevel_new_common(args
,
1420 (const struct fuse_lowlevel_ops
*) op
,
1424 __asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");