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