libfuse
passthrough_ll.c
Go to the documentation of this file.
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 GPLv2.
6  See the file COPYING.
7 */
8 
37 #define _GNU_SOURCE
38 #define FUSE_USE_VERSION 34
39 
40 #include "config.h"
41 
42 #include <fuse_lowlevel.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <stddef.h>
47 #include <stdbool.h>
48 #include <string.h>
49 #include <limits.h>
50 #include <dirent.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include <inttypes.h>
54 #include <pthread.h>
55 #include <sys/file.h>
56 #include <sys/xattr.h>
57 
58 #include "passthrough_helpers.h"
59 
60 /* We are re-using pointers to our `struct lo_inode` and `struct
61  lo_dirp` elements as inodes. This means that we must be able to
62  store uintptr_t values in a fuse_ino_t variable. The following
63  incantation checks this condition at compile time. */
64 #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
65 _Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
66  "fuse_ino_t too small to hold uintptr_t values!");
67 #else
68 struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
69  { unsigned _uintptr_to_must_hold_fuse_ino_t:
70  ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
71 #endif
72 
73 struct lo_inode {
74  struct lo_inode *next; /* protected by lo->mutex */
75  struct lo_inode *prev; /* protected by lo->mutex */
76  int fd;
77  ino_t ino;
78  dev_t dev;
79  uint64_t refcount; /* protected by lo->mutex */
80 };
81 
82 enum {
83  CACHE_NEVER,
84  CACHE_NORMAL,
85  CACHE_ALWAYS,
86 };
87 
88 struct lo_data {
89  pthread_mutex_t mutex;
90  int debug;
91  int writeback;
92  int flock;
93  int xattr;
94  const char *source;
95  double timeout;
96  int cache;
97  int timeout_set;
98  struct lo_inode root; /* protected by lo->mutex */
99 };
100 
101 static const struct fuse_opt lo_opts[] = {
102  { "writeback",
103  offsetof(struct lo_data, writeback), 1 },
104  { "no_writeback",
105  offsetof(struct lo_data, writeback), 0 },
106  { "source=%s",
107  offsetof(struct lo_data, source), 0 },
108  { "flock",
109  offsetof(struct lo_data, flock), 1 },
110  { "no_flock",
111  offsetof(struct lo_data, flock), 0 },
112  { "xattr",
113  offsetof(struct lo_data, xattr), 1 },
114  { "no_xattr",
115  offsetof(struct lo_data, xattr), 0 },
116  { "timeout=%lf",
117  offsetof(struct lo_data, timeout), 0 },
118  { "timeout=",
119  offsetof(struct lo_data, timeout_set), 1 },
120  { "cache=never",
121  offsetof(struct lo_data, cache), CACHE_NEVER },
122  { "cache=auto",
123  offsetof(struct lo_data, cache), CACHE_NORMAL },
124  { "cache=always",
125  offsetof(struct lo_data, cache), CACHE_ALWAYS },
126 
128 };
129 
130 static void passthrough_ll_help(void)
131 {
132  printf(
133 " -o writeback Enable writeback\n"
134 " -o no_writeback Disable write back\n"
135 " -o source=/home/dir Source directory to be mounted\n"
136 " -o flock Enable flock\n"
137 " -o no_flock Disable flock\n"
138 " -o xattr Enable xattr\n"
139 " -o no_xattr Disable xattr\n"
140 " -o timeout=1.0 Caching timeout\n"
141 " -o timeout=0/1 Timeout is set\n"
142 " -o cache=never Disable cache\n"
143 " -o cache=auto Auto enable cache\n"
144 " -o cache=always Cache always\n");
145 }
146 
147 static struct lo_data *lo_data(fuse_req_t req)
148 {
149  return (struct lo_data *) fuse_req_userdata(req);
150 }
151 
152 static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
153 {
154  if (ino == FUSE_ROOT_ID)
155  return &lo_data(req)->root;
156  else
157  return (struct lo_inode *) (uintptr_t) ino;
158 }
159 
160 static int lo_fd(fuse_req_t req, fuse_ino_t ino)
161 {
162  return lo_inode(req, ino)->fd;
163 }
164 
165 static bool lo_debug(fuse_req_t req)
166 {
167  return lo_data(req)->debug != 0;
168 }
169 
170 static void lo_init(void *userdata,
171  struct fuse_conn_info *conn)
172 {
173  struct lo_data *lo = (struct lo_data*) userdata;
174 
175  if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
176  conn->want |= FUSE_CAP_EXPORT_SUPPORT;
177 
178  if (lo->writeback &&
180  if (lo->debug)
181  fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
183  }
184  if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
185  if (lo->debug)
186  fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
187  conn->want |= FUSE_CAP_FLOCK_LOCKS;
188  }
189 }
190 
191 static void lo_destroy(void *userdata)
192 {
193  struct lo_data *lo = (struct lo_data*) userdata;
194 
195  while (lo->root.next != &lo->root) {
196  struct lo_inode* next = lo->root.next;
197  lo->root.next = next->next;
198  free(next);
199  }
200 }
201 
202 static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
203  struct fuse_file_info *fi)
204 {
205  int res;
206  struct stat buf;
207  struct lo_data *lo = lo_data(req);
208 
209  (void) fi;
210 
211  res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
212  if (res == -1)
213  return (void) fuse_reply_err(req, errno);
214 
215  fuse_reply_attr(req, &buf, lo->timeout);
216 }
217 
218 static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
219  int valid, struct fuse_file_info *fi)
220 {
221  int saverr;
222  char procname[64];
223  struct lo_inode *inode = lo_inode(req, ino);
224  int ifd = inode->fd;
225  int res;
226 
227  if (valid & FUSE_SET_ATTR_MODE) {
228  if (fi) {
229  res = fchmod(fi->fh, attr->st_mode);
230  } else {
231  sprintf(procname, "/proc/self/fd/%i", ifd);
232  res = chmod(procname, attr->st_mode);
233  }
234  if (res == -1)
235  goto out_err;
236  }
237  if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
238  uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
239  attr->st_uid : (uid_t) -1;
240  gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
241  attr->st_gid : (gid_t) -1;
242 
243  res = fchownat(ifd, "", uid, gid,
244  AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
245  if (res == -1)
246  goto out_err;
247  }
248  if (valid & FUSE_SET_ATTR_SIZE) {
249  if (fi) {
250  res = ftruncate(fi->fh, attr->st_size);
251  } else {
252  sprintf(procname, "/proc/self/fd/%i", ifd);
253  res = truncate(procname, attr->st_size);
254  }
255  if (res == -1)
256  goto out_err;
257  }
258  if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
259  struct timespec tv[2];
260 
261  tv[0].tv_sec = 0;
262  tv[1].tv_sec = 0;
263  tv[0].tv_nsec = UTIME_OMIT;
264  tv[1].tv_nsec = UTIME_OMIT;
265 
266  if (valid & FUSE_SET_ATTR_ATIME_NOW)
267  tv[0].tv_nsec = UTIME_NOW;
268  else if (valid & FUSE_SET_ATTR_ATIME)
269  tv[0] = attr->st_atim;
270 
271  if (valid & FUSE_SET_ATTR_MTIME_NOW)
272  tv[1].tv_nsec = UTIME_NOW;
273  else if (valid & FUSE_SET_ATTR_MTIME)
274  tv[1] = attr->st_mtim;
275 
276  if (fi)
277  res = futimens(fi->fh, tv);
278  else {
279  sprintf(procname, "/proc/self/fd/%i", ifd);
280  res = utimensat(AT_FDCWD, procname, tv, 0);
281  }
282  if (res == -1)
283  goto out_err;
284  }
285 
286  return lo_getattr(req, ino, fi);
287 
288 out_err:
289  saverr = errno;
290  fuse_reply_err(req, saverr);
291 }
292 
293 static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
294 {
295  struct lo_inode *p;
296  struct lo_inode *ret = NULL;
297 
298  pthread_mutex_lock(&lo->mutex);
299  for (p = lo->root.next; p != &lo->root; p = p->next) {
300  if (p->ino == st->st_ino && p->dev == st->st_dev) {
301  assert(p->refcount > 0);
302  ret = p;
303  ret->refcount++;
304  break;
305  }
306  }
307  pthread_mutex_unlock(&lo->mutex);
308  return ret;
309 }
310 
311 static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
312  struct fuse_entry_param *e)
313 {
314  int newfd;
315  int res;
316  int saverr;
317  struct lo_data *lo = lo_data(req);
318  struct lo_inode *inode;
319 
320  memset(e, 0, sizeof(*e));
321  e->attr_timeout = lo->timeout;
322  e->entry_timeout = lo->timeout;
323 
324  newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
325  if (newfd == -1)
326  goto out_err;
327 
328  res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
329  if (res == -1)
330  goto out_err;
331 
332  inode = lo_find(lo_data(req), &e->attr);
333  if (inode) {
334  close(newfd);
335  newfd = -1;
336  } else {
337  struct lo_inode *prev, *next;
338 
339  saverr = ENOMEM;
340  inode = calloc(1, sizeof(struct lo_inode));
341  if (!inode)
342  goto out_err;
343 
344  inode->refcount = 1;
345  inode->fd = newfd;
346  inode->ino = e->attr.st_ino;
347  inode->dev = e->attr.st_dev;
348 
349  pthread_mutex_lock(&lo->mutex);
350  prev = &lo->root;
351  next = prev->next;
352  next->prev = inode;
353  inode->next = next;
354  inode->prev = prev;
355  prev->next = inode;
356  pthread_mutex_unlock(&lo->mutex);
357  }
358  e->ino = (uintptr_t) inode;
359 
360  if (lo_debug(req))
361  fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
362  (unsigned long long) parent, name, (unsigned long long) e->ino);
363 
364  return 0;
365 
366 out_err:
367  saverr = errno;
368  if (newfd != -1)
369  close(newfd);
370  return saverr;
371 }
372 
373 static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
374 {
375  struct fuse_entry_param e;
376  int err;
377 
378  if (lo_debug(req))
379  fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
380  parent, name);
381 
382  err = lo_do_lookup(req, parent, name, &e);
383  if (err)
384  fuse_reply_err(req, err);
385  else
386  fuse_reply_entry(req, &e);
387 }
388 
389 static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
390  const char *name, mode_t mode, dev_t rdev,
391  const char *link)
392 {
393  int res;
394  int saverr;
395  struct lo_inode *dir = lo_inode(req, parent);
396  struct fuse_entry_param e;
397 
398  res = mknod_wrapper(dir->fd, name, link, mode, rdev);
399 
400  saverr = errno;
401  if (res == -1)
402  goto out;
403 
404  saverr = lo_do_lookup(req, parent, name, &e);
405  if (saverr)
406  goto out;
407 
408  if (lo_debug(req))
409  fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
410  (unsigned long long) parent, name, (unsigned long long) e.ino);
411 
412  fuse_reply_entry(req, &e);
413  return;
414 
415 out:
416  fuse_reply_err(req, saverr);
417 }
418 
419 static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
420  const char *name, mode_t mode, dev_t rdev)
421 {
422  lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
423 }
424 
425 static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
426  mode_t mode)
427 {
428  lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
429 }
430 
431 static void lo_symlink(fuse_req_t req, const char *link,
432  fuse_ino_t parent, const char *name)
433 {
434  lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
435 }
436 
437 static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
438  const char *name)
439 {
440  int res;
441  struct lo_data *lo = lo_data(req);
442  struct lo_inode *inode = lo_inode(req, ino);
443  struct fuse_entry_param e;
444  char procname[64];
445  int saverr;
446 
447  memset(&e, 0, sizeof(struct fuse_entry_param));
448  e.attr_timeout = lo->timeout;
449  e.entry_timeout = lo->timeout;
450 
451  sprintf(procname, "/proc/self/fd/%i", inode->fd);
452  res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
453  AT_SYMLINK_FOLLOW);
454  if (res == -1)
455  goto out_err;
456 
457  res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
458  if (res == -1)
459  goto out_err;
460 
461  pthread_mutex_lock(&lo->mutex);
462  inode->refcount++;
463  pthread_mutex_unlock(&lo->mutex);
464  e.ino = (uintptr_t) inode;
465 
466  if (lo_debug(req))
467  fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
468  (unsigned long long) parent, name,
469  (unsigned long long) e.ino);
470 
471  fuse_reply_entry(req, &e);
472  return;
473 
474 out_err:
475  saverr = errno;
476  fuse_reply_err(req, saverr);
477 }
478 
479 static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
480 {
481  int res;
482 
483  res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
484 
485  fuse_reply_err(req, res == -1 ? errno : 0);
486 }
487 
488 static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
489  fuse_ino_t newparent, const char *newname,
490  unsigned int flags)
491 {
492  int res;
493 
494  if (flags) {
495  fuse_reply_err(req, EINVAL);
496  return;
497  }
498 
499  res = renameat(lo_fd(req, parent), name,
500  lo_fd(req, newparent), newname);
501 
502  fuse_reply_err(req, res == -1 ? errno : 0);
503 }
504 
505 static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
506 {
507  int res;
508 
509  res = unlinkat(lo_fd(req, parent), name, 0);
510 
511  fuse_reply_err(req, res == -1 ? errno : 0);
512 }
513 
514 static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
515 {
516  if (!inode)
517  return;
518 
519  pthread_mutex_lock(&lo->mutex);
520  assert(inode->refcount >= n);
521  inode->refcount -= n;
522  if (!inode->refcount) {
523  struct lo_inode *prev, *next;
524 
525  prev = inode->prev;
526  next = inode->next;
527  next->prev = prev;
528  prev->next = next;
529 
530  pthread_mutex_unlock(&lo->mutex);
531  close(inode->fd);
532  free(inode);
533 
534  } else {
535  pthread_mutex_unlock(&lo->mutex);
536  }
537 }
538 
539 static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
540 {
541  struct lo_data *lo = lo_data(req);
542  struct lo_inode *inode = lo_inode(req, ino);
543 
544  if (lo_debug(req)) {
545  fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n",
546  (unsigned long long) ino,
547  (unsigned long long) inode->refcount,
548  (unsigned long long) nlookup);
549  }
550 
551  unref_inode(lo, inode, nlookup);
552 }
553 
554 static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
555 {
556  lo_forget_one(req, ino, nlookup);
557  fuse_reply_none(req);
558 }
559 
560 static void lo_forget_multi(fuse_req_t req, size_t count,
561  struct fuse_forget_data *forgets)
562 {
563  int i;
564 
565  for (i = 0; i < count; i++)
566  lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
567  fuse_reply_none(req);
568 }
569 
570 static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
571 {
572  char buf[PATH_MAX + 1];
573  int res;
574 
575  res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
576  if (res == -1)
577  return (void) fuse_reply_err(req, errno);
578 
579  if (res == sizeof(buf))
580  return (void) fuse_reply_err(req, ENAMETOOLONG);
581 
582  buf[res] = '\0';
583 
584  fuse_reply_readlink(req, buf);
585 }
586 
587 struct lo_dirp {
588  DIR *dp;
589  struct dirent *entry;
590  off_t offset;
591 };
592 
593 static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
594 {
595  return (struct lo_dirp *) (uintptr_t) fi->fh;
596 }
597 
598 static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
599 {
600  int error = ENOMEM;
601  struct lo_data *lo = lo_data(req);
602  struct lo_dirp *d;
603  int fd;
604 
605  d = calloc(1, sizeof(struct lo_dirp));
606  if (d == NULL)
607  goto out_err;
608 
609  fd = openat(lo_fd(req, ino), ".", O_RDONLY);
610  if (fd == -1)
611  goto out_errno;
612 
613  d->dp = fdopendir(fd);
614  if (d->dp == NULL)
615  goto out_errno;
616 
617  d->offset = 0;
618  d->entry = NULL;
619 
620  fi->fh = (uintptr_t) d;
621  if (lo->cache == CACHE_ALWAYS)
622  fi->cache_readdir = 1;
623  fuse_reply_open(req, fi);
624  return;
625 
626 out_errno:
627  error = errno;
628 out_err:
629  if (d) {
630  if (fd != -1)
631  close(fd);
632  free(d);
633  }
634  fuse_reply_err(req, error);
635 }
636 
637 static int is_dot_or_dotdot(const char *name)
638 {
639  return name[0] == '.' && (name[1] == '\0' ||
640  (name[1] == '.' && name[2] == '\0'));
641 }
642 
643 static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
644  off_t offset, struct fuse_file_info *fi, int plus)
645 {
646  struct lo_dirp *d = lo_dirp(fi);
647  char *buf;
648  char *p;
649  size_t rem = size;
650  int err;
651 
652  (void) ino;
653 
654  buf = calloc(1, size);
655  if (!buf) {
656  err = ENOMEM;
657  goto error;
658  }
659  p = buf;
660 
661  if (offset != d->offset) {
662  seekdir(d->dp, offset);
663  d->entry = NULL;
664  d->offset = offset;
665  }
666  while (1) {
667  size_t entsize;
668  off_t nextoff;
669  const char *name;
670 
671  if (!d->entry) {
672  errno = 0;
673  d->entry = readdir(d->dp);
674  if (!d->entry) {
675  if (errno) { // Error
676  err = errno;
677  goto error;
678  } else { // End of stream
679  break;
680  }
681  }
682  }
683  nextoff = d->entry->d_off;
684  name = d->entry->d_name;
685  fuse_ino_t entry_ino = 0;
686  if (plus) {
687  struct fuse_entry_param e;
688  if (is_dot_or_dotdot(name)) {
689  e = (struct fuse_entry_param) {
690  .attr.st_ino = d->entry->d_ino,
691  .attr.st_mode = d->entry->d_type << 12,
692  };
693  } else {
694  err = lo_do_lookup(req, ino, name, &e);
695  if (err)
696  goto error;
697  entry_ino = e.ino;
698  }
699 
700  entsize = fuse_add_direntry_plus(req, p, rem, name,
701  &e, nextoff);
702  } else {
703  struct stat st = {
704  .st_ino = d->entry->d_ino,
705  .st_mode = d->entry->d_type << 12,
706  };
707  entsize = fuse_add_direntry(req, p, rem, name,
708  &st, nextoff);
709  }
710  if (entsize > rem) {
711  if (entry_ino != 0)
712  lo_forget_one(req, entry_ino, 1);
713  break;
714  }
715 
716  p += entsize;
717  rem -= entsize;
718 
719  d->entry = NULL;
720  d->offset = nextoff;
721  }
722 
723  err = 0;
724 error:
725  // If there's an error, we can only signal it if we haven't stored
726  // any entries yet - otherwise we'd end up with wrong lookup
727  // counts for the entries that are already in the buffer. So we
728  // return what we've collected until that point.
729  if (err && rem == size)
730  fuse_reply_err(req, err);
731  else
732  fuse_reply_buf(req, buf, size - rem);
733  free(buf);
734 }
735 
736 static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
737  off_t offset, struct fuse_file_info *fi)
738 {
739  lo_do_readdir(req, ino, size, offset, fi, 0);
740 }
741 
742 static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
743  off_t offset, struct fuse_file_info *fi)
744 {
745  lo_do_readdir(req, ino, size, offset, fi, 1);
746 }
747 
748 static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
749 {
750  struct lo_dirp *d = lo_dirp(fi);
751  (void) ino;
752  closedir(d->dp);
753  free(d);
754  fuse_reply_err(req, 0);
755 }
756 
757 static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
758  mode_t mode, struct fuse_file_info *fi)
759 {
760  int fd;
761  struct lo_data *lo = lo_data(req);
762  struct fuse_entry_param e;
763  int err;
764 
765  if (lo_debug(req))
766  fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
767  parent, name);
768 
769  fd = openat(lo_fd(req, parent), name,
770  (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
771  if (fd == -1)
772  return (void) fuse_reply_err(req, errno);
773 
774  fi->fh = fd;
775  if (lo->cache == CACHE_NEVER)
776  fi->direct_io = 1;
777  else if (lo->cache == CACHE_ALWAYS)
778  fi->keep_cache = 1;
779 
780  err = lo_do_lookup(req, parent, name, &e);
781  if (err)
782  fuse_reply_err(req, err);
783  else
784  fuse_reply_create(req, &e, fi);
785 }
786 
787 static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
788  struct fuse_file_info *fi)
789 {
790  int res;
791  int fd = dirfd(lo_dirp(fi)->dp);
792  (void) ino;
793  if (datasync)
794  res = fdatasync(fd);
795  else
796  res = fsync(fd);
797  fuse_reply_err(req, res == -1 ? errno : 0);
798 }
799 
800 static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
801 {
802  int fd;
803  char buf[64];
804  struct lo_data *lo = lo_data(req);
805 
806  if (lo_debug(req))
807  fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
808  ino, fi->flags);
809 
810  /* With writeback cache, kernel may send read requests even
811  when userspace opened write-only */
812  if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
813  fi->flags &= ~O_ACCMODE;
814  fi->flags |= O_RDWR;
815  }
816 
817  /* With writeback cache, O_APPEND is handled by the kernel.
818  This breaks atomicity (since the file may change in the
819  underlying filesystem, so that the kernel's idea of the
820  end of the file isn't accurate anymore). In this example,
821  we just accept that. A more rigorous filesystem may want
822  to return an error here */
823  if (lo->writeback && (fi->flags & O_APPEND))
824  fi->flags &= ~O_APPEND;
825 
826  sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
827  fd = open(buf, fi->flags & ~O_NOFOLLOW);
828  if (fd == -1)
829  return (void) fuse_reply_err(req, errno);
830 
831  fi->fh = fd;
832  if (lo->cache == CACHE_NEVER)
833  fi->direct_io = 1;
834  else if (lo->cache == CACHE_ALWAYS)
835  fi->keep_cache = 1;
836  fuse_reply_open(req, fi);
837 }
838 
839 static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
840 {
841  (void) ino;
842 
843  close(fi->fh);
844  fuse_reply_err(req, 0);
845 }
846 
847 static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
848 {
849  int res;
850  (void) ino;
851  res = close(dup(fi->fh));
852  fuse_reply_err(req, res == -1 ? errno : 0);
853 }
854 
855 static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
856  struct fuse_file_info *fi)
857 {
858  int res;
859  (void) ino;
860  if (datasync)
861  res = fdatasync(fi->fh);
862  else
863  res = fsync(fi->fh);
864  fuse_reply_err(req, res == -1 ? errno : 0);
865 }
866 
867 static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
868  off_t offset, struct fuse_file_info *fi)
869 {
870  struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
871 
872  if (lo_debug(req))
873  fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
874  "off=%lu)\n", ino, size, (unsigned long) offset);
875 
877  buf.buf[0].fd = fi->fh;
878  buf.buf[0].pos = offset;
879 
881 }
882 
883 static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
884  struct fuse_bufvec *in_buf, off_t off,
885  struct fuse_file_info *fi)
886 {
887  (void) ino;
888  ssize_t res;
889  struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
890 
891  out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
892  out_buf.buf[0].fd = fi->fh;
893  out_buf.buf[0].pos = off;
894 
895  if (lo_debug(req))
896  fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
897  ino, out_buf.buf[0].size, (unsigned long) off);
898 
899  res = fuse_buf_copy(&out_buf, in_buf, 0);
900  if(res < 0)
901  fuse_reply_err(req, -res);
902  else
903  fuse_reply_write(req, (size_t) res);
904 }
905 
906 static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
907 {
908  int res;
909  struct statvfs stbuf;
910 
911  res = fstatvfs(lo_fd(req, ino), &stbuf);
912  if (res == -1)
913  fuse_reply_err(req, errno);
914  else
915  fuse_reply_statfs(req, &stbuf);
916 }
917 
918 static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
919  off_t offset, off_t length, struct fuse_file_info *fi)
920 {
921  int err = EOPNOTSUPP;
922  (void) ino;
923 
924 #ifdef HAVE_FALLOCATE
925  err = fallocate(fi->fh, mode, offset, length);
926  if (err < 0)
927  err = errno;
928 
929 #elif defined(HAVE_POSIX_FALLOCATE)
930  if (mode) {
931  fuse_reply_err(req, EOPNOTSUPP);
932  return;
933  }
934 
935  err = posix_fallocate(fi->fh, offset, length);
936 #endif
937 
938  fuse_reply_err(req, err);
939 }
940 
941 static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
942  int op)
943 {
944  int res;
945  (void) ino;
946 
947  res = flock(fi->fh, op);
948 
949  fuse_reply_err(req, res == -1 ? errno : 0);
950 }
951 
952 static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
953  size_t size)
954 {
955  char *value = NULL;
956  char procname[64];
957  struct lo_inode *inode = lo_inode(req, ino);
958  ssize_t ret;
959  int saverr;
960 
961  saverr = ENOSYS;
962  if (!lo_data(req)->xattr)
963  goto out;
964 
965  if (lo_debug(req)) {
966  fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
967  ino, name, size);
968  }
969 
970  sprintf(procname, "/proc/self/fd/%i", inode->fd);
971 
972  if (size) {
973  value = malloc(size);
974  if (!value)
975  goto out_err;
976 
977  ret = getxattr(procname, name, value, size);
978  if (ret == -1)
979  goto out_err;
980  saverr = 0;
981  if (ret == 0)
982  goto out;
983 
984  fuse_reply_buf(req, value, ret);
985  } else {
986  ret = getxattr(procname, name, NULL, 0);
987  if (ret == -1)
988  goto out_err;
989 
990  fuse_reply_xattr(req, ret);
991  }
992 out_free:
993  free(value);
994  return;
995 
996 out_err:
997  saverr = errno;
998 out:
999  fuse_reply_err(req, saverr);
1000  goto out_free;
1001 }
1002 
1003 static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
1004 {
1005  char *value = NULL;
1006  char procname[64];
1007  struct lo_inode *inode = lo_inode(req, ino);
1008  ssize_t ret;
1009  int saverr;
1010 
1011  saverr = ENOSYS;
1012  if (!lo_data(req)->xattr)
1013  goto out;
1014 
1015  if (lo_debug(req)) {
1016  fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
1017  ino, size);
1018  }
1019 
1020  sprintf(procname, "/proc/self/fd/%i", inode->fd);
1021 
1022  if (size) {
1023  value = malloc(size);
1024  if (!value)
1025  goto out_err;
1026 
1027  ret = listxattr(procname, value, size);
1028  if (ret == -1)
1029  goto out_err;
1030  saverr = 0;
1031  if (ret == 0)
1032  goto out;
1033 
1034  fuse_reply_buf(req, value, ret);
1035  } else {
1036  ret = listxattr(procname, NULL, 0);
1037  if (ret == -1)
1038  goto out_err;
1039 
1040  fuse_reply_xattr(req, ret);
1041  }
1042 out_free:
1043  free(value);
1044  return;
1045 
1046 out_err:
1047  saverr = errno;
1048 out:
1049  fuse_reply_err(req, saverr);
1050  goto out_free;
1051 }
1052 
1053 static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1054  const char *value, size_t size, int flags)
1055 {
1056  char procname[64];
1057  struct lo_inode *inode = lo_inode(req, ino);
1058  ssize_t ret;
1059  int saverr;
1060 
1061  saverr = ENOSYS;
1062  if (!lo_data(req)->xattr)
1063  goto out;
1064 
1065  if (lo_debug(req)) {
1066  fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
1067  ino, name, value, size);
1068  }
1069 
1070  sprintf(procname, "/proc/self/fd/%i", inode->fd);
1071 
1072  ret = setxattr(procname, name, value, size, flags);
1073  saverr = ret == -1 ? errno : 0;
1074 
1075 out:
1076  fuse_reply_err(req, saverr);
1077 }
1078 
1079 static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
1080 {
1081  char procname[64];
1082  struct lo_inode *inode = lo_inode(req, ino);
1083  ssize_t ret;
1084  int saverr;
1085 
1086  saverr = ENOSYS;
1087  if (!lo_data(req)->xattr)
1088  goto out;
1089 
1090  if (lo_debug(req)) {
1091  fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
1092  ino, name);
1093  }
1094 
1095  sprintf(procname, "/proc/self/fd/%i", inode->fd);
1096 
1097  ret = removexattr(procname, name);
1098  saverr = ret == -1 ? errno : 0;
1099 
1100 out:
1101  fuse_reply_err(req, saverr);
1102 }
1103 
1104 #ifdef HAVE_COPY_FILE_RANGE
1105 static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
1106  struct fuse_file_info *fi_in,
1107  fuse_ino_t ino_out, off_t off_out,
1108  struct fuse_file_info *fi_out, size_t len,
1109  int flags)
1110 {
1111  ssize_t res;
1112 
1113  if (lo_debug(req))
1114  fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
1115  "off=%lu, ino=%" PRIu64 "/fd=%lu, "
1116  "off=%lu, size=%zd, flags=0x%x)\n",
1117  ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
1118  len, flags);
1119 
1120  res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
1121  flags);
1122  if (res < 0)
1123  fuse_reply_err(req, errno);
1124  else
1125  fuse_reply_write(req, res);
1126 }
1127 #endif
1128 
1129 static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
1130  struct fuse_file_info *fi)
1131 {
1132  off_t res;
1133 
1134  (void)ino;
1135  res = lseek(fi->fh, off, whence);
1136  if (res != -1)
1137  fuse_reply_lseek(req, res);
1138  else
1139  fuse_reply_err(req, errno);
1140 }
1141 
1142 static const struct fuse_lowlevel_ops lo_oper = {
1143  .init = lo_init,
1144  .destroy = lo_destroy,
1145  .lookup = lo_lookup,
1146  .mkdir = lo_mkdir,
1147  .mknod = lo_mknod,
1148  .symlink = lo_symlink,
1149  .link = lo_link,
1150  .unlink = lo_unlink,
1151  .rmdir = lo_rmdir,
1152  .rename = lo_rename,
1153  .forget = lo_forget,
1154  .forget_multi = lo_forget_multi,
1155  .getattr = lo_getattr,
1156  .setattr = lo_setattr,
1157  .readlink = lo_readlink,
1158  .opendir = lo_opendir,
1159  .readdir = lo_readdir,
1160  .readdirplus = lo_readdirplus,
1161  .releasedir = lo_releasedir,
1162  .fsyncdir = lo_fsyncdir,
1163  .create = lo_create,
1164  .open = lo_open,
1165  .release = lo_release,
1166  .flush = lo_flush,
1167  .fsync = lo_fsync,
1168  .read = lo_read,
1169  .write_buf = lo_write_buf,
1170  .statfs = lo_statfs,
1171  .fallocate = lo_fallocate,
1172  .flock = lo_flock,
1173  .getxattr = lo_getxattr,
1174  .listxattr = lo_listxattr,
1175  .setxattr = lo_setxattr,
1176  .removexattr = lo_removexattr,
1177 #ifdef HAVE_COPY_FILE_RANGE
1178  .copy_file_range = lo_copy_file_range,
1179 #endif
1180  .lseek = lo_lseek,
1181 };
1182 
1183 int main(int argc, char *argv[])
1184 {
1185  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1186  struct fuse_session *se;
1187  struct fuse_cmdline_opts opts;
1188  struct fuse_loop_config config;
1189  struct lo_data lo = { .debug = 0,
1190  .writeback = 0 };
1191  int ret = -1;
1192 
1193  /* Don't mask creation mode, kernel already did that */
1194  umask(0);
1195 
1196  pthread_mutex_init(&lo.mutex, NULL);
1197  lo.root.next = lo.root.prev = &lo.root;
1198  lo.root.fd = -1;
1199  lo.cache = CACHE_NORMAL;
1200 
1201  if (fuse_parse_cmdline(&args, &opts) != 0)
1202  return 1;
1203  if (opts.show_help) {
1204  printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
1207  passthrough_ll_help();
1208  ret = 0;
1209  goto err_out1;
1210  } else if (opts.show_version) {
1211  printf("FUSE library version %s\n", fuse_pkgversion());
1213  ret = 0;
1214  goto err_out1;
1215  }
1216 
1217  if(opts.mountpoint == NULL) {
1218  printf("usage: %s [options] <mountpoint>\n", argv[0]);
1219  printf(" %s --help\n", argv[0]);
1220  ret = 1;
1221  goto err_out1;
1222  }
1223 
1224  if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
1225  return 1;
1226 
1227  lo.debug = opts.debug;
1228  lo.root.refcount = 2;
1229  if (lo.source) {
1230  struct stat stat;
1231  int res;
1232 
1233  res = lstat(lo.source, &stat);
1234  if (res == -1) {
1235  fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
1236  lo.source);
1237  exit(1);
1238  }
1239  if (!S_ISDIR(stat.st_mode)) {
1240  fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
1241  exit(1);
1242  }
1243 
1244  } else {
1245  lo.source = "/";
1246  }
1247  if (!lo.timeout_set) {
1248  switch (lo.cache) {
1249  case CACHE_NEVER:
1250  lo.timeout = 0.0;
1251  break;
1252 
1253  case CACHE_NORMAL:
1254  lo.timeout = 1.0;
1255  break;
1256 
1257  case CACHE_ALWAYS:
1258  lo.timeout = 86400.0;
1259  break;
1260  }
1261  } else if (lo.timeout < 0) {
1262  fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
1263  lo.timeout);
1264  exit(1);
1265  }
1266 
1267  lo.root.fd = open(lo.source, O_PATH);
1268  if (lo.root.fd == -1) {
1269  fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
1270  lo.source);
1271  exit(1);
1272  }
1273 
1274  se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
1275  if (se == NULL)
1276  goto err_out1;
1277 
1278  if (fuse_set_signal_handlers(se) != 0)
1279  goto err_out2;
1280 
1281  if (fuse_session_mount(se, opts.mountpoint) != 0)
1282  goto err_out3;
1283 
1284  fuse_daemonize(opts.foreground);
1285 
1286  /* Block until ctrl+c or fusermount -u */
1287  if (opts.singlethread)
1288  ret = fuse_session_loop(se);
1289  else {
1290  config.clone_fd = opts.clone_fd;
1291  config.max_idle_threads = opts.max_idle_threads;
1292  ret = fuse_session_loop_mt(se, &config);
1293  }
1294 
1296 err_out3:
1298 err_out2:
1300 err_out1:
1301  free(opts.mountpoint);
1302  fuse_opt_free_args(&args);
1303 
1304  if (lo.root.fd >= 0)
1305  close(lo.root.fd);
1306 
1307  return ret ? 1 : 0;
1308 }
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
#define FUSE_CAP_WRITEBACK_CACHE
Definition: fuse_common.h:296
@ FUSE_BUF_FD_SEEK
Definition: fuse_common.h:642
@ FUSE_BUF_IS_FD
Definition: fuse_common.h:633
#define FUSE_CAP_EXPORT_SUPPORT
Definition: fuse_common.h:165
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:284
const char * fuse_pkgversion(void)
Definition: fuse.c:5122
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
@ FUSE_BUF_SPLICE_MOVE
Definition: fuse_common.h:684
int fuse_daemonize(int foreground)
Definition: helper.c:225
#define FUSE_CAP_FLOCK_LOCKS
Definition: fuse_common.h:211
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition: fuse_log.c:33
void fuse_session_destroy(struct fuse_session *se)
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
#define FUSE_ROOT_ID
Definition: fuse_lowlevel.h:43
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
int fuse_reply_err(fuse_req_t req, int err)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
int fuse_reply_readlink(fuse_req_t req, const char *link)
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
void fuse_session_unmount(struct fuse_session *se)
void fuse_cmdline_help(void)
Definition: helper.c:129
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
void fuse_reply_none(fuse_req_t req)
void fuse_lowlevel_help(void)
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
int fuse_reply_write(fuse_req_t req, size_t count)
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
void * fuse_req_userdata(fuse_req_t req)
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
int fuse_reply_lseek(fuse_req_t req, off_t off)
void fuse_lowlevel_version(void)
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
int fuse_reply_xattr(fuse_req_t req, size_t count)
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:34
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:398
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
#define FUSE_OPT_END
Definition: fuse_opt.h:104
int argc
Definition: fuse_opt.h:111
char ** argv
Definition: fuse_opt.h:114
enum fuse_buf_flags flags
Definition: fuse_common.h:711
off_t pos
Definition: fuse_common.h:732
size_t size
Definition: fuse_common.h:706
size_t off
Definition: fuse_common.h:757
struct fuse_buf buf[1]
Definition: fuse_common.h:762
unsigned capable
Definition: fuse_common.h:459
unsigned want
Definition: fuse_common.h:467
Definition: fuse_lowlevel.h:59
double entry_timeout
fuse_ino_t ino
Definition: fuse_lowlevel.h:67
double attr_timeout
Definition: fuse_lowlevel.h:94
struct stat attr
Definition: fuse_lowlevel.h:88
unsigned int direct_io
Definition: fuse_common.h:57
unsigned int keep_cache
Definition: fuse_common.h:64
uint64_t fh
Definition: fuse_common.h:93
unsigned int cache_readdir
Definition: fuse_common.h:84
void(* init)(void *userdata, struct fuse_conn_info *conn)