1/* 2 FUSE: Filesystem in Userspace 3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 4 5 This program can be distributed under the terms of the GNU LGPLv2. 6 See the file COPYING.LIB 7*/ 8 9#include "config.h" 10#include "fuse_lowlevel.h" 11#include "fuse_kernel.h" 12#include "fuse_opt.h" 13#include "fuse_i.h" 14#include "fuse_misc.h" 15#include "fuse_lowlevel_compat.h" 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <stddef.h> 20#include <string.h> 21#include <unistd.h> 22#include <limits.h> 23#include <errno.h> 24 25#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) 26#define OFFSET_MAX 0x7fffffffffffffffLL 27 28struct fuse_ll; 29 30struct fuse_req { 31 struct fuse_ll *f; 32 uint64_t unique; 33 int ctr; 34 pthread_mutex_t lock; 35 struct fuse_ctx ctx; 36 struct fuse_chan *ch; 37 int interrupted; 38 union { 39 struct { 40 uint64_t unique; 41 } i; 42 struct { 43 fuse_interrupt_func_t func; 44 void *data; 45 } ni; 46 } u; 47 struct fuse_req *next; 48 struct fuse_req *prev; 49}; 50 51struct fuse_ll { 52 int debug; 53 int allow_root; 54 struct fuse_lowlevel_ops op; 55 int got_init; 56 void *userdata; 57 uid_t owner; 58 struct fuse_conn_info conn; 59 struct fuse_req list; 60 struct fuse_req interrupts; 61 pthread_mutex_t lock; 62 int got_destroy; 63}; 64 65static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) 66{ 67 attr->ino = stbuf->st_ino; 68 attr->mode = stbuf->st_mode; 69 attr->nlink = stbuf->st_nlink; 70 attr->uid = stbuf->st_uid; 71 attr->gid = stbuf->st_gid; 72 attr->rdev = stbuf->st_rdev; 73 attr->size = stbuf->st_size; 74 attr->blocks = stbuf->st_blocks; 75 attr->atime = stbuf->st_atime; 76 attr->mtime = stbuf->st_mtime; 77 attr->ctime = stbuf->st_ctime; 78 attr->atimensec = ST_ATIM_NSEC(stbuf); 79 attr->mtimensec = ST_MTIM_NSEC(stbuf); 80 attr->ctimensec = ST_CTIM_NSEC(stbuf); 81} 82 83static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf) 84{ 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 ST_ATIM_NSEC_SET(stbuf, attr->atimensec); 92 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); 93} 94 95static size_t iov_length(const struct iovec *iov, size_t count) 96{ 97 size_t seg; 98 size_t ret = 0; 99 100 for (seg = 0; seg < count; seg++) 101 ret += iov[seg].iov_len; 102 return ret; 103} 104 105static void list_init_req(struct fuse_req *req) 106{ 107 req->next = req; 108 req->prev = req; 109} 110 111static void list_del_req(struct fuse_req *req) 112{ 113 struct fuse_req *prev = req->prev; 114 struct fuse_req *next = req->next; 115 prev->next = next; 116 next->prev = prev; 117} 118 119static void list_add_req(struct fuse_req *req, struct fuse_req *next) 120{ 121 struct fuse_req *prev = next->prev; 122 req->next = next; 123 req->prev = prev; 124 prev->next = req; 125 next->prev = req; 126} 127 128static void destroy_req(fuse_req_t req) 129{ 130 pthread_mutex_destroy(&req->lock); 131 free(req); 132} 133 134static void free_req(fuse_req_t req) 135{ 136 int ctr; 137 struct fuse_ll *f = req->f; 138 139 pthread_mutex_lock(&req->lock); 140 req->u.ni.func = NULL; 141 req->u.ni.data = NULL; 142 pthread_mutex_unlock(&req->lock); 143 144 pthread_mutex_lock(&f->lock); 145 list_del_req(req); 146 ctr = --req->ctr; 147 pthread_mutex_unlock(&f->lock); 148 if (!ctr) 149 destroy_req(req); 150} 151 152static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, 153 int count) 154{ 155 struct fuse_out_header out; 156 int res; 157 158 if (error <= -1000 || error > 0) { 159 fprintf(stderr, "fuse: bad error value: %i\n", error); 160 error = -ERANGE; 161 } 162 163 out.unique = req->unique; 164 out.error = error; 165 iov[0].iov_base = &out; 166 iov[0].iov_len = sizeof(struct fuse_out_header); 167 out.len = iov_length(iov, count); 168 169 /* Foxconn removed start pling 06/19/2009 */ 170#if 0 171 if (req->f->debug) 172 fprintf(stderr, " unique: %llu, error: %i (%s), outsize: %i\n", 173 (unsigned long long) out.unique, out.error, 174 strerror(-out.error), out.len); 175#endif 176 /* Foxconn removed end pling 06/19/2009 */ 177 178 res = fuse_chan_send(req->ch, iov, count); 179 free_req(req); 180 181 return res; 182} 183 184static int send_reply(fuse_req_t req, int error, const void *arg, 185 size_t argsize) 186{ 187 struct iovec iov[2]; 188 int count = 1; 189 if (argsize) { 190 iov[1].iov_base = (void *) arg; 191 iov[1].iov_len = argsize; 192 count++; 193 } 194 return send_reply_iov(req, error, iov, count); 195} 196 197size_t fuse_dirent_size(size_t namelen) 198{ 199 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); 200} 201 202char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, 203 off_t off) 204{ 205 unsigned namelen = strlen(name); 206 unsigned entlen = FUSE_NAME_OFFSET + namelen; 207 unsigned entsize = fuse_dirent_size(namelen); 208 unsigned padlen = entsize - entlen; 209 struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 210 211 dirent->ino = stbuf->st_ino; 212 dirent->off = off; 213 dirent->namelen = namelen; 214 dirent->type = (stbuf->st_mode & 0170000) >> 12; 215 strncpy(dirent->name, name, namelen); 216 if (padlen) 217 memset(buf + entlen, 0, padlen); 218 219 return buf + entsize; 220} 221 222size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, 223 const char *name, const struct stat *stbuf, off_t off) 224{ 225 size_t entsize; 226 227 (void) req; 228 entsize = fuse_dirent_size(strlen(name)); 229 if (entsize <= bufsize && buf) 230 fuse_add_dirent(buf, name, stbuf, off); 231 return entsize; 232} 233 234static void convert_statfs(const struct statvfs *stbuf, 235 struct fuse_kstatfs *kstatfs) 236{ 237 kstatfs->bsize = stbuf->f_bsize; 238 kstatfs->frsize = stbuf->f_frsize; 239 kstatfs->blocks = stbuf->f_blocks; 240 kstatfs->bfree = stbuf->f_bfree; 241 kstatfs->bavail = stbuf->f_bavail; 242 kstatfs->files = stbuf->f_files; 243 kstatfs->ffree = stbuf->f_ffree; 244 kstatfs->namelen = stbuf->f_namemax; 245} 246 247static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) 248{ 249 return send_reply(req, 0, arg, argsize); 250} 251 252int fuse_reply_err(fuse_req_t req, int err) 253{ 254 return send_reply(req, -err, NULL, 0); 255} 256 257void fuse_reply_none(fuse_req_t req) 258{ 259 fuse_chan_send(req->ch, NULL, 0); 260 free_req(req); 261} 262 263static unsigned long calc_timeout_sec(double t) 264{ 265 if (t > (double) ULONG_MAX) 266 return ULONG_MAX; 267 else if (t < 0.0) 268 return 0; 269 else 270 return (unsigned long) t; 271} 272 273static unsigned int calc_timeout_nsec(double t) 274{ 275 double f = t - (double) calc_timeout_sec(t); 276 if (f < 0.0) 277 return 0; 278 else if (f >= 0.999999999) 279 return 999999999; 280 else 281 return (unsigned int) (f * 1.0e9); 282} 283 284static void fill_entry(struct fuse_entry_out *arg, 285 const struct fuse_entry_param *e) 286{ 287 arg->nodeid = e->ino; 288 arg->generation = e->generation; 289 arg->entry_valid = calc_timeout_sec(e->entry_timeout); 290 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); 291 arg->attr_valid = calc_timeout_sec(e->attr_timeout); 292 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); 293 convert_stat(&e->attr, &arg->attr); 294} 295 296static void fill_open(struct fuse_open_out *arg, 297 const struct fuse_file_info *f) 298{ 299 arg->fh = f->fh; 300 if (f->direct_io) 301 arg->open_flags |= FOPEN_DIRECT_IO; 302 if (f->keep_cache) 303 arg->open_flags |= FOPEN_KEEP_CACHE; 304} 305 306int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) 307{ 308 struct fuse_entry_out arg; 309 310 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant 311 negative entry */ 312 if (!e->ino && req->f->conn.proto_minor < 4) 313 return fuse_reply_err(req, ENOENT); 314 315 memset(&arg, 0, sizeof(arg)); 316 fill_entry(&arg, e); 317 return send_reply_ok(req, &arg, sizeof(arg)); 318} 319 320int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, 321 const struct fuse_file_info *f) 322{ 323 struct { 324 struct fuse_entry_out e; 325 struct fuse_open_out o; 326 } arg; 327 328 memset(&arg, 0, sizeof(arg)); 329 fill_entry(&arg.e, e); 330 fill_open(&arg.o, f); 331 return send_reply_ok(req, &arg, sizeof(arg)); 332} 333 334int fuse_reply_attr(fuse_req_t req, const struct stat *attr, 335 double attr_timeout) 336{ 337 struct fuse_attr_out arg; 338 339 memset(&arg, 0, sizeof(arg)); 340 arg.attr_valid = calc_timeout_sec(attr_timeout); 341 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); 342 convert_stat(attr, &arg.attr); 343 344 return send_reply_ok(req, &arg, sizeof(arg)); 345} 346 347int fuse_reply_readlink(fuse_req_t req, const char *linkname) 348{ 349 return send_reply_ok(req, linkname, strlen(linkname)); 350} 351 352int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) 353{ 354 struct fuse_open_out arg; 355 356 memset(&arg, 0, sizeof(arg)); 357 fill_open(&arg, f); 358 return send_reply_ok(req, &arg, sizeof(arg)); 359} 360 361int fuse_reply_write(fuse_req_t req, size_t count) 362{ 363 struct fuse_write_out arg; 364 365 memset(&arg, 0, sizeof(arg)); 366 arg.size = count; 367 368 return send_reply_ok(req, &arg, sizeof(arg)); 369} 370 371int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) 372{ 373 return send_reply_ok(req, buf, size); 374} 375 376int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) 377{ 378 struct fuse_statfs_out arg; 379 size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); 380 381 memset(&arg, 0, sizeof(arg)); 382 convert_statfs(stbuf, &arg.st); 383 384 return send_reply_ok(req, &arg, size); 385} 386 387int fuse_reply_xattr(fuse_req_t req, size_t count) 388{ 389 struct fuse_getxattr_out arg; 390 391 memset(&arg, 0, sizeof(arg)); 392 arg.size = count; 393 394 return send_reply_ok(req, &arg, sizeof(arg)); 395} 396 397int fuse_reply_lock(fuse_req_t req, struct flock *lock) 398{ 399 struct fuse_lk_out arg; 400 401 memset(&arg, 0, sizeof(arg)); 402 arg.lk.type = lock->l_type; 403 if (lock->l_type != F_UNLCK) { 404 arg.lk.start = lock->l_start; 405 if (lock->l_len == 0) 406 arg.lk.end = OFFSET_MAX; 407 else 408 arg.lk.end = lock->l_start + lock->l_len - 1; 409 } 410 arg.lk.pid = lock->l_pid; 411 return send_reply_ok(req, &arg, sizeof(arg)); 412} 413 414int fuse_reply_bmap(fuse_req_t req, uint64_t idx) 415{ 416 struct fuse_bmap_out arg; 417 418 memset(&arg, 0, sizeof(arg)); 419 arg.block = idx; 420 421 return send_reply_ok(req, &arg, sizeof(arg)); 422} 423 424static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 425{ 426 char *name = (char *) inarg; 427 428 if (req->f->op.lookup) 429 req->f->op.lookup(req, nodeid, name); 430 else 431 fuse_reply_err(req, ENOSYS); 432} 433 434static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 435{ 436 struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; 437 438 if (req->f->op.forget) 439 req->f->op.forget(req, nodeid, arg->nlookup); 440 else 441 fuse_reply_none(req); 442} 443 444static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 445{ 446 (void) inarg; 447 448 if (req->f->op.getattr) 449 req->f->op.getattr(req, nodeid, NULL); 450 else 451 fuse_reply_err(req, ENOSYS); 452} 453 454static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 455{ 456 struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg; 457 458 if (req->f->op.setattr) { 459 struct fuse_file_info *fi = NULL; 460 struct fuse_file_info fi_store; 461 struct stat stbuf; 462 memset(&stbuf, 0, sizeof(stbuf)); 463 convert_attr(arg, &stbuf); 464 if (arg->valid & FATTR_FH) { 465 arg->valid &= ~FATTR_FH; 466 memset(&fi_store, 0, sizeof(fi_store)); 467 fi = &fi_store; 468 fi->fh = arg->fh; 469 fi->fh_old = fi->fh; 470 } 471 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi); 472 } else 473 fuse_reply_err(req, ENOSYS); 474} 475 476static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 477{ 478 struct fuse_access_in *arg = (struct fuse_access_in *) inarg; 479 480 if (req->f->op.access) 481 req->f->op.access(req, nodeid, arg->mask); 482 else 483 fuse_reply_err(req, ENOSYS); 484} 485 486static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 487{ 488 (void) inarg; 489 490 if (req->f->op.readlink) 491 req->f->op.readlink(req, nodeid); 492 else 493 fuse_reply_err(req, ENOSYS); 494} 495 496static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 497{ 498 struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; 499 500 if (req->f->op.mknod) 501 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); 502 else 503 fuse_reply_err(req, ENOSYS); 504} 505 506static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 507{ 508 struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; 509 510 if (req->f->op.mkdir) 511 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); 512 else 513 fuse_reply_err(req, ENOSYS); 514} 515 516static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 517{ 518 char *name = (char *) inarg; 519 520 if (req->f->op.unlink) 521 req->f->op.unlink(req, nodeid, name); 522 else 523 fuse_reply_err(req, ENOSYS); 524} 525 526static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 527{ 528 char *name = (char *) inarg; 529 530 if (req->f->op.rmdir) 531 req->f->op.rmdir(req, nodeid, name); 532 else 533 fuse_reply_err(req, ENOSYS); 534} 535 536static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 537{ 538 char *name = (char *) inarg; 539 char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; 540 541 if (req->f->op.symlink) 542 req->f->op.symlink(req, linkname, nodeid, name); 543 else 544 fuse_reply_err(req, ENOSYS); 545} 546 547static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 548{ 549 struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; 550 char *oldname = PARAM(arg); 551 char *newname = oldname + strlen(oldname) + 1; 552 553 if (req->f->op.rename) 554 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); 555 else 556 fuse_reply_err(req, ENOSYS); 557} 558 559static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 560{ 561 struct fuse_link_in *arg = (struct fuse_link_in *) inarg; 562 563 if (req->f->op.link) 564 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); 565 else 566 fuse_reply_err(req, ENOSYS); 567} 568 569static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 570{ 571 struct fuse_open_in *arg = (struct fuse_open_in *) inarg; 572 573 if (req->f->op.create) { 574 struct fuse_file_info fi; 575 576 memset(&fi, 0, sizeof(fi)); 577 fi.flags = arg->flags; 578 579 req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi); 580 } else 581 fuse_reply_err(req, ENOSYS); 582} 583 584static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 585{ 586 struct fuse_open_in *arg = (struct fuse_open_in *) inarg; 587 struct fuse_file_info fi; 588 589 memset(&fi, 0, sizeof(fi)); 590 fi.flags = arg->flags; 591 592 if (req->f->op.open) 593 req->f->op.open(req, nodeid, &fi); 594 else 595 fuse_reply_open(req, &fi); 596} 597 598static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 599{ 600 struct fuse_read_in *arg = (struct fuse_read_in *) inarg; 601 602 if (req->f->op.read) { 603 struct fuse_file_info fi; 604 605 memset(&fi, 0, sizeof(fi)); 606 fi.fh = arg->fh; 607 fi.fh_old = fi.fh; 608 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); 609 } else 610 fuse_reply_err(req, ENOSYS); 611} 612 613static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 614{ 615 struct fuse_write_in *arg = (struct fuse_write_in *) inarg; 616 struct fuse_file_info fi; 617 618 memset(&fi, 0, sizeof(fi)); 619 fi.fh = arg->fh; 620 fi.fh_old = fi.fh; 621 fi.writepage = arg->write_flags & 1; 622 623 if (req->f->op.write) 624 req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi); 625 else 626 fuse_reply_err(req, ENOSYS); 627} 628 629static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 630{ 631 struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; 632 struct fuse_file_info fi; 633 634 memset(&fi, 0, sizeof(fi)); 635 fi.fh = arg->fh; 636 fi.fh_old = fi.fh; 637 fi.flush = 1; 638 if (req->f->conn.proto_minor >= 7) 639 fi.lock_owner = arg->lock_owner; 640 641 if (req->f->op.flush) 642 req->f->op.flush(req, nodeid, &fi); 643 else 644 fuse_reply_err(req, ENOSYS); 645} 646 647static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 648{ 649 struct fuse_release_in *arg = (struct fuse_release_in *) inarg; 650 struct fuse_file_info fi; 651 652 memset(&fi, 0, sizeof(fi)); 653 fi.flags = arg->flags; 654 fi.fh = arg->fh; 655 fi.fh_old = fi.fh; 656 if (req->f->conn.proto_minor >= 8) { 657 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; 658 fi.lock_owner = arg->lock_owner; 659 } 660 661 if (req->f->op.release) 662 req->f->op.release(req, nodeid, &fi); 663 else 664 fuse_reply_err(req, 0); 665} 666 667static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 668{ 669 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; 670 struct fuse_file_info fi; 671 672 memset(&fi, 0, sizeof(fi)); 673 fi.fh = arg->fh; 674 fi.fh_old = fi.fh; 675 676 if (req->f->op.fsync) 677 req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); 678 else 679 fuse_reply_err(req, ENOSYS); 680} 681 682static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 683{ 684 struct fuse_open_in *arg = (struct fuse_open_in *) inarg; 685 struct fuse_file_info fi; 686 687 memset(&fi, 0, sizeof(fi)); 688 fi.flags = arg->flags; 689 690 if (req->f->op.opendir) 691 req->f->op.opendir(req, nodeid, &fi); 692 else 693 fuse_reply_open(req, &fi); 694} 695 696static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 697{ 698 struct fuse_read_in *arg = (struct fuse_read_in *) inarg; 699 struct fuse_file_info fi; 700 701 memset(&fi, 0, sizeof(fi)); 702 fi.fh = arg->fh; 703 fi.fh_old = fi.fh; 704 705 if (req->f->op.readdir) 706 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); 707 else 708 fuse_reply_err(req, ENOSYS); 709} 710 711static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 712{ 713 struct fuse_release_in *arg = (struct fuse_release_in *) inarg; 714 struct fuse_file_info fi; 715 716 memset(&fi, 0, sizeof(fi)); 717 fi.flags = arg->flags; 718 fi.fh = arg->fh; 719 fi.fh_old = fi.fh; 720 721 if (req->f->op.releasedir) 722 req->f->op.releasedir(req, nodeid, &fi); 723 else 724 fuse_reply_err(req, 0); 725} 726 727static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 728{ 729 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; 730 struct fuse_file_info fi; 731 732 memset(&fi, 0, sizeof(fi)); 733 fi.fh = arg->fh; 734 fi.fh_old = fi.fh; 735 736 if (req->f->op.fsyncdir) 737 req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); 738 else 739 fuse_reply_err(req, ENOSYS); 740} 741 742static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 743{ 744 (void) nodeid; 745 (void) inarg; 746 747 if (req->f->op.statfs) 748 req->f->op.statfs(req, nodeid); 749 else { 750 struct statvfs buf = { 751 .f_namemax = 255, 752 .f_bsize = 512, 753 }; 754 fuse_reply_statfs(req, &buf); 755 } 756} 757 758static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 759{ 760 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; 761 char *name = PARAM(arg); 762 char *value = name + strlen(name) + 1; 763 764 if (req->f->op.setxattr) 765 req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags); 766 else 767 fuse_reply_err(req, ENOSYS); 768} 769 770static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 771{ 772 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; 773 774 if (req->f->op.getxattr) 775 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); 776 else 777 fuse_reply_err(req, ENOSYS); 778} 779 780static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 781{ 782 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; 783 784 if (req->f->op.listxattr) 785 req->f->op.listxattr(req, nodeid, arg->size); 786 else 787 fuse_reply_err(req, ENOSYS); 788} 789 790static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 791{ 792 char *name = (char *) inarg; 793 794 if (req->f->op.removexattr) 795 req->f->op.removexattr(req, nodeid, name); 796 else 797 fuse_reply_err(req, ENOSYS); 798} 799 800static void convert_fuse_file_lock(struct fuse_file_lock *fl, 801 struct flock *flock) 802{ 803 memset(flock, 0, sizeof(struct flock)); 804 flock->l_type = fl->type; 805 flock->l_whence = SEEK_SET; 806 flock->l_start = fl->start; 807 if (fl->end == OFFSET_MAX) 808 flock->l_len = 0; 809 else 810 flock->l_len = fl->end - fl->start + 1; 811 flock->l_pid = fl->pid; 812} 813 814static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 815{ 816 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; 817 struct fuse_file_info fi; 818 struct flock flock; 819 820 memset(&fi, 0, sizeof(fi)); 821 fi.fh = arg->fh; 822 fi.lock_owner = arg->owner; 823 824 convert_fuse_file_lock(&arg->lk, &flock); 825 if (req->f->op.getlk) 826 req->f->op.getlk(req, nodeid, &fi, &flock); 827 else 828 fuse_reply_err(req, ENOSYS); 829} 830 831static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, 832 const void *inarg, int should_sleep) 833{ 834 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; 835 struct fuse_file_info fi; 836 struct flock flock; 837 838 memset(&fi, 0, sizeof(fi)); 839 fi.fh = arg->fh; 840 fi.lock_owner = arg->owner; 841 842 convert_fuse_file_lock(&arg->lk, &flock); 843 if (req->f->op.setlk) 844 req->f->op.setlk(req, nodeid, &fi, &flock, should_sleep); 845 else 846 fuse_reply_err(req, ENOSYS); 847} 848 849static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 850{ 851 do_setlk_common(req, nodeid, inarg, 0); 852} 853 854static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 855{ 856 do_setlk_common(req, nodeid, inarg, 1); 857} 858 859static int find_interrupted(struct fuse_ll *f, struct fuse_req *req) 860{ 861 struct fuse_req *curr; 862 863 for (curr = f->list.next; curr != &f->list; curr = curr->next) { 864 if (curr->unique == req->u.i.unique) { 865 curr->ctr++; 866 pthread_mutex_unlock(&f->lock); 867 868 /* Ugh, ugly locking */ 869 pthread_mutex_lock(&curr->lock); 870 pthread_mutex_lock(&f->lock); 871 curr->interrupted = 1; 872 pthread_mutex_unlock(&f->lock); 873 if (curr->u.ni.func) 874 curr->u.ni.func(curr, curr->u.ni.data); 875 pthread_mutex_unlock(&curr->lock); 876 877 pthread_mutex_lock(&f->lock); 878 curr->ctr--; 879 if (!curr->ctr) 880 destroy_req(curr); 881 882 return 1; 883 } 884 } 885 for (curr = f->interrupts.next; curr != &f->interrupts; 886 curr = curr->next) { 887 if (curr->u.i.unique == req->u.i.unique) 888 return 1; 889 } 890 return 0; 891} 892 893static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 894{ 895 struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; 896 struct fuse_ll *f = req->f; 897 898 (void) nodeid; 899 if (f->debug) 900 fprintf(stderr, "INTERRUPT: %llu\n", (unsigned long long) arg->unique); 901 902 req->u.i.unique = arg->unique; 903 904 pthread_mutex_lock(&f->lock); 905 if (find_interrupted(f, req)) 906 destroy_req(req); 907 else 908 list_add_req(req, &f->interrupts); 909 pthread_mutex_unlock(&f->lock); 910} 911 912static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req) 913{ 914 struct fuse_req *curr; 915 916 for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) { 917 if (curr->u.i.unique == req->unique) { 918 req->interrupted = 1; 919 list_del_req(curr); 920 free(curr); 921 return NULL; 922 } 923 } 924 curr = f->interrupts.next; 925 if (curr != &f->interrupts) { 926 list_del_req(curr); 927 list_init_req(curr); 928 return curr; 929 } else 930 return NULL; 931} 932 933static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 934{ 935 struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; 936 937 if (req->f->op.bmap) 938 req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); 939 else 940 fuse_reply_err(req, ENOSYS); 941} 942 943static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 944{ 945 struct fuse_init_in *arg = (struct fuse_init_in *) inarg; 946 struct fuse_init_out outarg; 947 struct fuse_ll *f = req->f; 948 size_t bufsize = fuse_chan_bufsize(req->ch); 949 950 (void) nodeid; 951 if (f->debug) { 952 fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); 953 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { 954 fprintf(stderr, "flags=0x%08x\n", arg->flags); 955 fprintf(stderr, "max_readahead=0x%08x\n", arg->max_readahead); 956 } 957 } 958 f->conn.proto_major = arg->major; 959 f->conn.proto_minor = arg->minor; 960 961 if (arg->major < 7) { 962 fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", 963 arg->major, arg->minor); 964 fuse_reply_err(req, EPROTO); 965 return; 966 } 967 968 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { 969 if (f->conn.async_read) 970 f->conn.async_read = arg->flags & FUSE_ASYNC_READ; 971 if (arg->max_readahead < f->conn.max_readahead) 972 f->conn.max_readahead = arg->max_readahead; 973 } else { 974 f->conn.async_read = 0; 975 f->conn.max_readahead = 0; 976 } 977 978 if (bufsize < FUSE_MIN_READ_BUFFER) { 979 fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", 980 bufsize); 981 bufsize = FUSE_MIN_READ_BUFFER; 982 } 983 984 bufsize -= 4096; 985 if (bufsize < f->conn.max_write) 986 f->conn.max_write = bufsize; 987 988 f->got_init = 1; 989 if (f->op.init) 990 f->op.init(f->userdata, &f->conn); 991 992 memset(&outarg, 0, sizeof(outarg)); 993 outarg.major = FUSE_KERNEL_VERSION; 994 outarg.minor = FUSE_KERNEL_MINOR_VERSION; 995 if (f->conn.async_read) 996 outarg.flags |= FUSE_ASYNC_READ; 997 if (f->op.getlk && f->op.setlk) 998 outarg.flags |= FUSE_POSIX_LOCKS; 999 outarg.max_readahead = f->conn.max_readahead; 1000 outarg.max_write = f->conn.max_write; 1001 1002 if (f->debug) { 1003 fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); 1004 fprintf(stderr, " flags=0x%08x\n", outarg.flags); 1005 fprintf(stderr, " max_readahead=0x%08x\n", outarg.max_readahead); 1006 fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); 1007 } 1008 1009 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); 1010} 1011 1012static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) 1013{ 1014 struct fuse_ll *f = req->f; 1015 1016 (void) nodeid; 1017 (void) inarg; 1018 1019 f->got_destroy = 1; 1020 if (f->op.destroy) 1021 f->op.destroy(f->userdata); 1022 1023 send_reply_ok(req, NULL, 0); 1024} 1025 1026void *fuse_req_userdata(fuse_req_t req) 1027{ 1028 return req->f->userdata; 1029} 1030 1031const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) 1032{ 1033 return &req->ctx; 1034} 1035 1036void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, 1037 void *data) 1038{ 1039 pthread_mutex_lock(&req->lock); 1040 req->u.ni.func = func; 1041 req->u.ni.data = data; 1042 if (req->interrupted && func) 1043 func(req, data); 1044 pthread_mutex_unlock(&req->lock); 1045} 1046 1047int fuse_req_interrupted(fuse_req_t req) 1048{ 1049 int interrupted; 1050 1051 pthread_mutex_lock(&req->f->lock); 1052 interrupted = req->interrupted; 1053 pthread_mutex_unlock(&req->f->lock); 1054 1055 return interrupted; 1056} 1057 1058static struct { 1059 void (*func)(fuse_req_t, fuse_ino_t, const void *); 1060 const char *name; 1061} fuse_ll_ops[] = { 1062 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, 1063 [FUSE_FORGET] = { do_forget, "FORGET" }, 1064 [FUSE_GETATTR] = { do_getattr, "GETATTR" }, 1065 [FUSE_SETATTR] = { do_setattr, "SETATTR" }, 1066 [FUSE_READLINK] = { do_readlink, "READLINK" }, 1067 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, 1068 [FUSE_MKNOD] = { do_mknod, "MKNOD" }, 1069 [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, 1070 [FUSE_UNLINK] = { do_unlink, "UNLINK" }, 1071 [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, 1072 [FUSE_RENAME] = { do_rename, "RENAME" }, 1073 [FUSE_LINK] = { do_link, "LINK" }, 1074 [FUSE_OPEN] = { do_open, "OPEN" }, 1075 [FUSE_READ] = { do_read, "READ" }, 1076 [FUSE_WRITE] = { do_write, "WRITE" }, 1077 [FUSE_STATFS] = { do_statfs, "STATFS" }, 1078 [FUSE_RELEASE] = { do_release, "RELEASE" }, 1079 [FUSE_FSYNC] = { do_fsync, "FSYNC" }, 1080 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, 1081 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, 1082 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, 1083 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, 1084 [FUSE_FLUSH] = { do_flush, "FLUSH" }, 1085 [FUSE_INIT] = { do_init, "INIT" }, 1086 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, 1087 [FUSE_READDIR] = { do_readdir, "READDIR" }, 1088 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, 1089 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, 1090 [FUSE_GETLK] = { do_getlk, "GETLK" }, 1091 [FUSE_SETLK] = { do_setlk, "SETLK" }, 1092 [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, 1093 [FUSE_ACCESS] = { do_access, "ACCESS" }, 1094 [FUSE_CREATE] = { do_create, "CREATE" }, 1095 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, 1096 [FUSE_BMAP] = { do_bmap, "BMAP" }, 1097 [FUSE_DESTROY] = { do_destroy, "DESTROY" }, 1098}; 1099 1100#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) 1101 1102static const char *opname(enum fuse_opcode opcode) 1103{ 1104 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) 1105 return "???"; 1106 else 1107 return fuse_ll_ops[opcode].name; 1108} 1109 1110static void fuse_ll_process(void *data, const char *buf, size_t len, 1111 struct fuse_chan *ch) 1112{ 1113 struct fuse_ll *f = (struct fuse_ll *) data; 1114 struct fuse_in_header *in = (struct fuse_in_header *) buf; 1115 const void *inarg = buf + sizeof(struct fuse_in_header); 1116 struct fuse_req *req; 1117 1118 /* Foxconn removed start pling 06/19/2009 */ 1119#if 0 1120 if (f->debug) 1121 fprintf(stderr, "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n", 1122 (unsigned long long) in->unique, 1123 opname((enum fuse_opcode) in->opcode), in->opcode, 1124 (unsigned long) in->nodeid, len); 1125#endif 1126 /* Foxconn removed end pling 06/19/2009 */ 1127 1128 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); 1129 if (req == NULL) { 1130 fprintf(stderr, "fuse: failed to allocate request\n"); 1131 return; 1132 } 1133 1134 req->f = f; 1135 req->unique = in->unique; 1136 req->ctx.uid = in->uid; 1137 req->ctx.gid = in->gid; 1138 req->ctx.pid = in->pid; 1139 req->ch = ch; 1140 req->ctr = 1; 1141 list_init_req(req); 1142 fuse_mutex_init(&req->lock); 1143 1144 if (!f->got_init && in->opcode != FUSE_INIT) 1145 fuse_reply_err(req, EIO); 1146 else if (f->allow_root && in->uid != f->owner && in->uid != 0 && 1147 in->opcode != FUSE_INIT && in->opcode != FUSE_READ && 1148 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && 1149 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && 1150 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { 1151 fuse_reply_err(req, EACCES); 1152 } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) 1153 fuse_reply_err(req, ENOSYS); 1154 else { 1155 if (in->opcode != FUSE_INTERRUPT) { 1156 struct fuse_req *intr; 1157 pthread_mutex_lock(&f->lock); 1158 intr = check_interrupt(f, req); 1159 list_add_req(req, &f->list); 1160 pthread_mutex_unlock(&f->lock); 1161 if (intr) 1162 fuse_reply_err(intr, EAGAIN); 1163 } 1164 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); 1165 } 1166} 1167 1168enum { 1169 KEY_HELP, 1170 KEY_VERSION, 1171}; 1172 1173static struct fuse_opt fuse_ll_opts[] = { 1174 { "debug", offsetof(struct fuse_ll, debug), 1 }, 1175 { "-d", offsetof(struct fuse_ll, debug), 1 }, 1176 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, 1177 { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, 1178 { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, 1179 { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, 1180 { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, 1181 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), 1182 FUSE_OPT_KEY("-h", KEY_HELP), 1183 FUSE_OPT_KEY("--help", KEY_HELP), 1184 FUSE_OPT_KEY("-V", KEY_VERSION), 1185 FUSE_OPT_KEY("--version", KEY_VERSION), 1186 FUSE_OPT_END 1187}; 1188 1189static void fuse_ll_version(void) 1190{ 1191 fprintf(stderr, "using FUSE kernel interface version %i.%i\n", 1192 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 1193} 1194 1195static void fuse_ll_help(void) 1196{ 1197 fprintf(stderr, 1198" -o max_write=N set maximum size of write requests\n" 1199" -o max_readahead=N set maximum readahead\n" 1200" -o async_read perform reads asynchronously (default)\n" 1201" -o sync_read perform reads synchronously\n"); 1202} 1203 1204static int fuse_ll_opt_proc(void *data, const char *arg, int key, 1205 struct fuse_args *outargs) 1206{ 1207 (void) data; (void) outargs; 1208 1209 switch (key) { 1210 case KEY_HELP: 1211 fuse_ll_help(); 1212 break; 1213 1214 case KEY_VERSION: 1215 fuse_ll_version(); 1216 break; 1217 1218 default: 1219 fprintf(stderr, "fuse: unknown option `%s'\n", arg); 1220 } 1221 1222 return -1; 1223} 1224 1225static void fuse_ll_destroy(void *data) 1226{ 1227 struct fuse_ll *f = (struct fuse_ll *) data; 1228 1229 if (f->got_init && !f->got_destroy) { 1230 if (f->op.destroy) 1231 f->op.destroy(f->userdata); 1232 } 1233 1234 pthread_mutex_destroy(&f->lock); 1235 free(f); 1236} 1237 1238struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, 1239 const struct fuse_lowlevel_ops *op, 1240 size_t op_size, void *userdata) 1241{ 1242 struct fuse_ll *f; 1243 struct fuse_session *se; 1244 struct fuse_session_ops sop = { 1245 .process = fuse_ll_process, 1246 .destroy = fuse_ll_destroy, 1247 }; 1248 1249 if (sizeof(struct fuse_lowlevel_ops) < op_size) { 1250 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); 1251 op_size = sizeof(struct fuse_lowlevel_ops); 1252 } 1253 1254 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); 1255 if (f == NULL) { 1256 fprintf(stderr, "fuse: failed to allocate fuse object\n"); 1257 goto out; 1258 } 1259 1260 f->conn.async_read = 1; 1261 f->conn.max_write = UINT_MAX; 1262 f->conn.max_readahead = UINT_MAX; 1263 list_init_req(&f->list); 1264 list_init_req(&f->interrupts); 1265 fuse_mutex_init(&f->lock); 1266 1267 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) 1268 goto out_free; 1269 1270 memcpy(&f->op, op, op_size); 1271 f->owner = getuid(); 1272 f->userdata = userdata; 1273 1274 se = fuse_session_new(&sop, f); 1275 if (!se) 1276 goto out_free; 1277 1278 return se; 1279 1280 out_free: 1281 free(f); 1282 out: 1283 return NULL; 1284} 1285 1286