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