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