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